BasiliskII/0000755000175000017500000000000011735677734012765 5ustar centriscentrisBasiliskII/src/0000755000175000017500000000000011735674744013552 5ustar centriscentrisBasiliskII/src/SDL/0000755000175000017500000000000011735674751014172 5ustar centriscentrisBasiliskII/src/SDL/audio_sdl.cpp0000644000175000017500000001714311452741437016637 0ustar centriscentris/* * audio_sdl.cpp - Audio support, SDL implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "audio.h" #include "audio_defs.h" #include #include #define DEBUG 0 #include "debug.h" #if defined(BINCUE) #include "bincue_unix.h" #endif // The currently selected audio parameters (indices in audio_sample_rates[] etc. vectors) static int audio_sample_rate_index = 0; static int audio_sample_size_index = 0; static int audio_channel_count_index = 0; // Global variables static SDL_sem *audio_irq_done_sem = NULL; // Signal from interrupt to streaming thread: data block read static uint8 silence_byte; // Byte value to use to fill sound buffers with silence // Prototypes static void stream_func(void *arg, uint8 *stream, int stream_len); /* * Initialization */ // Set AudioStatus to reflect current audio stream format static void set_audio_status_format(void) { AudioStatus.sample_rate = audio_sample_rates[audio_sample_rate_index]; AudioStatus.sample_size = audio_sample_sizes[audio_sample_size_index]; AudioStatus.channels = audio_channel_counts[audio_channel_count_index]; } // Init SDL audio system static bool open_sdl_audio(void) { // SDL supports a variety of twisted little audio formats, all different if (audio_sample_sizes.empty()) { audio_sample_rates.push_back(11025 << 16); audio_sample_rates.push_back(22050 << 16); audio_sample_rates.push_back(44100 << 16); audio_sample_sizes.push_back(8); audio_sample_sizes.push_back(16); audio_channel_counts.push_back(1); audio_channel_counts.push_back(2); // Default to highest supported values audio_sample_rate_index = audio_sample_rates.size() - 1; audio_sample_size_index = audio_sample_sizes.size() - 1; audio_channel_count_index = audio_channel_counts.size() - 1; } SDL_AudioSpec audio_spec; audio_spec.freq = audio_sample_rates[audio_sample_rate_index] >> 16; audio_spec.format = (audio_sample_sizes[audio_sample_size_index] == 8) ? AUDIO_U8 : AUDIO_S16MSB; audio_spec.channels = audio_channel_counts[audio_channel_count_index]; audio_spec.samples = 4096; audio_spec.callback = stream_func; audio_spec.userdata = NULL; // Open the audio device, forcing the desired format if (SDL_OpenAudio(&audio_spec, NULL) < 0) { fprintf(stderr, "WARNING: Cannot open audio: %s\n", SDL_GetError()); return false; } #if defined(BINCUE) OpenAudio_bincue(audio_spec.freq, audio_spec.format, audio_spec.channels, audio_spec.silence); #endif char driver_name[32]; printf("Using SDL/%s audio output\n", SDL_AudioDriverName(driver_name, sizeof(driver_name) - 1)); silence_byte = audio_spec.silence; SDL_PauseAudio(0); // Sound buffer size = 4096 frames audio_frames_per_block = audio_spec.samples; return true; } static bool open_audio(void) { // Try to open SDL audio if (!open_sdl_audio()) { WarningAlert(GetString(STR_NO_AUDIO_WARN)); return false; } // Device opened, set AudioStatus set_audio_status_format(); // Everything went fine audio_open = true; return true; } void AudioInit(void) { // Init audio status and feature flags AudioStatus.sample_rate = 44100 << 16; AudioStatus.sample_size = 16; AudioStatus.channels = 2; AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; // Init semaphore audio_irq_done_sem = SDL_CreateSemaphore(0); // Open and initialize audio device open_audio(); } /* * Deinitialization */ static void close_audio(void) { // Close audio device SDL_CloseAudio(); audio_open = false; } void AudioExit(void) { // Close audio device close_audio(); // Delete semaphore if (audio_irq_done_sem) SDL_DestroySemaphore(audio_irq_done_sem); } /* * First source added, start audio stream */ void audio_enter_stream() { } /* * Last source removed, stop audio stream */ void audio_exit_stream() { } /* * Streaming function */ static void stream_func(void *arg, uint8 *stream, int stream_len) { if (AudioStatus.num_sources) { // Trigger audio interrupt to get new buffer D(bug("stream: triggering irq\n")); SetInterruptFlag(INTFLAG_AUDIO); TriggerInterrupt(); D(bug("stream: waiting for ack\n")); SDL_SemWait(audio_irq_done_sem); D(bug("stream: ack received\n")); // Get size of audio data uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); if (apple_stream_info) { int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels; D(bug("stream: work_size %d\n", work_size)); if (work_size > stream_len) work_size = stream_len; if (work_size == 0) goto silence; // Send data to audio device Mac2Host_memcpy(stream, ReadMacInt32(apple_stream_info + scd_buffer), work_size); if (work_size != stream_len) memset((uint8 *)stream + work_size, silence_byte, stream_len - work_size); D(bug("stream: data written\n")); } else goto silence; } else { // Audio not active, play silence silence: memset(stream, silence_byte, stream_len); } #if defined(BINCUE) MixAudio_bincue(stream, stream_len); #endif } /* * MacOS audio interrupt, read next data block */ void AudioInterrupt(void) { D(bug("AudioInterrupt\n")); // Get data from apple mixer if (AudioStatus.mixer) { M68kRegisters r; r.a[0] = audio_data + adatStreamInfo; r.a[1] = AudioStatus.mixer; Execute68k(audio_data + adatGetSourceData, &r); D(bug(" GetSourceData() returns %08lx\n", r.d[0])); } else WriteMacInt32(audio_data + adatStreamInfo, 0); // Signal stream function SDL_SemPost(audio_irq_done_sem); D(bug("AudioInterrupt done\n")); } /* * Set sampling parameters * "index" is an index into the audio_sample_rates[] etc. vectors * It is guaranteed that AudioStatus.num_sources == 0 */ bool audio_set_sample_rate(int index) { close_audio(); audio_sample_rate_index = index; return open_audio(); } bool audio_set_sample_size(int index) { close_audio(); audio_sample_size_index = index; return open_audio(); } bool audio_set_channels(int index) { close_audio(); audio_channel_count_index = index; return open_audio(); } /* * Get/set volume controls (volume values received/returned have the left channel * volume in the upper 16 bits and the right channel volume in the lower 16 bits; * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume")) */ bool audio_get_main_mute(void) { return false; } uint32 audio_get_main_volume(void) { return 0x01000100; } bool audio_get_speaker_mute(void) { return false; } uint32 audio_get_speaker_volume(void) { return 0x01000100; } void audio_set_main_mute(bool mute) { } void audio_set_main_volume(uint32 vol) { } void audio_set_speaker_mute(bool mute) { } void audio_set_speaker_volume(uint32 vol) { } BasiliskII/src/SDL/video_sdl.cpp0000644000175000017500000016642611704321416016644 0ustar centriscentris/* * video_sdl.cpp - Video/graphics emulation, SDL specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * NOTES: * The Ctrl key works like a qualifier for special actions: * Ctrl-Tab = suspend DGA mode (TODO) * Ctrl-Esc = emergency quit * Ctrl-F1 = mount floppy * Ctrl-F5 = grab mouse (in windowed mode) * * FIXMEs and TODOs: * - Windows requires an extra mouse event to update the actual cursor image? * - Ctr-Tab for suspend/resume but how? SDL does not support that for non-Linux * - Ctrl-Fn doesn't generate SDL_KEYDOWN events (SDL bug?) * - Mouse acceleration, there is no API in SDL yet for that * - Force relative mode in Grab mode even if SDL provides absolute coordinates? * - Gamma tables support is likely to be broken here * - Events processing is bound to the general emulation thread as SDL requires * to PumpEvents() within the same thread as the one that called SetVideoMode(). * Besides, there can't seem to be a way to call SetVideoMode() from a child thread. * - Backport hw cursor acceleration to Basilisk II? * - Factor out code */ #include "sysdeps.h" #include #include #include #include #include #ifdef WIN32 #include /* alloca() */ #endif #include "cpu_emulation.h" #include "main.h" #include "adb.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "video.h" #include "video_defs.h" #include "video_blit.h" #include "vm_alloc.h" #define DEBUG 0 #include "debug.h" // Supported video modes using std::vector; static vector VideoModes; // Display types #ifdef SHEEPSHAVER enum { DISPLAY_WINDOW = DIS_WINDOW, // windowed display DISPLAY_SCREEN = DIS_SCREEN // fullscreen display }; extern int display_type; // See enum above #else enum { DISPLAY_WINDOW, // windowed display DISPLAY_SCREEN // fullscreen display }; static int display_type = DISPLAY_WINDOW; // See enum above #endif // Constants #ifdef WIN32 const char KEYCODE_FILE_NAME[] = "BasiliskII_keycodes"; #else const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes"; #endif // Global variables static int32 frame_skip; // Prefs items static int16 mouse_wheel_mode; static int16 mouse_wheel_lines; static uint8 *the_buffer = NULL; // Mac frame buffer (where MacOS draws into) static uint8 *the_buffer_copy = NULL; // Copy of Mac frame buffer (for refreshed modes) static uint32 the_buffer_size; // Size of allocated the_buffer static bool redraw_thread_active = false; // Flag: Redraw thread installed #ifndef USE_CPU_EMUL_SERVICES static volatile bool redraw_thread_cancel; // Flag: Cancel Redraw thread static SDL_Thread *redraw_thread = NULL; // Redraw thread #ifdef SHEEPSHAVER static volatile bool thread_stop_req = false; static volatile bool thread_stop_ack = false; // Acknowledge for thread_stop_req #endif #endif #ifdef ENABLE_VOSF static bool use_vosf = false; // Flag: VOSF enabled #else static const bool use_vosf = false; // VOSF not possible #endif static bool ctrl_down = false; // Flag: Ctrl key pressed static bool caps_on = false; // Flag: Caps Lock on static bool quit_full_screen = false; // Flag: DGA close requested from redraw thread static bool emerg_quit = false; // Flag: Ctrl-Esc pressed, emergency quit requested from MacOS thread static bool emul_suspended = false; // Flag: Emulator suspended static bool classic_mode = false; // Flag: Classic Mac video mode static bool use_keycodes = false; // Flag: Use keycodes rather than keysyms static int keycode_table[256]; // X keycode -> Mac keycode translation table // SDL variables static int screen_depth; // Depth of current screen static SDL_Cursor *sdl_cursor; // Copy of Mac cursor static volatile bool cursor_changed = false; // Flag: cursor changed, redraw_func must update the cursor static SDL_Color sdl_palette[256]; // Color palette to be used as CLUT and gamma table static bool sdl_palette_changed = false; // Flag: Palette changed, redraw thread must set new colors static const int sdl_eventmask = SDL_MOUSEEVENTMASK | SDL_KEYEVENTMASK | SDL_VIDEOEXPOSEMASK | SDL_QUITMASK | SDL_ACTIVEEVENTMASK; // Mutex to protect SDL events static SDL_mutex *sdl_events_lock = NULL; #define LOCK_EVENTS SDL_LockMutex(sdl_events_lock) #define UNLOCK_EVENTS SDL_UnlockMutex(sdl_events_lock) // Mutex to protect palette static SDL_mutex *sdl_palette_lock = NULL; #define LOCK_PALETTE SDL_LockMutex(sdl_palette_lock) #define UNLOCK_PALETTE SDL_UnlockMutex(sdl_palette_lock) // Mutex to protect frame buffer static SDL_mutex *frame_buffer_lock = NULL; #define LOCK_FRAME_BUFFER SDL_LockMutex(frame_buffer_lock) #define UNLOCK_FRAME_BUFFER SDL_UnlockMutex(frame_buffer_lock) // Video refresh function static void VideoRefreshInit(void); static void (*video_refresh)(void); // Prototypes static int redraw_func(void *arg); // From sys_unix.cpp extern void SysMountFirstFloppy(void); /* * SDL surface locking glue */ #ifdef ENABLE_VOSF #define SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE) do { \ if ((SURFACE)->flags & (SDL_HWSURFACE | SDL_FULLSCREEN)) \ the_host_buffer = (uint8 *)(SURFACE)->pixels; \ } while (0) #else #define SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE) #endif #define SDL_VIDEO_LOCK_SURFACE(SURFACE) do { \ if (SDL_MUSTLOCK(SURFACE)) { \ SDL_LockSurface(SURFACE); \ SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE); \ } \ } while (0) #define SDL_VIDEO_UNLOCK_SURFACE(SURFACE) do { \ if (SDL_MUSTLOCK(SURFACE)) \ SDL_UnlockSurface(SURFACE); \ } while (0) /* * Framebuffer allocation routines */ static void *vm_acquire_framebuffer(uint32 size) { // always try to reallocate framebuffer at the same address static void *fb = VM_MAP_FAILED; if (fb != VM_MAP_FAILED) { if (vm_acquire_fixed(fb, size) < 0) { #ifndef SHEEPSHAVER printf("FATAL: Could not reallocate framebuffer at previous address\n"); #endif fb = VM_MAP_FAILED; } } if (fb == VM_MAP_FAILED) fb = vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT); return fb; } static inline void vm_release_framebuffer(void *fb, uint32 size) { vm_release(fb, size); } /* * Windows message handler */ #ifdef WIN32 #include static WNDPROC sdl_window_proc = NULL; // Window proc used by SDL extern void SysMediaArrived(void); extern void SysMediaRemoved(void); extern HWND GetMainWindowHandle(void); static LRESULT CALLBACK windows_message_handler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DEVICECHANGE: if (wParam == DBT_DEVICEREMOVECOMPLETE) { DEV_BROADCAST_HDR *p = (DEV_BROADCAST_HDR *)lParam; if (p->dbch_devicetype == DBT_DEVTYP_VOLUME) SysMediaRemoved(); } else if (wParam == DBT_DEVICEARRIVAL) { DEV_BROADCAST_HDR *p = (DEV_BROADCAST_HDR *)lParam; if (p->dbch_devicetype == DBT_DEVTYP_VOLUME) SysMediaArrived(); } return 0; default: if (sdl_window_proc) return CallWindowProc(sdl_window_proc, hwnd, msg, wParam, lParam); } return DefWindowProc(hwnd, msg, wParam, lParam); } #endif /* * SheepShaver glue */ #ifdef SHEEPSHAVER // Color depth modes type typedef int video_depth; // 1, 2, 4 and 8 bit depths use a color palette static inline bool IsDirectMode(VIDEO_MODE const & mode) { return IsDirectMode(mode.viAppleMode); } // Abstract base class representing one (possibly virtual) monitor // ("monitor" = rectangular display with a contiguous frame buffer) class monitor_desc { public: monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id) {} virtual ~monitor_desc() {} // Get current Mac frame buffer base address uint32 get_mac_frame_base(void) const {return screen_base;} // Set Mac frame buffer base address (called from switch_to_mode()) void set_mac_frame_base(uint32 base) {screen_base = base;} // Get current video mode const VIDEO_MODE &get_current_mode(void) const {return VModes[cur_mode];} // Called by the video driver to switch the video mode on this display // (must call set_mac_frame_base()) virtual void switch_to_current_mode(void) = 0; // Called by the video driver to set the color palette (in indexed modes) // or the gamma table (in direct modes) virtual void set_palette(uint8 *pal, int num) = 0; }; // Vector of pointers to available monitor descriptions, filled by VideoInit() static vector VideoMonitors; // Find Apple mode matching best specified dimensions static int find_apple_resolution(int xsize, int ysize) { if (xsize == 640 && ysize == 480) return APPLE_640x480; if (xsize == 800 && ysize == 600) return APPLE_800x600; if (xsize == 1024 && ysize == 768) return APPLE_1024x768; if (xsize == 1152 && ysize == 768) return APPLE_1152x768; if (xsize == 1152 && ysize == 900) return APPLE_1152x900; if (xsize == 1280 && ysize == 1024) return APPLE_1280x1024; if (xsize == 1600 && ysize == 1200) return APPLE_1600x1200; return APPLE_CUSTOM; } // Display error alert static void ErrorAlert(int error) { ErrorAlert(GetString(error)); } // Display warning alert static void WarningAlert(int warning) { WarningAlert(GetString(warning)); } #endif /* * monitor_desc subclass for SDL display */ class SDL_monitor_desc : public monitor_desc { public: SDL_monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id) : monitor_desc(available_modes, default_depth, default_id) {} ~SDL_monitor_desc() {} virtual void switch_to_current_mode(void); virtual void set_palette(uint8 *pal, int num); bool video_open(void); void video_close(void); }; /* * Utility functions */ // Find palette size for given color depth static int palette_size(int mode) { switch (mode) { case VIDEO_DEPTH_1BIT: return 2; case VIDEO_DEPTH_2BIT: return 4; case VIDEO_DEPTH_4BIT: return 16; case VIDEO_DEPTH_8BIT: return 256; case VIDEO_DEPTH_16BIT: return 32; case VIDEO_DEPTH_32BIT: return 256; default: return 0; } } // Return bytes per pixel for requested depth static inline int bytes_per_pixel(int depth) { int bpp; switch (depth) { case 8: bpp = 1; break; case 15: case 16: bpp = 2; break; case 24: case 32: bpp = 4; break; default: abort(); } return bpp; } // Map video_mode depth ID to numerical depth value static int mac_depth_of_video_depth(int video_depth) { int depth = -1; switch (video_depth) { case VIDEO_DEPTH_1BIT: depth = 1; break; case VIDEO_DEPTH_2BIT: depth = 2; break; case VIDEO_DEPTH_4BIT: depth = 4; break; case VIDEO_DEPTH_8BIT: depth = 8; break; case VIDEO_DEPTH_16BIT: depth = 16; break; case VIDEO_DEPTH_32BIT: depth = 32; break; default: abort(); } return depth; } // Map video_mode depth ID to SDL screen depth static int sdl_depth_of_video_depth(int video_depth) { return (video_depth <= VIDEO_DEPTH_8BIT) ? 8 : mac_depth_of_video_depth(video_depth); } // Get screen dimensions static void sdl_display_dimensions(int &width, int &height) { static int max_width, max_height; if (max_width == 0 && max_height == 0) { max_width = 640 ; max_height = 480; SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); if (modes && modes != (SDL_Rect **)-1) { // It turns out that on some implementations, and contrary to the documentation, // the returned list is not sorted from largest to smallest (e.g. Windows) for (int i = 0; modes[i] != NULL; i++) { const int w = modes[i]->w; const int h = modes[i]->h; if (w > max_width && h > max_height) { max_width = w; max_height = h; } } } } width = max_width; height = max_height; } static inline int sdl_display_width(void) { int width, height; sdl_display_dimensions(width, height); return width; } static inline int sdl_display_height(void) { int width, height; sdl_display_dimensions(width, height); return height; } // Check wether specified mode is available static bool has_mode(int type, int width, int height, int depth) { #ifdef SHEEPSHAVER // Filter out Classic resolutions if (width == 512 && height == 384) return false; #endif // Filter out out-of-bounds resolutions if (width > sdl_display_width() || height > sdl_display_height()) return false; // Rely on SDL capabilities return SDL_VideoModeOK(width, height, sdl_depth_of_video_depth(depth), SDL_HWSURFACE | (type == DISPLAY_SCREEN ? SDL_FULLSCREEN : 0)); } // Add mode to list of supported modes static void add_mode(int type, int width, int height, int resolution_id, int bytes_per_row, int depth) { // Filter out unsupported modes if (!has_mode(type, width, height, depth)) return; // Fill in VideoMode entry VIDEO_MODE mode; #ifdef SHEEPSHAVER resolution_id = find_apple_resolution(width, height); mode.viType = type; #endif VIDEO_MODE_X = width; VIDEO_MODE_Y = height; VIDEO_MODE_RESOLUTION = resolution_id; VIDEO_MODE_ROW_BYTES = bytes_per_row; VIDEO_MODE_DEPTH = (video_depth)depth; VideoModes.push_back(mode); } // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac) static void set_mac_frame_buffer(SDL_monitor_desc &monitor, int depth, bool native_byte_order) { #if !REAL_ADDRESSING && !DIRECT_ADDRESSING int layout = FLAYOUT_DIRECT; if (depth == VIDEO_DEPTH_16BIT) layout = (screen_depth == 15) ? FLAYOUT_HOST_555 : FLAYOUT_HOST_565; else if (depth == VIDEO_DEPTH_32BIT) layout = (screen_depth == 24) ? FLAYOUT_HOST_888 : FLAYOUT_DIRECT; if (native_byte_order) MacFrameLayout = layout; else MacFrameLayout = FLAYOUT_DIRECT; monitor.set_mac_frame_base(MacFrameBaseMac); // Set variables used by UAE memory banking const VIDEO_MODE &mode = monitor.get_current_mode(); MacFrameBaseHost = the_buffer; MacFrameSize = VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y; InitFrameBufferMapping(); #else monitor.set_mac_frame_base(Host2MacAddr(the_buffer)); #endif D(bug("monitor.mac_frame_base = %08x\n", monitor.get_mac_frame_base())); } // Set window name and class static void set_window_name(int name) { const SDL_VideoInfo *vi = SDL_GetVideoInfo(); if (vi && vi->wm_available) { const char *str = GetString(name); SDL_WM_SetCaption(str, str); } } // Set mouse grab mode static SDL_GrabMode set_grab_mode(SDL_GrabMode mode) { const SDL_VideoInfo *vi = SDL_GetVideoInfo(); return (vi && vi->wm_available ? SDL_WM_GrabInput(mode) : SDL_GRAB_OFF); } // Migrate preferences items (XXX to be handled in MigratePrefs()) static void migrate_screen_prefs(void) { #ifdef SHEEPSHAVER // Look-up priorities are: "screen", "screenmodes", "windowmodes". if (PrefsFindString("screen")) return; uint32 window_modes = PrefsFindInt32("windowmodes"); uint32 screen_modes = PrefsFindInt32("screenmodes"); int width = 0, height = 0; if (screen_modes) { static const struct { int id; int width; int height; } modes[] = { { 1, 640, 480 }, { 2, 800, 600 }, { 4, 1024, 768 }, { 64, 1152, 768 }, { 8, 1152, 900 }, { 16, 1280, 1024 }, { 32, 1600, 1200 }, { 0, } }; for (int i = 0; modes[i].id != 0; i++) { if (screen_modes & modes[i].id) { if (width < modes[i].width && height < modes[i].height) { width = modes[i].width; height = modes[i].height; } } } } else { if (window_modes & 1) width = 640, height = 480; if (window_modes & 2) width = 800, height = 600; } if (width && height) { char str[32]; sprintf(str, "%s/%d/%d", screen_modes ? "dga" : "win", width, height); PrefsReplaceString("screen", str); } #endif } /* * Display "driver" classes */ class driver_base { public: driver_base(SDL_monitor_desc &m); virtual ~driver_base(); virtual void update_palette(void); virtual void suspend(void) {} virtual void resume(void) {} virtual void toggle_mouse_grab(void) {} virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); } void disable_mouse_accel(void); void restore_mouse_accel(void); virtual void grab_mouse(void) {} virtual void ungrab_mouse(void) {} public: SDL_monitor_desc &monitor; // Associated video monitor const VIDEO_MODE &mode; // Video mode handled by the driver bool init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer) SDL_Surface *s; // The surface we draw into }; class driver_window; #ifdef ENABLE_VOSF static void update_display_window_vosf(driver_window *drv); #endif static void update_display_static(driver_base *drv); class driver_window : public driver_base { #ifdef ENABLE_VOSF friend void update_display_window_vosf(driver_window *drv); #endif friend void update_display_static(driver_base *drv); public: driver_window(SDL_monitor_desc &monitor); ~driver_window(); void toggle_mouse_grab(void); void mouse_moved(int x, int y); void grab_mouse(void); void ungrab_mouse(void); private: bool mouse_grabbed; // Flag: mouse pointer grabbed, using relative mouse mode int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode) }; class driver_fullscreen : public driver_base { public: driver_fullscreen(SDL_monitor_desc &monitor); ~driver_fullscreen(); }; static driver_base *drv = NULL; // Pointer to currently used driver object #ifdef ENABLE_VOSF # include "video_vosf.h" #endif driver_base::driver_base(SDL_monitor_desc &m) : monitor(m), mode(m.get_current_mode()), init_ok(false), s(NULL) { the_buffer = NULL; the_buffer_copy = NULL; } driver_base::~driver_base() { ungrab_mouse(); restore_mouse_accel(); if (s) SDL_FreeSurface(s); // the_buffer shall always be mapped through vm_acquire_framebuffer() if (the_buffer != VM_MAP_FAILED) { D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size)); vm_release_framebuffer(the_buffer, the_buffer_size); the_buffer = NULL; } // Free frame buffer(s) if (!use_vosf) { if (the_buffer_copy) { free(the_buffer_copy); the_buffer_copy = NULL; } } #ifdef ENABLE_VOSF else { if (the_host_buffer) { D(bug(" freeing the_host_buffer at %p\n", the_host_buffer)); free(the_host_buffer); the_host_buffer = NULL; } if (the_buffer_copy) { D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy)); free(the_buffer_copy); the_buffer_copy = NULL; } // Deinitialize VOSF video_vosf_exit(); } #endif } // Palette has changed void driver_base::update_palette(void) { const VIDEO_MODE &mode = monitor.get_current_mode(); if ((int)VIDEO_MODE_DEPTH <= VIDEO_DEPTH_8BIT) SDL_SetPalette(s, SDL_PHYSPAL, sdl_palette, 0, 256); } // Disable mouse acceleration void driver_base::disable_mouse_accel(void) { } // Restore mouse acceleration to original value void driver_base::restore_mouse_accel(void) { } /* * Windowed display driver */ static bool SDL_display_opened = false; // Open display driver_window::driver_window(SDL_monitor_desc &m) : driver_base(m), mouse_grabbed(false) { int width = VIDEO_MODE_X, height = VIDEO_MODE_Y; int aligned_height = (height + 15) & ~15; // Set absolute mouse mode ADBSetRelMouseMode(mouse_grabbed); // This is ugly: // If we're switching resolutions (ie, not setting it for the first time), // there's a bug in SDL where the SDL_Surface created will not be properly // setup. The solution is to SDL_QuitSubSystem(SDL_INIT_VIDEO) before calling // SDL_SetVideoMode for the second time (SDL_SetVideoMode will call SDL_Init() // and all will be well). Without this, the video becomes corrupted (at least // on Mac OS X), after the resolution switch. if (SDL_display_opened) SDL_QuitSubSystem(SDL_INIT_VIDEO); // Create surface int depth = sdl_depth_of_video_depth(VIDEO_MODE_DEPTH); if ((s = SDL_SetVideoMode(width, height, depth, SDL_HWSURFACE)) == NULL) return; SDL_display_opened = true; #ifdef ENABLE_VOSF use_vosf = true; // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = (uint8 *)s->pixels; the_buffer_size = page_extend((aligned_height + 2) * s->pitch); the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size); the_buffer_copy = (uint8 *)malloc(the_buffer_size); D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer)); // Check whether we can initialize the VOSF subsystem and it's profitable if (!video_vosf_init(m)) { WarningAlert(STR_VOSF_INIT_ERR); use_vosf = false; } else if (!video_vosf_profitable()) { video_vosf_exit(); printf("VOSF acceleration is not profitable on this platform, disabling it\n"); use_vosf = false; } if (!use_vosf) { free(the_buffer_copy); vm_release(the_buffer, the_buffer_size); the_host_buffer = NULL; } #endif if (!use_vosf) { // Allocate memory for frame buffer the_buffer_size = (aligned_height + 2) * s->pitch; the_buffer_copy = (uint8 *)calloc(1, the_buffer_size); the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size); D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy)); } #ifdef SHEEPSHAVER // Create cursor if ((sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, 0, 0)) != NULL) { SDL_SetCursor(sdl_cursor); cursor_changed = false; } #else // Hide cursor SDL_ShowCursor(0); #endif // Set window name/class set_window_name(STR_WINDOW_TITLE); // Init blitting routines SDL_PixelFormat *f = s->format; VisualFormat visualFormat; visualFormat.depth = depth; visualFormat.Rmask = f->Rmask; visualFormat.Gmask = f->Gmask; visualFormat.Bmask = f->Bmask; Screen_blitter_init(visualFormat, true, mac_depth_of_video_depth(VIDEO_MODE_DEPTH)); // Load gray ramp to 8->16/32 expand map if (!IsDirectMode(mode)) for (int i=0; i<256; i++) ExpandMap[i] = SDL_MapRGB(f, i, i, i); // Set frame buffer base set_mac_frame_buffer(monitor, VIDEO_MODE_DEPTH, true); // Everything went well init_ok = true; } // Close display driver_window::~driver_window() { #ifdef ENABLE_VOSF if (use_vosf) the_host_buffer = NULL; // don't free() in driver_base dtor #endif if (s) SDL_FreeSurface(s); } // Toggle mouse grab void driver_window::toggle_mouse_grab(void) { if (mouse_grabbed) ungrab_mouse(); else grab_mouse(); } // Grab mouse, switch to relative mouse mode void driver_window::grab_mouse(void) { if (!mouse_grabbed) { SDL_GrabMode new_mode = set_grab_mode(SDL_GRAB_ON); if (new_mode == SDL_GRAB_ON) { set_window_name(STR_WINDOW_TITLE_GRABBED); disable_mouse_accel(); mouse_grabbed = true; } } } // Ungrab mouse, switch to absolute mouse mode void driver_window::ungrab_mouse(void) { if (mouse_grabbed) { SDL_GrabMode new_mode = set_grab_mode(SDL_GRAB_OFF); if (new_mode == SDL_GRAB_OFF) { set_window_name(STR_WINDOW_TITLE); restore_mouse_accel(); mouse_grabbed = false; } } } // Mouse moved void driver_window::mouse_moved(int x, int y) { mouse_last_x = x; mouse_last_y = y; ADBMouseMoved(x, y); } /* * Full-screen display driver */ // Open display driver_fullscreen::driver_fullscreen(SDL_monitor_desc &m) : driver_base(m) { int width = VIDEO_MODE_X, height = VIDEO_MODE_Y; int aligned_height = (height + 15) & ~15; // Set absolute mouse mode ADBSetRelMouseMode(false); // Create surface int depth = sdl_depth_of_video_depth(VIDEO_MODE_DEPTH); if ((s = SDL_SetVideoMode(width, height, depth, SDL_HWSURFACE | SDL_FULLSCREEN)) == NULL) return; #ifdef ENABLE_VOSF use_vosf = true; // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = (uint8 *)s->pixels; the_buffer_size = page_extend((aligned_height + 2) * s->pitch); the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size); the_buffer_copy = (uint8 *)malloc(the_buffer_size); D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer)); // Check whether we can initialize the VOSF subsystem and it's profitable if (!video_vosf_init(m)) { WarningAlert(STR_VOSF_INIT_ERR); use_vosf = false; } else if (!video_vosf_profitable()) { video_vosf_exit(); printf("VOSF acceleration is not profitable on this platform, disabling it\n"); use_vosf = false; } if (!use_vosf) { free(the_buffer_copy); vm_release(the_buffer, the_buffer_size); the_host_buffer = NULL; } #endif if (!use_vosf) { // Allocate memory for frame buffer the_buffer_size = (aligned_height + 2) * s->pitch; the_buffer_copy = (uint8 *)calloc(1, the_buffer_size); the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size); D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy)); } // Hide cursor SDL_ShowCursor(0); // Init blitting routines SDL_PixelFormat *f = s->format; VisualFormat visualFormat; visualFormat.depth = depth; visualFormat.Rmask = f->Rmask; visualFormat.Gmask = f->Gmask; visualFormat.Bmask = f->Bmask; Screen_blitter_init(visualFormat, true, mac_depth_of_video_depth(VIDEO_MODE_DEPTH)); // Load gray ramp to 8->16/32 expand map if (!IsDirectMode(mode)) for (int i=0; i<256; i++) ExpandMap[i] = SDL_MapRGB(f, i, i, i); // Set frame buffer base set_mac_frame_buffer(monitor, VIDEO_MODE_DEPTH, true); // Everything went well init_ok = true; } // Close display driver_fullscreen::~driver_fullscreen() { #ifdef ENABLE_VOSF if (use_vosf) the_host_buffer = NULL; // don't free() in driver_base dtor #endif if (s) SDL_FreeSurface(s); // Show cursor SDL_ShowCursor(1); } /* * Initialization */ // Init keycode translation table static void keycode_init(void) { bool use_kc = PrefsFindBool("keycodes"); if (use_kc) { // Get keycode file path from preferences const char *kc_path = PrefsFindString("keycodefile"); // Open keycode table FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r"); if (f == NULL) { char str[256]; sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno)); WarningAlert(str); return; } // Default translation table for (int i=0; i<256; i++) keycode_table[i] = -1; // Search for server vendor string, then read keycodes char video_driver[256]; SDL_VideoDriverName(video_driver, sizeof(video_driver)); bool video_driver_found = false; char line[256]; int n_keys = 0; while (fgets(line, sizeof(line) - 1, f)) { // Read line int len = strlen(line); if (len == 0) continue; line[len-1] = 0; // Comments begin with "#" or ";" if (line[0] == '#' || line[0] == ';' || line[0] == 0) continue; if (video_driver_found) { // Skip aliases as long as we have read keycodes yet // Otherwise, it's another mapping and we have to stop static const char sdl_str[] = "sdl"; if (strncmp(line, sdl_str, sizeof(sdl_str) - 1) == 0 && n_keys == 0) continue; // Read keycode int x_code, mac_code; if (sscanf(line, "%d %d", &x_code, &mac_code) == 2) keycode_table[x_code & 0xff] = mac_code, n_keys++; else break; } else { // Search for SDL video driver string static const char sdl_str[] = "sdl"; if (strncmp(line, sdl_str, sizeof(sdl_str) - 1) == 0) { char *p = line + sizeof(sdl_str); if (strstr(video_driver, p) == video_driver) video_driver_found = true; } } } // Keycode file completely read fclose(f); use_keycodes = video_driver_found; // Vendor not found? Then display warning if (!video_driver_found) { char str[256]; sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), video_driver, kc_path ? kc_path : KEYCODE_FILE_NAME); WarningAlert(str); return; } D(bug("Using SDL/%s keycodes table, %d key mappings\n", video_driver, n_keys)); } } // Open display for current mode bool SDL_monitor_desc::video_open(void) { D(bug("video_open()\n")); #if DEBUG const VIDEO_MODE &mode = get_current_mode(); D(bug("Current video mode:\n")); D(bug(" %dx%d (ID %02x), %d bpp\n", VIDEO_MODE_X, VIDEO_MODE_Y, VIDEO_MODE_RESOLUTION, 1 << (VIDEO_MODE_DEPTH & 0x0f))); #endif // Create display driver object of requested type switch (display_type) { case DISPLAY_WINDOW: drv = new(std::nothrow) driver_window(*this); break; case DISPLAY_SCREEN: drv = new(std::nothrow) driver_fullscreen(*this); break; } if (drv == NULL) return false; if (!drv->init_ok) { delete drv; drv = NULL; return false; } #ifdef WIN32 // Chain in a new message handler for WM_DEVICECHANGE HWND the_window = GetMainWindowHandle(); sdl_window_proc = (WNDPROC)GetWindowLongPtr(the_window, GWLP_WNDPROC); SetWindowLongPtr(the_window, GWLP_WNDPROC, (LONG_PTR)windows_message_handler); #endif // Initialize VideoRefresh function VideoRefreshInit(); // Lock down frame buffer LOCK_FRAME_BUFFER; // Start redraw/input thread #ifndef USE_CPU_EMUL_SERVICES redraw_thread_cancel = false; redraw_thread_active = ((redraw_thread = SDL_CreateThread(redraw_func, NULL)) != NULL); if (!redraw_thread_active) { printf("FATAL: cannot create redraw thread\n"); return false; } #else redraw_thread_active = true; #endif return true; } #ifdef SHEEPSHAVER bool VideoInit(void) { const bool classic = false; #else bool VideoInit(bool classic) { #endif classic_mode = classic; #ifdef ENABLE_VOSF // Zero the mainBuffer structure mainBuffer.dirtyPages = NULL; mainBuffer.pageInfo = NULL; #endif // Create Mutexes if ((sdl_events_lock = SDL_CreateMutex()) == NULL) return false; if ((sdl_palette_lock = SDL_CreateMutex()) == NULL) return false; if ((frame_buffer_lock = SDL_CreateMutex()) == NULL) return false; // Init keycode translation keycode_init(); // Read prefs frame_skip = PrefsFindInt32("frameskip"); mouse_wheel_mode = PrefsFindInt32("mousewheelmode"); mouse_wheel_lines = PrefsFindInt32("mousewheellines"); // Get screen mode from preferences migrate_screen_prefs(); const char *mode_str = NULL; if (classic_mode) mode_str = "win/512/342"; else mode_str = PrefsFindString("screen"); // Determine display type and default dimensions int default_width, default_height; if (classic) { default_width = 512; default_height = 384; } else { default_width = 640; default_height = 480; } display_type = DISPLAY_WINDOW; if (mode_str) { if (sscanf(mode_str, "win/%d/%d", &default_width, &default_height) == 2) display_type = DISPLAY_WINDOW; else if (sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2) display_type = DISPLAY_SCREEN; } if (default_width <= 0) default_width = sdl_display_width(); else if (default_width > sdl_display_width()) default_width = sdl_display_width(); if (default_height <= 0) default_height = sdl_display_height(); else if (default_height > sdl_display_height()) default_height = sdl_display_height(); // Mac screen depth follows X depth screen_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel; int default_depth; switch (screen_depth) { case 8: default_depth = VIDEO_DEPTH_8BIT; break; case 15: case 16: default_depth = VIDEO_DEPTH_16BIT; break; case 24: case 32: default_depth = VIDEO_DEPTH_32BIT; break; default: default_depth = VIDEO_DEPTH_1BIT; break; } // Initialize list of video modes to try struct { int w; int h; int resolution_id; } video_modes[] = { { -1, -1, 0x80 }, { 512, 384, 0x80 }, { 640, 480, 0x81 }, { 800, 600, 0x82 }, { 1024, 768, 0x83 }, { 1152, 870, 0x84 }, { 1280, 1024, 0x85 }, { 1600, 1200, 0x86 }, { 0, } }; video_modes[0].w = default_width; video_modes[0].h = default_height; // Construct list of supported modes if (display_type == DISPLAY_WINDOW) { if (classic) add_mode(display_type, 512, 342, 0x80, 64, VIDEO_DEPTH_1BIT); else { for (int i = 0; video_modes[i].w != 0; i++) { const int w = video_modes[i].w; const int h = video_modes[i].h; if (i > 0 && (w >= default_width || h >= default_height)) continue; for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d); } } } else if (display_type == DISPLAY_SCREEN) { for (int i = 0; video_modes[i].w != 0; i++) { const int w = video_modes[i].w; const int h = video_modes[i].h; if (i > 0 && (w >= default_width || h >= default_height)) continue; if (w == 512 && h == 384) continue; for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d); } } if (VideoModes.empty()) { ErrorAlert(STR_NO_XVISUAL_ERR); return false; } // Find requested default mode with specified dimensions uint32 default_id; std::vector::const_iterator i, end = VideoModes.end(); for (i = VideoModes.begin(); i != end; ++i) { const VIDEO_MODE & mode = (*i); if (VIDEO_MODE_X == default_width && VIDEO_MODE_Y == default_height && VIDEO_MODE_DEPTH == default_depth) { default_id = VIDEO_MODE_RESOLUTION; #ifdef SHEEPSHAVER std::vector::const_iterator begin = VideoModes.begin(); cur_mode = distance(begin, i); #endif break; } } if (i == end) { // not found, use first available mode const VIDEO_MODE & mode = VideoModes[0]; default_depth = VIDEO_MODE_DEPTH; default_id = VIDEO_MODE_RESOLUTION; #ifdef SHEEPSHAVER cur_mode = 0; #endif } #ifdef SHEEPSHAVER for (int i = 0; i < VideoModes.size(); i++) VModes[i] = VideoModes[i]; VideoInfo *p = &VModes[VideoModes.size()]; p->viType = DIS_INVALID; // End marker p->viRowBytes = 0; p->viXsize = p->viYsize = 0; p->viAppleMode = 0; p->viAppleID = 0; #endif #if DEBUG D(bug("Available video modes:\n")); for (i = VideoModes.begin(); i != end; ++i) { const VIDEO_MODE & mode = (*i); int bits = 1 << VIDEO_MODE_DEPTH; if (bits == 16) bits = 15; else if (bits == 32) bits = 24; D(bug(" %dx%d (ID %02x), %d colors\n", VIDEO_MODE_X, VIDEO_MODE_Y, VIDEO_MODE_RESOLUTION, 1 << bits)); } #endif // Create SDL_monitor_desc for this (the only) display SDL_monitor_desc *monitor = new SDL_monitor_desc(VideoModes, (video_depth)default_depth, default_id); VideoMonitors.push_back(monitor); // Open display return monitor->video_open(); } /* * Deinitialization */ // Close display void SDL_monitor_desc::video_close(void) { D(bug("video_close()\n")); #ifdef WIN32 // Remove message handler for WM_DEVICECHANGE HWND the_window = GetMainWindowHandle(); SetWindowLongPtr(the_window, GWLP_WNDPROC, (LONG_PTR)sdl_window_proc); #endif // Stop redraw thread #ifndef USE_CPU_EMUL_SERVICES if (redraw_thread_active) { redraw_thread_cancel = true; SDL_WaitThread(redraw_thread, NULL); } #endif redraw_thread_active = false; // Unlock frame buffer UNLOCK_FRAME_BUFFER; D(bug(" frame buffer unlocked\n")); // Close display delete drv; drv = NULL; } void VideoExit(void) { // Close displays vector::iterator i, end = VideoMonitors.end(); for (i = VideoMonitors.begin(); i != end; ++i) dynamic_cast(*i)->video_close(); // Destroy locks if (frame_buffer_lock) SDL_DestroyMutex(frame_buffer_lock); if (sdl_palette_lock) SDL_DestroyMutex(sdl_palette_lock); if (sdl_events_lock) SDL_DestroyMutex(sdl_events_lock); } /* * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode) */ void VideoQuitFullScreen(void) { D(bug("VideoQuitFullScreen()\n")); quit_full_screen = true; } /* * Mac VBL interrupt */ /* * Execute video VBL routine */ #ifdef SHEEPSHAVER void VideoVBL(void) { // Emergency quit requested? Then quit if (emerg_quit) QuitEmulator(); // Temporarily give up frame buffer lock (this is the point where // we are suspended when the user presses Ctrl-Tab) UNLOCK_FRAME_BUFFER; LOCK_FRAME_BUFFER; // Execute video VBL if (private_data != NULL && private_data->interruptsEnabled) VSLDoInterruptService(private_data->vslServiceID); } #else void VideoInterrupt(void) { // We must fill in the events queue in the same thread that did call SDL_SetVideoMode() SDL_PumpEvents(); // Emergency quit requested? Then quit if (emerg_quit) QuitEmulator(); // Temporarily give up frame buffer lock (this is the point where // we are suspended when the user presses Ctrl-Tab) UNLOCK_FRAME_BUFFER; LOCK_FRAME_BUFFER; } #endif /* * Set palette */ #ifdef SHEEPSHAVER void video_set_palette(void) { monitor_desc * monitor = VideoMonitors[0]; int n_colors = palette_size(monitor->get_current_mode().viAppleMode); uint8 pal[256 * 3]; for (int c = 0; c < n_colors; c++) { pal[c*3 + 0] = mac_pal[c].red; pal[c*3 + 1] = mac_pal[c].green; pal[c*3 + 2] = mac_pal[c].blue; } monitor->set_palette(pal, n_colors); } #endif void SDL_monitor_desc::set_palette(uint8 *pal, int num_in) { const VIDEO_MODE &mode = get_current_mode(); // FIXME: how can we handle the gamma ramp? if ((int)VIDEO_MODE_DEPTH > VIDEO_DEPTH_8BIT) return; LOCK_PALETTE; // Convert colors to XColor array int num_out = 256; bool stretch = false; SDL_Color *p = sdl_palette; for (int i=0; ir = pal[c*3 + 0] * 0x0101; p->g = pal[c*3 + 1] * 0x0101; p->b = pal[c*3 + 2] * 0x0101; p++; } // Recalculate pixel color expansion map if (!IsDirectMode(mode)) { for (int i=0; i<256; i++) { int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier) ExpandMap[i] = SDL_MapRGB(drv->s->format, pal[c*3+0], pal[c*3+1], pal[c*3+2]); } #ifdef ENABLE_VOSF if (use_vosf) { // We have to redraw everything because the interpretation of pixel values changed LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y); } #endif } // Tell redraw thread to change palette sdl_palette_changed = true; UNLOCK_PALETTE; } /* * Switch video mode */ #ifdef SHEEPSHAVER int16 video_mode_change(VidLocals *csSave, uint32 ParamPtr) { /* return if no mode change */ if ((csSave->saveData == ReadMacInt32(ParamPtr + csData)) && (csSave->saveMode == ReadMacInt16(ParamPtr + csMode))) return noErr; /* first find video mode in table */ for (int i=0; VModes[i].viType != DIS_INVALID; i++) { if ((ReadMacInt16(ParamPtr + csMode) == VModes[i].viAppleMode) && (ReadMacInt32(ParamPtr + csData) == VModes[i].viAppleID)) { csSave->saveMode = ReadMacInt16(ParamPtr + csMode); csSave->saveData = ReadMacInt32(ParamPtr + csData); csSave->savePage = ReadMacInt16(ParamPtr + csPage); // Disable interrupts and pause redraw thread DisableInterrupt(); thread_stop_ack = false; thread_stop_req = true; while (!thread_stop_ack) ; cur_mode = i; monitor_desc *monitor = VideoMonitors[0]; monitor->switch_to_current_mode(); WriteMacInt32(ParamPtr + csBaseAddr, screen_base); csSave->saveBaseAddr=screen_base; csSave->saveData=VModes[cur_mode].viAppleID;/* First mode ... */ csSave->saveMode=VModes[cur_mode].viAppleMode; // Enable interrupts and resume redraw thread thread_stop_req = false; EnableInterrupt(); return noErr; } } return paramErr; } #endif void SDL_monitor_desc::switch_to_current_mode(void) { // Close and reopen display LOCK_EVENTS; video_close(); video_open(); UNLOCK_EVENTS; if (drv == NULL) { ErrorAlert(STR_OPEN_WINDOW_ERR); QuitEmulator(); } } /* * Can we set the MacOS cursor image into the window? */ #ifdef SHEEPSHAVER bool video_can_change_cursor(void) { static char driver[] = "Quartz?"; static int quartzok = -1; if (display_type != DISPLAY_WINDOW) return false; if (quartzok < 0) { if (SDL_VideoDriverName(driver, sizeof driver) == NULL || strncmp(driver, "Quartz", sizeof driver)) quartzok = true; else { // Quartz driver bug prevents cursor changing in SDL 1.2.11 to 1.2.14. const SDL_version *vp = SDL_Linked_Version(); int version = SDL_VERSIONNUM(vp->major, vp->minor, vp->patch); quartzok = (version <= SDL_VERSIONNUM(1, 2, 10) || version >= SDL_VERSIONNUM(1, 2, 15)); } } return quartzok; } #endif /* * Set cursor image for window */ #ifdef SHEEPSHAVER void video_set_cursor(void) { cursor_changed = true; } #endif /* * Keyboard-related utilify functions */ static bool is_modifier_key(SDL_KeyboardEvent const & e) { switch (e.keysym.sym) { case SDLK_NUMLOCK: case SDLK_CAPSLOCK: case SDLK_SCROLLOCK: case SDLK_RSHIFT: case SDLK_LSHIFT: case SDLK_RCTRL: case SDLK_LCTRL: case SDLK_RALT: case SDLK_LALT: case SDLK_RMETA: case SDLK_LMETA: case SDLK_LSUPER: case SDLK_RSUPER: case SDLK_MODE: case SDLK_COMPOSE: return true; } return false; } static bool is_ctrl_down(SDL_keysym const & ks) { return ctrl_down || (ks.mod & KMOD_CTRL); } /* * Translate key event to Mac keycode, returns -1 if no keycode was found * and -2 if the key was recognized as a hotkey */ static int kc_decode(SDL_keysym const & ks, bool key_down) { switch (ks.sym) { case SDLK_a: return 0x00; case SDLK_b: return 0x0b; case SDLK_c: return 0x08; case SDLK_d: return 0x02; case SDLK_e: return 0x0e; case SDLK_f: return 0x03; case SDLK_g: return 0x05; case SDLK_h: return 0x04; case SDLK_i: return 0x22; case SDLK_j: return 0x26; case SDLK_k: return 0x28; case SDLK_l: return 0x25; case SDLK_m: return 0x2e; case SDLK_n: return 0x2d; case SDLK_o: return 0x1f; case SDLK_p: return 0x23; case SDLK_q: return 0x0c; case SDLK_r: return 0x0f; case SDLK_s: return 0x01; case SDLK_t: return 0x11; case SDLK_u: return 0x20; case SDLK_v: return 0x09; case SDLK_w: return 0x0d; case SDLK_x: return 0x07; case SDLK_y: return 0x10; case SDLK_z: return 0x06; case SDLK_1: case SDLK_EXCLAIM: return 0x12; case SDLK_2: case SDLK_AT: return 0x13; case SDLK_3: case SDLK_HASH: return 0x14; case SDLK_4: case SDLK_DOLLAR: return 0x15; case SDLK_5: return 0x17; case SDLK_6: return 0x16; case SDLK_7: return 0x1a; case SDLK_8: return 0x1c; case SDLK_9: return 0x19; case SDLK_0: return 0x1d; case SDLK_BACKQUOTE: return 0x0a; case SDLK_MINUS: case SDLK_UNDERSCORE: return 0x1b; case SDLK_EQUALS: case SDLK_PLUS: return 0x18; case SDLK_LEFTBRACKET: return 0x21; case SDLK_RIGHTBRACKET: return 0x1e; case SDLK_BACKSLASH: return 0x2a; case SDLK_SEMICOLON: case SDLK_COLON: return 0x29; case SDLK_QUOTE: case SDLK_QUOTEDBL: return 0x27; case SDLK_COMMA: case SDLK_LESS: return 0x2b; case SDLK_PERIOD: case SDLK_GREATER: return 0x2f; case SDLK_SLASH: case SDLK_QUESTION: return 0x2c; case SDLK_TAB: if (is_ctrl_down(ks)) {if (!key_down) drv->suspend(); return -2;} else return 0x30; case SDLK_RETURN: return 0x24; case SDLK_SPACE: return 0x31; case SDLK_BACKSPACE: return 0x33; case SDLK_DELETE: return 0x75; case SDLK_INSERT: return 0x72; case SDLK_HOME: case SDLK_HELP: return 0x73; case SDLK_END: return 0x77; case SDLK_PAGEUP: return 0x74; case SDLK_PAGEDOWN: return 0x79; case SDLK_LCTRL: return 0x36; case SDLK_RCTRL: return 0x36; case SDLK_LSHIFT: return 0x38; case SDLK_RSHIFT: return 0x38; #if (defined(__APPLE__) && defined(__MACH__)) case SDLK_LALT: return 0x3a; case SDLK_RALT: return 0x3a; case SDLK_LMETA: return 0x37; case SDLK_RMETA: return 0x37; #else case SDLK_LALT: return 0x37; case SDLK_RALT: return 0x37; case SDLK_LMETA: return 0x3a; case SDLK_RMETA: return 0x3a; #endif case SDLK_LSUPER: return 0x3a; // "Windows" key case SDLK_RSUPER: return 0x3a; case SDLK_MENU: return 0x32; case SDLK_CAPSLOCK: return 0x39; case SDLK_NUMLOCK: return 0x47; case SDLK_UP: return 0x3e; case SDLK_DOWN: return 0x3d; case SDLK_LEFT: return 0x3b; case SDLK_RIGHT: return 0x3c; case SDLK_ESCAPE: if (is_ctrl_down(ks)) {if (!key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35; case SDLK_F1: if (is_ctrl_down(ks)) {if (!key_down) SysMountFirstFloppy(); return -2;} else return 0x7a; case SDLK_F2: return 0x78; case SDLK_F3: return 0x63; case SDLK_F4: return 0x76; case SDLK_F5: if (is_ctrl_down(ks)) {if (!key_down) drv->toggle_mouse_grab(); return -2;} else return 0x60; case SDLK_F6: return 0x61; case SDLK_F7: return 0x62; case SDLK_F8: return 0x64; case SDLK_F9: return 0x65; case SDLK_F10: return 0x6d; case SDLK_F11: return 0x67; case SDLK_F12: return 0x6f; case SDLK_PRINT: return 0x69; case SDLK_SCROLLOCK: return 0x6b; case SDLK_PAUSE: return 0x71; case SDLK_KP0: return 0x52; case SDLK_KP1: return 0x53; case SDLK_KP2: return 0x54; case SDLK_KP3: return 0x55; case SDLK_KP4: return 0x56; case SDLK_KP5: return 0x57; case SDLK_KP6: return 0x58; case SDLK_KP7: return 0x59; case SDLK_KP8: return 0x5b; case SDLK_KP9: return 0x5c; case SDLK_KP_PERIOD: return 0x41; case SDLK_KP_PLUS: return 0x45; case SDLK_KP_MINUS: return 0x4e; case SDLK_KP_MULTIPLY: return 0x43; case SDLK_KP_DIVIDE: return 0x4b; case SDLK_KP_ENTER: return 0x4c; case SDLK_KP_EQUALS: return 0x51; } D(bug("Unhandled SDL keysym: %d\n", ks.sym)); return -1; } static int event2keycode(SDL_KeyboardEvent const &ev, bool key_down) { return kc_decode(ev.keysym, key_down); } /* * SDL event handling */ static void handle_events(void) { SDL_Event events[10]; const int n_max_events = sizeof(events) / sizeof(events[0]); int n_events; while ((n_events = SDL_PeepEvents(events, n_max_events, SDL_GETEVENT, sdl_eventmask)) > 0) { for (int i = 0; i < n_events; i++) { SDL_Event const & event = events[i]; switch (event.type) { // Mouse button case SDL_MOUSEBUTTONDOWN: { unsigned int button = event.button.button; if (button == SDL_BUTTON_LEFT) ADBMouseDown(0); else if (button == SDL_BUTTON_RIGHT) ADBMouseDown(1); else if (button == SDL_BUTTON_MIDDLE) ADBMouseDown(2); else if (button < 6) { // Wheel mouse if (mouse_wheel_mode == 0) { int key = (button == 5) ? 0x79 : 0x74; // Page up/down ADBKeyDown(key); ADBKeyUp(key); } else { int key = (button == 5) ? 0x3d : 0x3e; // Cursor up/down for(int i=0; imouse_moved(event.motion.x, event.motion.y); break; // Keyboard case SDL_KEYDOWN: { int code = -1; if (use_keycodes && !is_modifier_key(event.key)) { if (event2keycode(event.key, true) != -2) // This is called to process the hotkeys code = keycode_table[event.key.keysym.scancode & 0xff]; } else code = event2keycode(event.key, true); if (code >= 0) { if (!emul_suspended) { if (code == 0x39) { // Caps Lock pressed if (caps_on) { ADBKeyUp(code); caps_on = false; } else { ADBKeyDown(code); caps_on = true; } } else ADBKeyDown(code); if (code == 0x36) ctrl_down = true; } else { if (code == 0x31) drv->resume(); // Space wakes us up } } break; } case SDL_KEYUP: { int code = -1; if (use_keycodes && !is_modifier_key(event.key)) { if (event2keycode(event.key, false) != -2) // This is called to process the hotkeys code = keycode_table[event.key.keysym.scancode & 0xff]; } else code = event2keycode(event.key, false); if (code >= 0) { if (code == 0x39) { // Caps Lock released if (caps_on) { ADBKeyUp(code); caps_on = false; } else { ADBKeyDown(code); caps_on = true; } } else ADBKeyUp(code); if (code == 0x36) ctrl_down = false; } break; } // Hidden parts exposed, force complete refresh of window case SDL_VIDEOEXPOSE: if (display_type == DISPLAY_WINDOW) { const VIDEO_MODE &mode = VideoMonitors[0]->get_current_mode(); #ifdef ENABLE_VOSF if (use_vosf) { // VOSF refresh LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y); } else #endif memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y); } break; // Window "close" widget clicked case SDL_QUIT: ADBKeyDown(0x7f); // Power key ADBKeyUp(0x7f); break; // Application activate/deactivate; consume the event but otherwise ignore it case SDL_ACTIVEEVENT: break; } } } } /* * Window display update */ // Static display update (fixed frame rate, but incremental) static void update_display_static(driver_base *drv) { // Incremental update code int wide = 0, high = 0, x1, x2, y1, y2, i, j; const VIDEO_MODE &mode = drv->mode; int bytes_per_row = VIDEO_MODE_ROW_BYTES; uint8 *p, *p2; // Check for first line from top and first line from bottom that have changed y1 = 0; for (j=0; j=y1; j--) { if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) { y2 = j; break; } } high = y2 - y1 + 1; // Check for first column from left and first column from right that have changed if (high) { if ((int)VIDEO_MODE_DEPTH < VIDEO_DEPTH_8BIT) { const int src_bytes_per_row = bytes_per_row; const int dst_bytes_per_row = drv->s->pitch; const int pixels_per_byte = VIDEO_MODE_X / src_bytes_per_row; x1 = VIDEO_MODE_X / pixels_per_byte; for (j = y1; j <= y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; for (i = 0; i < x1; i++) { if (*p != *p2) { x1 = i; break; } p++; p2++; } } x2 = x1; for (j = y1; j <= y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; p += bytes_per_row; p2 += bytes_per_row; for (i = (VIDEO_MODE_X / pixels_per_byte); i > x2; i--) { p--; p2--; if (*p != *p2) { x2 = i; break; } } } x1 *= pixels_per_byte; x2 *= pixels_per_byte; wide = (x2 - x1 + pixels_per_byte - 1) & -pixels_per_byte; // Update copy of the_buffer if (high && wide) { // Lock surface, if required if (SDL_MUSTLOCK(drv->s)) SDL_LockSurface(drv->s); // Blit to screen surface int si = y1 * src_bytes_per_row + (x1 / pixels_per_byte); int di = y1 * dst_bytes_per_row + x1; for (j = y1; j <= y2; j++) { memcpy(the_buffer_copy + si, the_buffer + si, wide / pixels_per_byte); Screen_blit((uint8 *)drv->s->pixels + di, the_buffer + si, wide / pixels_per_byte); si += src_bytes_per_row; di += dst_bytes_per_row; } // Unlock surface, if required if (SDL_MUSTLOCK(drv->s)) SDL_UnlockSurface(drv->s); // Refresh display SDL_UpdateRect(drv->s, x1, y1, wide, high); } } else { const int bytes_per_pixel = VIDEO_MODE_ROW_BYTES / VIDEO_MODE_X; const int dst_bytes_per_row = drv->s->pitch; x1 = VIDEO_MODE_X; for (j=y1; j<=y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; for (i=0; ix2*bytes_per_pixel; i--) { p--; p2--; if (*p != *p2) { x2 = i / bytes_per_pixel; break; } } } wide = x2 - x1; // Update copy of the_buffer if (high && wide) { // Lock surface, if required if (SDL_MUSTLOCK(drv->s)) SDL_LockSurface(drv->s); // Blit to screen surface for (j=y1; j<=y2; j++) { i = j * bytes_per_row + x1 * bytes_per_pixel; int dst_i = j * dst_bytes_per_row + x1 * bytes_per_pixel; memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * wide); Screen_blit((uint8 *)drv->s->pixels + dst_i, the_buffer + i, bytes_per_pixel * wide); } // Unlock surface, if required if (SDL_MUSTLOCK(drv->s)) SDL_UnlockSurface(drv->s); // Refresh display SDL_UpdateRect(drv->s, x1, y1, wide, high); } } } } // Static display update (fixed frame rate, bounding boxes based) // XXX use NQD bounding boxes to help detect dirty areas? static void update_display_static_bbox(driver_base *drv) { const VIDEO_MODE &mode = drv->mode; // Allocate bounding boxes for SDL_UpdateRects() const int N_PIXELS = 64; const int n_x_boxes = (VIDEO_MODE_X + N_PIXELS - 1) / N_PIXELS; const int n_y_boxes = (VIDEO_MODE_Y + N_PIXELS - 1) / N_PIXELS; SDL_Rect *boxes = (SDL_Rect *)alloca(sizeof(SDL_Rect) * n_x_boxes * n_y_boxes); int nr_boxes = 0; // Lock surface, if required if (SDL_MUSTLOCK(drv->s)) SDL_LockSurface(drv->s); // Update the surface from Mac screen const int bytes_per_row = VIDEO_MODE_ROW_BYTES; const int bytes_per_pixel = bytes_per_row / VIDEO_MODE_X; const int dst_bytes_per_row = drv->s->pitch; int x, y; for (y = 0; y < VIDEO_MODE_Y; y += N_PIXELS) { int h = N_PIXELS; if (h > VIDEO_MODE_Y - y) h = VIDEO_MODE_Y - y; for (x = 0; x < VIDEO_MODE_X; x += N_PIXELS) { int w = N_PIXELS; if (w > VIDEO_MODE_X - x) w = VIDEO_MODE_X - x; const int xs = w * bytes_per_pixel; const int xb = x * bytes_per_pixel; bool dirty = false; for (int j = y; j < (y + h); j++) { const int yb = j * bytes_per_row; const int dst_yb = j * dst_bytes_per_row; if (memcmp(&the_buffer[yb + xb], &the_buffer_copy[yb + xb], xs) != 0) { memcpy(&the_buffer_copy[yb + xb], &the_buffer[yb + xb], xs); Screen_blit((uint8 *)drv->s->pixels + dst_yb + xb, the_buffer + yb + xb, xs); dirty = true; } } if (dirty) { boxes[nr_boxes].x = x; boxes[nr_boxes].y = y; boxes[nr_boxes].w = w; boxes[nr_boxes].h = h; nr_boxes++; } } } // Unlock surface, if required if (SDL_MUSTLOCK(drv->s)) SDL_UnlockSurface(drv->s); // Refresh display if (nr_boxes) SDL_UpdateRects(drv->s, nr_boxes, boxes); } // We suggest the compiler to inline the next two functions so that it // may specialise the code according to the current screen depth and // display type. A clever compiler would do that job by itself though... // NOTE: update_display_vosf is inlined too static inline void possibly_quit_dga_mode() { // Quit DGA mode if requested (something terrible has happened and we // want to give control back to the user) if (quit_full_screen) { quit_full_screen = false; delete drv; drv = NULL; } } static inline void possibly_ungrab_mouse() { // Ungrab mouse if requested (something terrible has happened and we // want to give control back to the user) if (quit_full_screen) { quit_full_screen = false; if (drv) drv->ungrab_mouse(); } } static inline void handle_palette_changes(void) { LOCK_PALETTE; if (sdl_palette_changed) { sdl_palette_changed = false; drv->update_palette(); } UNLOCK_PALETTE; } static void video_refresh_window_static(void); static void video_refresh_dga(void) { // Quit DGA mode if requested possibly_quit_dga_mode(); video_refresh_window_static(); } #ifdef ENABLE_VOSF #if REAL_ADDRESSING || DIRECT_ADDRESSING static void video_refresh_dga_vosf(void) { // Quit DGA mode if requested possibly_quit_dga_mode(); // Update display (VOSF variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { tick_counter = 0; if (mainBuffer.dirty) { LOCK_VOSF; update_display_dga_vosf(static_cast(drv)); UNLOCK_VOSF; } } } #endif static void video_refresh_window_vosf(void) { // Ungrab mouse if requested possibly_ungrab_mouse(); // Update display (VOSF variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { tick_counter = 0; if (mainBuffer.dirty) { LOCK_VOSF; update_display_window_vosf(static_cast(drv)); UNLOCK_VOSF; } } } #endif // def ENABLE_VOSF static void video_refresh_window_static(void) { // Ungrab mouse if requested possibly_ungrab_mouse(); // Update display (static variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { tick_counter = 0; const VIDEO_MODE &mode = drv->mode; if ((int)VIDEO_MODE_DEPTH >= VIDEO_DEPTH_8BIT) update_display_static_bbox(drv); else update_display_static(drv); } } /* * Thread for screen refresh, input handling etc. */ static void VideoRefreshInit(void) { // TODO: set up specialised 8bpp VideoRefresh handlers ? if (display_type == DISPLAY_SCREEN) { #if ENABLE_VOSF && (REAL_ADDRESSING || DIRECT_ADDRESSING) if (use_vosf) video_refresh = video_refresh_dga_vosf; else #endif video_refresh = video_refresh_dga; } else { #ifdef ENABLE_VOSF if (use_vosf) video_refresh = video_refresh_window_vosf; else #endif video_refresh = video_refresh_window_static; } } static inline void do_video_refresh(void) { // Handle SDL events handle_events(); // Update display video_refresh(); #ifdef SHEEPSHAVER // Set new cursor image if it was changed if (cursor_changed && sdl_cursor) { cursor_changed = false; LOCK_EVENTS; SDL_FreeCursor(sdl_cursor); sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, MacCursor[2], MacCursor[3]); if (sdl_cursor) { SDL_ShowCursor(private_data == NULL || private_data->cursorVisible); SDL_SetCursor(sdl_cursor); #ifdef WIN32 // XXX Windows apparently needs an extra mouse event to // make the new cursor image visible int visible = SDL_ShowCursor(-1); if (visible) { int x, y; SDL_GetMouseState(&x, &y); SDL_WarpMouse(x, y); } #endif } UNLOCK_EVENTS; } #endif // Set new palette if it was changed handle_palette_changes(); } // This function is called on non-threaded platforms from a timer interrupt void VideoRefresh(void) { // We need to check redraw_thread_active to inhibit refreshed during // mode changes on non-threaded platforms if (!redraw_thread_active) return; // Process pending events and update display do_video_refresh(); } const int VIDEO_REFRESH_HZ = 60; const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ; #ifndef USE_CPU_EMUL_SERVICES static int redraw_func(void *arg) { uint64 start = GetTicks_usec(); int64 ticks = 0; uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY; while (!redraw_thread_cancel) { // Wait next += VIDEO_REFRESH_DELAY; int64 delay = next - GetTicks_usec(); if (delay > 0) Delay_usec(delay); else if (delay < -VIDEO_REFRESH_DELAY) next = GetTicks_usec(); ticks++; #ifdef SHEEPSHAVER // Pause if requested (during video mode switches) if (thread_stop_req) { thread_stop_ack = true; continue; } #endif // Process pending events and update display do_video_refresh(); } uint64 end = GetTicks_usec(); D(bug("%lld refreshes in %lld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); return 0; } #endif /* * Record dirty area from NQD */ #ifdef SHEEPSHAVER void video_set_dirty_area(int x, int y, int w, int h) { #ifdef ENABLE_VOSF const VIDEO_MODE &mode = drv->mode; const int screen_width = VIDEO_MODE_X; const int screen_height = VIDEO_MODE_Y; const int bytes_per_row = VIDEO_MODE_ROW_BYTES; if (use_vosf) { vosf_set_dirty_area(x, y, w, h, screen_width, screen_height, bytes_per_row); return; } #endif // XXX handle dirty bounding boxes for non-VOSF modes } #endif BasiliskII/src/SDL/SDLMain.h0000644000175000017500000000046311153162232015551 0ustar centriscentris/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import @interface SDLMain : NSObject @end BasiliskII/src/SDL/SDLMain.m0000644000175000017500000002571711677014372015603 0ustar centriscentris/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import "SDL.h" #import "SDLMain.h" #import /* for MAXPATHLEN */ #import /* For some reaon, Apple removed setAppleMenu from the headers in 10.4, but the method still is there and works. To avoid warnings, we declare it ourselves here. */ @interface NSApplication(SDL_Missing_Methods) - (void)setAppleMenu:(NSMenu *)menu; @end /* Use this flag to determine whether we use SDLMain.nib or not */ #define SDL_USE_NIB_FILE 0 /* Use this flag to determine whether we use CPS (docking) or not */ #define SDL_USE_CPS 1 #ifdef SDL_USE_CPS /* Portions of CPS.h */ typedef struct CPSProcessSerNum { UInt32 lo; UInt32 hi; } CPSProcessSerNum; extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); #endif /* SDL_USE_CPS */ static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; static NSString *getApplicationName(void) { NSDictionary *dict; NSString *appName = 0; /* Determine the application name */ dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } #if SDL_USE_NIB_FILE /* A helper category for NSString */ @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end #endif @interface SDLApplication : NSApplication @end @implementation SDLApplication /* Invoked from the Quit menu item */ - (void)terminate:(id)sender { /* Post a SDL_QUIT event */ SDL_Event event; event.type = SDL_QUIT; SDL_PushEvent(&event); } @end /* The main class of the application, the application's delegate */ @implementation SDLMain /* Set the working directory to the .app's parent directory */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { if (shouldChdir) { char parentdir[MAXPATHLEN]; CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ } CFRelease(url); CFRelease(url2); } } #if SDL_USE_NIB_FILE /* Fix menu to contain the real app name instead of "SDL App" */ - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName { NSRange aRange; NSEnumerator *enumerator; NSMenuItem *menuItem; aRange = [[aMenu title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; enumerator = [[aMenu itemArray] objectEnumerator]; while ((menuItem = [enumerator nextObject])) { aRange = [[menuItem title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; if ([menuItem hasSubmenu]) [self fixMenu:[menuItem submenu] withAppName:appName]; } [ aMenu sizeToFit ]; } #else static void setApplicationMenu(void) { /* warning: this code is very odd */ NSMenu *appleMenu; NSMenuItem *menuItem; NSString *title; NSString *appName; appName = getApplicationName(); appleMenu = [[NSMenu alloc] initWithTitle:@""]; /* Add menu items */ title = [@"About " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; [menuItem setSubmenu:appleMenu]; [[NSApp mainMenu] addItem:menuItem]; /* Tell the application object that this is now the application menu */ [NSApp setAppleMenu:appleMenu]; /* Finally give up our references to the objects */ [appleMenu release]; [menuItem release]; } /* Create a window menu */ static void setupWindowMenu(void) { NSMenu *windowMenu; NSMenuItem *windowMenuItem; NSMenuItem *menuItem; windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; /* "Minimize" item */ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItem:menuItem]; [menuItem release]; /* Put menu into the menubar */ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; [windowMenuItem setSubmenu:windowMenu]; [[NSApp mainMenu] addItem:windowMenuItem]; /* Tell the application object that this is now the window menu */ [NSApp setWindowsMenu:windowMenu]; /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; } /* Replacement for NSApplicationMain */ static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; /* Ensure the application object is initialised */ [SDLApplication sharedApplication]; #ifdef SDL_USE_CPS { CPSProcessSerNum PSN; /* Tell the dock about us */ if (!CPSGetCurrentProcess(&PSN)) if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) if (!CPSSetFrontProcess(&PSN)) [SDLApplication sharedApplication]; } #endif /* SDL_USE_CPS */ /* Set up the menubar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; setApplicationMenu(); setupWindowMenu(); /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; [NSApp setDelegate:sdlMain]; /* Start the main event loop */ [NSApp run]; [sdlMain release]; [pool release]; } #endif /* * Catch document open requests...this lets us notice files when the app * was launched by double-clicking a document, or when a document was * dragged/dropped on the app's icon. You need to have a * CFBundleDocumentsType section in your Info.plist to get this message, * apparently. * * Files are added to gArgv, so to the app, they'll look like command line * arguments. Previously, apps launched from the finder had nothing but * an argv[0]. * * This message may be received multiple times to open several docs on launch. * * This message is ignored once the app's mainline has been called. */ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { const char *temparg; size_t arglen; char *arg; char **newargv; if (!gFinderLaunch) /* MacOS is passing command line args. */ return FALSE; if (gCalledAppMainline) /* app has started, ignore this document. */ return FALSE; temparg = [filename UTF8String]; arglen = SDL_strlen(temparg) + 1; arg = (char *) SDL_malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); if (newargv == NULL) { SDL_free(arg); return FALSE; } gArgv = newargv; SDL_strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } /* Called when the internal event loop has just started running */ - (void) applicationDidFinishLaunching: (NSNotification *) note { int status; /* Set the working directory to the .app's parent directory */ [self setupWorkingDirectory:gFinderLaunch]; #if SDL_USE_NIB_FILE /* Set the main menu to contain the real app name instead of "SDL App" */ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif /* Hand off to main application code */ gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); /* We're done, thank you for playing */ exit(status); } @end @implementation NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString { unsigned int bufferSize; unsigned int selfLen = [self length]; unsigned int aStringLen = [aString length]; unichar *buffer; NSRange localRange; NSString *result; bufferSize = selfLen + aStringLen - aRange.length; buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); /* Get first part into buffer */ localRange.location = 0; localRange.length = aRange.location; [self getCharacters:buffer range:localRange]; /* Get middle part into buffer */ localRange.location = 0; localRange.length = aStringLen; [aString getCharacters:(buffer+aRange.location) range:localRange]; /* Get last part into buffer */ localRange.location = aRange.location + aRange.length; localRange.length = selfLen - localRange.location; [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; /* Build output string */ result = [NSString stringWithCharacters:buffer length:bufferSize]; NSDeallocateMemoryPages(buffer, bufferSize); return result; } @end #ifdef main # undef main #endif /* Main entry point to executable - should *not* be SDL_main! */ int main (int argc, char **argv) { /* Copy the arguments into a global variable */ /* This is passed if we are launched by double-clicking */ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) SDL_malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } #if SDL_USE_NIB_FILE [SDLApplication poseAsClass:[NSApplication class]]; NSApplicationMain (argc, argv); #else CustomApplicationMain (argc, argv); #endif return 0; } BasiliskII/src/SDL/keycodes0000644000175000017500000001461311434604606015714 0ustar centriscentris# /usr/share/BasiliskII/keycodes # # Basilisk II (C) 1997-2005 Christian Bauer # # This file is used to translate the (server-specific) scancodes to # Mac keycodes depending on the window server being used. # # The format of this file is as follows: # # sdl # # # # ... # sdl # # # ... # # The "driver string" must match the first part of the SDL driver vendor # description as reported by SDL_VideoDriverName(). If a match is found, # the keycode translation table is constructed from the following # lines. Each line contains an SDL scancode followed by its associated # Mac keycode. Both keycodes have to be given in decimal. Lines # beginning with "#" or ";" are treated as comments and ignored. # # # X11 server # sdl x11 sdl dga 9 53 # Esc 67 122 # F1 68 120 # F2 69 99 # F3 70 118 # F4 71 96 # F5 72 97 # F6 73 98 # F7 74 100 # F8 75 101 # F9 76 109 # F10 95 103 # F11 96 111 # F12 111 105 # PrintScrn 78 107 # Scroll Lock 110 113 # Pause 49 50 # ` 10 18 # 1 11 19 # 2 12 20 # 3 13 21 # 4 14 23 # 5 15 22 # 6 16 26 # 7 17 28 # 8 18 25 # 9 19 29 # 0 20 27 # - 21 24 # = 22 51 # Backspace 106 114 # Insert 97 115 # Home 99 116 # Page Up 77 71 # Num Lock 112 75 # KP / 63 67 # KP * 82 78 # KP - 23 48 # Tab 24 12 # Q 25 13 # W 26 14 # E 27 15 # R 28 17 # T 29 16 # Y 30 32 # U 31 34 # I 32 31 # O 33 35 # P 34 33 # [ 35 30 # ] 36 36 # Return 107 117 # Delete 103 119 # End 105 121 # Page Down 79 89 # KP 7 80 91 # KP 8 81 92 # KP 9 86 69 # KP + 66 57 # Caps Lock 38 0 # A 39 1 # S 40 2 # D 41 3 # F 42 5 # G 43 4 # H 44 38 # J 45 40 # K 46 37 # L 47 41 # ; 48 39 # ' 83 86 # KP 4 84 87 # KP 5 85 88 # KP 6 50 56 # Shift Left 94 50 # International 52 6 # Z 53 7 # X 54 8 # C 55 9 # V 56 11 # B 57 45 # N 58 46 # M 59 43 # , 60 47 # . 61 44 # / 62 56 # Shift Right 51 42 # \ 98 62 # Cursor Up 87 83 # KP 1 88 84 # KP 2 89 85 # KP 3 108 76 # KP Enter 37 54 # Ctrl Left 115 58 # Logo Left (-> Option) 64 55 # Alt Left (-> Command) 65 49 # Space 113 55 # Alt Right (-> Command) 116 58 # Logo Right (-> Option) 117 50 # Menu (-> International) 109 54 # Ctrl Right 100 59 # Cursor Left 104 61 # Cursor Down 102 60 # Cursor Right 90 82 # KP 0 91 65 # KP . # # Linux Framebuffer Console # sdl fbcon 1 53 # Esc 59 122 # F1 60 120 # F2 61 99 # F3 62 118 # F4 63 96 # F5 64 97 # F6 65 98 # F7 66 100 # F8 67 101 # F9 68 109 # F10 87 103 # F11 88 111 # F12 99 105 # PrintScrn 70 107 # Scroll Lock 119 113 # Pause 41 50 # ` 2 18 # 1 3 19 # 2 4 20 # 3 5 21 # 4 6 23 # 5 7 22 # 6 8 26 # 7 9 28 # 8 10 25 # 9 11 29 # 0 12 27 # - 13 24 # = 14 51 # Backspace 110 114 # Insert 102 115 # Home 104 116 # Page Up 69 71 # Num Lock 98 75 # KP / 55 67 # KP * 74 78 # KP - 15 48 # Tab 16 12 # Q 17 13 # W 18 14 # E 19 15 # R 20 17 # T 21 16 # Y 22 32 # U 23 34 # I 24 31 # O 25 35 # P 26 33 # [ 27 30 # ] 28 36 # Return 111 117 # Delete 107 119 # End 109 121 # Page Down 71 89 # KP 7 72 91 # KP 8 73 92 # KP 9 78 69 # KP + 58 57 # Caps Lock 30 0 # A 31 1 # S 32 2 # D 33 3 # F 34 5 # G 35 4 # H 36 38 # J 37 40 # K 38 37 # L 39 41 # ; 40 39 # ' 75 86 # KP 4 76 87 # KP 5 77 88 # KP 6 42 56 # Shift Left 86 50 # International 44 6 # Z 45 7 # X 46 8 # C 47 9 # V 48 11 # B 49 45 # N 50 46 # M 51 43 # , 52 47 # . 53 44 # / 54 56 # Shift Right 43 42 # \ 103 62 # Cursor Up 79 83 # KP 1 80 84 # KP 2 81 85 # KP 3 96 76 # KP Enter 29 54 # Ctrl Left 125 58 # Logo Left (-> Option) 56 55 # Alt Left (-> Command) 57 49 # Space 100 55 # Alt Right (-> Command) 126 58 # Logo Right (-> Option) 97 54 # Ctrl Right 105 59 # Cursor Left 108 61 # Cursor Down 106 60 # Cursor Right 82 82 # KP 0 83 65 # KP . # # Quartz (1:1 translation actually) # sdl Quartz 53 53 # Esc 122 122 # F1 120 120 # F2 99 99 # F3 118 118 # F4 96 96 # F5 97 97 # F6 98 98 # F7 100 100 # F8 101 101 # F9 109 109 # F10 103 103 # F11 111 111 # F12 105 105 # F13/PrintScrn 107 107 # F14/Scroll Lock 113 113 # F15/Pause 10 10 # ` 18 18 # 1 19 19 # 2 20 20 # 3 21 21 # 4 23 23 # 5 22 22 # 6 26 26 # 7 28 28 # 8 25 25 # 9 29 29 # 0 27 27 # - 24 24 # = 51 51 # Backspace 114 114 # Help/Insert 115 115 # Home 116 116 # Page Up 71 71 # Num Lock 81 81 # KP = 75 75 # KP / 67 67 # KP * 48 48 # Tab 12 12 # Q 13 13 # W 14 14 # E 15 15 # R 17 17 # T 16 16 # Y 32 32 # U 34 34 # I 31 31 # O 35 35 # P 33 33 # [ 30 30 # ] 36 36 # Return 117 117 # Delete 119 119 # End 121 121 # Page Down 89 89 # KP 7 91 91 # KP 8 92 92 # KP 9 78 78 # KP - 57 57 # Caps Lock 0 0 # A 1 1 # S 2 2 # D 3 3 # F 5 5 # G 4 4 # H 38 38 # J 40 40 # K 37 37 # L 41 41 # ; 39 39 # ' 42 42 # \ 86 86 # KP 4 87 87 # KP 5 88 88 # KP 6 69 69 # KP + 56 56 # Shift 50 50 # International 6 6 # Z 7 7 # X 8 8 # C 9 9 # V 11 11 # B 45 45 # N 46 46 # M 43 43 # , 47 47 # . 44 44 # / 126 62 # Cursor Up 123 59 # Cursor Left 125 61 # Cursor Down 124 60 # Cursor Right 83 83 # KP 1 84 84 # KP 2 85 85 # KP 3 76 76 # KP Enter 54 54 # Ctrl 58 58 # Option 55 55 # Command 54 54 # Ctrl Left 49 49 # Space 82 82 # KP 0 65 65 # KP . # # Windows # sdl windib sdl directx 1 53 # Esc 59 122 # F1 60 120 # F2 61 99 # F3 62 118 # F4 63 96 # F5 64 97 # F6 65 98 # F7 66 100 # F8 67 101 # F9 68 109 # F10 87 103 # F11 88 111 # F12 183 105 # PrintScrn 70 107 # Scroll Lock 197 113 # Pause 41 50 # ` 2 18 # 1 3 19 # 2 4 20 # 3 5 21 # 4 6 23 # 5 7 22 # 6 8 26 # 7 9 28 # 8 10 25 # 9 11 29 # 0 12 27 # - 13 24 # = 14 51 # Backspace 210 114 # Insert 199 115 # Home 201 116 # Page Up 69 71 # Num Lock 181 75 # KP / 55 67 # KP * 74 78 # KP - 15 48 # Tab 16 12 # Q 17 13 # W 18 14 # E 19 15 # R 20 17 # T 21 16 # Y 22 32 # U 23 34 # I 24 31 # O 25 35 # P 26 33 # [ 27 30 # ] 28 36 # Return 211 117 # Delete 207 119 # End 209 121 # Page Down 71 89 # KP 7 72 91 # KP 8 73 92 # KP 9 78 69 # KP + 58 57 # Caps Lock 30 0 # A 31 1 # S 32 2 # D 33 3 # F 34 5 # G 35 4 # H 36 38 # J 37 40 # K 38 37 # L 39 41 # ; 40 39 # ' 75 86 # KP 4 76 87 # KP 5 77 88 # KP 6 42 56 # Shift Left 86 50 # International 44 6 # Z 45 7 # X 46 8 # C 47 9 # V 48 11 # B 49 45 # N 50 46 # M 51 43 # , 52 47 # . 53 44 # / 54 56 # Shift Right 43 42 # \ 200 62 # Cursor Up 79 83 # KP 1 80 84 # KP 2 81 85 # KP 3 156 76 # KP Enter 29 54 # Ctrl Left 219 58 # Logo Left (-> Option) 56 55 # Alt Left (-> Command) 57 49 # Space 184 55 # Alt Right (-> Command) 220 58 # Logo Right (-> Option) 221 50 # Menu (-> International) 157 54 # Ctrl Right 203 59 # Cursor Left 208 61 # Cursor Down 205 60 # Cursor Right 82 82 # KP 0 83 65 # KP . BasiliskII/src/BeOS/0000755000175000017500000000000011735674751014340 5ustar centriscentrisBasiliskII/src/BeOS/Makefile0000644000175000017500000001257607324323134015774 0ustar centriscentris## BeOS Generic Makefile v2.1 ## ## Fill in this file to specify the project being created, and the referenced ## makefile-engine will do all of the hard work for you. This handles both ## Intel and PowerPC builds of the BeOS. ## Application Specific Settings --------------------------------------------- # specify the name of the binary NAME= BasiliskII # specify the type of binary # APP: Application # SHARED: Shared library or add-on # STATIC: Static library archive # DRIVER: Kernel Driver TYPE= APP # add support for new Pe and Eddie features # to fill in generic makefile #%{ # @src->@ # specify the source files to use # full paths or paths relative to the makefile can be included # all files, regardless of directory, will have their object # files created in the common object directory. # Note that this means this makefile will not work correctly # if two source files with the same name (source.c or source.cpp) # are included from different directories. Also note that spaces # in folder names do not work well with this makefile. MACHINE=$(shell uname -m) ifeq ($(MACHINE), BePC) CPUSRCS = ../uae_cpu/basilisk_glue.cpp ../uae_cpu/memory.cpp ../uae_cpu/newcpu.cpp \ ../uae_cpu/readcpu.cpp ../uae_cpu/fpu/fpu_x86.cpp cpustbl.cpp cpudefs.cpp cpufast.s else # CPUSRCS = ../powerrom_cpu/powerrom_cpu.cpp CPUSRCS = ../uae_cpu/basilisk_glue.cpp ../uae_cpu/newcpu.cpp \ ../uae_cpu/readcpu.cpp ../uae_cpu/fpu/fpu_uae.cpp cpustbl.cpp cpudefs.cpp cpuemu.cpp endif SRCS = ../main.cpp main_beos.cpp ../prefs.cpp ../prefs_items.cpp prefs_beos.cpp \ prefs_editor_beos.cpp sys_beos.cpp ../rom_patches.cpp ../slot_rom.cpp \ ../rsrc_patches.cpp ../emul_op.cpp ../macos_util.cpp ../xpram.cpp \ xpram_beos.cpp ../timer.cpp timer_beos.cpp clip_beos.cpp ../adb.cpp \ ../serial.cpp serial_beos.cpp ../ether.cpp ether_beos.cpp ../sony.cpp \ ../disk.cpp ../cdrom.cpp ../scsi.cpp scsi_beos.cpp ../video.cpp \ video_beos.cpp ../audio.cpp audio_beos.cpp ../extfs.cpp extfs_beos.cpp \ ../user_strings.cpp user_strings_beos.cpp about_window.cpp \ $(CPUSRCS) # specify the resource files to use # full path or a relative path to the resource file can be used. RSRCS= # @<-src@ #%} # end support for Pe and Eddie # specify additional libraries to link against # there are two acceptable forms of library specifications # - if your library follows the naming pattern of: # libXXX.so or libXXX.a you can simply specify XXX # library: libbe.so entry: be # # - if your library does not follow the standard library # naming scheme you need to specify the path to the library # and it's name # library: my_lib.a entry: my_lib.a or path/my_lib.a LIBS=be game media device textencoding tracker net # specify additional paths to directories following the standard # libXXX.so or libXXX.a naming scheme. You can specify full paths # or paths relative to the makefile. The paths included may not # be recursive, so include all of the paths where libraries can # be found. Directories where source files are found are # automatically included. LIBPATHS= # additional paths to look for system headers # thes use the form: #include
# source file directories are NOT auto-included here SYSTEM_INCLUDE_PATHS = # additional paths to look for local headers # thes use the form: #include "header" # source file directories are automatically included LOCAL_INCLUDE_PATHS = ../include SheepDriver SheepNet # specify the level of optimization that you desire # NONE, SOME, FULL OPTIMIZE= FULL # specify any preprocessor symbols to be defined. The symbols will not # have their values set automatically; you must supply the value (if any) # to use. For example, setting DEFINES to "DEBUG=1" will cause the # compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" # would pass "-DDEBUG" on the compiler's command line. DEFINES= # specify special warning levels # if unspecified default warnings will be used # NONE = supress all warnings # ALL = enable all warnings WARNINGS = # specify whether image symbols will be created # so that stack crawls in the debugger are meaningful # if TRUE symbols will be created SYMBOLS = # specify debug settings # if TRUE will allow application to be run from # a source-level debugger DEBUGGER = # specify additional compiler flags for all files COMPILER_FLAGS = # specify additional linker flags LINKER_FLAGS = ## include the makefile-engine include /boot/develop/etc/makefile-engine # special handling of UAE CPU engine $(OBJ_DIR)/%.o : %.s $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuopti: $(OBJ_DIR)/cpuopti.o $(CC) $(LDFLAGS) -o $(OBJ_DIR)/cpuopti $(OBJ_DIR)/cpuopti.o $(OBJ_DIR)/build68k: $(OBJ_DIR)/build68k.o $(CC) $(LDFLAGS) -o $(OBJ_DIR)/build68k $(OBJ_DIR)/build68k.o $(OBJ_DIR)/gencpu: $(OBJ_DIR)/gencpu.o $(OBJ_DIR)/readcpu.o $(OBJ_DIR)/cpudefs.o $(CC) $(LDFLAGS) -o $(OBJ_DIR)/gencpu $(OBJ_DIR)/gencpu.o $(OBJ_DIR)/readcpu.o $(OBJ_DIR)/cpudefs.o cpudefs.cpp: $(OBJ_DIR)/build68k ../uae_cpu/table68k $(OBJ_DIR)/build68k <../uae_cpu/table68k >cpudefs.cpp cpuemu.cpp: $(OBJ_DIR)/gencpu $(OBJ_DIR)/gencpu cpustbl.cpp: cpuemu.cpp cputbl.h: cpuemu.cpp cpufast.s: cpuemu.cpp $(OBJ_DIR)/cpuopti $(CXX) $(INCLUDES) -S $(CFLAGS) $< -o cputmp.s $(OBJ_DIR)/cpuopti $@ || mv cputmp.s $@ rm -f cputmp.s streifenfrei: -rm -f $(OBJ_DIR)/gencpu $(OBJ_DIR)/build68k $(OBJ_DIR)/cpuopti -rm -f cpuemu.cpp cpudefs.cpp cputmp.s cpufast*.s cpustbl.cpp cputbl.h BasiliskII/src/BeOS/SheepDriver/0000755000175000017500000000000011735674761016561 5ustar centriscentrisBasiliskII/src/BeOS/SheepDriver/Makefile0000644000175000017500000000726507241316534020217 0ustar centriscentris## BeOS Generic Makefile v2.1 ## ## Fill in this file to specify the project being created, and the referenced ## makefile-engine will do all of the hard work for you. This handles both ## Intel and PowerPC builds of the BeOS. ## Application Specific Settings --------------------------------------------- # specify the name of the binary NAME= sheep # specify the type of binary # APP: Application # SHARED: Shared library or add-on # STATIC: Static library archive # DRIVER: Kernel Driver TYPE= DRIVER # add support for new Pe and Eddie features # to fill in generic makefile #%{ # @src->@ # specify the source files to use # full paths or paths relative to the makefile can be included # all files, regardless of directory, will have their object # files created in the common object directory. # Note that this means this makefile will not work correctly # if two source files with the same name (source.c or source.cpp) # are included from different directories. Also note that spaces # in folder names do not work well with this makefile. SRCS= sheep_driver.c # specify the resource files to use # full path or a relative path to the resource file can be used. RSRCS= # @<-src@ #%} # end support for Pe and Eddie # specify additional libraries to link against # there are two acceptable forms of library specifications # - if your library follows the naming pattern of: # libXXX.so or libXXX.a you can simply specify XXX # library: libbe.so entry: be # # - if your library does not follow the standard library # naming scheme you need to specify the path to the library # and it's name # library: my_lib.a entry: my_lib.a or path/my_lib.a LIBS= # specify additional paths to directories following the standard # libXXX.so or libXXX.a naming scheme. You can specify full paths # or paths relative to the makefile. The paths included may not # be recursive, so include all of the paths where libraries can # be found. Directories where source files are found are # automatically included. LIBPATHS= # additional paths to look for system headers # thes use the form: #include
# source file directories are NOT auto-included here SYSTEM_INCLUDE_PATHS = # additional paths to look for local headers # thes use the form: #include "header" # source file directories are automatically included LOCAL_INCLUDE_PATHS = # specify the level of optimization that you desire # NONE, SOME, FULL OPTIMIZE= FULL # specify any preprocessor symbols to be defined. The symbols will not # have their values set automatically; you must supply the value (if any) # to use. For example, setting DEFINES to "DEBUG=1" will cause the # compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" # would pass "-DDEBUG" on the compiler's command line. DEFINES= # specify special warning levels # if unspecified default warnings will be used # NONE = supress all warnings # ALL = enable all warnings WARNINGS = # specify whether image symbols will be created # so that stack crawls in the debugger are meaningful # if TRUE symbols will be created SYMBOLS = # specify debug settings # if TRUE will allow application to be run from a source-level # debugger. Note that this will disable all optimzation. DEBUGGER = # specify additional compiler flags for all files COMPILER_FLAGS = # specify additional linker flags LINKER_FLAGS = ## include the makefile-engine include /boot/develop/etc/makefile-engine install: $(TARGET) cp $(TARGET) /boot/home/config/add-ons/kernel/drivers/bin ln -sf /boot/home/config/add-ons/kernel/drivers/bin/$(NAME) /boot/home/config/add-ons/kernel/drivers/dev/$(NAME) uninstall: rm /boot/home/config/add-ons/kernel/drivers/bin/$(NAME) rm /boot/home/config/add-ons/kernel/drivers/dev/$(NAME) BasiliskII/src/BeOS/SheepDriver/sheep_driver.c0000644000175000017500000002673507421041634021401 0ustar centriscentris/* * sheep_driver.c - Low memory and ROM access driver for SheepShaver and * Basilisk II on PowerPC systems * * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer * Basilisk II (C) 1997-2002 Christian Bauer * * 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 */ #ifdef __i386__ #error The sheep driver only runs on PowerPC machines. #endif #include #include #include #include #include #include #include #include "sheep_driver.h" #define DEBUG 0 #if DEBUG==1 #define bug pprintf #elif DEBUG==2 #define bug dprintf #endif #if DEBUG #define D(x) (x) #else #define D(x) ; #endif #define PORT_NAME "sheep_driver installed" /* * For debugging */ static int pprintf(const char* format, ...) { port_id PortNum; int len, ret; char Buffer[1024]; va_list ap; if ((PortNum = find_port("PortLogger")) == B_NAME_NOT_FOUND) return(PortNum); for (len=0; len<1024; len++) Buffer[len]='\0'; va_start(ap, format); vsprintf(Buffer, format, ap); ret = write_port(PortNum, 0, Buffer, strlen(Buffer)); return ret; } /* * Page table functions */ static uint32 *pte_address = 0; static uint32 vsid; static uint32 table_size; static status_t map_page(uint32 ea, uint32 ra, uint32 **free_pte, uint32 bits) { int i; int pte_class; uint32 hash1, hash2, api, *pteg1, *pteg2; D(bug("Trying to map EA %p -> RA %p\n", ea, ra)); // Find PTEG addresses for given EA hash1 = (vsid & 0x7ffff) ^ ((ea >> 12) & 0xffff); hash2 = ~hash1 & 0x7ffff; api = (ea >> 22) & 0x3f; pteg1 = (uint32 *)((uint32)pte_address + ((hash1 << 6) & (table_size - 1))); pteg2 = (uint32 *)((uint32)pte_address + ((hash2 << 6) & (table_size - 1))); D(bug("PTEG1 at %p, PTEG2 at %p\n", pteg1, pteg2)); // Search all 8 PTEs of each PTEG *free_pte = NULL; pte_class = 0; for (i=0; i<8; i++) { D(bug(" found %08lx %08lx\n", pteg1[i*2], pteg1[i*2+1])); if (pteg1[i*2] == (0x80000000 | (vsid << 7) | (pte_class << 6) | api)) { *free_pte = pteg1 + i*2; D(bug(" existing PTE found (PTEG1)\n")); break; } else if (!pteg1[i*2]) { *free_pte = pteg1 + i*2; D(bug(" free PTE found (PTEG1)\n")); break; } } if (*free_pte == NULL) { pte_class = 1; for (i=0; i<8; i++) { D(bug(" found %08lx %08lx\n", pteg2[i*2], pteg2[i*2+1])); if (pteg2[i*2] == (0x80000000 | (vsid << 7) | (pte_class << 6) | api)) { *free_pte = pteg2 + i*2; D(bug(" existing PTE found (PTEG2)\n")); break; } else if (!pteg2[i*2]) { *free_pte = pteg2 + i*2; D(bug(" free PTE found (PTEG2)\n")); break; } } } // Remap page if (*free_pte == NULL) { D(bug(" No free PTE found :-(\m")); return B_DEVICE_FULL; } else { (*free_pte)[0] = 0x80000000 | (vsid << 7) | (pte_class << 6) | api; (*free_pte)[1] = ra | bits; D(bug(" written %08lx %08lx to PTE\n", (*free_pte)[0], (*free_pte)[1])); return B_NO_ERROR; } } static status_t remap_page(uint32 *free_pte, uint32 ra, uint32 bits) { D(bug("Remapping PTE %p -> RA %p\n", free_pte, ra)); // Remap page if (free_pte == NULL) { D(bug(" Invalid PTE :-(\n")); return B_BAD_ADDRESS; } else { free_pte[1] = ra | bits; D(bug(" written %08lx %08lx to PTE\n", free_pte[0], free_pte[1])); return B_NO_ERROR; } } /* * Foward declarations for hook functions */ static status_t sheep_open(const char *name, uint32 flags, void **cookie); static status_t sheep_close(void *cookie); static status_t sheep_free(void *cookie); static status_t sheep_control(void *cookie, uint32 op, void *data, size_t len); static status_t sheep_read(void *cookie, off_t pos, void *data, size_t *len); static status_t sheep_write(void *cookie, off_t pos, const void *data, size_t *len); /* * Version of our driver */ int32 api_version = B_CUR_DRIVER_API_VERSION; /* * Device_hooks structure - has function pointers to the * various entry points for device operations */ static device_hooks my_device_hooks = { &sheep_open, &sheep_close, &sheep_free, &sheep_control, &sheep_read, &sheep_write, NULL, NULL, NULL, NULL }; /* * List of device names to be returned by publish_devices() */ static char *device_name_list[] = { "sheep", 0 }; /* * Init - do nothing */ status_t init_hardware(void) { #if DEBUG==2 set_dprintf_enabled(true); #endif D(bug("init_hardware()\n")); return B_NO_ERROR; } status_t init_driver(void) { D(bug("init_driver()\n")); return B_NO_ERROR; } void uninit_driver(void) { D(bug("uninit_driver()\n")); } /* * publish_devices - return list of device names implemented by this driver */ const char **publish_devices(void) { return device_name_list; } /* * find_device - return device hooks for a specific device name */ device_hooks *find_device(const char *name) { if (!strcmp(name, device_name_list[0])) return &my_device_hooks; return NULL; } /* * sheep_open - hook function for the open call. */ static status_t sheep_open(const char *name, uint32 flags, void **cookie) { return B_NO_ERROR; } /* * sheep_close - hook function for the close call. */ static status_t sheep_close(void *cookie) { return B_NO_ERROR; } /* * sheep_free - hook function to free the cookie returned * by the open hook. Since the open hook did not return * a cookie, this is a no-op. */ static status_t sheep_free(void *cookie) { return B_NO_ERROR; } /* * sheep_control - hook function for the ioctl call */ static asm void inval_tlb(uint32 ea) { isync tlbie r3 sync blr } static asm void tlbsync(void) { machine 604 tlbsync sync blr } static status_t sheep_control(void *cookie, uint32 op, void *data, size_t len) { static void *block; static void *block_aligned; physical_entry pe[2]; system_info sysinfo; area_id id; area_info info; cpu_status cpu_st; status_t res; uint32 ra0, ra1; uint32 *free_pte_0, *free_pte_1; int i; D(bug("control(%d) data %p, len %08x\n", op, data, len)); switch (op) { case SHEEP_UP: // Already messed up? Then do nothing now if (find_port(PORT_NAME) != B_NAME_NOT_FOUND) return B_NO_ERROR; // Get system info get_system_info(&sysinfo); // Prepare replacement memory block = malloc(B_PAGE_SIZE * 3); D(bug("3 pages malloc()ed at %p\n", block)); block_aligned = (void *)(((uint32)block + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE-1)); D(bug("Address aligned to %p\n", block_aligned)); res = lock_memory(block_aligned, B_PAGE_SIZE * 2, 0); if (res < 0) return res; // Get memory mapping D(bug("Memory locked\n")); res = get_memory_map(block_aligned, B_PAGE_SIZE * 2, pe, 2); D(bug("get_memory_map returned %d\n", res)); if (res != B_NO_ERROR) return res; // Find PTE table area id = find_area("pte_table"); get_area_info(id, &info); pte_address = (uint32 *)info.address; D(bug("PTE table seems to be at %p\n", pte_address)); table_size = info.size; D(bug("PTE table size: %dKB\n", table_size / 1024)); // Disable interrupts cpu_st = disable_interrupts(); // Find vsid and real addresses of replacement memory for (i=0; i> 31),((pte_address[i*2]&0x7fffff80) >> 7), ((pte_address[i*2]&0x00000040) >> 6),(pte_address[i*2] & 0x3f), ((pte_address[i*2+1]&0xfffff000) >> 12),((pte_address[i*2+1]&0x00000100) >> 8), ((pte_address[i*2+1]&0x00000080) >> 7),((pte_address[i*2+1]&0x00000078) >> 3), (pte_address[i*2+1]&0x00000003))); vsid = (pte_address[i*2]&0x7fffff80) >> 7; ra0 = (uint32)pe[0].address & 0xfffff000; } if ((uint32)pe[0].size == B_PAGE_SIZE) { if (((uint32)pe[1].address & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) { D(bug("Found page 1f PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n", i << 2, ((pte_address[i*2]&0x80000000) >> 31), ((pte_address[i*2]&0x7fffff80) >> 7), ((pte_address[i*2]&0x00000040) >> 6), (pte_address[i*2] & 0x3f), ((pte_address[i*2+1]&0xfffff000) >> 12), ((pte_address[i*2+1]&0x00000100) >> 8), ((pte_address[i*2+1]&0x00000080) >> 7), ((pte_address[i*2+1]&0x00000078) >> 3), (pte_address[i*2+1]&0x00000003))); ra1 = (uint32)pe[1].address & 0xfffff000; } } else { if ((((uint32)pe[0].address + B_PAGE_SIZE) & 0xfffff000)==(pte_address[i*2+1]&0xfffff000)) { D(bug("Found page 1d PtePos %04x V%x VSID %03x H%x API %02x RPN %03x R%1x C%1x WIMG%1x PP%1x \n", i << 2, ((pte_address[i*2]&0x80000000) >> 31), ((pte_address[i*2]&0x7fffff80) >> 7), ((pte_address[i*2]&0x00000040) >> 6), (pte_address[i*2] & 0x3f), ((pte_address[i*2+1]&0xfffff000) >> 12), ((pte_address[i*2+1]&0x00000100) >> 8), ((pte_address[i*2+1]&0x00000080) >> 7), ((pte_address[i*2+1]&0x00000078) >> 3), (pte_address[i*2+1]&0x00000003))); ra1 = ((uint32)pe[0].address + B_PAGE_SIZE) & 0xfffff000; } } } // Map low memory for emulator free_pte_0 = NULL; free_pte_1 = NULL; __sync(); __isync(); inval_tlb(0); inval_tlb(B_PAGE_SIZE); if (sysinfo.cpu_type != B_CPU_PPC_603 && sysinfo.cpu_type != B_CPU_PPC_603e) tlbsync(); res = map_page(0, ra0, &free_pte_0, 0x12); if (res == B_NO_ERROR) res = map_page(B_PAGE_SIZE, ra1, &free_pte_1, 0x12); inval_tlb(0); inval_tlb(B_PAGE_SIZE); if (sysinfo.cpu_type != B_CPU_PPC_603 && sysinfo.cpu_type != B_CPU_PPC_603e) tlbsync(); __sync(); __isync(); // Restore interrupts restore_interrupts(cpu_st); // Create port so we know that messing was successful set_port_owner(create_port(1, PORT_NAME), B_SYSTEM_TEAM); return B_NO_ERROR; case SHEEP_DOWN: return B_NO_ERROR; default: return B_BAD_VALUE; } } /* * sheep_read - hook function for the read call */ static status_t sheep_read(void *cookie, off_t pos, void *data, size_t *len) { void *rom_adr; area_id area; system_info info; D(bug("read() pos %Lx, data %p, len %08x\n", pos, data, *len)); get_system_info(&info); if (info.platform_type == B_BEBOX_PLATFORM) { *len = 0; return B_ERROR; } if (*len != 0x400000 && pos != 0) { *len = 0; return B_BAD_VALUE; } area = map_physical_memory("mac_rom", (void *)0xff000000, 0x00400000, B_ANY_KERNEL_ADDRESS, B_READ_AREA, &rom_adr); D(bug("Mapped ROM to %p, area id %d\n", rom_adr, area)); if (area < 0) { *len = 0; return area; } D(bug("Copying ROM\n")); memcpy(data, rom_adr, *len); D(bug("Deleting area\n")); delete_area(area); return B_NO_ERROR; } /* * sheep_write - hook function for the write call */ static status_t sheep_write(void *cookie, off_t pos, const void *data, size_t *len) { D(bug("write() pos %Lx, data %p, len %08x\n", pos, data, *len)); return B_READ_ONLY_DEVICE; } BasiliskII/src/BeOS/SheepDriver/sheep_driver.h0000644000175000017500000000213710736405220021372 0ustar centriscentris/* * sheep_driver.h - Low memory and ROM access driver for SheepShaver and * Basilisk II on PowerPC systems * * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SHEEP_DRIVER_H #define SHEEP_DRIVER_H #include enum { SHEEP_UP = B_DEVICE_OP_CODES_END + 1, SHEEP_DOWN }; #endif BasiliskII/src/BeOS/scsi_beos.cpp0000644000175000017500000001261110736405220016775 0ustar centriscentris/* * scsi_beos.cpp - SCSI Manager, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include "sysdeps.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "scsi.h" #define DEBUG 0 #include "debug.h" // Global variables static raw_device_command rdc; static int fds[8*8]; // fd's for 8 units and 8 LUNs each static int fd; // Active fd (selected target) static uint32 buffer_size; // Size of data buffer static uint8 *buffer = NULL; // Pointer to data buffer static uint8 sense_data[256]; // Buffer for autosense data /* * Initialization */ void SCSIInit(void) { int id, lun; // Allocate buffer buffer = (uint8 *)malloc(buffer_size = 0x10000); // Open scsi_raw driver for all 8 units (and all 8 LUNs) char dev_name[256]; for (id=0; id<8; id++) { for (lun=0; lun<8; lun++) fds[id*8+lun] = -1; char prefs_name[16]; sprintf(prefs_name, "scsi%d", id); const char *str = PrefsFindString(prefs_name); if (str) { int bus, unit; if (sscanf(str, "%d/%d", &bus, &unit) == 2) { for (lun=0; lun<8; lun++) { sprintf(dev_name, "/dev/bus/scsi/%d/%d/%d/raw", bus, unit, lun); D(bug("SCSI %d: Opening %s\n", id, dev_name)); fds[id*8+lun] = open(dev_name, O_RDWR); } } } } // Reset SCSI bus SCSIReset(); // Init rdc memset(&rdc, 0, sizeof(rdc)); rdc.data = buffer; rdc.sense_data = sense_data; } /* * Deinitialization */ void SCSIExit(void) { // Close all devices for (int i=0; i<8; i++) for (int j=0; j<8; j++) { int fd = fds[i*8+j]; if (fd > 0) close(fd); } // Free buffer if (buffer) { free(buffer); buffer = NULL; } } /* * Check if requested data size fits into buffer, allocate new buffer if needed */ static bool try_buffer(int size) { if (size <= buffer_size) return true; uint8 *new_buffer = (uint8 *)malloc(size); if (new_buffer == NULL) return false; free(buffer); buffer = new_buffer; buffer_size = size; return true; } /* * Set SCSI command to be sent by scsi_send_cmd() */ void scsi_set_cmd(int cmd_length, uint8 *cmd) { rdc.command_length = cmd_length; memcpy(rdc.command, cmd, cmd_length); } /* * Check for presence of SCSI target */ bool scsi_is_target_present(int id) { return fds[id * 8] > 0; } /* * Set SCSI target (returns false on error) */ bool scsi_set_target(int id, int lun) { int new_fd = fds[id * 8 + lun]; if (new_fd < 0) return false; if (new_fd != fd) rdc.cam_status &= ~CAM_AUTOSNS_VALID; // Clear sense data when selecting new target fd = new_fd; return true; } /* * Send SCSI command to active target (scsi_set_command() must have been called), * read/write data according to S/G table (returns false on error); timeout is in 1/60 sec */ bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout) { // Check if buffer is large enough, allocate new buffer if needed if (!try_buffer(data_length)) { char str[256]; sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length); ErrorAlert(str); return false; } // Process S/G table when writing if (!reading) { D(bug(" writing to buffer\n")); uint8 *buffer_ptr = buffer; for (int i=0; i #include #include #include "user_strings_beos.h" // Are the Mac and the host address space the same? #ifdef __i386__ #define REAL_ADDRESSING 0 #undef WORDS_BIGENDIAN #else #define REAL_ADDRESSING 1 #define WORDS_BIGENDIAN 1 #endif // Using 68k emulator #define EMULATED_68K 1 // Mac ROM is write protected #define ROM_IS_WRITE_PROTECTED 1 // ExtFS is supported #define SUPPORTS_EXTFS 1 // BSD socket API is supported #define SUPPORTS_UDP_TUNNEL 1 // mon is not supported #undef ENABLE_MON // Time data type for Time Manager emulation typedef bigtime_t tm_time_t; // 64 bit file offsets typedef off_t loff_t; // Networking types #define PF_INET AF_INET typedef int socklen_t; // UAE CPU data types #define uae_s8 int8 #define uae_u8 uint8 #define uae_s16 int16 #define uae_u16 uint16 #define uae_s32 int32 #define uae_u32 uint32 #define uae_s64 int64 #define uae_u64 uint64 typedef uae_u32 uaecptr; #define VAL64(a) (a ## LL) #define UVAL64(a) (a ## uLL) typedef uint32 uintptr; typedef int32 intptr; /* Timing functions */ extern void Delay_usec(uint32 usec); // UAE CPU defines #ifdef __i386__ // Intel x86 assembler optimizations #define X86_PPRO_OPT static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 retval; __asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc"); return retval;} #ifdef X86_PPRO_OPT static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswap %k0\n" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #else static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #endif #define HAVE_GET_WORD_UNSWAPPED #define do_get_mem_word_unswapped(a) ((uae_u32)*((uae_u16 *)(a))) static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #ifdef X86_PPRO_OPT static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("bswap %0" : "=&r" (v) : "0" (v << 16) : "cc"); *a = v;} #else static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #endif #define X86_ASSEMBLY #define UNALIGNED_PROFITABLE #define OPTIMIZED_FLAGS #define ASM_SYM_FOR_FUNC(a) __asm__(a) #define REGPARAM __attribute__((regparm(3))) #else // PowerPC (memory.cpp not used, so no optimization neccessary) static inline uae_u32 do_get_mem_long(uae_u32 *a) {return *a;} static inline uae_u32 do_get_mem_word(uae_u16 *a) {return *a;} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {*a = v;} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {*a = v;} #undef X86_ASSEMBLY #define UNALIGNED_PROFITABLE #undef OPTIMIZED_FLAGS #define ASM_SYM_FOR_FUNC(a) #define REGPARAM #endif #define do_get_mem_byte(a) ((uae_u32)*((uae_u8 *)(a))) #define do_put_mem_byte(a, v) (*(uae_u8 *)(a) = (v)) #define call_mem_get_func(func, addr) ((*func)(addr)) #define call_mem_put_func(func, addr, v) ((*func)(addr, v)) #define __inline__ inline #define CPU_EMU_SIZE 0 #undef NO_INLINE_MEMORY_ACCESS #undef MD_HAVE_MEM_1_FUNCS #undef USE_COMPILER #define REGPARAM2 #define ENUMDECL typedef enum #define ENUMNAME(name) name #define write_log printf #endif BasiliskII/src/BeOS/video_beos.cpp0000644000175000017500000006254110736405220017151 0ustar centriscentris/* * video_beos.cpp - Video/graphics emulation, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * Portions written by Marc Hellwig * * 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 */ #include #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "adb.h" #include "prefs.h" #include "user_strings.h" #include "about_window.h" #include "video.h" #include "m68k.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" #define DEBUG 0 #include "debug.h" #define DEBUGGER_AVAILABLE 0 // Messages const uint32 MSG_REDRAW = 'draw'; const uint32 MSG_ABOUT_REQUESTED = B_ABOUT_REQUESTED; const uint32 MSG_REF_5HZ = ' 5Hz'; const uint32 MSG_REF_7_5HZ = ' 7Hz'; const uint32 MSG_REF_10HZ = '10Hz'; const uint32 MSG_REF_15HZ = '15Hz'; const uint32 MSG_REF_30HZ = '30Hz'; const uint32 MSG_REF_60HZ = '60Hz'; const uint32 MSG_MOUNT = 'moun'; const uint32 MSG_DEBUGGER = 'dbug'; // Display types enum { DISPLAY_WINDOW, DISPLAY_SCREEN }; // From sys_beos.cpp extern void SysCreateVolumeMenu(BMenu *menu, uint32 msg); extern void SysMountVolume(const char *name); /* * A simple view class for blitting a bitmap on the screen */ class BitmapView : public BView { public: BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "bitmap", B_FOLLOW_NONE, B_WILL_DRAW) { the_bitmap = bitmap; } virtual void Draw(BRect update) { DrawBitmap(the_bitmap, update, update); } virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); private: BBitmap *the_bitmap; }; /* * Window class */ class MacWindow : public BDirectWindow { public: MacWindow(BRect frame); virtual ~MacWindow(); virtual void MessageReceived(BMessage *msg); virtual void DirectConnected(direct_buffer_info *info); virtual void WindowActivated(bool active); int32 frame_skip; bool mouse_in_view; // Flag: Mouse pointer within bitmap view uint8 remap_mac_be[256]; // For remapping of Mac colors to Be colors private: static status_t tick_func(void *arg); thread_id tick_thread; bool tick_thread_active; // Flag for quitting the tick thread BitmapView *main_view; // Main view for bitmap drawing BBitmap *the_bitmap; // Mac screen bitmap uint8 *the_buffer; // Mac frame buffer uint32 old_scroll_lock_state; bool supports_direct_mode; // Flag: Direct frame buffer access supported sem_id drawing_sem; void *bits; int32 bytes_per_row; color_space pixel_format; bool unclipped; }; /* * Screen class */ class MacScreen : public BWindowScreen { public: MacScreen(const char *name, int mode_bit, status_t *error); virtual ~MacScreen(); virtual void Quit(void); virtual void ScreenConnected(bool active); rgb_color palette[256]; // Color palette, 256 entries bool palette_changed; private: static status_t tick_func(void *arg); thread_id tick_thread; bool tick_thread_active; // Flag for quitting the tick thread BView *main_view; // Main view for GetMouse() uint8 *frame_backup; // Frame buffer backup when switching from/to different workspace bool quitting; // Flag for ScreenConnected: We are quitting, don't pause emulator thread bool screen_active; bool first_time; }; // Global variables static int display_type = DISPLAY_WINDOW; // See enum above static MacWindow *the_window = NULL; // Pointer to the window static MacScreen *the_screen = NULL; // Pointer to the screen static sem_id mac_os_lock = -1; // This is used to stop the MacOS thread when the Basilisk workspace is switched out static uint8 MacCursor[68] = {16, 1}; // Mac cursor image /* * Initialization */ // Add resolution to list of supported modes and set VideoMonitor static void set_video_monitor(uint32 width, uint32 height, uint32 bytes_per_row, int depth) { video_mode mode; mode.x = width; mode.y = height; mode.resolution_id = 0x80; mode.bytes_per_row = bytes_per_row; switch (depth) { case 1: mode.depth = VDEPTH_1BIT; break; case 2: mode.depth = VDEPTH_2BIT; break; case 4: mode.depth = VDEPTH_4BIT; break; case 8: mode.depth = VDEPTH_8BIT; break; case 15: mode.depth = VDEPTH_16BIT; break; case 16: mode.depth = VDEPTH_16BIT; break; case 24: case 32: mode.depth = VDEPTH_32BIT; break; } VideoModes.push_back(mode); video_init_depth_list(); VideoMonitor.mode = mode; } bool VideoInit(bool classic) { // Create semaphore mac_os_lock = create_sem(0, "MacOS Frame Buffer Lock"); // Get screen mode from preferences const char *mode_str = PrefsFindString("screen"); // Determine type and mode display_type = DISPLAY_WINDOW; int width = 512, height = 384; int scr_mode_bit = 0; if (mode_str) { if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2) display_type = DISPLAY_WINDOW; else if (sscanf(mode_str, "scr/%d", &scr_mode_bit) == 1) display_type = DISPLAY_SCREEN; } // Open display switch (display_type) { case DISPLAY_WINDOW: the_window = new MacWindow(BRect(0, 0, width-1, height-1)); break; case DISPLAY_SCREEN: { status_t screen_error; the_screen = new MacScreen(GetString(STR_WINDOW_TITLE), scr_mode_bit & 0x1f, &screen_error); if (screen_error != B_NO_ERROR) { the_screen->PostMessage(B_QUIT_REQUESTED); while (the_screen) snooze(200000); ErrorAlert(STR_OPEN_SCREEN_ERR); return false; } else { the_screen->Show(); acquire_sem(mac_os_lock); } break; } } return true; } /* * Deinitialization */ void VideoExit(void) { // Close display switch (display_type) { case DISPLAY_WINDOW: if (the_window != NULL) { the_window->PostMessage(B_QUIT_REQUESTED); while (the_window) snooze(200000); } break; case DISPLAY_SCREEN: if (the_screen != NULL) { the_screen->PostMessage(B_QUIT_REQUESTED); while (the_screen) snooze(200000); } break; } // Delete semaphore delete_sem(mac_os_lock); } /* * Set palette */ void video_set_palette(uint8 *pal, int num) { switch (display_type) { case DISPLAY_WINDOW: { BScreen screen(the_window); for (int i=0; i<256; i++) the_window->remap_mac_be[i] = screen.IndexForColor(pal[i*3], pal[i*3+1], pal[i*3+2]); break; } case DISPLAY_SCREEN: for (int i=0; i<256; i++) { the_screen->palette[i].red = pal[i*3]; the_screen->palette[i].green = pal[i*3+1]; the_screen->palette[i].blue = pal[i*3+2]; } the_screen->palette_changed = true; break; } } /* * Switch video mode */ void video_switch_to_mode(const video_mode &mode) { } /* * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode) */ void VideoQuitFullScreen(void) { D(bug("VideoQuitFullScreen()\n")); if (display_type == DISPLAY_SCREEN) { if (the_screen != NULL) { the_screen->PostMessage(B_QUIT_REQUESTED); while (the_screen) snooze(200000); } } } /* * Video event handling (not neccessary under BeOS, handled by filter function) */ void VideoInterrupt(void) { release_sem(mac_os_lock); while (acquire_sem(mac_os_lock) == B_INTERRUPTED) ; } /* * Filter function for receiving mouse and keyboard events */ #define MENU_IS_POWER 0 // Be -> Mac raw keycode translation table static const uint8 keycode2mac[0x80] = { 0xff, 0x35, 0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, // inv Esc F1 F2 F3 F4 F5 F6 0x62, 0x64, 0x65, 0x6d, 0x67, 0x6f, 0x69, 0x6b, // F7 F8 F9 F10 F11 F12 F13 F14 0x71, 0x0a, 0x12, 0x13, 0x14, 0x15, 0x17, 0x16, // F15 ` 1 2 3 4 5 6 0x1a, 0x1c, 0x19, 0x1d, 0x1b, 0x18, 0x33, 0x72, // 7 8 9 0 - = BSP INS 0x73, 0x74, 0x47, 0x4b, 0x43, 0x4e, 0x30, 0x0c, // HOM PUP NUM / * - TAB Q 0x0d, 0x0e, 0x0f, 0x11, 0x10, 0x20, 0x22, 0x1f, // W E R T Y U I O 0x23, 0x21, 0x1e, 0x2a, 0x75, 0x77, 0x79, 0x59, // P [ ] \ DEL END PDN 7 0x5b, 0x5c, 0x45, 0x39, 0x00, 0x01, 0x02, 0x03, // 8 9 + CAP A S D F 0x05, 0x04, 0x26, 0x28, 0x25, 0x29, 0x27, 0x24, // G H J K L ; ' RET 0x56, 0x57, 0x58, 0x38, 0x06, 0x07, 0x08, 0x09, // 4 5 6 SHL Z X C V 0x0b, 0x2d, 0x2e, 0x2b, 0x2f, 0x2c, 0x38, 0x3e, // B N M , . / SHR CUP 0x53, 0x54, 0x55, 0x4c, 0x36, 0x37, 0x31, 0x37, // 1 2 3 ENT CTL ALT SPC ALT 0x36, 0x3b, 0x3d, 0x3c, 0x52, 0x41, 0x3a, 0x3a, // CTR CLF CDN CRT 0 . CMD CMD #if MENU_IS_POWER 0x7f, 0x32, 0x51, 0x7f, 0xff, 0xff, 0xff, 0xff, // MNU EUR = POW inv inv inv inv #else 0x32, 0x32, 0x51, 0x7f, 0xff, 0xff, 0xff, 0xff, // MNU EUR = POW inv inv inv inv #endif 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv }; static const uint8 modifier2mac[0x20] = { #if MENU_IS_POWER 0x38, 0x37, 0x36, 0x39, 0x6b, 0x47, 0x3a, 0x7f, // SHF CMD inv CAP F14 NUM OPT MNU #else 0x38, 0x37, 0x36, 0x39, 0x6b, 0x47, 0x3a, 0x32, // SHF CMD CTR CAP F14 NUM OPT MNU #endif 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv }; static filter_result filter_func(BMessage *msg, BHandler **target, BMessageFilter *filter) { switch (msg->what) { case B_KEY_DOWN: case B_KEY_UP: { uint32 be_code = msg->FindInt32("key") & 0xff; uint32 mac_code = keycode2mac[be_code]; // Intercept Ctrl-F1 (mount floppy disk shortcut) uint32 mods = msg->FindInt32("modifiers"); if (be_code == 0x02 && (mods & B_CONTROL_KEY)) SysMountVolume("/dev/disk/floppy/raw"); if (mac_code == 0xff) return B_DISPATCH_MESSAGE; if (msg->what == B_KEY_DOWN) ADBKeyDown(mac_code); else ADBKeyUp(mac_code); return B_SKIP_MESSAGE; } case B_MODIFIERS_CHANGED: { uint32 mods = msg->FindInt32("modifiers"); uint32 old_mods = msg->FindInt32("be:old_modifiers"); uint32 changed = mods ^ old_mods; uint32 mask = 1; for (int i=0; i<32; i++, mask<<=1) if (changed & mask) { uint32 mac_code = modifier2mac[i]; if (mac_code == 0xff) continue; if (mods & mask) ADBKeyDown(mac_code); else ADBKeyUp(mac_code); } return B_SKIP_MESSAGE; } case B_MOUSE_MOVED: { BPoint point; msg->FindPoint("where", &point); ADBMouseMoved(int(point.x), int(point.y)); return B_DISPATCH_MESSAGE; // Otherwise BitmapView::MouseMoved() wouldn't be called } case B_MOUSE_DOWN: { uint32 buttons = msg->FindInt32("buttons"); if (buttons & B_PRIMARY_MOUSE_BUTTON) ADBMouseDown(0); if (buttons & B_SECONDARY_MOUSE_BUTTON) ADBMouseDown(1); if (buttons & B_TERTIARY_MOUSE_BUTTON) ADBMouseDown(2); return B_SKIP_MESSAGE; } case B_MOUSE_UP: // B_MOUSE_UP means "all buttons released" ADBMouseUp(0); ADBMouseUp(1); ADBMouseUp(2); return B_SKIP_MESSAGE; default: return B_DISPATCH_MESSAGE; } } /* * Window constructor */ MacWindow::MacWindow(BRect frame) : BDirectWindow(frame, GetString(STR_WINDOW_TITLE), B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE) { supports_direct_mode = SupportsWindowMode(); // Move window to right position Lock(); MoveTo(80, 60); // Allocate bitmap and Mac frame buffer uint32 x = frame.IntegerWidth() + 1; uint32 y = frame.IntegerHeight() + 1; the_bitmap = new BBitmap(frame, B_COLOR_8_BIT); the_buffer = new uint8[x * (y + 2)]; // "y + 2" for safety // Add resolution and set VideoMonitor set_video_monitor(x, y, x, 8); #if REAL_ADDRESSING VideoMonitor.mac_frame_base = (uint32)the_buffer; #else VideoMonitor.mac_frame_base = MacFrameBaseMac; #endif #if !REAL_ADDRESSING // Set variables for UAE memory mapping MacFrameBaseHost = the_buffer; MacFrameSize = x * y; MacFrameLayout = FLAYOUT_DIRECT; #endif // Create bitmap view main_view = new BitmapView(frame, the_bitmap); AddChild(main_view); main_view->MakeFocus(); // Read frame skip prefs frame_skip = PrefsFindInt32("frameskip"); if (frame_skip == 0) frame_skip = 1; // Set up menus BRect bounds = Bounds(); bounds.OffsetBy(0, bounds.IntegerHeight() + 1); BMenuItem *item; BMenuBar *bar = new BMenuBar(bounds, "menu"); BMenu *menu = new BMenu(GetString(STR_WINDOW_MENU)); menu->AddItem(new BMenuItem(GetString(STR_WINDOW_ITEM_ABOUT), new BMessage(MSG_ABOUT_REQUESTED))); menu->AddItem(new BSeparatorItem); BMenu *submenu = new BMenu(GetString(STR_WINDOW_ITEM_REFRESH)); submenu->AddItem(new BMenuItem(GetString(STR_REF_5HZ_LAB), new BMessage(MSG_REF_5HZ))); submenu->AddItem(new BMenuItem(GetString(STR_REF_7_5HZ_LAB), new BMessage(MSG_REF_7_5HZ))); submenu->AddItem(new BMenuItem(GetString(STR_REF_10HZ_LAB), new BMessage(MSG_REF_10HZ))); submenu->AddItem(new BMenuItem(GetString(STR_REF_15HZ_LAB), new BMessage(MSG_REF_15HZ))); submenu->AddItem(new BMenuItem(GetString(STR_REF_30HZ_LAB), new BMessage(MSG_REF_30HZ))); submenu->AddItem(new BMenuItem(GetString(STR_REF_60HZ_LAB), new BMessage(MSG_REF_60HZ))); submenu->SetRadioMode(true); if (frame_skip == 12) { if ((item = submenu->FindItem(GetString(STR_REF_5HZ_LAB))) != NULL) item->SetMarked(true); } else if (frame_skip == 8) { if ((item = submenu->FindItem(GetString(STR_REF_7_5HZ_LAB))) != NULL) item->SetMarked(true); } else if (frame_skip == 6) { if ((item = submenu->FindItem(GetString(STR_REF_10HZ_LAB))) != NULL) item->SetMarked(true); } else if (frame_skip == 4) { if ((item = submenu->FindItem(GetString(STR_REF_15HZ_LAB))) != NULL) item->SetMarked(true); } else if (frame_skip == 2) { if ((item = submenu->FindItem(GetString(STR_REF_30HZ_LAB))) != NULL) item->SetMarked(true); } else if (frame_skip == 1) { if ((item = submenu->FindItem(GetString(STR_REF_60HZ_LAB))) != NULL) item->SetMarked(true); } menu->AddItem(submenu); submenu = new BMenu(GetString(STR_WINDOW_ITEM_MOUNT)); SysCreateVolumeMenu(submenu, MSG_MOUNT); menu->AddItem(submenu); #if DEBUGGER_AVAILABLE menu->AddItem(new BMenuItem("Debugger", new BMessage(MSG_DEBUGGER))); #endif bar->AddItem(menu); AddChild(bar); SetKeyMenuBar(bar); int mbar_height = bar->Frame().IntegerHeight() + 1; // Resize window to fit menu bar ResizeBy(0, mbar_height); // Set absolute mouse mode and get scroll lock state ADBSetRelMouseMode(false); mouse_in_view = true; old_scroll_lock_state = modifiers() & B_SCROLL_LOCK; if (old_scroll_lock_state) SetTitle(GetString(STR_WINDOW_TITLE_FROZEN)); else SetTitle(GetString(STR_WINDOW_TITLE)); // Keep window aligned to 8-byte frame buffer boundaries for faster blitting SetWindowAlignment(B_BYTE_ALIGNMENT, 8); // Create drawing semaphore (for direct mode) drawing_sem = create_sem(0, "direct frame buffer access"); // Start 60Hz interrupt tick_thread_active = true; tick_thread = spawn_thread(tick_func, "Window Redraw", B_DISPLAY_PRIORITY, this); resume_thread(tick_thread); // Add filter for keyboard and mouse events BMessageFilter *filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, filter_func); main_view->AddFilter(filter); // Show window Unlock(); Show(); Sync(); } /* * Window destructor */ MacWindow::~MacWindow() { // Restore cursor mouse_in_view = false; be_app->SetCursor(B_HAND_CURSOR); // Hide window Hide(); Sync(); // Stop 60Hz interrupt status_t l; tick_thread_active = false; delete_sem(drawing_sem); wait_for_thread(tick_thread, &l); // Free bitmap and frame buffer delete the_bitmap; delete[] the_buffer; // Tell emulator that we're done the_window = NULL; } /* * Window connected/disconnected */ void MacWindow::DirectConnected(direct_buffer_info *info) { switch (info->buffer_state & B_DIRECT_MODE_MASK) { case B_DIRECT_STOP: acquire_sem(drawing_sem); break; case B_DIRECT_MODIFY: acquire_sem(drawing_sem); case B_DIRECT_START: bits = (void *)((uint8 *)info->bits + info->window_bounds.top * info->bytes_per_row + info->window_bounds.left * info->bits_per_pixel / 8); bytes_per_row = info->bytes_per_row; pixel_format = info->pixel_format; unclipped = false; if (info->clip_list_count == 1) if (memcmp(&info->clip_bounds, &info->window_bounds, sizeof(clipping_rect)) == 0) unclipped = true; release_sem(drawing_sem); break; } } /* * Handle redraw and menu messages */ void MacWindow::MessageReceived(BMessage *msg) { BMessage *msg2; switch (msg->what) { case MSG_REDRAW: { // Prevent backlog of messages MessageQueue()->Lock(); while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) { MessageQueue()->RemoveMessage(msg2); delete msg2; } MessageQueue()->Unlock(); // Convert Mac screen buffer to BeOS palette and blit uint8 *source = the_buffer - 1; uint8 *dest = (uint8 *)the_bitmap->Bits() - 1; uint32 length = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y; for (int i=0; iDrawBitmapAsync(the_bitmap, update_rect, update_rect); break; } case MSG_ABOUT_REQUESTED: { ShowAboutWindow(); break; } case MSG_REF_5HZ: PrefsReplaceInt32("frameskip", frame_skip = 12); break; case MSG_REF_7_5HZ: PrefsReplaceInt32("frameskip", frame_skip = 8); break; case MSG_REF_10HZ: PrefsReplaceInt32("frameskip", frame_skip = 6); break; case MSG_REF_15HZ: PrefsReplaceInt32("frameskip", frame_skip = 4); break; case MSG_REF_30HZ: PrefsReplaceInt32("frameskip", frame_skip = 2); break; case MSG_REF_60HZ: PrefsReplaceInt32("frameskip", frame_skip = 1); break; case MSG_MOUNT: { BMenuItem *source = NULL; msg->FindPointer("source", (void **)&source); if (source) SysMountVolume(source->Label()); break; } #if DEBUGGER_AVAILABLE case MSG_DEBUGGER: extern int debugging; debugging = 1; regs.spcflags |= SPCFLAG_BRK; break; #endif default: BDirectWindow::MessageReceived(msg); } } /* * Window activated/deactivated */ void MacWindow::WindowActivated(bool active) { if (active) { frame_skip = PrefsFindInt32("frameskip"); if (frame_skip == 0) frame_skip = 1; } else frame_skip = 12; // 5Hz in background } /* * 60Hz interrupt routine */ status_t MacWindow::tick_func(void *arg) { MacWindow *obj = (MacWindow *)arg; static int tick_counter = 0; while (obj->tick_thread_active) { tick_counter++; if (tick_counter >= obj->frame_skip) { tick_counter = 0; // Window title is determined by Scroll Lock state uint32 scroll_lock_state = modifiers() & B_SCROLL_LOCK; if (scroll_lock_state != obj->old_scroll_lock_state) { if (scroll_lock_state) obj->SetTitle(GetString(STR_WINDOW_TITLE_FROZEN)); else obj->SetTitle(GetString(STR_WINDOW_TITLE)); obj->old_scroll_lock_state = scroll_lock_state; } // Has the Mac started? if (HasMacStarted()) { // Yes, set new cursor image if it was changed if (memcmp(MacCursor+4, Mac2HostAddr(0x844), 64)) { Mac2Host_memcpy(MacCursor+4, 0x844, 64); // Cursor image MacCursor[2] = ReadMacInt8(0x885); // Hotspot MacCursor[3] = ReadMacInt8(0x887); be_app->SetCursor(MacCursor); } } // Refresh screen unless Scroll Lock is down if (!scroll_lock_state) { // If direct frame buffer access is supported and the content area is completely visible, // convert the Mac screen buffer directly. Otherwise, send a message to the window to do // it into a bitmap if (obj->supports_direct_mode) { if (acquire_sem(obj->drawing_sem) != B_NO_ERROR) return 0; if (obj->unclipped && obj->pixel_format == B_CMAP8) { uint8 *source = obj->the_buffer - 1; uint8 *dest = (uint8 *)obj->bits; uint32 bytes_per_row = obj->bytes_per_row; int xsize = VideoMonitor.mode.x; int ysize = VideoMonitor.mode.y; for (int y=0; yremap_mac_be[*++source] << 24; c |= obj->remap_mac_be[*++source] << 16; c |= obj->remap_mac_be[*++source] << 8; c |= obj->remap_mac_be[*++source]; #else uint32 c = obj->remap_mac_be[*++source]; c |= obj->remap_mac_be[*++source] << 8; c |= obj->remap_mac_be[*++source] << 16; c |= obj->remap_mac_be[*++source] << 24; #endif *++p = c; } dest += bytes_per_row; } } else obj->PostMessage(MSG_REDRAW); release_sem(obj->drawing_sem); } else obj->PostMessage(MSG_REDRAW); } } snooze(16666); } return 0; } /* * Mouse moved in window */ void BitmapView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) { switch (transit) { case B_ENTERED_VIEW: ((MacWindow *)Window())->mouse_in_view = true; be_app->SetCursor(MacCursor); break; case B_EXITED_VIEW: ((MacWindow *)Window())->mouse_in_view = false; be_app->SetCursor(B_HAND_CURSOR); break; } } /* * Screen constructor */ MacScreen::MacScreen(const char *name, int mode_bit, status_t *error) : BWindowScreen(name, 1 << mode_bit, error), tick_thread(-1) { // Set all variables frame_backup = NULL; palette_changed = false; screen_active = false; first_time = true; quitting = false; // Set relative mouse mode ADBSetRelMouseMode(true); // Create view to get mouse events main_view = new BView(Frame(), NULL, B_FOLLOW_NONE, 0); AddChild(main_view); // Start 60Hz interrupt tick_thread_active = true; tick_thread = spawn_thread(tick_func, "Polling sucks...", B_DISPLAY_PRIORITY, this); resume_thread(tick_thread); // Add filter for keyboard and mouse events BMessageFilter *filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, filter_func); AddCommonFilter(filter); } /* * Screen destructor */ MacScreen::~MacScreen() { // Stop 60Hz interrupt if (tick_thread > 0) { status_t l; tick_thread_active = false; wait_for_thread(tick_thread, &l); } // Tell emulator that we're done the_screen = NULL; } /* * Screen closed */ void MacScreen::Quit(void) { // Tell ScreenConnected() that we are quitting quitting = true; BWindowScreen::Quit(); } /* * Screen connected/disconnected */ void MacScreen::ScreenConnected(bool active) { graphics_card_info *info = CardInfo(); screen_active = active; if (active == true) { // Add resolution and set VideoMonitor if (first_time) { set_video_monitor(info->width, info->height, info->bytes_per_row, info->bits_per_pixel); first_time = false; } // Set VideoMonitor #if REAL_ADDRESSING VideoMonitor.mac_frame_base = (uint32)info->frame_buffer; #else VideoMonitor.mac_frame_base = MacFrameBaseMac; #endif #if !REAL_ADDRESSING // Set variables for UAE memory mapping MacFrameBaseHost = (uint8 *)info->frame_buffer; MacFrameSize = VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y; switch (info->bits_per_pixel) { case 15: MacFrameLayout = FLAYOUT_HOST_555; break; case 16: MacFrameLayout = FLAYOUT_HOST_565; break; case 32: MacFrameLayout = FLAYOUT_HOST_888; break; default: MacFrameLayout = FLAYOUT_DIRECT; break; } #endif // Copy from backup store to frame buffer if (frame_backup != NULL) { memcpy(info->frame_buffer, frame_backup, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y); delete[] frame_backup; frame_backup = NULL; } // Restore palette if (VideoMonitor.mode.depth == VDEPTH_8BIT) SetColorList(palette); // Restart/signal emulator thread release_sem(mac_os_lock); } else { if (!quitting) { // Stop emulator thread acquire_sem(mac_os_lock); // Create backup store and save frame buffer frame_backup = new uint8[VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y]; memcpy(frame_backup, info->frame_buffer, VideoMonitor.mode.bytes_per_row * VideoMonitor.mode.y); } } } /* * Screen 60Hz interrupt routine */ status_t MacScreen::tick_func(void *arg) { MacScreen *obj = (MacScreen *)arg; while (obj->tick_thread_active) { // Wait snooze(16667); // Workspace activated? Then poll the mouse and set the palette if needed if (!obj->quitting && obj->LockWithTimeout(200000) == B_OK) { if (obj->screen_active) { BPoint pt; uint32 button = 0; if (obj->palette_changed) { obj->palette_changed = false; obj->SetColorList(obj->palette); } obj->main_view->GetMouse(&pt, &button); set_mouse_position(320, 240); ADBMouseMoved(int(pt.x) - 320, int(pt.y) - 240); if (button & B_PRIMARY_MOUSE_BUTTON) ADBMouseDown(0); if (!(button & B_PRIMARY_MOUSE_BUTTON)) ADBMouseUp(0); if (button & B_SECONDARY_MOUSE_BUTTON) ADBMouseDown(1); if (!(button & B_SECONDARY_MOUSE_BUTTON)) ADBMouseUp(1); if (button & B_TERTIARY_MOUSE_BUTTON) ADBMouseDown(2); if (!(button & B_TERTIARY_MOUSE_BUTTON)) ADBMouseUp(2); } obj->Unlock(); } } return 0; } BasiliskII/src/BeOS/user_strings_beos.h0000644000175000017500000000212210736405220020224 0ustar centriscentris/* * user_strings_beos.h - BeOS-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef USER_STRINGS_BEOS_H #define USER_STRINGS_BEOS_H enum { STR_NO_SHEEP_DRIVER_ERR = 10000, STR_SHEEP_UP_ERR, STR_NO_KERNEL_DATA_ERR, STR_NO_NET_ADDON_WARN, STR_NET_CONFIG_MODIFY_WARN, STR_NET_ADDON_INIT_FAILED, STR_NET_ADDON_CLONE_FAILED }; #endif BasiliskII/src/BeOS/sys_beos.cpp0000644000175000017500000004122010736405220016650 0ustar centriscentris/* * sys_beos.cpp - System dependent routines, BeOS implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "sys.h" #define DEBUG 0 #include "debug.h" // File handles are pointers to these structures struct file_handle { file_handle *next; // Pointer to next file handle (must be first in struct!) const char *name; // File/device name (copied, for mount menu) int fd; // fd of file/device bool is_file; // Flag: plain file or /dev/something? bool read_only; // Copy of Sys_open() flag loff_t start_byte; // Size of file header (if any) loff_t file_size; // Size of file data (only valid if is_file is true) }; // Linked list of file handles static file_handle *first_file_handle; // Temporary buffer for transfers from/to kernel space const int TMP_BUF_SIZE = 0x10000; static uint8 *tmp_buf; // For B_SCSI_PREVENT_ALLOW static const int32 PREVENT = 1; static const int32 ALLOW = 0; /* * Check if device is a mounted HFS volume, get mount name */ static bool is_drive_mounted(const char *dev_name, char *mount_name) { int32 i = 0; dev_t d; fs_info info; while ((d = next_dev(&i)) >= 0) { fs_stat_dev(d, &info); if (strcmp(dev_name, info.device_name) == 0) { status_t err = -1; BPath mount; BDirectory dir; BEntry entry; node_ref node; node.device = info.dev; node.node = info.root; err = dir.SetTo(&node); if (!err) err = dir.GetEntry(&entry); if (!err) err = entry.GetPath(&mount); if (!err) { strcpy(mount_name, mount.Path()); return true; } } } return false; } /* * Initialization */ void SysInit(void) { first_file_handle = NULL; // Allocate temporary buffer tmp_buf = new uint8[TMP_BUF_SIZE]; } /* * Deinitialization */ void SysExit(void) { delete[] tmp_buf; } /* * Create menu of used volumes (for "mount" menu) */ void SysCreateVolumeMenu(BMenu *menu, uint32 msg) { for (file_handle *fh=first_file_handle; fh; fh=fh->next) if (!SysIsFixedDisk(fh)) menu->AddItem(new BMenuItem(fh->name, new BMessage(msg))); } /* * Mount volume given name from mount menu */ void SysMountVolume(const char *name) { file_handle *fh; for (fh=first_file_handle; fh && strcmp(fh->name, name); fh=fh->next) ; if (fh) MountVolume(fh); } /* * This gets called when no "floppy" prefs items are found * It scans for available floppy drives and adds appropriate prefs items */ void SysAddFloppyPrefs(void) { // Only one floppy drive under BeOS PrefsAddString("floppy", "/dev/disk/floppy/raw"); } /* * This gets called when no "disk" prefs items are found * It scans for available HFS volumes and adds appropriate prefs items */ void SysAddDiskPrefs(void) { // Let BeOS scan for HFS drives D(bug("Looking for Mac volumes...\n")); system("mountvolume -allhfs"); // Add all HFS volumes int32 i = 0; dev_t d; fs_info info; while ((d = next_dev(&i)) >= 0) { fs_stat_dev(d, &info); status_t err = -1; BPath mount; if (!strcmp(info.fsh_name, "hfs")) { BDirectory dir; BEntry entry; node_ref node; node.device = info.dev; node.node = info.root; err = dir.SetTo(&node); if (!err) err = dir.GetEntry(&entry); if (!err) err = entry.GetPath(&mount); } if (!err) err = unmount(mount.Path()); if (!err) { char dev_name[B_FILE_NAME_LENGTH]; if (info.flags & B_FS_IS_READONLY) { dev_name[0] = '*'; dev_name[1] = 0; } else dev_name[0] = 0; strcat(dev_name, info.device_name); PrefsAddString("disk", dev_name); } } } /* * This gets called when no "cdrom" prefs items are found * It scans for available CD-ROM drives and adds appropriate prefs items */ // Scan directory for CD-ROM drives, add them to prefs static void scan_for_cdrom_drives(const char *directory) { // Set directory BDirectory dir; dir.SetTo(directory); if (dir.InitCheck() != B_NO_ERROR) return; dir.Rewind(); // Scan each entry BEntry entry; while (dir.GetNextEntry(&entry) >= 0) { // Get path and ref for entry BPath path; if (entry.GetPath(&path) != B_NO_ERROR) continue; const char *name = path.Path(); entry_ref e; if (entry.GetRef(&e) != B_NO_ERROR) continue; // Recursively enter subdirectories (except for floppy) if (entry.IsDirectory()) { if (!strcmp(e.name, "floppy")) continue; scan_for_cdrom_drives(name); } else { D(bug(" checking '%s'\n", name)); // Ignore partitions if (strcmp(e.name, "raw")) continue; // Open device int fd = open(name, O_RDONLY); if (fd < 0) continue; // Get geometry and device type device_geometry g; if (ioctl(fd, B_GET_GEOMETRY, &g, sizeof(g)) < 0) { close(fd); continue; } // Insert to list if it is a CD drive if (g.device_type == B_CD) PrefsAddString("cdrom", name); close(fd); } } } void SysAddCDROMPrefs(void) { // Don't scan for drives if nocdrom option given if (PrefsFindBool("nocdrom")) return; // Look for CD-ROM drives and add prefs items D(bug("Looking for CD-ROM drives...\n")); scan_for_cdrom_drives("/dev/disk"); } /* * Add default serial prefs (must be added, even if no ports present) */ void SysAddSerialPrefs(void) { system_info info; get_system_info(&info); switch (info.platform_type) { case B_BEBOX_PLATFORM: case B_AT_CLONE_PLATFORM: PrefsAddString("seriala", "serial1"); PrefsAddString("serialb", "serial2"); break; case B_MAC_PLATFORM: PrefsAddString("seriala", "modem"); PrefsAddString("serialb", "printer"); break; default: PrefsAddString("seriala", "none"); PrefsAddString("serialb", "none"); break; } } /* * Open file/device, create new file handle (returns NULL on error) */ void *Sys_open(const char *name, bool read_only) { static bool published_all = false; bool is_file = (strstr(name, "/dev/") != name); D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write")); // Print warning message and eventually unmount drive when this is an HFS volume mounted under BeOS (double mounting will corrupt the volume) char mount_name[B_FILE_NAME_LENGTH]; if (!is_file && !read_only && is_drive_mounted(name, mount_name)) { char str[256 + B_FILE_NAME_LENGTH]; sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name); WarningAlert(str); if (unmount(mount_name) != 0) { sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name); WarningAlert(str); return NULL; } } int fd = open(name, read_only ? O_RDONLY : O_RDWR); if (fd < 0 && !published_all) { // Open failed, create all device nodes and try again, but only the first time system("mountvolume -publishall"); published_all = true; fd = open(name, read_only ? O_RDONLY : O_RDWR); } if (fd >= 0) { file_handle *fh = new file_handle; fh->name = strdup(name); fh->fd = fd; fh->is_file = is_file; fh->read_only = read_only; fh->start_byte = 0; if (fh->is_file) { // Detect disk image file layout loff_t size = lseek(fd, 0, SEEK_END); uint8 data[256]; lseek(fd, 0, SEEK_SET); read(fd, data, 256); FileDiskLayout(size, data, fh->start_byte, fh->file_size); } // Enqueue file handle fh->next = NULL; file_handle *q = first_file_handle; if (q) { while (q->next) q = q->next; q->next = fh; } else first_file_handle = fh; return fh; } else return NULL; } /* * Close file/device, delete file handle */ void Sys_close(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; // Free device name and close file/device free((void *)fh->name); close(fh->fd); // Dequeue file handle file_handle *q = first_file_handle; if (q == fh) { first_file_handle = NULL; delete fh; return; } while (q) { if (q->next == fh) { q->next = fh->next; delete fh; return; } q = q->next; } } /* * Read "length" bytes from file/device, starting at "offset", to "buffer", * returns number of bytes read (or 0) */ static inline ssize_t sread(int fd, void *buf, size_t count) { ssize_t res; while ((res = read(fd, buf, count)) == B_INTERRUPTED) ; return res; } size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length) { file_handle *fh = (file_handle *)arg; if (!fh) return 0; // D(bug("Sys_read(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length)); // Seek to position if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) return 0; // Buffer in kernel space? size_t actual = 0; if ((uint32)buffer < 0x80000000) { // Yes, transfer via buffer while (length) { size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; if (sread(fh->fd, tmp_buf, transfer_size) != transfer_size) return actual; memcpy(buffer, tmp_buf, transfer_size); buffer = (void *)((uint8 *)buffer + transfer_size); length -= transfer_size; actual += transfer_size; } } else { // No, transfer directly actual = sread(fh->fd, buffer, length); if (actual < 0) actual = 0; } return actual; } /* * Write "length" bytes from "buffer" to file/device, starting at "offset", * returns number of bytes written (or 0) */ static inline ssize_t swrite(int fd, void *buf, size_t count) { ssize_t res; while ((res = write(fd, buf, count)) == B_INTERRUPTED) ; return res; } size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length) { file_handle *fh = (file_handle *)arg; if (!fh) return 0; // D(bug("Sys_write(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length)); // Seek to position if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) return 0; // Buffer in kernel space? size_t actual = 0; if ((uint32)buffer < 0x80000000) { // Yes, transfer via buffer while (length) { size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; memcpy(tmp_buf, buffer, transfer_size); if (swrite(fh->fd, tmp_buf, transfer_size) != transfer_size) return actual; buffer = (void *)((uint8 *)buffer + transfer_size); length -= transfer_size; actual += transfer_size; } } else { // No, transfer directly actual = swrite(fh->fd, buffer, length); if (actual < 0) actual = 0; } return actual; } /* * Return size of file/device (minus header) */ loff_t SysGetFileSize(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; if (fh->is_file) return fh->file_size; else { device_geometry g; if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) return (loff_t)g.bytes_per_sector * g.sectors_per_track * g.cylinder_count * g.head_count; else return 0; } } /* * Eject volume (if applicable) */ void SysEject(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) ioctl(fh->fd, B_EJECT_DEVICE); } /* * Format volume (if applicable) */ bool SysFormat(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (!fh->is_file) return ioctl(fh->fd, B_FORMAT_DEVICE) >= 0; else return false; } /* * Check if file/device is read-only (this includes the read-only flag on Sys_open()) */ bool SysIsReadOnly(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; if (fh->is_file) { // File, return flag given to Sys_open return fh->read_only; } else { // Device, check write protection device_geometry g; if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) return g.read_only | fh->read_only; else return fh->read_only; // Removable but not inserted } } /* * Check if the given file handle refers to a fixed or a removable disk */ bool SysIsFixedDisk(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; if (fh->is_file) return true; else { device_geometry g; if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) return !g.removable; else return false; // Removable but not inserted } } /* * Check if a disk is inserted in the drive (always true for files) */ bool SysIsDiskInserted(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return true; else { status_t l; if (ioctl(fh->fd, B_GET_MEDIA_STATUS, &l, sizeof(l)) >= 0 && l == B_NO_ERROR) return true; else return false; } } /* * Prevent medium removal (if applicable) */ void SysPreventRemoval(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &PREVENT, sizeof(PREVENT)); } /* * Allow medium removal (if applicable) */ void SysAllowRemoval(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &ALLOW, sizeof(ALLOW)); } /* * Read CD-ROM TOC (binary MSF format, 804 bytes max.) */ bool SysCDReadTOC(void *arg, uint8 *toc) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (!fh->is_file) { memset(tmp_buf, 0, 804); if (ioctl(fh->fd, B_SCSI_GET_TOC, tmp_buf, 804) < 0) return false; memcpy(toc, tmp_buf, 804); return true; } else return false; } /* * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard) */ bool SysCDGetPosition(void *arg, uint8 *pos) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (!fh->is_file) { if (ioctl(fh->fd, B_SCSI_GET_POSITION, tmp_buf, 16) < 0) return false; memcpy(pos, tmp_buf, 16); return true; } else return false; } /* * Play CD audio */ bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (!fh->is_file) { scsi_play_position *p = (scsi_play_position *)tmp_buf; p->start_m = start_m; p->start_s = start_s; p->start_f = start_f; p->end_m = end_m; p->end_s = end_s; p->end_f = end_f; return ioctl(fh->fd, B_SCSI_PLAY_POSITION, p, sizeof(scsi_play_position)) == 0; } else return false; } /* * Pause CD audio */ bool SysCDPause(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; if (!fh->is_file) return ioctl(fh->fd, B_SCSI_PAUSE_AUDIO) == 0; else return false; } /* * Resume paused CD audio */ bool SysCDResume(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (!fh->is_file) return ioctl(fh->fd, B_SCSI_RESUME_AUDIO) == 0; else return false; } /* * Stop CD audio */ bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (!fh->is_file) return ioctl(fh->fd, B_SCSI_STOP_AUDIO) == 0; else return false; } /* * Perform CD audio fast-forward/fast-reverse operation starting from specified address */ bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (!fh->is_file) { scsi_scan *p = (scsi_scan *)tmp_buf; p->speed = 0; p->direction = reverse ? -1 : 1; return ioctl(fh->fd, B_SCSI_SCAN, p, sizeof(scsi_scan)) == 0; } else return false; } /* * Set CD audio volume (0..255 each channel) */ void SysCDSetVolume(void *arg, uint8 left, uint8 right) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) { scsi_volume *p = (scsi_volume *)tmp_buf; p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME; p->port0_volume = left; p->port1_volume = right; ioctl(fh->fd, B_SCSI_SET_VOLUME, p, sizeof(scsi_volume)); } } /* * Get CD audio volume (0..255 each channel) */ void SysCDGetVolume(void *arg, uint8 &left, uint8 &right) { file_handle *fh = (file_handle *)arg; if (!fh) return; left = right = 0; if (!fh->is_file) { scsi_volume *p = (scsi_volume *)tmp_buf; p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME; if (ioctl(fh->fd, B_SCSI_GET_VOLUME, p, sizeof(scsi_volume)) == 0) { left = p->port0_volume; right = p->port1_volume; } } } BasiliskII/src/BeOS/main_beos.cpp0000644000175000017500000004640611255572000016767 0ustar centriscentris/* * main_beos.cpp - Startup code for BeOS * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "xpram.h" #include "timer.h" #include "video.h" #include "rom_patches.h" #include "prefs.h" #include "prefs_editor.h" #include "sys.h" #include "user_strings.h" #include "version.h" #include "main.h" #include "sheep_driver.h" #define DEBUG 0 #include "debug.h" // Constants const char APP_SIGNATURE[] = "application/x-vnd.cebix-BasiliskII"; const char ROM_FILE_NAME[] = "ROM"; const char RAM_AREA_NAME[] = "Macintosh RAM"; const char ROM_AREA_NAME[] = "Macintosh ROM"; const uint32 MSG_START = 'strt'; // Emulator start message const uint32 ROM_AREA_SIZE = 0x500000; // Enough to hold PowerMac ROM (for powerrom_cpu) // Prototypes #if __POWERPC__ static void sigsegv_handler(vregs *r); #endif // Application object class BasiliskII : public BApplication { public: BasiliskII() : BApplication(APP_SIGNATURE) { // Find application directory and cwd to it app_info the_info; GetAppInfo(&the_info); BEntry the_file(&the_info.ref); BEntry the_dir; the_file.GetParent(&the_dir); BPath the_path; the_dir.GetPath(&the_path); chdir(the_path.Path()); // Initialize other variables rom_area = ram_area = -1; xpram_thread = tick_thread = -1; xpram_thread_active = true; tick_thread_active = true; AllowQuitting = true; } virtual void ReadyToRun(void); virtual void MessageReceived(BMessage *msg); void StartEmulator(void); virtual bool QuitRequested(void); virtual void Quit(void); thread_id xpram_thread; // XPRAM watchdog thread_id tick_thread; // 60Hz thread volatile bool xpram_thread_active; // Flag for quitting the XPRAM thread volatile bool tick_thread_active; // Flag for quitting the 60Hz thread bool AllowQuitting; // Flag: Alt-Q quitting allowed private: static status_t emul_func(void *arg); static status_t tick_func(void *arg); static status_t xpram_func(void *arg); static void sigsegv_invoc(int sig, void *arg, vregs *r); void init_rom(void); void load_rom(void); area_id rom_area; // ROM area ID area_id ram_area; // RAM area ID struct sigaction sigsegv_action; // Data access exception signal (of emulator thread) // Exceptions class area_error {}; class file_open_error {}; class file_read_error {}; class rom_size_error {}; }; static BasiliskII *the_app; // CPU and FPU type, addressing mode int CPUType; bool CPUIs68060; int FPUType; bool TwentyFourBitAddressing; // Global variables for PowerROM CPU thread_id emul_thread = -1; // Emulator thread #if __POWERPC__ int sheep_fd = -1; // fd of sheep driver #endif /* * Create application object and start it */ int main(int argc, char **argv) { the_app = new BasiliskII(); the_app->Run(); delete the_app; return 0; } /* * Run application */ void BasiliskII::ReadyToRun(void) { // Initialize variables RAMBaseHost = NULL; ROMBaseHost = NULL; srand(real_time_clock()); tzset(); // Print some info printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); printf(" %s\n", GetString(STR_ABOUT_TEXT2)); // Delete old areas area_id old_ram_area = find_area(RAM_AREA_NAME); if (old_ram_area > 0) delete_area(old_ram_area); area_id old_rom_area = find_area(ROM_AREA_NAME); if (old_rom_area > 0) delete_area(old_rom_area); // Read preferences int argc = 0; char **argv = NULL; PrefsInit(argc, argv); // Init system routines SysInit(); // Show preferences editor (or start emulator directly) if (!PrefsFindBool("nogui")) PrefsEditor(); else PostMessage(MSG_START); } /* * Message received */ void BasiliskII::MessageReceived(BMessage *msg) { switch (msg->what) { case MSG_START: StartEmulator(); break; default: BApplication::MessageReceived(msg); } } /* * Start emulator */ void BasiliskII::StartEmulator(void) { char str[256]; #if REAL_ADDRESSING // Open sheep driver and remap low memory sheep_fd = open("/dev/sheep", 0); if (sheep_fd < 0) { sprintf(str, GetString(STR_NO_SHEEP_DRIVER_ERR), strerror(sheep_fd), sheep_fd); ErrorAlert(str); PostMessage(B_QUIT_REQUESTED); return; } status_t res = ioctl(sheep_fd, SHEEP_UP); if (res < 0) { sprintf(str, GetString(STR_SHEEP_UP_ERR), strerror(res), res); ErrorAlert(str); PostMessage(B_QUIT_REQUESTED); return; } #endif // Create area for Mac RAM RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary if (RAMSize < 1024*1024) { WarningAlert(GetString(STR_SMALL_RAM_WARN)); RAMSize = 1024*1024; } RAMBaseHost = (uint8 *)0x10000000; ram_area = create_area(RAM_AREA_NAME, (void **)&RAMBaseHost, B_BASE_ADDRESS, RAMSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); if (ram_area < 0) { ErrorAlert(STR_NO_RAM_AREA_ERR); PostMessage(B_QUIT_REQUESTED); return; } D(bug("RAM area %ld at %p\n", ram_area, RAMBaseHost)); // Create area and load Mac ROM try { init_rom(); } catch (area_error) { ErrorAlert(STR_NO_ROM_AREA_ERR); PostMessage(B_QUIT_REQUESTED); return; } catch (file_open_error) { ErrorAlert(STR_NO_ROM_FILE_ERR); PostMessage(B_QUIT_REQUESTED); return; } catch (file_read_error) { ErrorAlert(STR_ROM_FILE_READ_ERR); PostMessage(B_QUIT_REQUESTED); return; } catch (rom_size_error) { ErrorAlert(STR_ROM_SIZE_ERR); PostMessage(B_QUIT_REQUESTED); return; } // Initialize everything if (!InitAll(NULL)) { PostMessage(B_QUIT_REQUESTED); return; } // Write protect ROM set_area_protection(rom_area, B_READ_AREA); // Disallow quitting with Alt-Q from now on AllowQuitting = false; // Start XPRAM watchdog thread xpram_thread = spawn_thread(xpram_func, "XPRAM Watchdog", B_LOW_PRIORITY, this); resume_thread(xpram_thread); // Start 60Hz interrupt tick_thread = spawn_thread(tick_func, "60Hz", B_REAL_TIME_PRIORITY, this); resume_thread(tick_thread); // Start emulator thread emul_thread = spawn_thread(emul_func, "MacOS", B_NORMAL_PRIORITY, this); resume_thread(emul_thread); } /* * Quit emulator */ void QuitEmulator(void) { the_app->AllowQuitting = true; be_app->PostMessage(B_QUIT_REQUESTED); exit_thread(0); } bool BasiliskII::QuitRequested(void) { if (AllowQuitting) return BApplication::QuitRequested(); else return false; } void BasiliskII::Quit(void) { status_t l; // Stop 60Hz interrupt if (tick_thread > 0) { tick_thread_active = false; wait_for_thread(tick_thread, &l); } // Wait for emulator thread to finish if (emul_thread > 0) wait_for_thread(emul_thread, &l); // Exit 680x0 emulation Exit680x0(); // Stop XPRAM watchdog thread if (xpram_thread > 0) { xpram_thread_active = false; suspend_thread(xpram_thread); // Wake thread up from snooze() snooze(1000); resume_thread(xpram_thread); wait_for_thread(xpram_thread, &l); } // Deinitialize everything ExitAll(); // Delete ROM area if (rom_area >= 0) delete_area(rom_area); // Delete RAM area if (ram_area >= 0) delete_area(ram_area); #if REAL_ADDRESSING // Unmap low memory and close memory mess driver if (sheep_fd >= 0) { ioctl(sheep_fd, SHEEP_DOWN); close(sheep_fd); } #endif // Exit system routines SysExit(); // Exit preferences PrefsExit(); BApplication::Quit(); } /* * Create area for ROM (sets rom_area) and load ROM file * * area_error : Cannot create area * file_open_error: Cannot open ROM file * file_read_error: Cannot read ROM file */ void BasiliskII::init_rom(void) { // Create area for ROM ROMBaseHost = (uint8 *)0x40800000; rom_area = create_area(ROM_AREA_NAME, (void **)&ROMBaseHost, B_BASE_ADDRESS, ROM_AREA_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); if (rom_area < 0) throw area_error(); D(bug("ROM area %ld at %p\n", rom_area, ROMBaseHost)); // Load ROM load_rom(); } /* * Load ROM file * * file_open_error: Cannot open ROM file * file_read_error: Cannot read ROM file */ void BasiliskII::load_rom(void) { // Get rom file path from preferences const char *rom_path = PrefsFindString("rom"); // Try to open ROM file BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY); if (file.InitCheck() != B_NO_ERROR) throw file_open_error(); printf(GetString(STR_READING_ROM_FILE)); // Is the ROM size correct? off_t rom_size = 0; file.GetSize(&rom_size); if (rom_size != 64*1024 && rom_size != 128*1024 && rom_size != 256*1024 && rom_size != 512*1024 && rom_size != 1024*1024) throw rom_size_error(); uint8 *rom = new uint8[rom_size]; // Reading directly into the area doesn't work ssize_t actual = file.Read((void *)rom, rom_size); if (actual == rom_size) memcpy(ROMBaseHost, rom, rom_size); delete[] rom; if (actual != rom_size) throw file_read_error(); ROMSize = rom_size; } /* * Emulator thread function */ status_t BasiliskII::emul_func(void *arg) { BasiliskII *obj = (BasiliskII *)arg; #if __POWERPC__ // Install data access signal handler sigemptyset(&obj->sigsegv_action.sa_mask); obj->sigsegv_action.sa_handler = (__signal_func_ptr)(obj->sigsegv_invoc); obj->sigsegv_action.sa_flags = 0; obj->sigsegv_action.sa_userdata = arg; sigaction(SIGSEGV, &obj->sigsegv_action, NULL); #endif // Exceptions will send signals disable_debugger(true); // Start 68k and jump to ROM boot routine Start680x0(); // Quit program obj->AllowQuitting = true; be_app->PostMessage(B_QUIT_REQUESTED); return 0; } /* * Code was patched, flush caches if neccessary (i.e. when using a real 680x0 * or a dynamically recompiling emulator) */ void FlushCodeCache(void *start, uint32 size) { } /* * Mutexes */ struct B2_mutex { int dummy; //!! }; B2_mutex *B2_create_mutex(void) { return new B2_mutex; } void B2_lock_mutex(B2_mutex *mutex) { } void B2_unlock_mutex(B2_mutex *mutex) { } void B2_delete_mutex(B2_mutex *mutex) { delete mutex; } /* * Interrupt flags (must be handled atomically!) */ uint32 InterruptFlags = 0; void SetInterruptFlag(uint32 flag) { atomic_or((int32 *)&InterruptFlags, flag); } void ClearInterruptFlag(uint32 flag) { atomic_and((int32 *)&InterruptFlags, ~flag); } /* * 60Hz thread (really 60.15Hz) */ status_t BasiliskII::tick_func(void *arg) { BasiliskII *obj = (BasiliskII *)arg; int tick_counter = 0; bigtime_t current = system_time(); while (obj->tick_thread_active) { // Wait current += 16625; snooze_until(current, B_SYSTEM_TIMEBASE); // Pseudo Mac 1Hz interrupt, update local time if (++tick_counter > 60) { tick_counter = 0; WriteMacInt32(0x20c, TimerDateTime()); SetInterruptFlag(INTFLAG_1HZ); TriggerInterrupt(); } // Trigger 60Hz interrupt SetInterruptFlag(INTFLAG_60HZ); TriggerInterrupt(); } return 0; } /* * XPRAM watchdog thread (saves XPRAM every minute) */ status_t BasiliskII::xpram_func(void *arg) { uint8 last_xpram[XPRAM_SIZE]; memcpy(last_xpram, XPRAM, XPRAM_SIZE); while (((BasiliskII *)arg)->xpram_thread_active) { snooze(60*1000000); if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) { memcpy(last_xpram, XPRAM, XPRAM_SIZE); SaveXPRAM(); } } return 0; } /* * Display error alert */ void ErrorAlert(const char *text) { if (PrefsFindBool("nogui")) { printf(GetString(STR_SHELL_ERROR_PREFIX), text); return; } VideoQuitFullScreen(); char str[256]; sprintf(str, GetString(STR_GUI_ERROR_PREFIX), text); BAlert *alert = new BAlert(GetString(STR_ERROR_ALERT_TITLE), str, GetString(STR_QUIT_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); alert->Go(); } /* * Display warning alert */ void WarningAlert(const char *text) { if (PrefsFindBool("nogui")) { printf(GetString(STR_SHELL_WARNING_PREFIX), text); return; } char str[256]; sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text); BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT); alert->Go(); } /* * Display choice alert */ bool ChoiceAlert(const char *text, const char *pos, const char *neg) { char str[256]; sprintf(str, GetString(STR_GUI_WARNING_PREFIX), text); BAlert *alert = new BAlert(GetString(STR_WARNING_ALERT_TITLE), str, pos, neg, NULL, B_WIDTH_AS_USUAL, B_INFO_ALERT); return alert->Go() == 0; } /* * SEGV handler */ #if __POWERPC__ static uint32 segv_r[32]; asm void BasiliskII::sigsegv_invoc(register int sig, register void *arg, register vregs *r) { mflr r0 stw r0,8(r1) stwu r1,-56(r1) lwz r3,segv_r(r2) stmw r13,13*4(r3) mr r3,r5 bl sigsegv_handler lwz r3,segv_r(r2) lmw r13,13*4(r3) lwz r0,56+8(r1) mtlr r0 addi r1,r1,56 blr } static void sigsegv_handler(vregs *r) { // Fetch volatile registers segv_r[0] = r->r0; segv_r[1] = r->r1; segv_r[2] = r->r2; segv_r[3] = r->r3; segv_r[4] = r->r4; segv_r[5] = r->r5; segv_r[6] = r->r6; segv_r[7] = r->r7; segv_r[8] = r->r8; segv_r[9] = r->r9; segv_r[10] = r->r10; segv_r[11] = r->r11; segv_r[12] = r->r12; // Get opcode and divide into fields uint32 opcode = *(uint32 *)r->pc; uint32 primop = opcode >> 26; uint32 exop = (opcode >> 1) & 0x3ff; uint32 ra = (opcode >> 16) & 0x1f; uint32 rb = (opcode >> 11) & 0x1f; uint32 rd = (opcode >> 21) & 0x1f; uint32 imm = opcode & 0xffff; // Analyze opcode enum { TYPE_UNKNOWN, TYPE_LOAD, TYPE_STORE } transfer_type = TYPE_UNKNOWN; enum { SIZE_UNKNOWN, SIZE_BYTE, SIZE_HALFWORD, SIZE_WORD } transfer_size = SIZE_UNKNOWN; enum { MODE_UNKNOWN, MODE_NORM, MODE_U, MODE_X, MODE_UX } addr_mode = MODE_UNKNOWN; switch (primop) { case 31: switch (exop) { case 23: // lwzx transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; case 55: // lwzux transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; case 87: // lbzx transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; case 119: // lbzux transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; case 151: // stwx transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; case 183: // stwux transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; case 215: // stbx transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; case 247: // stbux transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; case 279: // lhzx transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; case 311: // lhzux transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; case 343: // lhax transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; case 375: // lhaux transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; case 407: // sthx transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_X; break; case 439: // sthux transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_UX; break; } break; case 32: // lwz transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; case 33: // lwzu transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; case 34: // lbz transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; case 35: // lbzu transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; case 36: // stw transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; case 37: // stwu transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; case 38: // stb transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; case 39: // stbu transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; case 40: // lhz transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; case 41: // lhzu transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; case 42: // lha transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; case 43: // lhau transfer_type = TYPE_LOAD; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; case 44: // sth transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_NORM; break; case 45: // sthu transfer_type = TYPE_STORE; transfer_size = SIZE_HALFWORD; addr_mode = MODE_U; break; } // Calculate effective address uint32 addr = 0; switch (addr_mode) { case MODE_X: case MODE_UX: if (ra == 0) addr = segv_r[rb]; else addr = segv_r[ra] + segv_r[rb]; break; case MODE_NORM: case MODE_U: if (ra == 0) addr = (int32)(int16)imm; else addr = segv_r[ra] + (int32)(int16)imm; break; } // Ignore ROM writes if (transfer_type == TYPE_STORE && addr >= (uint32)ROMBaseHost && addr < (uint32)ROMBaseHost + ROMSize) { // D(bug("WARNING: %s write access to ROM at %p, 68k pc %p\n", transfer_size == SIZE_BYTE ? "Byte" : transfer_size == SIZE_HALFWORD ? "Halfword" : "Word", addr, r->pc)); if (addr_mode == MODE_U || addr_mode == MODE_UX) segv_r[ra] = addr; r->pc += 4; goto rti; } // For all other errors, jump into debugger char str[256]; sprintf(str, "SIGSEGV\n" " pc %08lx lr %08lx ctr %08lx msr %08lx\n" " xer %08lx cr %08lx fpscr %08lx\n" " r0 %08lx r1 %08lx r2 %08lx r3 %08lx\n" " r4 %08lx r5 %08lx r6 %08lx r7 %08lx\n" " r8 %08lx r9 %08lx r10 %08lx r11 %08lx\n" " r12 %08lx r13 %08lx r14 %08lx r15 %08lx\n" " r16 %08lx r17 %08lx r18 %08lx r19 %08lx\n" " r20 %08lx r21 %08lx r22 %08lx r23 %08lx\n" " r24 %08lx r25 %08lx r26 %08lx r27 %08lx\n" " r28 %08lx r29 %08lx r30 %08lx r31 %08lx\n", r->pc, r->lr, r->ctr, r->msr, r->xer, r->cr, r->fpscr, r->r0, r->r1, r->r2, r->r3, r->r4, r->r5, r->r6, r->r7, r->r8, r->r9, r->r10, r->r11, r->r12, segv_r[13], segv_r[14], segv_r[15], segv_r[16], segv_r[17], segv_r[18], segv_r[19], segv_r[20], segv_r[21], segv_r[22], segv_r[23], segv_r[24], segv_r[25], segv_r[26], segv_r[27], segv_r[28], segv_r[29], segv_r[30], segv_r[31]); disable_debugger(false); debugger(str); QuitEmulator(); return; rti: // Restore volatile registers r->r0 = segv_r[0]; r->r1 = segv_r[1]; r->r2 = segv_r[2]; r->r3 = segv_r[3]; r->r4 = segv_r[4]; r->r5 = segv_r[5]; r->r6 = segv_r[6]; r->r7 = segv_r[7]; r->r8 = segv_r[8]; r->r9 = segv_r[9]; r->r10 = segv_r[10]; r->r11 = segv_r[11]; r->r12 = segv_r[12]; } #endif BasiliskII/src/BeOS/serial_beos.cpp0000644000175000017500000005277710736405220017334 0ustar centriscentris/* * serial_beos.cpp - Serial device driver, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "serial.h" #include "serial_defs.h" #define DEBUG 0 #include "debug.h" #define MONITOR 0 // Buffer size for kernel-space transfers const int TMP_BUF_SIZE = 2048; // These packets are sent to the input/output threads const uint32 CMD_READ = 'read'; const uint32 CMD_WRITE = 'writ'; const uint32 CMD_QUIT = 'quit'; struct ThreadPacket { uint32 pb; }; // Driver private variables class BeSERDPort : public SERDPort { public: BeSERDPort(const char *dev) { device_name = dev; if (strstr(dev, "parallel")) { is_parallel = true; fd = -1; device = NULL; } else { is_parallel = false; device = new BSerialPort; } device_sem = create_sem(1, "serial port"); input_thread = output_thread = 0; } virtual ~BeSERDPort() { status_t l; if (input_thread > 0) { send_data(input_thread, CMD_QUIT, NULL, 0); suspend_thread(input_thread); // Unblock thread snooze(1000); resume_thread(input_thread); while (wait_for_thread(input_thread, &l) == B_INTERRUPTED) ; } if (output_thread > 0) { send_data(output_thread, CMD_QUIT, NULL, 0); suspend_thread(output_thread); // Unblock thread snooze(1000); resume_thread(output_thread); while (wait_for_thread(output_thread, &l) == B_INTERRUPTED) ; } acquire_sem(device_sem); delete_sem(device_sem); delete device; } virtual int16 open(uint16 config); virtual int16 prime_in(uint32 pb, uint32 dce); virtual int16 prime_out(uint32 pb, uint32 dce); virtual int16 control(uint32 pb, uint32 dce, uint16 code); virtual int16 status(uint32 pb, uint32 dce, uint16 code); virtual int16 close(void); private: bool configure(uint16 config); void set_handshake(uint32 s, bool with_dtr); static status_t input_func(void *arg); static status_t output_func(void *arg); const char *device_name; // Name of BeOS port BSerialPort *device; // BeOS port object bool is_parallel; // Flag: Port is parallel, use fd int fd; // FD for parallel ports sem_id device_sem; // BSerialPort arbitration thread_id input_thread; // Data input thread thread_id output_thread; // Data output thread bool io_killed; // Flag: KillIO called, I/O threads must not call deferred tasks bool drop_dtr_on_close; // Flag: Negate DTR when driver is closed uint8 tmp_in_buf[TMP_BUF_SIZE]; // Buffers for copying from/to kernel space uint8 tmp_out_buf[TMP_BUF_SIZE]; }; #if DEBUG static const int baud_rates[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 31250 }; #endif /* * Initialization */ void SerialInit(void) { // Read serial preferences and create structs for both ports the_serd_port[0] = new BeSERDPort(PrefsFindString("seriala")); the_serd_port[1] = new BeSERDPort(PrefsFindString("serialb")); } /* * Deinitialization */ void SerialExit(void) { delete (BeSERDPort *)the_serd_port[0]; delete (BeSERDPort *)the_serd_port[1]; } /* * Open serial port */ int16 BeSERDPort::open(uint16 config) { // Don't open NULL name devices if (device_name == NULL) return openErr; // Init variables io_killed = false; drop_dtr_on_close = true; // Open port while (acquire_sem(device_sem) == B_INTERRUPTED) ; if (is_parallel) { char name[256]; sprintf(name, "/dev/parallel/%s", device_name); fd = ::open(name, O_WRONLY); if (fd < 0) { release_sem(device_sem); return openErr; } } else { device->SetFlowControl(B_HARDWARE_CONTROL); // Must be set before port is opened if (device->Open(device_name) > 0) { device->SetBlocking(true); device->SetTimeout(10000000); device->SetDTR(true); device->SetRTS(true); } else { release_sem(device_sem); return openErr; } } // Start input/output threads release_sem(device_sem); configure(config); while (acquire_sem(device_sem) == B_INTERRUPTED) ; while ((input_thread = spawn_thread(input_func, "Serial Input", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ; resume_thread(input_thread); while ((output_thread = spawn_thread(output_func, "Serial Output", B_NORMAL_PRIORITY, this)) == B_INTERRUPTED) ; resume_thread(output_thread); release_sem(device_sem); return noErr; } /* * Read data from port */ int16 BeSERDPort::prime_in(uint32 pb, uint32 dce) { // Send input command to input_thread read_done = false; read_pending = true; ThreadPacket p; p.pb = pb; WriteMacInt32(input_dt + serdtDCE, dce); while (send_data(input_thread, CMD_READ, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ; return 1; // Command in progress } /* * Write data to port */ int16 BeSERDPort::prime_out(uint32 pb, uint32 dce) { // Send output command to output_thread write_done = false; write_pending = true; ThreadPacket p; p.pb = pb; WriteMacInt32(output_dt + serdtDCE, dce); while (send_data(output_thread, CMD_WRITE, &p, sizeof(ThreadPacket)) == B_INTERRUPTED) ; return 1; // Command in progress } /* * Control calls */ int16 BeSERDPort::control(uint32 pb, uint32 dce, uint16 code) { switch (code) { case 1: // KillIO io_killed = true; suspend_thread(input_thread); // Unblock threads suspend_thread(output_thread); snooze(1000); resume_thread(input_thread); resume_thread(output_thread); while (read_pending || write_pending) snooze(10000); if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->ClearInput(); device->ClearOutput(); release_sem(device_sem); } io_killed = false; return noErr; case kSERDConfiguration: if (configure(ReadMacInt16(pb + csParam))) return noErr; else return paramErr; case kSERDInputBuffer: return noErr; // Not supported under BeOS case kSERDSerHShake: set_handshake(pb + csParam, false); return noErr; case kSERDClearBreak: case kSERDSetBreak: return noErr; // Not supported under BeOS case kSERDBaudRate: if (!is_parallel) { uint16 rate = ReadMacInt16(pb + csParam); data_rate baud_rate; if (rate <= 50) { rate = 50; baud_rate = B_50_BPS; } else if (rate <= 75) { rate = 75; baud_rate = B_75_BPS; } else if (rate <= 110) { rate = 110; baud_rate = B_110_BPS; } else if (rate <= 134) { rate = 134; baud_rate = B_134_BPS; } else if (rate <= 150) { rate = 150; baud_rate = B_150_BPS; } else if (rate <= 200) { rate = 200; baud_rate = B_200_BPS; } else if (rate <= 300) { rate = 300; baud_rate = B_300_BPS; } else if (rate <= 600) { rate = 600; baud_rate = B_600_BPS; } else if (rate <= 1200) { rate = 1200; baud_rate = B_1200_BPS; } else if (rate <= 1800) { rate = 1800; baud_rate = B_1800_BPS; } else if (rate <= 2400) { rate = 2400; baud_rate = B_2400_BPS; } else if (rate <= 4800) { rate = 4800; baud_rate = B_4800_BPS; } else if (rate <= 9600) { rate = 9600; baud_rate = B_9600_BPS; } else if (rate <= 19200) { rate = 19200; baud_rate = B_19200_BPS; } else if (rate <= 31250) { rate = 31250; baud_rate = B_31250_BPS; } else if (rate <= 38400) { rate = 38400; baud_rate = B_38400_BPS; } else if (rate <= 57600) { rate = 57600; baud_rate = B_57600_BPS; } WriteMacInt16(pb + csParam, rate); acquire_sem(device_sem); if (device->SetDataRate(baud_rate) == B_OK) { release_sem(device_sem); return noErr; } else { release_sem(device_sem); return paramErr; } } else return noErr; case kSERDHandshake: case kSERDHandshakeRS232: set_handshake(pb + csParam, true); return noErr; case kSERDClockMIDI: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->SetParityMode(B_NO_PARITY); device->SetDataBits(B_DATA_BITS_8); device->SetStopBits(B_STOP_BITS_1); if (device->SetDataRate(B_31250_BPS) == B_OK) { release_sem(device_sem); return noErr; } else { release_sem(device_sem); return paramErr; } } else return noErr; case kSERDMiscOptions: drop_dtr_on_close = !(ReadMacInt8(pb + csParam) & kOptionPreserveDTR); return noErr; case kSERDAssertDTR: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->SetDTR(true); release_sem(device_sem); } return noErr; case kSERDNegateDTR: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->SetDTR(false); release_sem(device_sem); } return noErr; case kSERDSetPEChar: case kSERDSetPEAltChar: return noErr; // Not supported under BeOS case kSERDResetChannel: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->ClearInput(); device->ClearOutput(); release_sem(device_sem); } return noErr; case kSERDAssertRTS: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->SetRTS(true); release_sem(device_sem); } return noErr; case kSERDNegateRTS: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->SetRTS(false); release_sem(device_sem); } return noErr; case kSERD115KBaud: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; if (device->DataRate() != B_115200_BPS) if (device->SetDataRate(B_115200_BPS) != B_OK) { release_sem(device_sem); return paramErr; } release_sem(device_sem); } return noErr; case kSERD230KBaud: case kSERDSetHighSpeed: if (!is_parallel) { while (acquire_sem(device_sem) == B_INTERRUPTED) ; if (device->DataRate() != B_230400_BPS) if (device->SetDataRate(B_230400_BPS) != B_OK) { release_sem(device_sem); return paramErr; } release_sem(device_sem); } return noErr; default: printf("WARNING: SerialControl(): unimplemented control code %d\n", code); return controlErr; } } /* * Status calls */ int16 BeSERDPort::status(uint32 pb, uint32 dce, uint16 code) { switch (code) { case kSERDInputCount: WriteMacInt32(pb + csParam, 0); if (!is_parallel) { int32 num = 0; while (acquire_sem(device_sem) == B_INTERRUPTED) ; device->NumCharsAvailable(&num); release_sem(device_sem); D(bug(" %d bytes in buffer\n", num)); WriteMacInt32(pb + csParam, num); } return noErr; case kSERDStatus: { uint32 p = pb + csParam; WriteMacInt8(p + staCumErrs, cum_errors); cum_errors = 0; WriteMacInt8(p + staXOffSent, 0); WriteMacInt8(p + staXOffHold, 0); WriteMacInt8(p + staRdPend, read_pending); WriteMacInt8(p + staWrPend, write_pending); if (is_parallel) { WriteMacInt8(p + staCtsHold, 0); WriteMacInt8(p + staDsrHold, 0); WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent); } else { while (acquire_sem(device_sem) == B_INTERRUPTED) ; WriteMacInt8(p + staCtsHold, !device->IsCTS()); WriteMacInt8(p + staDsrHold, !device->IsDSR()); WriteMacInt8(p + staModemStatus, (device->IsDSR() ? dsrEvent : 0) | (device->IsRI() ? riEvent : 0) | (device->IsDCD() ? dcdEvent : 0) | (device->IsCTS() ? ctsEvent : 0)); release_sem(device_sem); } return noErr; } default: printf("WARNING: SerialStatus(): unimplemented status code %d\n", code); return statusErr; } } /* * Close serial port */ int16 BeSERDPort::close() { // Kill threads status_t l; io_killed = true; if (input_thread > 0) { while (send_data(input_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ; if (read_pending) { suspend_thread(input_thread); // Unblock thread snooze(1000); resume_thread(input_thread); } while (wait_for_thread(input_thread, &l) == B_INTERRUPTED) ; } if (output_thread > 0) { while (send_data(output_thread, CMD_QUIT, NULL, 0) == B_INTERRUPTED) ; if (write_pending) { suspend_thread(output_thread); // Unblock thread snooze(1000); resume_thread(output_thread); } while (wait_for_thread(output_thread, &l) == B_INTERRUPTED) ; } input_thread = output_thread = 0; // Close port while (acquire_sem(device_sem) == B_INTERRUPTED) ; if (is_parallel) { ::close(fd); fd = -1; } else { if (drop_dtr_on_close) device->SetDTR(false); device->Close(); } release_sem(device_sem); return noErr; } /* * Configure serial port with MacOS config word */ bool BeSERDPort::configure(uint16 config) { D(bug(" configure %04x\n", config)); if (is_parallel) return true; while (acquire_sem(device_sem) == B_INTERRUPTED) ; // Set number of stop bits switch (config & 0xc000) { case stop10: if (device->StopBits() != B_STOP_BITS_1) device->SetStopBits(B_STOP_BITS_1); break; case stop20: if (device->StopBits() != B_STOP_BITS_2) device->SetStopBits(B_STOP_BITS_2); break; default: release_sem(device_sem); return false; } // Set parity mode switch (config & 0x3000) { case noParity: if (device->ParityMode() != B_NO_PARITY) device->SetParityMode(B_NO_PARITY); break; case oddParity: if (device->ParityMode() != B_ODD_PARITY) device->SetParityMode(B_ODD_PARITY); break; case evenParity: if (device->ParityMode() != B_EVEN_PARITY) device->SetParityMode(B_EVEN_PARITY); break; default: release_sem(device_sem); return false; } // Set number of data bits switch (config & 0x0c00) { case data7: if (device->DataBits() != B_DATA_BITS_7) device->SetDataBits(B_DATA_BITS_7); break; case data8: if (device->DataBits() != B_DATA_BITS_8) device->SetDataBits(B_DATA_BITS_8); break; default: release_sem(device_sem); return false; } // Set baud rate data_rate baud_rate; switch (config & 0x03ff) { case baud150: baud_rate = B_150_BPS; break; case baud300: baud_rate = B_300_BPS; break; case baud600: baud_rate = B_600_BPS; break; case baud1200: baud_rate = B_1200_BPS; break; case baud1800: baud_rate = B_1800_BPS; break; case baud2400: baud_rate = B_2400_BPS; break; case baud4800: baud_rate = B_4800_BPS; break; case baud9600: baud_rate = B_9600_BPS; break; case baud19200: baud_rate = B_19200_BPS; break; case baud38400: baud_rate = B_38400_BPS; break; case baud57600: baud_rate = B_57600_BPS; break; default: release_sem(device_sem); return false; } D(bug(" baud rate %d, %d stop bits, %s parity, %d data bits\n", baud_rates[baud_rate], device->StopBits() == B_STOP_BITS_1 ? 1 : 2, device->ParityMode() == B_NO_PARITY ? "no" : device->ParityMode() == B_ODD_PARITY ? "odd" : "even", device->DataBits() == B_DATA_BITS_7 ? 7 : 8)); if (device->DataRate() != baud_rate) { bool res = device->SetDataRate(baud_rate) == B_OK; release_sem(device_sem); return res; } else { release_sem(device_sem); return true; } } /* * Set serial handshaking */ void BeSERDPort::set_handshake(uint32 s, bool with_dtr) { D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n", ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3), ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7))); if (is_parallel) return; uint32 flow; if (with_dtr) { if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR)) flow = B_HARDWARE_CONTROL; else flow = B_SOFTWARE_CONTROL; } else { if (ReadMacInt8(s + shkFCTS)) flow = B_HARDWARE_CONTROL; else flow = B_SOFTWARE_CONTROL; } D(bug(" %sware flow control\n", flow == B_HARDWARE_CONTROL ? "hard" : "soft")); while (acquire_sem(device_sem) == B_INTERRUPTED) ; if (device->FlowControl() != flow) { device->Close(); device->SetFlowControl(flow); device->Open(device_name); } release_sem(device_sem); } /* * Data input thread */ status_t BeSERDPort::input_func(void *arg) { BeSERDPort *s = (BeSERDPort *)arg; for (;;) { // Wait for commands thread_id sender; ThreadPacket p; uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket)); if (code == CMD_QUIT) break; if (code != CMD_READ) continue; // Execute command void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer)); uint32 length = ReadMacInt32(p.pb + ioReqCount); D(bug("input_func waiting for %ld bytes of data...\n", length)); int32 actual; // Buffer in kernel space? if ((uint32)buf < 0x80000000) { // Yes, transfer via buffer actual = 0; while (length) { uint32 transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; int32 transferred; acquire_sem(s->device_sem); if (s->is_parallel) { if ((transferred = read(s->fd, s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) { // Error actual = transferred; release_sem(s->device_sem); break; } } else { if ((transferred = s->device->Read(s->tmp_in_buf, transfer_size)) < 0 || s->io_killed) { // Error actual = transferred; release_sem(s->device_sem); break; } } release_sem(s->device_sem); memcpy(buf, s->tmp_in_buf, transferred); buf = (void *)((uint8 *)buf + transferred); length -= transferred; actual += transferred; } } else { // No, transfer directly acquire_sem(s->device_sem); if (s->is_parallel) actual = read(s->fd, buf, length); else actual = s->device->Read(buf, length); release_sem(s->device_sem); } D(bug(" %ld bytes received\n", actual)); #if MONITOR bug("Receiving serial data:\n"); uint8 *adr = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer)); for (int i=0; iio_killed) { WriteMacInt16(p.pb + ioResult, abortErr); WriteMacInt32(p.pb + ioActCount, 0); s->read_pending = s->read_done = false; } else { // Set error code if (actual >= 0) { WriteMacInt32(p.pb + ioActCount, actual); WriteMacInt32(s->input_dt + serdtResult, noErr); } else { WriteMacInt32(p.pb + ioActCount, 0); WriteMacInt32(s->input_dt + serdtResult, readErr); } // Trigger serial interrupt D(bug(" triggering serial interrupt\n")); s->read_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } return 0; } /* * Data output thread */ status_t BeSERDPort::output_func(void *arg) { BeSERDPort *s = (BeSERDPort *)arg; for (;;) { // Wait for commands thread_id sender; ThreadPacket p; uint32 code = receive_data(&sender, &p, sizeof(ThreadPacket)); if (code == CMD_QUIT) break; if (code != CMD_WRITE) continue; // Execute command void *buf = Mac2HostAddr(ReadMacInt32(p.pb + ioBuffer)); uint32 length = ReadMacInt32(p.pb + ioReqCount); D(bug("output_func transmitting %ld bytes of data...\n", length)); int32 actual; #if MONITOR bug("Sending serial data:\n"); uint8 *adr = (uint8 *)buf; for (int i=0; i TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; memcpy(s->tmp_out_buf, buf, transfer_size); int32 transferred; acquire_sem(s->device_sem); if (s->is_parallel) { if ((transferred = write(s->fd, s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) { if (transferred < 0) // Error actual = transferred; else actual += transferred; release_sem(s->device_sem); break; } } else { if ((transferred = s->device->Write(s->tmp_out_buf, transfer_size)) < transfer_size || s->io_killed) { if (transferred < 0) // Error actual = transferred; else actual += transferred; release_sem(s->device_sem); break; } } release_sem(s->device_sem); if (transferred > transfer_size) // R3 parallel port driver bug transferred = transfer_size; buf = (void *)((uint8 *)buf + transferred); length -= transferred; actual += transferred; } } else { // No, transfer directly acquire_sem(s->device_sem); if (s->is_parallel) actual = write(s->fd, buf, length); else actual = s->device->Write(buf, length); release_sem(s->device_sem); if (actual > length) // R3 parallel port driver bug actual = length; } D(bug(" %ld bytes transmitted\n", actual)); // KillIO called? Then simply return if (s->io_killed) { WriteMacInt16(p.pb + ioResult, abortErr); WriteMacInt32(p.pb + ioActCount, 0); s->write_pending = s->write_done = false; } else { // Set error code if (actual >= 0) { WriteMacInt32(p.pb + ioActCount, actual); WriteMacInt32(s->output_dt + serdtResult, noErr); } else { WriteMacInt32(p.pb + ioActCount, 0); WriteMacInt32(s->output_dt + serdtResult, writErr); } // Trigger serial interrupt D(bug(" triggering serial interrupt\n")); s->write_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } return 0; } BasiliskII/src/BeOS/extfs_beos.cpp0000644000175000017500000002503010736405220017164 0ustar centriscentris/* * extfs_beos.cpp - MacOS file system for access native file system access, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "extfs.h" #include "extfs_defs.h" #define DEBUG 0 #include "debug.h" // Default Finder flags const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; // Temporary buffer for transfers from/to kernel space const int TMP_BUF_SIZE = 0x10000; static uint8 *tmp_buf = NULL; /* * Initialization */ void extfs_init(void) { // Allocate temporary buffer tmp_buf = new uint8[TMP_BUF_SIZE]; } /* * Deinitialization */ void extfs_exit(void) { // Delete temporary buffer delete[] tmp_buf; } /* * Add component to path name */ void add_path_component(char *path, const char *component) { int l = strlen(path); if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') { path[l] = '/'; path[l+1] = 0; } strncat(path, component, MAX_PATH_LENGTH-1); } /* * Get/set finder info for file/directory specified by full path */ struct mime2type { const char *mime; uint32 type; uint32 creator; bool reversible; // type -> mime translation possible }; static const mime2type m2t_translation[] = { {"application/x-compress", 'ZIVM', 'LZIV', true}, {"application/x-gzip", 'Gzip', 'Gzip', true}, {"application/x-macbinary", 'BINA', '????', false}, {"application/mac-binhex40", 'TEXT', 'SITx', false}, {"application/pdf", 'PDF ', 'CARO', true}, {"application/postscript", 'TEXT', 'ttxt', false}, {"application/x-stuffit", 'SIT!', 'SITx', true}, {"application/x-tar", 'TARF', 'TAR ', true}, {"application/x-uuencode", 'TEXT', 'SITx', false}, {"application/zip", 'ZIP ', 'ZIP ', true}, {"audio/x-8svx", '8SVX', 'SNDM', true}, {"audio/x-aifc", 'AIFC', 'TVOD', true}, {"audio/x-aiff", 'AIFF', 'TVOD', true}, {"audio/basic", 'ULAW', 'TVOD', true}, {"audio/x-midi", 'MIDI', 'TVOD', true}, {"audio/x-mpeg", 'MPG ', 'TVOD', true}, {"audio/x-wav", 'WAVE', 'TVOD', true}, {"image/x-bmp", 'BMPf', 'ogle', true}, {"image/gif", 'GIFf', 'ogle', true}, {"image/x-ilbm", 'ILBM', 'GKON', true}, {"image/jpeg", 'JPEG', 'ogle', true}, {"image/jpeg", 'JFIF', 'ogle', true}, {"image/x-photoshop", '8BPS', '8BIM', true}, {"image/pict", 'PICT', 'ogle', true}, {"image/png", 'PNGf', 'ogle', true}, {"image/x-sgi", '.SGI', 'ogle', true}, {"image/x-targa", 'TPIC', 'ogle', true}, {"image/tiff", 'TIFF', 'ogle', true}, {"text/html", 'TEXT', 'MOSS', false}, {"text/plain", 'TEXT', 'ttxt', true}, {"text/rtf", 'TEXT', 'MSWD', false}, {"text/x-source-code", 'TEXT', 'R*ch', false}, {"video/mpeg", 'MPEG', 'TVOD', true}, {"video/quicktime", 'MooV', 'TVOD', true}, {"video/x-flc", 'FLI ', 'TVOD', true}, {"video/x-msvideo", 'VfW ', 'TVOD', true}, {NULL, 0, 0, false} // End marker }; void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Open file int fd = open(path, O_RDONLY); if (fd < 0) return; if (!is_dir) { // Read BeOS MIME type ssize_t actual = fs_read_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, tmp_buf, 256); tmp_buf[255] = 0; if (actual > 0) { // Translate MIME type to MacOS type/creator uint8 mactype[4]; if (sscanf((char *)tmp_buf, "application/x-MacOS-%c%c%c%c", mactype, mactype+1, mactype+2, mactype+3) == 4) { // MacOS style type WriteMacInt32(finfo + fdType, (mactype[0] << 24) | (mactype[1] << 16) | (mactype[2] << 8) | mactype[3]); } else { // MIME string, look in table for (int i=0; m2t_translation[i].mime; i++) { if (!strcmp((char *)tmp_buf, m2t_translation[i].mime)) { WriteMacInt32(finfo + fdType, m2t_translation[i].type); WriteMacInt32(finfo + fdCreator, m2t_translation[i].creator); break; } } } } // Override file type with MACOS:CREATOR attribute if (fs_read_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, tmp_buf, 4) == 4) WriteMacInt32(finfo + fdCreator, (tmp_buf[0] << 24) | (tmp_buf[1] << 16) | (tmp_buf[2] << 8) | tmp_buf[3]); } // Read MACOS:HFS_FLAGS attribute if (fs_read_attr(fd, "MACOS:HFS_FLAGS", B_UINT16_TYPE, 0, tmp_buf, 2) == 2) WriteMacInt16(finfo + fdFlags, (tmp_buf[0] << 8) | tmp_buf[1]); // Close file close(fd); } void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Open file int fd = open(path, O_WRONLY); if (fd < 0) return; if (!is_dir) { // Set BEOS:TYPE attribute uint32 type = ReadMacInt32(finfo + fdType); if (type) { for (int i=0; m2t_translation[i].mime; i++) { if (m2t_translation[i].type == type && m2t_translation[i].reversible) { fs_write_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, m2t_translation[i].mime, strlen(m2t_translation[i].mime) + 1); break; } } } // Set MACOS:CREATOR attribute uint32 creator = ReadMacInt32(finfo + fdCreator); if (creator) { tmp_buf[0] = creator >> 24; tmp_buf[1] = creator >> 16; tmp_buf[2] = creator >> 8; tmp_buf[3] = creator; fs_write_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, tmp_buf, 4); } } // Write MACOS:HFS_FLAGS attribute uint16 flags = ReadMacInt16(finfo + fdFlags); if (flags != DEFAULT_FINDER_FLAGS) { tmp_buf[0] = flags >> 8; tmp_buf[1] = flags; fs_write_attr(fd, "MACOS:HFS_FLAGS", B_UINT16_TYPE, 0, tmp_buf, 2); } else fs_remove_attr(fd, "MACOS:HFS_FLAGS"); // Close file close(fd); } /* * Resource fork emulation functions */ uint32 get_rfork_size(const char *path) { // Open file int fd = open(path, O_RDONLY); if (fd < 0) return 0; // Get size of MACOS:RFORK attribute struct attr_info info; if (fs_stat_attr(fd, "MACOS:RFORK", &info) < 0) info.size = 0; // Close file and return size close(fd); return info.size; } int open_rfork(const char *path, int flag) { // Open original file int fd = open(path, flag); if (fd < 0) return -1; // Open temporary file for resource fork char rname[L_tmpnam]; tmpnam(rname); int rfd = open(rname, O_RDWR | O_CREAT | O_TRUNC, 0666); if (rfd < 0) { close(fd); return -1; } unlink(rname); // File will be deleted when closed // Get size of MACOS:RFORK attribute struct attr_info info; if (fs_stat_attr(fd, "MACOS:RFORK", &info) < 0) info.size = 0; // Copy resource data from attribute to temporary file if (info.size > 0) { // Allocate buffer void *buf = malloc(info.size); if (buf == NULL) { close(rfd); close(fd); return -1; } // Copy data fs_read_attr(fd, "MACOS:RFORK", B_RAW_TYPE, 0, buf, info.size); write(rfd, buf, info.size); lseek(rfd, 0, SEEK_SET); // Free buffer if (buf) free(buf); } // Close original file close(fd); return rfd; } void close_rfork(const char *path, int fd) { if (fd < 0) return; // Get size of temporary file struct stat st; if (fstat(fd, &st) < 0) st.st_size = 0; // Open original file int ofd = open(path, O_WRONLY); if (ofd > 0) { // Copy resource data to MACOS:RFORK attribute if (st.st_size > 0) { // Allocate buffer void *buf = malloc(st.st_size); if (buf == NULL) { close(ofd); close(fd); return; } // Copy data lseek(fd, 0, SEEK_SET); read(fd, buf, st.st_size); fs_write_attr(ofd, "MACOS:RFORK", B_RAW_TYPE, 0, buf, st.st_size); // Free buffer if (buf) free(buf); } else fs_remove_attr(ofd, "MACOS:RFORK"); // Close original file close(ofd); } // Close temporary file close(fd); } /* * Read "length" bytes from file to "buffer", * returns number of bytes read (or -1 on error) */ static inline ssize_t sread(int fd, void *buf, size_t count) { ssize_t res; while ((res = read(fd, buf, count)) == B_INTERRUPTED) ; return res; } ssize_t extfs_read(int fd, void *buffer, size_t length) { // Buffer in kernel space? if ((uint32)buffer < 0x80000000) { // Yes, transfer via buffer ssize_t actual = 0; while (length) { size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; ssize_t res = sread(fd, tmp_buf, transfer_size); if (res < 0) return res; memcpy(buffer, tmp_buf, res); buffer = (void *)((uint8 *)buffer + res); length -= res; actual += res; if (res != transfer_size) return actual; } return actual; } else { // No, transfer directly return sread(fd, buffer, length); } } /* * Write "length" bytes from "buffer" to file, * returns number of bytes written (or -1 on error) */ static inline ssize_t swrite(int fd, void *buf, size_t count) { ssize_t res; while ((res = write(fd, buf, count)) == B_INTERRUPTED) ; return res; } ssize_t extfs_write(int fd, void *buffer, size_t length) { // Buffer in kernel space? if ((uint32)buffer < 0x80000000) { // Yes, transfer via buffer ssize_t actual = 0; while (length) { size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; memcpy(tmp_buf, buffer, transfer_size); ssize_t res = swrite(fd, tmp_buf, transfer_size); if (res < 0) return res; buffer = (void *)((uint8 *)buffer + res); length -= res; actual += res; if (res != transfer_size) return actual; } return actual; } else { // No, transfer directly return swrite(fd, buffer, length); } } /* * Remove file/directory, returns false on error (and sets errno) */ bool extfs_remove(const char *path) { if (remove(path) < 0) { if (errno == EISDIR) return rmdir(path) == 0; else return false; } return true; } /* * Rename/move file/directory, returns false on error (and sets errno) */ bool extfs_rename(const char *old_path, const char *new_path) { return rename(old_path, new_path) == 0; } BasiliskII/src/BeOS/about_window.h0000644000175000017500000000165010736405220017173 0ustar centriscentris/* * about_window.h - "About" window * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef ABOUT_WINDOW_H #define ABOUT_WINDOW_H // Display "About" window extern void ShowAboutWindow(void); #endif BasiliskII/src/BeOS/prefs_editor_beos.cpp0000644000175000017500000007521310736405220020530 0ustar centriscentris/* * prefs_editor_beos.cpp - Preferences editor, BeOS implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "main.h" #include "cdrom.h" #include "xpram.h" #include "prefs.h" #include "about_window.h" #include "user_strings.h" #include "prefs_editor.h" // Special colors const rgb_color fill_color = {216, 216, 216, 0}; const rgb_color slider_fill_color = {102, 152, 255, 0}; // Display types enum { DISPLAY_WINDOW, DISPLAY_SCREEN }; // Window messages const uint32 MSG_OK = 'okok'; // "Start" clicked const uint32 MSG_CANCEL = 'cncl'; // "Quit" clicked const uint32 MSG_ZAP_PRAM = 'zprm'; const int NUM_PANES = 4; const uint32 MSG_VOLUME_SELECTED = 'volu'; // "Volumes" pane const uint32 MSG_VOLUME_INVOKED = 'voli'; const uint32 MSG_ADD_VOLUME = 'addv'; const uint32 MSG_CREATE_VOLUME = 'crev'; const uint32 MSG_REMOVE_VOLUME = 'remv'; const uint32 MSG_ADD_VOLUME_PANEL = 'advp'; const uint32 MSG_CREATE_VOLUME_PANEL = 'crvp'; const uint32 MSG_DEVICE_NAME = 'devn'; const uint32 MSG_BOOT_ANY = 'bany'; const uint32 MSG_BOOT_CDROM = 'bcdr'; const uint32 MSG_NOCDROM = 'nocd'; const uint32 MSG_REF_5HZ = ' 5Hz'; // "Graphics/Sound" pane const uint32 MSG_REF_7_5HZ = ' 7Hz'; const uint32 MSG_REF_10HZ = '10Hz'; const uint32 MSG_REF_15HZ = '15Hz'; const uint32 MSG_REF_30HZ = '30Hz'; const uint32 MSG_VIDEO_WINDOW = 'vtyw'; const uint32 MSG_VIDEO_SCREEN = 'vtys'; const uint32 MSG_SCREEN_MODE = 'sm\0\0'; const uint32 MSG_NOSOUND = 'nosn'; const uint32 MSG_SER_A = 'sera'; // "Serial/Network" pane const uint32 MSG_SER_B = 'serb'; const uint32 MSG_ETHER = 'ethr'; const uint32 MSG_UDPTUNNEL = 'udpt'; const uint32 MSG_RAMSIZE = 'rmsz'; // "Memory/Misc" pane const uint32 MSG_MODELID_5 = 'mi05'; const uint32 MSG_MODELID_14 = 'mi14'; const uint32 MSG_CPU_68020 = 'cpu2'; const uint32 MSG_CPU_68020_FPU = 'cpf2'; const uint32 MSG_CPU_68030 = 'cpu3'; const uint32 MSG_CPU_68030_FPU = 'cpf3'; const uint32 MSG_CPU_68040 = 'cpu4'; // RAM size slider class class RAMSlider : public BSlider { public: RAMSlider(BRect frame, const char *name, const char *label, BMessage *message, int32 minValue, int32 maxValue, thumb_style thumbType = B_BLOCK_THUMB, uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS) : BSlider(frame, name, label, message, minValue, maxValue, thumbType, resizingMode, flags) { update_text = (char *)malloc(256); } virtual ~RAMSlider() { if (update_text) free(update_text); } virtual char *UpdateText(void) const { if (update_text) { sprintf(update_text, GetString(STR_RAMSIZE_FMT), Value()); } return update_text; } private: char *update_text; }; // Volumes list view class class VolumeListView : public BListView { public: VolumeListView(BRect frame, const char *name, list_view_type type = B_SINGLE_SELECTION_LIST, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP, uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE) : BListView(frame, name, type, resizeMask, flags) {} // Handle dropped files and volumes virtual void MessageReceived(BMessage *msg) { if (msg->what == B_SIMPLE_DATA) { BMessage msg2(MSG_ADD_VOLUME_PANEL); entry_ref ref; for (int i=0; msg->FindRef("refs", i, &ref) == B_NO_ERROR; i++) msg2.AddRef("refs", &ref); Window()->PostMessage(&msg2); } else BListView::MessageReceived(msg); } }; // Number-entry BTextControl class NumberControl : public BTextControl { public: NumberControl(BRect frame, float divider, const char *name, const char *label, long value, BMessage *message) : BTextControl(frame, name, label, NULL, message, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE) { SetDivider(divider); for (int c=0; c<256; c++) if (!isdigit(c) && c != B_BACKSPACE && c != B_LEFT_ARROW && c != B_RIGHT_ARROW) ((BTextView *)ChildAt(0))->DisallowChar(c); SetValue(value); } // Set integer value void SetValue(long value) { char str[32]; sprintf(str, "%ld", value); SetText(str); } // Get integer value long Value(void) { return atol(Text()); } }; // Path-entry BTextControl class PathControl : public BTextControl { public: PathControl(bool dir_ctrl_, BRect frame, const char *name, const char *label, const char *text, BMessage *message) : BTextControl(frame, name, label, text, message), dir_ctrl(dir_ctrl_) { for (int c=0; c<' '; c++) if (c != B_BACKSPACE && c != B_LEFT_ARROW && c != B_RIGHT_ARROW) ((BTextView *)ChildAt(0))->DisallowChar(c); } virtual void MessageReceived(BMessage *msg) { if (msg->what == B_SIMPLE_DATA) { entry_ref the_ref; BEntry the_entry; // Look for dropped refs if (msg->FindRef("refs", &the_ref) == B_NO_ERROR) { if (the_entry.SetTo(&the_ref) == B_NO_ERROR && (dir_ctrl&& the_entry.IsDirectory() || !dir_ctrl && the_entry.IsFile())) { BPath the_path; the_entry.GetPath(&the_path); SetText(the_path.Path()); } } else BTextControl::MessageReceived(msg); MakeFocus(); } else BTextControl::MessageReceived(msg); } private: bool dir_ctrl; }; // Preferences window class class PrefsWindow : public BWindow { public: PrefsWindow(uint32 msg); virtual ~PrefsWindow(); virtual void MessageReceived(BMessage *msg); private: void read_volumes_prefs(void); void hide_show_graphics_ctrls(void); void read_graphics_prefs(void); void hide_show_serial_ctrls(void); void read_serial_prefs(void); void add_serial_names(BPopUpMenu *menu, uint32 msg); void read_memory_prefs(void); BView *create_volumes_pane(void); BView *create_graphics_pane(void); BView *create_serial_pane(void); BView *create_memory_pane(void); uint32 ok_message; bool send_quit_on_close; system_info sys_info; BMessenger this_messenger; BView *top; BRect top_frame; BTabView *pane_tabs; BView *panes[NUM_PANES]; int current_pane; VolumeListView *volume_list; BCheckBox *nocdrom_checkbox; BMenuField *frameskip_menu; NumberControl *display_x_ctrl; NumberControl *display_y_ctrl; BMenuField *scr_mode_menu; BCheckBox *nosound_checkbox; BCheckBox *ether_checkbox; BCheckBox *udptunnel_checkbox; NumberControl *udpport_ctrl; RAMSlider *ramsize_slider; PathControl *extfs_control; PathControl *rom_control; BCheckBox *fpu_checkbox; BFilePanel *add_volume_panel; BFilePanel *create_volume_panel; uint32 max_ramsize; // In MB int display_type; int scr_mode_bit; }; /* * Show preferences editor (asynchronously) * Under BeOS, the return value is ignored. Instead, a message is sent to the * application when the user clicks on "Start" or "Quit" */ bool PrefsEditor(void) { new PrefsWindow('strt'); return true; } /* * Preferences window constructor */ PrefsWindow::PrefsWindow(uint32 msg) : BWindow(BRect(0, 0, 400, 289), GetString(STR_PREFS_TITLE), B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS), this_messenger(this) { int i; ok_message = msg; send_quit_on_close = true; get_system_info(&sys_info); // Move window to right position Lock(); MoveTo(80, 80); // Set up menus BMenuBar *bar = new BMenuBar(Bounds(), "menu"); BMenu *menu = new BMenu(GetString(STR_PREFS_MENU)); menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_ABOUT), new BMessage(B_ABOUT_REQUESTED))); menu->AddItem(new BSeparatorItem); menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_START), new BMessage(MSG_OK))); menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_ZAP_PRAM), new BMessage(MSG_ZAP_PRAM))); menu->AddItem(new BSeparatorItem); menu->AddItem(new BMenuItem(GetString(STR_PREFS_ITEM_QUIT), new BMessage(MSG_CANCEL), 'Q')); bar->AddItem(menu); AddChild(bar); SetKeyMenuBar(bar); int mbar_height = int(bar->Bounds().bottom) + 1; // Resize window to fit menu bar ResizeBy(0, mbar_height); // Light gray background BRect b = Bounds(); top = new BView(BRect(0, mbar_height, b.right, b.bottom), "top", B_FOLLOW_NONE, B_WILL_DRAW); AddChild(top); top->SetViewColor(fill_color); top_frame = top->Bounds(); // Create panes panes[0] = create_volumes_pane(); panes[1] = create_graphics_pane(); panes[2] = create_serial_pane(); panes[3] = create_memory_pane(); // Prefs item tab view pane_tabs = new BTabView(BRect(10, 10, top_frame.right-10, top_frame.bottom-50), "items", B_WIDTH_FROM_LABEL); for (i=0; iAddTab(panes[i]); top->AddChild(pane_tabs); volume_list->Select(0); // Create volume file panels add_volume_panel = new BFilePanel(B_OPEN_PANEL, &this_messenger, NULL, B_FILE_NODE | B_DIRECTORY_NODE, false, new BMessage(MSG_ADD_VOLUME_PANEL)); add_volume_panel->SetButtonLabel(B_DEFAULT_BUTTON, GetString(STR_ADD_VOLUME_PANEL_BUTTON)); add_volume_panel->Window()->SetTitle(GetString(STR_ADD_VOLUME_TITLE)); create_volume_panel = new BFilePanel(B_SAVE_PANEL, &this_messenger, NULL, B_FILE_NODE | B_DIRECTORY_NODE, false, new BMessage(MSG_CREATE_VOLUME_PANEL)); create_volume_panel->SetButtonLabel(B_DEFAULT_BUTTON, GetString(STR_CREATE_VOLUME_PANEL_BUTTON)); create_volume_panel->Window()->SetTitle(GetString(STR_CREATE_VOLUME_TITLE)); create_volume_panel->Window()->Lock(); BView *background = create_volume_panel->Window()->ChildAt(0); background->FindView("PoseView")->ResizeBy(0, -30); background->FindView("VScrollBar")->ResizeBy(0, -30); background->FindView("CountVw")->MoveBy(0, -30); BView *v = background->FindView("HScrollBar"); if (v) v->MoveBy(0, -30); else { i = 0; while ((v = background->ChildAt(i++)) != NULL) { if (v->Name() == NULL || v->Name()[0] == 0) { v->MoveBy(0, -30); // unnamed horizontal scroll bar break; } } } BView *filename = background->FindView("text view"); BRect fnr(filename->Frame()); fnr.OffsetBy(0, -30); NumberControl *nc = new NumberControl(fnr, 80, "hardfile_size", GetString(STR_HARDFILE_SIZE_CTRL), 40, NULL); background->AddChild(nc); create_volume_panel->Window()->Unlock(); // "Start" button BButton *button = new BButton(BRect(20, top_frame.bottom-35, 90, top_frame.bottom-10), "start", GetString(STR_START_BUTTON), new BMessage(MSG_OK)); top->AddChild(button); SetDefaultButton(button); // "Quit" button top->AddChild(new BButton(BRect(top_frame.right-90, top_frame.bottom-35, top_frame.right-20, top_frame.bottom-10), "cancel", GetString(STR_QUIT_BUTTON), new BMessage(MSG_CANCEL))); Unlock(); Show(); } /* * Preferences window destructor */ PrefsWindow::~PrefsWindow() { delete add_volume_panel; delete create_volume_panel; if (send_quit_on_close) be_app->PostMessage(B_QUIT_REQUESTED); } /* * Create "Volumes" pane */ void PrefsWindow::read_volumes_prefs(void) { PrefsReplaceString("extfs", extfs_control->Text()); } BView *PrefsWindow::create_volumes_pane(void) { BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_VOLUMES_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); pane->SetViewColor(fill_color); float right = pane->Bounds().right-10; const char *str; int32 index = 0; volume_list = new VolumeListView(BRect(15, 10, pane->Bounds().right-30, 113), "volumes"); while ((str = PrefsFindString("disk", index++)) != NULL) volume_list->AddItem(new BStringItem(str)); volume_list->SetSelectionMessage(new BMessage(MSG_VOLUME_SELECTED)); volume_list->SetInvocationMessage(new BMessage(MSG_VOLUME_INVOKED)); pane->AddChild(new BScrollView("volumes_border", volume_list, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true)); pane->AddChild(new BButton(BRect(10, 118, pane->Bounds().right/3, 138), "add_volume", GetString(STR_ADD_VOLUME_BUTTON), new BMessage(MSG_ADD_VOLUME))); pane->AddChild(new BButton(BRect(pane->Bounds().right/3, 118, pane->Bounds().right*2/3, 138), "create_volume", GetString(STR_CREATE_VOLUME_BUTTON), new BMessage(MSG_CREATE_VOLUME))); pane->AddChild(new BButton(BRect(pane->Bounds().right*2/3, 118, pane->Bounds().right-11, 138), "remove_volume", GetString(STR_REMOVE_VOLUME_BUTTON), new BMessage(MSG_REMOVE_VOLUME))); extfs_control = new PathControl(true, BRect(10, 145, right, 160), "extfs", GetString(STR_EXTFS_CTRL), PrefsFindString("extfs"), NULL); extfs_control->SetDivider(90); pane->AddChild(extfs_control); BMenuField *menu_field; BPopUpMenu *menu = new BPopUpMenu(""); menu_field = new BMenuField(BRect(10, 165, right, 180), "bootdriver", GetString(STR_BOOTDRIVER_CTRL), menu); menu_field->SetDivider(90); menu->AddItem(new BMenuItem(GetString(STR_BOOT_ANY_LAB), new BMessage(MSG_BOOT_ANY))); menu->AddItem(new BMenuItem(GetString(STR_BOOT_CDROM_LAB), new BMessage(MSG_BOOT_CDROM))); pane->AddChild(menu_field); int32 i32 = PrefsFindInt32("bootdriver"); BMenuItem *item; if (i32 == 0) { if ((item = menu->FindItem(GetString(STR_BOOT_ANY_LAB))) != NULL) item->SetMarked(true); } else if (i32 == CDROMRefNum) { if ((item = menu->FindItem(GetString(STR_BOOT_CDROM_LAB))) != NULL) item->SetMarked(true); } nocdrom_checkbox = new BCheckBox(BRect(10, 185, right, 200), "nocdrom", GetString(STR_NOCDROM_CTRL), new BMessage(MSG_NOCDROM)); pane->AddChild(nocdrom_checkbox); nocdrom_checkbox->SetValue(PrefsFindBool("nocdrom") ? B_CONTROL_ON : B_CONTROL_OFF); return pane; } /* * Create "Graphics/Sound" pane */ // Screen mode list struct scr_mode_desc { int mode_mask; int str; }; static const scr_mode_desc scr_mode[] = { {B_8_BIT_640x480, STR_8_BIT_640x480_LAB}, {B_8_BIT_800x600, STR_8_BIT_800x600_LAB}, {B_8_BIT_1024x768, STR_8_BIT_1024x768_LAB}, {B_8_BIT_1152x900, STR_8_BIT_1152x900_LAB}, {B_8_BIT_1280x1024, STR_8_BIT_1280x1024_LAB}, {B_8_BIT_1600x1200, STR_8_BIT_1600x1200_LAB}, {B_15_BIT_640x480, STR_15_BIT_640x480_LAB}, {B_15_BIT_800x600, STR_15_BIT_800x600_LAB}, {B_15_BIT_1024x768, STR_15_BIT_1024x768_LAB}, {B_15_BIT_1152x900, STR_15_BIT_1152x900_LAB}, {B_15_BIT_1280x1024, STR_15_BIT_1280x1024_LAB}, {B_15_BIT_1600x1200, STR_15_BIT_1600x1200_LAB}, {B_32_BIT_640x480, STR_24_BIT_640x480_LAB}, {B_32_BIT_800x600, STR_24_BIT_800x600_LAB}, {B_32_BIT_1024x768, STR_24_BIT_1024x768_LAB}, {B_32_BIT_1152x900, STR_24_BIT_1152x900_LAB}, {B_32_BIT_1280x1024, STR_24_BIT_1280x1024_LAB}, {B_32_BIT_1600x1200, STR_24_BIT_1600x1200_LAB}, {0, 0} // End marker }; void PrefsWindow::hide_show_graphics_ctrls(void) { if (display_type == DISPLAY_WINDOW) { if (!scr_mode_menu->IsHidden()) scr_mode_menu->Hide(); if (frameskip_menu->IsHidden()) frameskip_menu->Show(); if (display_x_ctrl->IsHidden()) display_x_ctrl->Show(); if (display_y_ctrl->IsHidden()) display_y_ctrl->Show(); } else { if (!frameskip_menu->IsHidden()) frameskip_menu->Hide(); if (!display_x_ctrl->IsHidden()) display_x_ctrl->Hide(); if (!display_y_ctrl->IsHidden()) display_y_ctrl->Hide(); if (scr_mode_menu->IsHidden()) scr_mode_menu->Show(); } } void PrefsWindow::read_graphics_prefs(void) { char str[64]; if (display_type == DISPLAY_WINDOW) { sprintf(str, "win/%d/%d", display_x_ctrl->Value(), display_y_ctrl->Value()); } else { sprintf(str, "scr/%d", scr_mode_bit); } PrefsReplaceString("screen", str); } BView *PrefsWindow::create_graphics_pane(void) { BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_GRAPHICS_SOUND_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); pane->SetViewColor(fill_color); float right = pane->Bounds().right-10; const char *mode_str = PrefsFindString("screen"); int width = 512, height = 384; scr_mode_bit = 0; display_type = DISPLAY_WINDOW; if (mode_str) { if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2) display_type = DISPLAY_WINDOW; else if (sscanf(mode_str, "scr/%d", &scr_mode_bit) == 1) display_type = DISPLAY_SCREEN; } BMenuField *menu_field; BMenuItem *item; BPopUpMenu *menu; menu = new BPopUpMenu(""); menu_field = new BMenuField(BRect(10, 5, right, 20), "videotype", GetString(STR_VIDEO_TYPE_CTRL), menu); menu_field->SetDivider(120); menu->AddItem(item = new BMenuItem(GetString(STR_WINDOW_LAB), new BMessage(MSG_VIDEO_WINDOW))); if (display_type == DISPLAY_WINDOW) item->SetMarked(true); menu->AddItem(item = new BMenuItem(GetString(STR_FULLSCREEN_LAB), new BMessage(MSG_VIDEO_SCREEN))); if (display_type == DISPLAY_SCREEN) item->SetMarked(true); pane->AddChild(menu_field); menu = new BPopUpMenu(""); frameskip_menu = new BMenuField(BRect(10, 26, right, 41), "frameskip", GetString(STR_FRAMESKIP_CTRL), menu); frameskip_menu->SetDivider(120); menu->AddItem(new BMenuItem(GetString(STR_REF_5HZ_LAB), new BMessage(MSG_REF_5HZ))); menu->AddItem(new BMenuItem(GetString(STR_REF_7_5HZ_LAB), new BMessage(MSG_REF_7_5HZ))); menu->AddItem(new BMenuItem(GetString(STR_REF_10HZ_LAB), new BMessage(MSG_REF_10HZ))); menu->AddItem(new BMenuItem(GetString(STR_REF_15HZ_LAB), new BMessage(MSG_REF_15HZ))); menu->AddItem(new BMenuItem(GetString(STR_REF_30HZ_LAB), new BMessage(MSG_REF_30HZ))); pane->AddChild(frameskip_menu); int32 i32 = PrefsFindInt32("frameskip"); if (i32 == 12) { if ((item = menu->FindItem(GetString(STR_REF_5HZ_LAB))) != NULL) item->SetMarked(true); } else if (i32 == 8) { if ((item = menu->FindItem(GetString(STR_REF_7_5HZ_LAB))) != NULL) item->SetMarked(true); } else if (i32 == 6) { if ((item = menu->FindItem(GetString(STR_REF_10HZ_LAB))) != NULL) item->SetMarked(true); } else if (i32 == 4) { if ((item = menu->FindItem(GetString(STR_REF_15HZ_LAB))) != NULL) item->SetMarked(true); } else if (i32 == 2) { if ((item = menu->FindItem(GetString(STR_REF_30HZ_LAB))) != NULL) item->SetMarked(true); } display_x_ctrl = new NumberControl(BRect(10, 48, right / 2, 66), 118, "width", GetString(STR_DISPLAY_X_CTRL), width, NULL); pane->AddChild(display_x_ctrl); display_y_ctrl = new NumberControl(BRect(10, 69, right / 2, 87), 118, "height", GetString(STR_DISPLAY_Y_CTRL), height, NULL); pane->AddChild(display_y_ctrl); menu = new BPopUpMenu(""); scr_mode_menu = new BMenuField(BRect(10, 26, right, 41), "screenmode", GetString(STR_SCREEN_MODE_CTRL), menu); scr_mode_menu->SetDivider(120); for (int i=0; scr_mode[i].mode_mask; i++) { menu->AddItem(item = new BMenuItem(GetString(scr_mode[i].str), new BMessage(MSG_SCREEN_MODE + i))); if (scr_mode[i].mode_mask & (1 << scr_mode_bit)) item->SetMarked(true); } pane->AddChild(scr_mode_menu); nosound_checkbox = new BCheckBox(BRect(10, 90, right, 105), "nosound", GetString(STR_NOSOUND_CTRL), new BMessage(MSG_NOSOUND)); pane->AddChild(nosound_checkbox); nosound_checkbox->SetValue(PrefsFindBool("nosound") ? B_CONTROL_ON : B_CONTROL_OFF); hide_show_graphics_ctrls(); return pane; } /* * Create "Serial/Network" pane */ void PrefsWindow::hide_show_serial_ctrls(void) { if (udptunnel_checkbox->Value() == B_CONTROL_ON) { ether_checkbox->SetEnabled(false); udpport_ctrl->SetEnabled(true); } else { ether_checkbox->SetEnabled(true); udpport_ctrl->SetEnabled(false); } } void PrefsWindow::read_serial_prefs(void) { PrefsReplaceInt32("udpport", udpport_ctrl->Value()); } void PrefsWindow::add_serial_names(BPopUpMenu *menu, uint32 msg) { BSerialPort *port = new BSerialPort; char name[B_PATH_NAME_LENGTH]; for (int i=0; iCountDevices(); i++) { port->GetDeviceName(i, name); menu->AddItem(new BMenuItem(name, new BMessage(msg))); } if (sys_info.platform_type == B_BEBOX_PLATFORM) { BDirectory dir; BEntry entry; dir.SetTo("/dev/parallel"); if (dir.InitCheck() == B_NO_ERROR) { dir.Rewind(); while (dir.GetNextEntry(&entry) >= 0) { if (!entry.IsDirectory()) { entry.GetName(name); menu->AddItem(new BMenuItem(name, new BMessage(msg))); } } } } delete port; } static void set_serial_label(BPopUpMenu *menu, const char *prefs_name) { const char *str; BMenuItem *item; if ((str = PrefsFindString(prefs_name)) != NULL) if ((item = menu->FindItem(str)) != NULL) item->SetMarked(true); } BView *PrefsWindow::create_serial_pane(void) { BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_SERIAL_NETWORK_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); pane->SetViewColor(fill_color); float right = pane->Bounds().right-10; BMenuField *menu_field; BPopUpMenu *menu_a = new BPopUpMenu(""); add_serial_names(menu_a, MSG_SER_A); menu_field = new BMenuField(BRect(10, 5, right, 20), "seriala", GetString(STR_SERIALA_CTRL), menu_a); menu_field->SetDivider(90); pane->AddChild(menu_field); set_serial_label(menu_a, "seriala"); BPopUpMenu *menu_b = new BPopUpMenu(""); add_serial_names(menu_b, MSG_SER_B); menu_field = new BMenuField(BRect(10, 26, right, 41), "serialb", GetString(STR_SERIALB_CTRL), menu_b); menu_field->SetDivider(90); pane->AddChild(menu_field); set_serial_label(menu_b, "serialb"); ether_checkbox = new BCheckBox(BRect(10, 47, right, 62), "ether", GetString(STR_ETHER_ENABLE_CTRL), new BMessage(MSG_ETHER)); pane->AddChild(ether_checkbox); ether_checkbox->SetValue(PrefsFindString("ether") ? B_CONTROL_ON : B_CONTROL_OFF); udptunnel_checkbox = new BCheckBox(BRect(10, 67, right, 72), "udptunnel", GetString(STR_UDPTUNNEL_CTRL), new BMessage(MSG_UDPTUNNEL)); pane->AddChild(udptunnel_checkbox); udptunnel_checkbox->SetValue(PrefsFindBool("udptunnel") ? B_CONTROL_ON : B_CONTROL_OFF); udpport_ctrl = new NumberControl(BRect(10, 87, right / 2, 105), 118, "udpport", GetString(STR_UDPPORT_CTRL), PrefsFindInt32("udpport"), NULL); pane->AddChild(udpport_ctrl); hide_show_serial_ctrls(); return pane; } /* * Create "Memory" pane */ void PrefsWindow::read_memory_prefs(void) { const char *str = rom_control->Text(); if (strlen(str)) PrefsReplaceString("rom", str); else PrefsRemoveItem("rom"); } BView *PrefsWindow::create_memory_pane(void) { char str[256], str2[256]; BView *pane = new BView(BRect(0, 0, top_frame.right-20, top_frame.bottom-80), GetString(STR_MEMORY_MISC_PANE_TITLE), B_FOLLOW_NONE, B_WILL_DRAW); pane->SetViewColor(fill_color); float right = pane->Bounds().right-10; BEntry entry("/boot/var/swap"); off_t swap_space; if (entry.GetSize(&swap_space) == B_NO_ERROR) max_ramsize = swap_space / (1024 * 1024) - 8; else max_ramsize = sys_info.max_pages * B_PAGE_SIZE / (1024 * 1024) - 8; int32 value = PrefsFindInt32("ramsize") / (1024 * 1024); ramsize_slider = new RAMSlider(BRect(10, 5, right, 55), "ramsize", GetString(STR_RAMSIZE_SLIDER), new BMessage(MSG_RAMSIZE), 1, max_ramsize, B_TRIANGLE_THUMB); ramsize_slider->SetValue(value); ramsize_slider->UseFillColor(true, &slider_fill_color); sprintf(str, GetString(STR_RAMSIZE_FMT), 1); sprintf(str2, GetString(STR_RAMSIZE_FMT), max_ramsize); ramsize_slider->SetLimitLabels(str, str2); pane->AddChild(ramsize_slider); BMenuField *menu_field; BMenuItem *item; BPopUpMenu *menu; int id = PrefsFindInt32("modelid"); menu = new BPopUpMenu(""); menu_field = new BMenuField(BRect(10, 60, right, 75), "modelid", GetString(STR_MODELID_CTRL), menu); menu_field->SetDivider(120); menu->AddItem(item = new BMenuItem(GetString(STR_MODELID_5_LAB), new BMessage(MSG_MODELID_5))); if (id == 5) item->SetMarked(true); menu->AddItem(item = new BMenuItem(GetString(STR_MODELID_14_LAB), new BMessage(MSG_MODELID_14))); if (id == 14) item->SetMarked(true); pane->AddChild(menu_field); int cpu = PrefsFindInt32("cpu"); bool fpu = PrefsFindBool("fpu"); menu = new BPopUpMenu(""); menu_field = new BMenuField(BRect(10, 82, right, 97), "cpu", GetString(STR_CPU_CTRL), menu); menu_field->SetDivider(120); menu->AddItem(item = new BMenuItem(GetString(STR_CPU_68020_LAB), new BMessage(MSG_CPU_68020))); if (cpu == 2 && !fpu) item->SetMarked(true); menu->AddItem(item = new BMenuItem(GetString(STR_CPU_68020_FPU_LAB), new BMessage(MSG_CPU_68020_FPU))); if (cpu == 2 && fpu) item->SetMarked(true); menu->AddItem(item = new BMenuItem(GetString(STR_CPU_68030_LAB), new BMessage(MSG_CPU_68030))); if (cpu == 3 && !fpu) item->SetMarked(true); menu->AddItem(item = new BMenuItem(GetString(STR_CPU_68030_FPU_LAB), new BMessage(MSG_CPU_68030_FPU))); if (cpu == 3 && fpu) item->SetMarked(true); menu->AddItem(item = new BMenuItem(GetString(STR_CPU_68040_LAB), new BMessage(MSG_CPU_68040))); if (cpu == 4) item->SetMarked(true); pane->AddChild(menu_field); rom_control = new PathControl(false, BRect(10, 104, right, 119), "rom", GetString(STR_ROM_FILE_CTRL), PrefsFindString("rom"), NULL); rom_control->SetDivider(117); pane->AddChild(rom_control); return pane; } /* * Message from controls/menus received */ void PrefsWindow::MessageReceived(BMessage *msg) { switch (msg->what) { case MSG_OK: { // "Start" button clicked read_volumes_prefs(); read_memory_prefs(); read_graphics_prefs(); SavePrefs(); send_quit_on_close = false; PostMessage(B_QUIT_REQUESTED); be_app->PostMessage(ok_message); break; } case MSG_CANCEL: // "Quit" button clicked send_quit_on_close = false; PostMessage(B_QUIT_REQUESTED); be_app->PostMessage(B_QUIT_REQUESTED); break; case B_ABOUT_REQUESTED: { // "About" menu item selected ShowAboutWindow(); break; } case MSG_ZAP_PRAM: // "Zap PRAM File" menu item selected ZapPRAM(); break; case MSG_VOLUME_INVOKED: { // Double-clicked on volume name, toggle read-only flag int selected = volume_list->CurrentSelection(); if (selected >= 0) { const char *str = PrefsFindString("disk", selected); BStringItem *item = (BStringItem *)volume_list->RemoveItem(selected); delete item; char newstr[256]; if (str[0] == '*') strcpy(newstr, str+1); else { strcpy(newstr, "*"); strcat(newstr, str); } PrefsReplaceString("disk", newstr, selected); volume_list->AddItem(new BStringItem(newstr), selected); volume_list->Select(selected); } break; } case MSG_ADD_VOLUME: add_volume_panel->Show(); break; case MSG_CREATE_VOLUME: create_volume_panel->Show(); break; case MSG_ADD_VOLUME_PANEL: { entry_ref ref; if (msg->FindRef("refs", &ref) == B_NO_ERROR) { BEntry entry(&ref, true); BPath path; entry.GetPath(&path); if (entry.IsFile()) { PrefsAddString("disk", path.Path()); volume_list->AddItem(new BStringItem(path.Path())); } else if (entry.IsDirectory()) { BVolume volume; if (path.Path()[0] == '/' && strchr(path.Path()+1, '/') == NULL && entry.GetVolume(&volume) == B_NO_ERROR) { int32 i = 0; dev_t d; fs_info info; while ((d = next_dev(&i)) >= 0) { fs_stat_dev(d, &info); if (volume.Device() == info.dev) { PrefsAddString("disk", info.device_name); volume_list->AddItem(new BStringItem(info.device_name)); } } } } } break; } case MSG_CREATE_VOLUME_PANEL: { entry_ref dir; if (msg->FindRef("directory", &dir) == B_NO_ERROR) { BEntry entry(&dir, true); BPath path; entry.GetPath(&path); path.Append(msg->FindString("name")); create_volume_panel->Window()->Lock(); BView *background = create_volume_panel->Window()->ChildAt(0); NumberControl *v = (NumberControl *)background->FindView("hardfile_size"); int size = v->Value(); char cmd[1024]; sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", path.Path(), size); int ret = system(cmd); if (ret == 0) { PrefsAddString("disk", path.Path()); volume_list->AddItem(new BStringItem(path.Path())); } else { sprintf(cmd, GetString(STR_CREATE_VOLUME_WARN), strerror(ret)); WarningAlert(cmd); } } break; } case MSG_REMOVE_VOLUME: { int selected = volume_list->CurrentSelection(); if (selected >= 0) { PrefsRemoveItem("disk", selected); BStringItem *item = (BStringItem *)volume_list->RemoveItem(selected); delete item; volume_list->Select(selected); } break; } case MSG_BOOT_ANY: PrefsReplaceInt32("bootdriver", 0); break; case MSG_BOOT_CDROM: PrefsReplaceInt32("bootdriver", CDROMRefNum); break; case MSG_NOCDROM: PrefsReplaceBool("nocdrom", nocdrom_checkbox->Value() == B_CONTROL_ON); break; case MSG_VIDEO_WINDOW: display_type = DISPLAY_WINDOW; hide_show_graphics_ctrls(); break; case MSG_VIDEO_SCREEN: display_type = DISPLAY_SCREEN; hide_show_graphics_ctrls(); break; case MSG_REF_5HZ: PrefsReplaceInt32("frameskip", 12); break; case MSG_REF_7_5HZ: PrefsReplaceInt32("frameskip", 8); break; case MSG_REF_10HZ: PrefsReplaceInt32("frameskip", 6); break; case MSG_REF_15HZ: PrefsReplaceInt32("frameskip", 4); break; case MSG_REF_30HZ: PrefsReplaceInt32("frameskip", 2); break; case MSG_NOSOUND: PrefsReplaceBool("nosound", nosound_checkbox->Value() == B_CONTROL_ON); break; case MSG_SER_A: { BMenuItem *source = NULL; msg->FindPointer("source", (void **)&source); if (source) PrefsReplaceString("seriala", source->Label()); break; } case MSG_SER_B: { BMenuItem *source = NULL; msg->FindPointer("source", (void **)&source); if (source) PrefsReplaceString("serialb", source->Label()); break; } case MSG_ETHER: if (ether_checkbox->Value() == B_CONTROL_ON) PrefsReplaceString("ether", "yes"); else PrefsRemoveItem("ether"); break; case MSG_UDPTUNNEL: PrefsReplaceBool("udptunnel", udptunnel_checkbox->Value() == B_CONTROL_ON); hide_show_serial_ctrls(); break; case MSG_RAMSIZE: PrefsReplaceInt32("ramsize", ramsize_slider->Value() * 1024 * 1024); break; case MSG_MODELID_5: PrefsReplaceInt32("modelid", 5); break; case MSG_MODELID_14: PrefsReplaceInt32("modelid", 14); break; case MSG_CPU_68020: PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false); break; case MSG_CPU_68020_FPU: PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true); break; case MSG_CPU_68030: PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false); break; case MSG_CPU_68030_FPU: PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true); break; case MSG_CPU_68040: PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true); break; default: { // Screen mode messages if ((msg->what & 0xffff0000) == MSG_SCREEN_MODE) { int m = msg->what & 0xffff; uint32 mask = scr_mode[m].mode_mask; for (int i=0; i<32; i++) if (mask & (1 << i)) scr_mode_bit = i; } else BWindow::MessageReceived(msg); } } } BasiliskII/src/BeOS/timer_beos.cpp0000644000175000017500000000612210736405220017154 0ustar centriscentris/* * timer_beos.cpp - Time Manager emulation, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include "sysdeps.h" #include "macos_util.h" #include "timer.h" #define DEBUG 0 #include "debug.h" // From main_beos.cpp extern thread_id emul_thread; /* * Return microseconds since boot (64 bit) */ void Microseconds(uint32 &hi, uint32 &lo) { D(bug("Microseconds\n")); bigtime_t time = system_time(); hi = time >> 32; lo = time; } /* * Return local date/time in Mac format (seconds since 1.1.1904) */ uint32 TimerDateTime(void) { return TimeToMacTime(time(NULL)); } /* * Get current time */ void timer_current_time(tm_time_t &t) { t = system_time(); } /* * Add times */ void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b) { res = a + b; } /* * Subtract times */ void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b) { res = a - b; } /* * Compare times (<0: a < b, =0: a = b, >0: a > b) */ int timer_cmp_time(tm_time_t a, tm_time_t b) { tm_time_t r = a - b; return r < 0 ? -1 : (r > 0 ? 1 : 0); } /* * Convert Mac time value (>0: microseconds, <0: microseconds) to tm_time_t */ void timer_mac2host_time(tm_time_t &res, int32 mactime) { if (mactime > 0) res = mactime * 1000; // Time in milliseconds else res = -mactime; // Time in negative microseconds } /* * Convert positive tm_time_t to Mac time value (>0: microseconds, <0: microseconds) * A negative input value for hosttime results in a zero return value * As long as the microseconds value fits in 32 bit, it must not be converted to milliseconds! */ int32 timer_host2mac_time(tm_time_t hosttime) { if (hosttime < 0) return 0; else if (hosttime > 0x7fffffff) return hosttime / 1000; // Time in milliseconds else return -hosttime; // Time in negative microseconds } /* * Delay by specified number of microseconds (<1 second) */ void Delay_usec(uint32 usec) { snooze(usec); } /* * Suspend emulator thread, virtual CPU in idle mode */ void idle_wait(void) { #if 0 /* FIXME: add a semaphore (counter) to avoid a B_BAD_THREAD_STATE return if we call idle_resume() when thread is not suspended? Sorry, I can't test -- gb. */ suspend_thread(emul_thread); #endif } /* * Resume execution of emulator thread, events just arrived */ void idle_resume(void) { #if 0 resume_thread(emul_thread); #endif } BasiliskII/src/BeOS/about_window.cpp0000644000175000017500000000347710736405220017537 0ustar centriscentris\/* * about_window.cpp - "About" window * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include "sysdeps.h" #include "version.h" #include "user_strings.h" /* * Display "About" window */ void ShowAboutWindow(void) { char str[512]; sprintf(str, "Basilisk II\nVersion %d.%d\n\n" "Copyright " B_UTF8_COPYRIGHT " 1997-2008 Christian Bauer et al.\n" "E-mail: Christian.Bauer@uni-mainz.de\n" "http://www.uni-mainz.de/~bauec002/B2Main.html\n\n" "Basilisk II comes with ABSOLUTELY NO\n" "WARRANTY. This is free software, and\n" "you are welcome to redistribute it\n" "under the terms of the GNU General\n" "Public License.\n", VERSION_MAJOR, VERSION_MINOR ); BAlert *about = new BAlert("", str, GetString(STR_OK_BUTTON), NULL, NULL, B_WIDTH_FROM_LABEL); BTextView *theText = about->TextView(); if (theText) { theText->SetStylable(true); theText->Select(0, 11); BFont ourFont; theText->SetFontAndColor(be_bold_font); theText->GetFontAndColor(2, &ourFont, NULL); ourFont.SetSize(24); theText->SetFontAndColor(&ourFont); } about->Go(); } BasiliskII/src/BeOS/SheepNet/0000755000175000017500000000000011735674761016054 5ustar centriscentrisBasiliskII/src/BeOS/SheepNet/Makefile0000644000175000017500000000701307204016776017505 0ustar centriscentris## BeOS Generic Makefile v2.1 ## ## Fill in this file to specify the project being created, and the referenced ## makefile-engine will do all of the hard work for you. This handles both ## Intel and PowerPC builds of the BeOS. ## Application Specific Settings --------------------------------------------- # specify the name of the binary NAME= sheep_net # specify the type of binary # APP: Application # SHARED: Shared library or add-on # STATIC: Static library archive # DRIVER: Kernel Driver TYPE= SHARED # add support for new Pe and Eddie features # to fill in generic makefile #%{ # @src->@ # specify the source files to use # full paths or paths relative to the makefile can be included # all files, regardless of directory, will have their object # files created in the common object directory. # Note that this means this makefile will not work correctly # if two source files with the same name (source.c or source.cpp) # are included from different directories. Also note that spaces # in folder names do not work well with this makefile. SRCS= sheep_net.cpp # specify the resource files to use # full path or a relative path to the resource file can be used. RSRCS= # @<-src@ #%} # end support for Pe and Eddie # specify additional libraries to link against # there are two acceptable forms of library specifications # - if your library follows the naming pattern of: # libXXX.so or libXXX.a you can simply specify XXX # library: libbe.so entry: be # # - if your library does not follow the standard library # naming scheme you need to specify the path to the library # and it's name # library: my_lib.a entry: my_lib.a or path/my_lib.a LIBS= netdev # specify additional paths to directories following the standard # libXXX.so or libXXX.a naming scheme. You can specify full paths # or paths relative to the makefile. The paths included may not # be recursive, so include all of the paths where libraries can # be found. Directories where source files are found are # automatically included. LIBPATHS= # additional paths to look for system headers # thes use the form: #include
# source file directories are NOT auto-included here SYSTEM_INCLUDE_PATHS = # additional paths to look for local headers # thes use the form: #include "header" # source file directories are automatically included LOCAL_INCLUDE_PATHS = # specify the level of optimization that you desire # NONE, SOME, FULL OPTIMIZE= FULL # specify any preprocessor symbols to be defined. The symbols will not # have their values set automatically; you must supply the value (if any) # to use. For example, setting DEFINES to "DEBUG=1" will cause the # compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" # would pass "-DDEBUG" on the compiler's command line. DEFINES= # specify special warning levels # if unspecified default warnings will be used # NONE = supress all warnings # ALL = enable all warnings WARNINGS = # specify whether image symbols will be created # so that stack crawls in the debugger are meaningful # if TRUE symbols will be created SYMBOLS = # specify debug settings # if TRUE will allow application to be run from a source-level # debugger. Note that this will disable all optimzation. DEBUGGER = # specify additional compiler flags for all files COMPILER_FLAGS = # specify additional linker flags LINKER_FLAGS = ## include the makefile-engine include /boot/develop/etc/makefile-engine install: $(TARGET) cp $(TARGET) /boot/beos/system/add-ons/net_server/$(NAME) uninstall: rm /boot/beos/system/add-ons/net_server/$(NAME) BasiliskII/src/BeOS/SheepNet/sheep_net.cpp0000644000175000017500000001736310736405220020522 0ustar centriscentris/* * sheep_net.cpp - Net server add-on for SheepShaver and Basilisk II * * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #include #include "sheep_net.h" #define DEBUG 0 #if DEBUG==1 #define bug pprintf #elif DEBUG==2 #define bug kprintf #endif #if DEBUG #define D(x) (x) #else #define D(x) ; #endif static int pprintf(const char* format, ...) { port_id PortNum; int len,Ret; char Buffer[1024]; va_list ap; if ((PortNum = find_port("PortLogger")) == B_NAME_NOT_FOUND) return(PortNum); for (len=0; len<1024; len++) Buffer[len]='\0'; va_start(ap, format); vsprintf(Buffer, format, ap); Ret = write_port(PortNum, 0, Buffer, strlen(Buffer)); return(Ret); } // Constants #define NETDUMP_PRIO 1 // Default is 0 const uint32 buffer_size = (sizeof(net_buffer) / B_PAGE_SIZE + 1) * B_PAGE_SIZE; // SheepNet add-on object class SheepNetAddOn : public BNetProtocol, BPacketHandler { public: void AddDevice(BNetDevice *dev, const char *name); bool PacketReceived(BNetPacket *buf, BNetDevice *dev); }; // Global variables static bool shutdown_now = false; static bool active = false; static thread_id write_thread; // Packet writer static sem_id write_sem; // Semaphore to trigger packet writing static BNetDevice *EtherCard = NULL; // The Ethernet card we are attached to static area_id buffer_area; // Packet buffer area static net_buffer *net_buffer_ptr; // Pointer to packet buffer static uint32 rd_pos; // Current read position in packet buffer static uint32 wr_pos; // Current write position in packet buffer /* * Clear packet buffer */ static void clear(void) { int i; for (i=0;iread[i].cmd = 0; net_buffer_ptr->read[i].length = 0; net_buffer_ptr->read[i].card = 0; net_buffer_ptr->read[i].reserved = 0; } for (i=0;iwrite[i].cmd = 0; net_buffer_ptr->write[i].length = 0; net_buffer_ptr->write[i].card = 0; net_buffer_ptr->write[i].reserved = 0; } rd_pos = wr_pos = 0; } /* * Packet writer thread */ static status_t write_packet_func(void *arg) { while (!shutdown_now) { // Read and execute command net_packet *p = &net_buffer_ptr->write[wr_pos]; while (p->cmd & IN_USE) { D(bug("wp: %d\n", wr_pos)); switch (p->cmd >> 8) { case ACTIVATE_SHEEP_NET: D(bug("activate sheep-net\n")); active = false; clear(); active = true; goto next; case DEACTIVATE_SHEEP_NET: D(bug("deactivate sheep-net\n")); active = false; clear(); goto next; case SHUTDOWN_SHEEP_NET: D(bug("shutdown sheep-net\n")); active = false; clear(); shutdown_now = true; goto next; case ADD_MULTICAST: { const char *data = (const char *)p->data; D(bug("add multicast %02x %02x %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3], data[4], data[5])); if (active) { status_t result; if ((result = EtherCard->AddMulticastAddress(data)) != B_OK) { // !! handle error !! error while creating multicast address D(bug("error while creating multicast address %d\n", result)); } } break; } case REMOVE_MULTICAST: { const char *data = (const char *)p->data; D(bug("remove multicast %02x %02x %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3], data[4], data[5])); if (active) { status_t result; if ((result = EtherCard->RemoveMulticastAddress(data)) != B_OK) { // !! handle error !! error while removing multicast address D(bug("error while removing multicast address %d\n", result)); } } break; } case SHEEP_PACKET: { uint32 length = p->length; // D(bug("sheep packet %d\n", length)); if (active) { BStandardPacket *packet = new BStandardPacket(length); packet->Write(0, (const char *)p->data, length); EtherCard->SendPacket(packet); } break; } default: D(bug("error: unknown port packet type\n")); break; } p->cmd = 0; // Free packet wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; p = &net_buffer_ptr->write[wr_pos]; } // Wait for next packet next: acquire_sem_etc(write_sem, 1, B_TIMEOUT, 25000); } return 0; } /* * Init the net add-on */ static void init_addon() { int i; D(bug("init sheep-net\n")); // Create packet buffer if ((buffer_area = create_area("packet buffer", (void **)&net_buffer_ptr, B_ANY_ADDRESS, buffer_size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA)) < B_NO_ERROR) { D(bug("FATAL ERROR: can't create shared area\n")); return; } // Init packet buffer clear(); EtherCard->Address((char *)net_buffer_ptr->ether_addr); net_buffer_ptr->read_sem = -1; net_buffer_ptr->read_ofs = (uint32)(net_buffer_ptr->read) - (uint32)net_buffer_ptr; net_buffer_ptr->read_packet_size = sizeof(net_packet); net_buffer_ptr->read_packet_count = READ_PACKET_COUNT; if ((write_sem = create_sem(0, "ether write")) < B_NO_ERROR) { D(bug("FATAL ERROR: can't create semaphore\n")); return; } net_buffer_ptr->write_sem = write_sem; net_buffer_ptr->write_ofs = (uint32)(net_buffer_ptr->write) - (uint32)net_buffer_ptr; net_buffer_ptr->write_packet_size = sizeof(net_packet); net_buffer_ptr->write_packet_count = WRITE_PACKET_COUNT; // Start packet writer thread write_thread = spawn_thread(write_packet_func, "sheep_net ether write", B_URGENT_DISPLAY_PRIORITY, NULL); resume_thread(write_thread); } /* * Add-on attached to Ethernet card */ void SheepNetAddOn::AddDevice(BNetDevice *dev, const char *name) { if (dev->Type() != B_ETHER_NET_DEVICE) return; if (EtherCard != NULL) { // !! handle error !! support for multiple ethernet cards ... D(bug("error: SheepShaver doesn't support multiple Ethernetcards !\n")); return; } EtherCard = dev; init_addon(); register_packet_handler(this, dev, NETDUMP_PRIO); } /* * Ethernet packet received */ bool SheepNetAddOn::PacketReceived(BNetPacket *pkt, BNetDevice *dev) { if (shutdown_now) { unregister_packet_handler(this, dev); return false; } // D(bug("read_packet_func %d\n", pkt->Size())); if (active) { D(bug("rp: %d\n", rd_pos)); net_packet *p = &net_buffer_ptr->read[rd_pos]; if (p->cmd & IN_USE) { D(bug("error: full read buffer ... lost packet\n")); } else { memcpy(p->data, pkt->Data(), pkt->Size()); p->length = pkt->Size(); p->cmd = IN_USE | (SHEEP_PACKET << 8); rd_pos = (rd_pos + 1) % READ_PACKET_COUNT; release_sem(net_buffer_ptr->read_sem); } } //D(bug("%02x %02x %02x %02x %02x %02x", (uchar) (pkt->Data())[0],(uchar) (pkt->Data())[1],(uchar) (pkt->Data())[2],(uchar) (pkt->Data())[3],(uchar) (pkt->Data())[4],(uchar) (pkt->Data())[5])); return false; } #pragma export on extern "C" BNetProtocol *open_protocol(const char *device) { SheepNetAddOn *dev = new SheepNetAddOn; return dev; } #pragma export off BasiliskII/src/BeOS/SheepNet/sheep_net.h0000644000175000017500000000352410736405220020161 0ustar centriscentris/* * sheep_net.h - Net server add-on for SheepShaver and Basilisk II * * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SHEEP_NET_H #define SHEEP_NET_H // Net buffer dimensions #define READ_PACKET_COUNT 10 #define WRITE_PACKET_COUNT 10 // Net packet struct net_packet { uint32 cmd; // Command uint32 length; // Data length uint32 card; // Network card ID uint32 reserved; uint8 data[1584]; }; // Net buffer (shared area) struct net_buffer { uint8 ether_addr[6]; // Ethernet address uint8 filler1[2]; sem_id read_sem; // Semaphore for read packets uint32 read_ofs; uint32 read_packet_size; uint32 read_packet_count; sem_id write_sem; // Semaphore for write packets uint32 write_ofs; uint32 write_packet_size; uint32 write_packet_count; uint8 filler[24]; net_packet read[READ_PACKET_COUNT]; net_packet write[WRITE_PACKET_COUNT]; }; // Packet commands #define SHEEP_PACKET 0 #define ADD_MULTICAST 1 #define REMOVE_MULTICAST 2 #define ACTIVATE_SHEEP_NET 8 #define DEACTIVATE_SHEEP_NET 9 #define SHUTDOWN_SHEEP_NET 10 #define IN_USE 1 #endif BasiliskII/src/BeOS/audio_beos.cpp0000644000175000017500000001753410736405220017146 0ustar centriscentris/* * audio_beos.cpp - Audio support, BeOS implementation * * Basilisk II (C) 1997-2008 Christian Bauer * Portions written by Marc Hellwig * * 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 */ #include "sysdeps.h" #include #include #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "audio.h" #include "audio_defs.h" #define DEBUG 0 #include "debug.h" // Global variables static int audio_irq_done_sem = -1; // Signal from interrupt to streaming thread: data block read static BSoundPlayer *the_player; // Prototypes static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format); /* * Audio manager thread (for calling media kit functions; * this is not safe under R4 when running on the MacOS stack in kernel space) */ // Message constants const uint32 MSG_QUIT_AUDIO_MANAGER = 'quit'; const uint32 MSG_ENTER_STREAM = 'entr'; const uint32 MSG_EXIT_STREAM = 'exit'; const uint32 MSG_GET_VOLUME = 'getv'; const uint32 MSG_SET_VOLUME = 'setv'; static thread_id am_thread = -1; static sem_id am_done_sem = -1; static volatile float am_volume; static status_t audio_manager(void *arg) { for (;;) { // Receive message thread_id sender; uint32 code = receive_data(&sender, NULL, 0); D(bug("Audio manager received %08lx\n", code)); switch (code) { case MSG_QUIT_AUDIO_MANAGER: return 0; case MSG_ENTER_STREAM: the_player->Start(); break; case MSG_EXIT_STREAM: the_player->Stop(); break; case MSG_GET_VOLUME: am_volume = the_player->Volume(); break; case MSG_SET_VOLUME: the_player->SetVolume(am_volume); break; } // Acknowledge release_sem(am_done_sem); } } /* * Initialization */ // Set AudioStatus to reflect current audio stream format static void set_audio_status_format(void) { AudioStatus.sample_rate = audio_sample_rates[0]; AudioStatus.sample_size = audio_sample_sizes[0]; AudioStatus.channels = audio_channel_counts[0]; } void AudioInit(void) { // Init audio status and feature flags audio_sample_rates.push_back(44100 << 16); audio_sample_sizes.push_back(16); audio_channel_counts.push_back(2); set_audio_status_format(); AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; // Init semaphores audio_irq_done_sem = create_sem(0, "Audio IRQ Done"); am_done_sem = create_sem(0, "Audio Manager Done"); // Start audio manager thread am_thread = spawn_thread(audio_manager, "Audio Manager", B_NORMAL_PRIORITY, NULL); resume_thread(am_thread); // Start stream media_raw_audio_format format; format.frame_rate = AudioStatus.sample_rate >> 16; format.channel_count = AudioStatus.channels; format.format = media_raw_audio_format::B_AUDIO_SHORT; format.byte_order = B_MEDIA_BIG_ENDIAN; audio_frames_per_block = 4096; size_t block_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block; D(bug("AudioInit: block size %d\n", block_size)); format.buffer_size = block_size; the_player = new BSoundPlayer(&format, "MacOS Audio", playbuffer_func, NULL, NULL); if (the_player->InitCheck() != B_NO_ERROR) { printf("FATAL: Cannot initialize BSoundPlayer\n"); delete the_player; the_player = NULL; return; } else the_player->SetHasData(true); // Everything OK audio_open = true; } /* * Deinitialization */ void AudioExit(void) { // Stop stream if (the_player) { the_player->Stop(); delete the_player; the_player = NULL; } // Stop audio manager if (am_thread > 0) { status_t l; send_data(am_thread, MSG_QUIT_AUDIO_MANAGER, NULL, 0); wait_for_thread(am_thread, &l); } // Delete semaphores delete_sem(am_done_sem); delete_sem(audio_irq_done_sem); } /* * First source added, start audio stream */ void audio_enter_stream() { while (send_data(am_thread, MSG_ENTER_STREAM, NULL, 0) == B_INTERRUPTED) ; while (acquire_sem(am_done_sem) == B_INTERRUPTED) ; } /* * Last source removed, stop audio stream */ void audio_exit_stream() { while (send_data(am_thread, MSG_EXIT_STREAM, NULL, 0) == B_INTERRUPTED) ; while (acquire_sem(am_done_sem) == B_INTERRUPTED) ; } /* * Streaming function */ static uint32 apple_stream_info; // Mac address of SoundComponentData struct describing next buffer static void playbuffer_func(void *arg, void *buf, size_t size, const media_raw_audio_format &format) { // Check if new buffer is available if (acquire_sem_etc(audio_irq_done_sem, 1, B_TIMEOUT, 0) == B_NO_ERROR) { // Get size of audio data D(bug("stream: new buffer present\n")); uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); if (apple_stream_info) { size_t work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels; D(bug("stream: size %d, work_size %d\n", size, work_size)); if (work_size > size) work_size = size; if (format.format != media_raw_audio_format::B_AUDIO_SHORT) { D(bug("Wrong audio format %04x\n", format.format)); return; } // Place data into Media Kit buffer Mac2Host_memcpy(buf, ReadMacInt32(apple_stream_info + scd_buffer), work_size); if (work_size != size) memset((uint8 *)buf + work_size, 0, size - work_size); } } else memset(buf, 0, size); // Trigger audio interrupt to get new buffer if (AudioStatus.num_sources) { D(bug("stream: triggering irq\n")); SetInterruptFlag(INTFLAG_AUDIO); TriggerInterrupt(); } } /* * MacOS audio interrupt, read next data block */ void AudioInterrupt(void) { D(bug("AudioInterrupt\n")); // Get data from apple mixer if (AudioStatus.mixer) { M68kRegisters r; r.a[0] = audio_data + adatStreamInfo; r.a[1] = AudioStatus.mixer; Execute68k(audio_data + adatGetSourceData, &r); D(bug(" GetSourceData() returns %08lx\n", r.d[0])); } else WriteMacInt32(audio_data + adatStreamInfo, 0); // Signal stream function release_sem(audio_irq_done_sem); D(bug("AudioInterrupt done\n")); } /* * Set sampling parameters * "index" is an index into the audio_sample_rates[] etc. arrays * It is guaranteed that AudioStatus.num_sources == 0 */ bool audio_set_sample_rate(int index) { return true; } bool audio_set_sample_size(int index) { return true; } bool audio_set_channels(int index) { return true; } /* * Get/set audio info */ bool audio_get_main_mute(void) { return false; } uint32 audio_get_main_volume(void) { if (audio_open) { while (send_data(am_thread, MSG_GET_VOLUME, NULL, 0) == B_INTERRUPTED) ; while (acquire_sem(am_done_sem) == B_INTERRUPTED) ; return int(am_volume * 256.0) * 0x00010001; } else return 0x01000100; } bool audio_get_speaker_mute(void) { return false; } uint32 audio_get_speaker_volume(void) { return 0x01000100; } void audio_set_main_mute(bool mute) { } void audio_set_main_volume(uint32 vol) { if (audio_open) { am_volume = float((vol >> 16) + (vol & 0xffff)) / 512.0; while (send_data(am_thread, MSG_SET_VOLUME, NULL, 0) == B_INTERRUPTED) ; while (acquire_sem(am_done_sem) == B_INTERRUPTED) ; } } void audio_set_speaker_mute(bool mute) { } void audio_set_speaker_volume(uint32 vol) { } BasiliskII/src/BeOS/ether_beos.cpp0000644000175000017500000003151010736405220017142 0ustar centriscentris/* * ether_beos.cpp - Ethernet device driver, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * Portions written by Marc Hellwig * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include #include #include #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "macos_util.h" #include "ether.h" #include "ether_defs.h" #include "sheep_net.h" #define DEBUG 0 #include "debug.h" #define MONITOR 0 // List of attached protocols struct NetProtocol { uint16 type; uint32 handler; }; static BList prot_list; // Global variables static thread_id read_thread; // Packet reception thread static bool ether_thread_active = true; // Flag for quitting the reception thread static area_id buffer_area; // Packet buffer area static net_buffer *net_buffer_ptr; // Pointer to packet buffer static uint32 rd_pos; // Current read position in packet buffer static uint32 wr_pos; // Current write position in packet buffer static sem_id read_sem, write_sem; // Semaphores to trigger packet reading/writing static int fd = -1; // UDP socket fd static bool udp_tunnel = false; // Prototypes static status_t receive_proc(void *data); /* * Find protocol in list */ static NetProtocol *find_protocol(uint16 type) { // All 802.2 types are the same if (type <= 1500) type = 0; // Search list (we could use hashing here but there are usually only three // handlers installed: 0x0000 for AppleTalk and 0x0800/0x0806 for TCP/IP) NetProtocol *p; for (int i=0; (p = (NetProtocol *)prot_list.ItemAt(i)) != NULL; i++) if (p->type == type) return p; return NULL; } /* * Remove all protocols */ static void remove_all_protocols(void) { NetProtocol *p; while ((p = (NetProtocol *)prot_list.RemoveItem((long)0)) != NULL) delete p; } /* * Initialization */ bool ether_init(void) { // Do nothing if no Ethernet device specified if (PrefsFindString("ether") == NULL) return false; // Find net_server team i_wanna_try_that_again: bool found_add_on = false; team_info t_info; int32 t_cookie = 0; image_info i_info; int32 i_cookie = 0; while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) { if (strstr(t_info.args,"net_server")!=NULL) { // Check if sheep_net add-on is loaded while (get_next_image_info(t_info.team, &i_cookie, &i_info) == B_NO_ERROR) { if (strstr(i_info.name, "sheep_net") != NULL) { found_add_on = true; break; } } } if (found_add_on) break; } if (!found_add_on) { // Search for sheep_net in network config file char str[1024]; bool sheep_net_found = false; FILE *fin = fopen("/boot/home/config/settings/network", "r"); while (!feof(fin)) { fgets(str, 1024, fin); if (strstr(str, "PROTOCOLS")) if (strstr(str, "sheep_net")) sheep_net_found = true; } fclose(fin); // It was found, so something else must be wrong if (sheep_net_found) { WarningAlert(GetString(STR_NO_NET_ADDON_WARN)); return false; } // Not found, inform the user if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON))) return false; // Change the network config file and restart the network fin = fopen("/boot/home/config/settings/network", "r"); FILE *fout = fopen("/boot/home/config/settings/network.2", "w"); bool global_found = false; bool modified = false; while (!feof(fin)) { str[0] = 0; fgets(str, 1024, fin); if (!global_found && strstr(str, "GLOBAL:")) { global_found = true; } else if (global_found && !modified && strstr(str, "PROTOCOLS")) { str[strlen(str)-1] = 0; strcat(str, " sheep_net\n"); modified = true; } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') { fputs("\tPROTOCOLS = sheep_net\n", fout); modified = true; } fputs(str, fout); } if (!modified) fputs("\tPROTOCOLS = sheep_net\n", fout); fclose(fout); fclose(fin); remove("/boot/home/config/settings/network.orig"); rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig"); rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network"); app_info ai; if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) { BMessenger msg(NULL, ai.team); if (msg.IsValid()) { while (be_roster->IsRunning("application/x-vnd.Be-NETS")) { msg.SendMessage(B_QUIT_REQUESTED); snooze(500000); } } } BPath path; find_directory(B_BEOS_BOOT_DIRECTORY, &path); path.Append("Netscript"); const char *argv[3] = {"/bin/sh", path.Path(), NULL}; thread_id net_server = load_image(2, argv, (const char **)environ); resume_thread(net_server); status_t l; wait_for_thread(net_server, &l); goto i_wanna_try_that_again; } // Set up communications with add-on area_id handler_buffer; if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) { WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED)); return false; } if ((buffer_area = clone_area("local packet buffer", (void **)&net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) { D(bug("EtherInit: couldn't clone packet area\n")); WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED)); return false; } if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) { printf("FATAL: can't create Ethernet semaphore\n"); return false; } net_buffer_ptr->read_sem = read_sem; write_sem = net_buffer_ptr->write_sem; read_thread = spawn_thread(receive_proc, "Ethernet Receiver", B_URGENT_DISPLAY_PRIORITY, NULL); resume_thread(read_thread); for (int i=0; iwrite[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8); rd_pos = wr_pos = 0; release_sem(write_sem); // Get Ethernet address memcpy(ether_addr, net_buffer_ptr->ether_addr, 6); D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); // Everything OK return true; } /* * Deinitialization */ void ether_exit(void) { // Close communications with add-on for (int i=0; iwrite[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8); release_sem(write_sem); // Quit reception thread ether_thread_active = false; status_t result; release_sem(read_sem); wait_for_thread(read_thread, &result); delete_sem(read_sem); delete_area(buffer_area); // Remove all protocols remove_all_protocols(); } /* * Reset */ void ether_reset(void) { remove_all_protocols(); } /* * Add multicast address */ int16 ether_add_multicast(uint32 pb) { net_packet *p = &net_buffer_ptr->write[wr_pos]; if (p->cmd & IN_USE) { D(bug("WARNING: Couldn't enable multicast address\n")); } else { Mac2Host_memcpy(p->data, pb + eMultiAddr, 6); p->length = 6; p->cmd = IN_USE | (ADD_MULTICAST << 8); wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; release_sem(write_sem); } return noErr; } /* * Delete multicast address */ int16 ether_del_multicast(uint32 pb) { net_packet *p = &net_buffer_ptr->write[wr_pos]; if (p->cmd & IN_USE) { D(bug("WARNING: Couldn't enable multicast address\n")); } else { Mac2Host_memcpy(p->data, pb + eMultiAddr, 6); p->length = 6; p->cmd = IN_USE | (REMOVE_MULTICAST << 8); wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; release_sem(write_sem); } return noErr; } /* * Attach protocol handler */ int16 ether_attach_ph(uint16 type, uint32 handler) { // Already attached? NetProtocol *p = find_protocol(type); if (p != NULL) return lapProtErr; else { // No, create and attach p = new NetProtocol; p->type = type; p->handler = handler; prot_list.AddItem(p); return noErr; } } /* * Detach protocol handler */ int16 ether_detach_ph(uint16 type) { NetProtocol *p = find_protocol(type); if (p != NULL) { prot_list.RemoveItem(p); delete p; return noErr; } else return lapProtErr; } /* * Transmit raw ethernet packet */ int16 ether_write(uint32 wds) { net_packet *p = &net_buffer_ptr->write[wr_pos]; if (p->cmd & IN_USE) { D(bug("WARNING: Couldn't transmit packet (buffer full)\n")); } else { // Copy packet to buffer int len = ether_wds_to_buffer(wds, p->data); #if MONITOR bug("Sending Ethernet packet:\n"); for (int i=0; idata[i]); } bug("\n"); #endif // Notify add-on p->length = len; p->cmd = IN_USE | (SHEEP_PACKET << 8); wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; release_sem(write_sem); } return noErr; } /* * Packet reception thread (non-UDP) */ static status_t receive_proc(void *data) { while (ether_thread_active) { if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) { D(bug(" packet received, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); } acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000); } return 0; } /* * Packet reception thread (UDP) */ static status_t receive_proc_udp(void *data) { while (ether_thread_active) { fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds); struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0) { D(bug(" packet received, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); } } return 0; } /* * Start UDP packet reception thread */ bool ether_start_udp_thread(int socket_fd) { fd = socket_fd; udp_tunnel = true; ether_thread_active = true; read_thread = spawn_thread(receive_proc_udp, "UDP Receiver", B_URGENT_DISPLAY_PRIORITY, NULL); resume_thread(read_thread); return true; } /* * Stop UDP packet reception thread */ void ether_stop_udp_thread(void) { ether_thread_active = false; status_t result; wait_for_thread(read_thread, &result); } /* * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers */ void EtherInterrupt(void) { D(bug("EtherIRQ\n")); EthernetPacket ether_packet; uint32 packet = ether_packet.addr(); if (udp_tunnel) { ssize_t length; // Read packets from socket and hand to ether_udp_read() for processing while (true) { struct sockaddr_in from; socklen_t from_len = sizeof(from); length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len); if (length < 14) break; ether_udp_read(packet, length, &from); } } else { // Call protocol handler for received packets net_packet *p = &net_buffer_ptr->read[rd_pos]; while (p->cmd & IN_USE) { if ((p->cmd >> 8) == SHEEP_PACKET) { Host2Mac_memcpy(packet, p->data, p->length); #if MONITOR bug("Receiving Ethernet packet:\n"); for (int i=0; ilength; i++) { bug("%02x ", ReadMacInt8(packet + i)); } bug("\n"); #endif // Get packet type uint16 type = ReadMacInt16(packet + 12); // Look for protocol NetProtocol *prot = find_protocol(type); if (prot == NULL) goto next; // No default handler if (prot->handler == 0) goto next; // Copy header to RHA Mac2Mac_memcpy(ether_data + ed_RHA, packet, 14); D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12))); // Call protocol handler M68kRegisters r; r.d[0] = type; // Packet type r.d[1] = p->length - 14; // Remaining packet length (without header, for ReadPacket) r.a[0] = packet + 14; // Pointer to packet (Mac address, for ReadPacket) r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", prot->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4])); Execute68k(prot->handler, &r); } next: p->cmd = 0; // Free packet rd_pos = (rd_pos + 1) % READ_PACKET_COUNT; p = &net_buffer_ptr->read[rd_pos]; } } D(bug(" EtherIRQ done\n")); } BasiliskII/src/BeOS/clip_beos.cpp0000644000175000017500000000526710736405220016774 0ustar centriscentris/* * clip_beos.cpp - Clipboard handling, BeOS implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include "clip.h" #include "prefs.h" #define DEBUG 1 #include "debug.h" // Flag: Don't convert clipboard text static bool no_clip_conversion; /* * Initialization */ void ClipInit(void) { no_clip_conversion = PrefsFindBool("noclipconversion"); } /* * Deinitialization */ void ClipExit(void) { } /* * Mac application reads clipboard */ void GetScrap(void **handle, uint32 type, int32 offset) { D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); } /* * Mac application wrote to clipboard */ void PutScrap(uint32 type, void *scrap, int32 length) { D(bug("PutScrap type %08lx, data %08lx, length %ld\n", type, scrap, length)); if (length <= 0) return; switch (type) { case 'TEXT': D(bug(" clipping TEXT\n")); if (be_clipboard->Lock()) { be_clipboard->Clear(); BMessage *clipper = be_clipboard->Data(); if (no_clip_conversion) { // Only convert CR->LF char *buf = new char[length]; for (int i=0; iAddData("text/plain", B_MIME_TYPE, buf, length); be_clipboard->Commit(); delete[] buf; } else { // Convert text from Mac charset to UTF-8 int32 dest_length = length*3; int32 state = 0; char *buf = new char[dest_length]; if (convert_to_utf8(B_MAC_ROMAN_CONVERSION, (char *)scrap, &length, buf, &dest_length, &state) == B_OK) { for (int i=0; iAddData("text/plain", B_MIME_TYPE, buf, dest_length); be_clipboard->Commit(); } delete[] buf; } be_clipboard->Unlock(); } break; } } BasiliskII/src/BeOS/user_strings_beos.cpp0000644000175000017500000000507310736405220020567 0ustar centriscentris/* * user_strings_beos.cpp - BeOS-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "user_strings.h" // Platform-specific string definitions user_string_def platform_strings[] = { // Common strings that have a platform-specific variant {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under BeOS. Basilisk II will try to unmount it."}, {STR_EXTFS_CTRL, "BeOS Root"}, {STR_EXTFS_NAME, "BeOS Directory Tree"}, {STR_EXTFS_VOLUME_NAME, "BeOS"}, // Purely platform-specific strings {STR_NO_SHEEP_DRIVER_ERR, "Cannot open /dev/sheep: %s (%08x). Basilisk II is not properly installed."}, {STR_SHEEP_UP_ERR, "Cannot allocate Low Memory Globals: %s (%08x)."}, {STR_NO_KERNEL_DATA_ERR, "Cannot create Kernel Data area: %s (%08x)."}, {STR_NO_NET_ADDON_WARN, "The SheepShaver net server add-on cannot be found. Ethernet will not be available."}, {STR_NET_CONFIG_MODIFY_WARN, "To enable Ethernet networking for Basilisk II, your network configuration has to be modified and the network restarted. Do you want this to be done now (selecting \"Cancel\" will disable Ethernet under Basilisk II)?."}, {STR_NET_ADDON_INIT_FAILED, "SheepShaver net server add-on found\nbut there seems to be no network hardware.\nPlease check your network preferences."}, {STR_NET_ADDON_CLONE_FAILED, "Cloning of the network transfer area failed."}, {-1, NULL} // End marker }; /* * Fetch pointer to string, given the string number */ const char *GetString(int num) { // First search for platform-specific string int i = 0; while (platform_strings[i].num >= 0) { if (platform_strings[i].num == num) return platform_strings[i].str; i++; } // Not found, search for common string i = 0; while (common_strings[i].num >= 0) { if (common_strings[i].num == num) return common_strings[i].str; i++; } return NULL; } BasiliskII/src/BeOS/prefs_beos.cpp0000644000175000017500000000406610736405220017160 0ustar centriscentris/* * prefs_beos.cpp - Preferences handling, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include "sysdeps.h" #include "prefs.h" #include "main.h" // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {"powerrom", TYPE_STRING, false, "path of PowerMac ROM"}, {NULL, TYPE_END, false, NULL} // End of list }; // Preferences file name and path const char PREFS_FILE_NAME[] = "BasiliskII_prefs"; static BPath prefs_path; /* * Load preferences from settings file */ void LoadPrefs(void) { // Construct prefs path find_directory(B_USER_SETTINGS_DIRECTORY, &prefs_path, true); prefs_path.Append(PREFS_FILE_NAME); // Read preferences from settings file FILE *f = fopen(prefs_path.Path(), "r"); if (f != NULL) { // Prefs file found, load settings LoadPrefsFromStream(f); fclose(f); } else { // No prefs file, save defaults SavePrefs(); } } /* * Save preferences to settings file */ void SavePrefs(void) { FILE *f; if ((f = fopen(prefs_path.Path(), "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit() */ void AddPlatformPrefsDefaults(void) { PrefsReplaceString("extfs", "/boot"); } BasiliskII/src/BeOS/xpram_beos.cpp0000644000175000017500000000361711232133662017171 0ustar centriscentris/* * xpram_beos.cpp - XPRAM handling, BeOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include "sysdeps.h" #include "xpram.h" // XPRAM file name and path #if POWERPC_ROM const char XPRAM_FILE_NAME[] = "SheepShaver_NVRAM"; #else const char XPRAM_FILE_NAME[] = "BasiliskII_XPRAM"; #endif static BPath xpram_path; /* * Load XPRAM from settings file */ void LoadXPRAM(const char *vmdir) { // Construct XPRAM path find_directory(B_USER_SETTINGS_DIRECTORY, &xpram_path, true); xpram_path.Append(XPRAM_FILE_NAME); // Load XPRAM from settings file int fd; if ((fd = open(xpram_path.Path(), O_RDONLY)) >= 0) { read(fd, XPRAM, XPRAM_SIZE); close(fd); } } /* * Save XPRAM to settings file */ void SaveXPRAM(void) { if (xpram_path.InitCheck() != B_NO_ERROR) return; int fd; if ((fd = open(xpram_path.Path(), O_WRONLY | O_CREAT, 0666)) >= 0) { write(fd, XPRAM, XPRAM_SIZE); close(fd); } } /* * Delete PRAM file */ void ZapPRAM(void) { // Construct PRAM path find_directory(B_USER_SETTINGS_DIRECTORY, &xpram_path, true); xpram_path.Append(XPRAM_FILE_NAME); // Delete file unlink(xpram_path.Path()); } BasiliskII/src/Unix/0000755000175000017500000000000011735674751014473 5ustar centriscentrisBasiliskII/src/Unix/m4/0000755000175000017500000000000011735674761015014 5ustar centriscentrisBasiliskII/src/Unix/m4/gettext.m40000644000175000017500000030202710261155214016722 0ustar centriscentris# codeset.m4 serial AM1 (gettext-0.10.40) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. AC_DEFUN([AM_LANGINFO_CODESET], [ AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, [AC_TRY_LINK([#include ], [char* cs = nl_langinfo(CODESET);], am_cv_langinfo_codeset=yes, am_cv_langinfo_codeset=no) ]) if test $am_cv_langinfo_codeset = yes; then AC_DEFINE(HAVE_LANGINFO_CODESET, 1, [Define if you have and nl_langinfo(CODESET).]) fi ]) # gettext.m4 serial 28 (gettext-0.13) dnl Copyright (C) 1995-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. dnl Macro to add for using GNU gettext. dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The dnl default (if it is not specified or empty) is 'no-libtool'. dnl INTLSYMBOL should be 'external' for packages with no intl directory, dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. dnl If INTLSYMBOL is 'use-libtool', then a libtool library dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, dnl depending on --{enable,disable}-{shared,static} and on the presence of dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library dnl $(top_builddir)/intl/libintl.a will be created. dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext dnl implementations (in libc or libintl) without the ngettext() function dnl will be ignored. If NEEDSYMBOL is specified and is dnl 'need-formatstring-macros', then GNU gettext implementations that don't dnl support the ISO C 99 formatstring macros will be ignored. dnl INTLDIR is used to find the intl libraries. If empty, dnl the value `$(top_builddir)/intl/' is used. dnl dnl The result of the configuration is one of three cases: dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled dnl and used. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 2) GNU gettext has been found in the system's C library. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 3) No internationalization, always use English msgid. dnl Catalog format: none dnl Catalog extension: none dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. dnl The use of .gmo is historical (it was needed to avoid overwriting the dnl GNU format catalogs when building on a platform with an X/Open gettext), dnl but we keep it in order not to force irrelevant filename changes on the dnl maintainers. dnl AC_DEFUN([AM_GNU_GETTEXT], [ dnl Argument checking. ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT ])])])])]) ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT ])])])]) define(gt_included_intl, ifelse([$1], [external], [no], [yes])) define(gt_libtool_suffix_prefix, ifelse([$1], [use-libtool], [l], [])) AC_REQUIRE([AM_PO_SUBDIRS])dnl ifelse(gt_included_intl, yes, [ AC_REQUIRE([AM_INTL_SUBDIR])dnl ]) dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Sometimes libintl requires libiconv, so first search for libiconv. dnl Ideally we would do this search only after the dnl if test "$USE_NLS" = "yes"; then dnl if test "$gt_cv_func_gnugettext_libc" != "yes"; then dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT dnl the configure script would need to contain the same shell code dnl again, outside any 'if'. There are two solutions: dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not dnl documented, we avoid it. ifelse(gt_included_intl, yes, , [ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) ]) dnl Set USE_NLS. AM_NLS ifelse(gt_included_intl, yes, [ BUILD_INCLUDED_LIBINTL=no USE_INCLUDED_LIBINTL=no ]) LIBINTL= LTLIBINTL= POSUB= dnl If we use NLS figure out what method if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no ifelse(gt_included_intl, yes, [ AC_MSG_CHECKING([whether included gettext is requested]) AC_ARG_WITH(included-gettext, [ --with-included-gettext use the GNU gettext library included here], nls_cv_force_use_gnu_gettext=$withval, nls_cv_force_use_gnu_gettext=no) AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" if test "$nls_cv_force_use_gnu_gettext" != "yes"; then ]) dnl User does not insist on using GNU NLS library. Figure out what dnl to use. If GNU gettext is available we use this. Else we have dnl to fall back to GNU NLS library. dnl Add a version number to the cache macros. define([gt_api_version], ifelse([$2], [need-formatstring-macros], 3, ifelse([$2], [need-ngettext], 2, 1))) define([gt_cv_func_gnugettext_libc], [gt_cv_func_gnugettext]gt_api_version[_libc]) define([gt_cv_func_gnugettext_libintl], [gt_cv_func_gnugettext]gt_api_version[_libintl]) AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc, [AC_TRY_LINK([#include ]ifelse([$2], [need-formatstring-macros], [#ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ], [])[extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings;], [bindtextdomain ("", ""); return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_domain_bindings], gt_cv_func_gnugettext_libc=yes, gt_cv_func_gnugettext_libc=no)]) if test "$gt_cv_func_gnugettext_libc" != "yes"; then dnl Sometimes libintl requires libiconv, so first search for libiconv. ifelse(gt_included_intl, yes, , [ AM_ICONV_LINK ]) dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) dnl because that would add "-liconv" to LIBINTL and LTLIBINTL dnl even if libiconv doesn't exist. AC_LIB_LINKFLAGS_BODY([intl]) AC_CACHE_CHECK([for GNU gettext in libintl], gt_cv_func_gnugettext_libintl, [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" dnl Now see whether libintl exists and does not depend on libiconv. AC_TRY_LINK([#include ]ifelse([$2], [need-formatstring-macros], [#ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ], [])[extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias ();], [bindtextdomain ("", ""); return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], gt_cv_func_gnugettext_libintl=yes, gt_cv_func_gnugettext_libintl=no) dnl Now see whether libintl exists and depends on libiconv. if test "$gt_cv_func_gnugettext_libintl" != yes && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include ]ifelse([$2], [need-formatstring-macros], [#ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ], [])[extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias ();], [bindtextdomain ("", ""); return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], [LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" gt_cv_func_gnugettext_libintl=yes ]) fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) fi dnl If an already present or preinstalled GNU gettext() is found, dnl use it. But if this macro is used in GNU gettext, and GNU dnl gettext is already preinstalled in libintl, we update this dnl libintl. (Cf. the install rule in intl/Makefile.in.) if test "$gt_cv_func_gnugettext_libc" = "yes" \ || { test "$gt_cv_func_gnugettext_libintl" = "yes" \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else dnl Reset the values set by searching for libintl. LIBINTL= LTLIBINTL= INCINTL= fi ifelse(gt_included_intl, yes, [ if test "$gt_use_preinstalled_gnugettext" != "yes"; then dnl GNU gettext is not found in the C library. dnl Fall back on included GNU gettext library. nls_cv_use_gnu_gettext=yes fi fi if test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions used to generate GNU NLS library. BUILD_INCLUDED_LIBINTL=yes USE_INCLUDED_LIBINTL=yes LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV" LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV" LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions to use GNU gettext tools. CATOBJEXT=.gmo fi ]) if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if translation of program messages to the user's native language is requested.]) else USE_NLS=no fi fi AC_MSG_CHECKING([whether to use NLS]) AC_MSG_RESULT([$USE_NLS]) if test "$USE_NLS" = "yes"; then AC_MSG_CHECKING([where the gettext function comes from]) if test "$gt_use_preinstalled_gnugettext" = "yes"; then if test "$gt_cv_func_gnugettext_libintl" = "yes"; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi AC_MSG_RESULT([$gt_source]) fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if test "$gt_cv_func_gnugettext_libintl" = "yes"; then AC_MSG_CHECKING([how to link with libintl]) AC_MSG_RESULT([$LIBINTL]) AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) fi dnl For backward compatibility. Some packages may be using this. AC_DEFINE(HAVE_GETTEXT, 1, [Define if the GNU gettext() function is already present or preinstalled.]) AC_DEFINE(HAVE_DCGETTEXT, 1, [Define if the GNU dcgettext() function is already present or preinstalled.]) fi dnl We need to process the po/ directory. POSUB=po fi ifelse(gt_included_intl, yes, [ dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL dnl to 'yes' because some of the testsuite requires it. if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then BUILD_INCLUDED_LIBINTL=yes fi dnl Make all variables we use known to autoconf. AC_SUBST(BUILD_INCLUDED_LIBINTL) AC_SUBST(USE_INCLUDED_LIBINTL) AC_SUBST(CATOBJEXT) dnl For backward compatibility. Some configure.ins may be using this. nls_cv_header_intl= nls_cv_header_libgt= dnl For backward compatibility. Some Makefiles may be using this. DATADIRNAME=share AC_SUBST(DATADIRNAME) dnl For backward compatibility. Some Makefiles may be using this. INSTOBJEXT=.mo AC_SUBST(INSTOBJEXT) dnl For backward compatibility. Some Makefiles may be using this. GENCAT=gencat AC_SUBST(GENCAT) dnl For backward compatibility. Some Makefiles may be using this. if test "$USE_INCLUDED_LIBINTL" = yes; then INTLOBJS="\$(GETTOBJS)" fi AC_SUBST(INTLOBJS) dnl Enable libtool support if the surrounding package wishes it. INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) ]) dnl For backward compatibility. Some Makefiles may be using this. INTLLIBS="$LIBINTL" AC_SUBST(INTLLIBS) dnl Make all documented variables known to autoconf. AC_SUBST(LIBINTL) AC_SUBST(LTLIBINTL) AC_SUBST(POSUB) ]) dnl Checks for all prerequisites of the intl subdirectory, dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. AC_DEFUN([AM_INTL_SUBDIR], [ AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_MKINSTALLDIRS])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_RANLIB])dnl AC_REQUIRE([AC_ISC_POSIX])dnl AC_REQUIRE([AC_HEADER_STDC])dnl AC_REQUIRE([AC_C_CONST])dnl AC_REQUIRE([bh_C_SIGNED])dnl AC_REQUIRE([AC_C_INLINE])dnl AC_REQUIRE([AC_TYPE_OFF_T])dnl AC_REQUIRE([AC_TYPE_SIZE_T])dnl AC_REQUIRE([jm_AC_TYPE_LONG_LONG])dnl AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl AC_REQUIRE([gt_TYPE_WCHAR_T])dnl AC_REQUIRE([gt_TYPE_WINT_T])dnl AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) AC_REQUIRE([jm_AC_HEADER_STDINT_H]) AC_REQUIRE([gt_TYPE_INTMAX_T]) AC_REQUIRE([gt_PRINTF_POSIX]) AC_REQUIRE([AC_FUNC_ALLOCA])dnl AC_REQUIRE([AC_FUNC_MMAP])dnl AC_REQUIRE([jm_GLIBC21])dnl AC_REQUIRE([gt_INTDIV0])dnl AC_REQUIRE([jm_AC_TYPE_UINTMAX_T])dnl AC_REQUIRE([gt_HEADER_INTTYPES_H])dnl AC_REQUIRE([gt_INTTYPES_PRI])dnl AC_REQUIRE([gl_XSIZE])dnl AC_CHECK_TYPE([ptrdiff_t], , [AC_DEFINE([ptrdiff_t], [long], [Define as the type of the result of subtracting two pointers, if the system doesn't define it.]) ]) AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ stdlib.h string.h unistd.h sys/param.h]) AC_CHECK_FUNCS([asprintf fwprintf getcwd getegid geteuid getgid getuid \ mempcpy munmap putenv setenv setlocale snprintf stpcpy strcasecmp strdup \ strtoul tsearch wcslen __argz_count __argz_stringify __argz_next \ __fsetlocking]) dnl Use the _snprintf function only if it is declared (because on NetBSD it dnl is defined as a weak alias of snprintf; we prefer to use the latter). gt_CHECK_DECL(_snprintf, [#include ]) gt_CHECK_DECL(_snwprintf, [#include ]) dnl Use the *_unlocked functions only if they are declared. dnl (because some of them were defined without being declared in Solaris dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built dnl on Solaris 2.5.1 to run on Solaris 2.6). dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. gt_CHECK_DECL(feof_unlocked, [#include ]) gt_CHECK_DECL(fgets_unlocked, [#include ]) gt_CHECK_DECL(getc_unlocked, [#include ]) case $gt_cv_func_printf_posix in *yes) HAVE_POSIX_PRINTF=1 ;; *) HAVE_POSIX_PRINTF=0 ;; esac AC_SUBST([HAVE_POSIX_PRINTF]) if test "$ac_cv_func_asprintf" = yes; then HAVE_ASPRINTF=1 else HAVE_ASPRINTF=0 fi AC_SUBST([HAVE_ASPRINTF]) if test "$ac_cv_func_snprintf" = yes; then HAVE_SNPRINTF=1 else HAVE_SNPRINTF=0 fi AC_SUBST([HAVE_SNPRINTF]) if test "$ac_cv_func_wprintf" = yes; then HAVE_WPRINTF=1 else HAVE_WPRINTF=0 fi AC_SUBST([HAVE_WPRINTF]) AM_ICONV AM_LANGINFO_CODESET if test $ac_cv_header_locale_h = yes; then AM_LC_MESSAGES fi dnl intl/plural.c is generated from intl/plural.y. It requires bison, dnl because plural.y uses bison specific features. It requires at least dnl bison-1.26 because earlier versions generate a plural.c that doesn't dnl compile. dnl bison is only needed for the maintainer (who touches plural.y). But in dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put dnl the rule in general Makefile. Now, some people carelessly touch the dnl files or have a broken "make" program, hence the plural.c rule will dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not dnl present or too old. AC_CHECK_PROGS([INTLBISON], [bison]) if test -z "$INTLBISON"; then ac_verc_fail=yes else dnl Found it, now check the version. AC_MSG_CHECKING([version of bison]) changequote(<<,>>)dnl ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` case $ac_prog_version in '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) changequote([,])dnl ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; esac AC_MSG_RESULT([$ac_prog_version]) fi if test $ac_verc_fail = yes; then INTLBISON=: fi ]) dnl gt_CHECK_DECL(FUNC, INCLUDES) dnl Check whether a function is declared. AC_DEFUN([gt_CHECK_DECL], [ AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1, [AC_TRY_COMPILE([$2], [ #ifndef $1 char *p = (char *) $1; #endif ], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)]) if test $ac_cv_have_decl_$1 = yes; then gt_value=1 else gt_value=0 fi AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value], [Define to 1 if you have the declaration of `$1', and to 0 if you don't.]) ]) dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) # glibc21.m4 serial 2 (fileutils-4.1.3, gettext-0.10.40) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. # Test for the GNU C Library, version 2.1 or newer. # From Bruno Haible. AC_DEFUN([jm_GLIBC21], [ AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, ac_cv_gnu_library_2_1, [AC_EGREP_CPP([Lucky GNU user], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) Lucky GNU user #endif #endif ], ac_cv_gnu_library_2_1=yes, ac_cv_gnu_library_2_1=no) ] ) AC_SUBST(GLIBC21) GLIBC21="$ac_cv_gnu_library_2_1" ] ) # iconv.m4 serial AM4 (gettext-0.11.3) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_lib_iconv=yes am_cv_func_iconv=yes) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST(LIBICONV) AC_SUBST(LTLIBICONV) ]) AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_TRY_COMPILE([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) fi ]) # intdiv0.m4 serial 1 (gettext-0.11.3) dnl Copyright (C) 2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. AC_DEFUN([gt_INTDIV0], [ AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], gt_cv_int_divbyzero_sigfpe, [ AC_TRY_RUN([ #include #include static void #ifdef __cplusplus sigfpe_handler (int sig) #else sigfpe_handler (sig) int sig; #endif { /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ exit (sig != SIGFPE); } int x = 1; int y = 0; int z; int nan; int main () { signal (SIGFPE, sigfpe_handler); /* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ #if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) signal (SIGTRAP, sigfpe_handler); #endif /* Linux/SPARC yields signal SIGILL. */ #if defined (__sparc__) && defined (__linux__) signal (SIGILL, sigfpe_handler); #endif z = x / y; nan = y / y; exit (1); } ], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, [ # Guess based on the CPU. case "$host_cpu" in alpha* | i[34567]86 | m68k | s390*) gt_cv_int_divbyzero_sigfpe="guessing yes";; *) gt_cv_int_divbyzero_sigfpe="guessing no";; esac ]) ]) case "$gt_cv_int_divbyzero_sigfpe" in *yes) value=1;; *) value=0;; esac AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, [Define if integer division by zero raises signal SIGFPE.]) ]) # intmax.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl Test whether the system has the 'intmax_t' type, but don't attempt to dnl find a replacement if it is lacking. AC_DEFUN([gt_TYPE_INTMAX_T], [ AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) AC_REQUIRE([jm_AC_HEADER_STDINT_H]) AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, [AC_TRY_COMPILE([ #include #include #if HAVE_STDINT_H_WITH_UINTMAX #include #endif #if HAVE_INTTYPES_H_WITH_UINTMAX #include #endif ], [intmax_t x = -1;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)]) if test $gt_cv_c_intmax_t = yes; then AC_DEFINE(HAVE_INTMAX_T, 1, [Define if you have the 'intmax_t' type in or .]) fi ]) # inttypes-pri.m4 serial 1 (gettext-0.11.4) dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. # Define PRI_MACROS_BROKEN if exists and defines the PRI* # macros to non-string values. This is the case on AIX 4.3.3. AC_DEFUN([gt_INTTYPES_PRI], [ AC_REQUIRE([gt_HEADER_INTTYPES_H]) if test $gt_cv_header_inttypes_h = yes; then AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], gt_cv_inttypes_pri_broken, [ AC_TRY_COMPILE([#include #ifdef PRId32 char *p = PRId32; #endif ], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) ]) fi if test "$gt_cv_inttypes_pri_broken" = yes; then AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, [Define if exists and defines unusable PRI* macros.]) fi ]) # inttypes.m4 serial 1 (gettext-0.11.4) dnl Copyright (C) 1997-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Paul Eggert. # Define HAVE_INTTYPES_H if exists and doesn't clash with # . AC_DEFUN([gt_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], gt_cv_header_inttypes_h, [ AC_TRY_COMPILE( [#include #include ], [], gt_cv_header_inttypes_h=yes, gt_cv_header_inttypes_h=no) ]) if test $gt_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, [Define if exists and doesn't clash with .]) fi ]) # inttypes_h.m4 serial 5 (gettext-0.12) dnl Copyright (C) 1997-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Paul Eggert. # Define HAVE_INTTYPES_H_WITH_UINTMAX if exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([jm_AC_HEADER_INTTYPES_H], [ AC_CACHE_CHECK([for inttypes.h], jm_ac_cv_header_inttypes_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1;], jm_ac_cv_header_inttypes_h=yes, jm_ac_cv_header_inttypes_h=no)]) if test $jm_ac_cv_header_inttypes_h = yes; then AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) # lcmessage.m4 serial 3 (gettext-0.11.3) dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995. # Check whether LC_MESSAGES is available in . AC_DEFUN([AM_LC_MESSAGES], [ AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, [AC_TRY_LINK([#include ], [return LC_MESSAGES], am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) if test $am_cv_val_LC_MESSAGES = yes; then AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your file defines LC_MESSAGES.]) fi ]) # longdouble.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl Test whether the compiler supports the 'long double' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_LONGDOUBLE], [ AC_CACHE_CHECK([for long double], gt_cv_c_long_double, [if test "$GCC" = yes; then gt_cv_c_long_double=yes else AC_TRY_COMPILE([ /* The Stardent Vistra knows sizeof(long double), but does not support it. */ long double foo = 0.0; /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ int array [2*(sizeof(long double) >= sizeof(double)) - 1]; ], , gt_cv_c_long_double=yes, gt_cv_c_long_double=no) fi]) if test $gt_cv_c_long_double = yes; then AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) fi ]) # longlong.m4 serial 4 dnl Copyright (C) 1999-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Paul Eggert. # Define HAVE_LONG_LONG if 'long long' works. AC_DEFUN([jm_AC_TYPE_LONG_LONG], [ AC_CACHE_CHECK([for long long], ac_cv_type_long_long, [AC_TRY_LINK([long long ll = 1LL; int i = 63;], [long long llmax = (long long) -1; return ll << i | ll >> i | llmax / ll | llmax % ll;], ac_cv_type_long_long=yes, ac_cv_type_long_long=no)]) if test $ac_cv_type_long_long = yes; then AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have the 'long long' type.]) fi ]) # nls.m4 serial 1 (gettext-0.12) dnl Copyright (C) 1995-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_DEFUN([AM_NLS], [ AC_MSG_CHECKING([whether NLS is requested]) dnl Default is enabled NLS AC_ARG_ENABLE(nls, [ --disable-nls do not use Native Language Support], USE_NLS=$enableval, USE_NLS=yes) AC_MSG_RESULT($USE_NLS) AC_SUBST(USE_NLS) ]) AC_DEFUN([AM_MKINSTALLDIRS], [ dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly dnl find the mkinstalldirs script in another subdir but $(top_srcdir). dnl Try to locate it. MKINSTALLDIRS= if test -n "$ac_aux_dir"; then case "$ac_aux_dir" in /*) MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" ;; *) MKINSTALLDIRS="\$(top_builddir)/$ac_aux_dir/mkinstalldirs" ;; esac fi if test -z "$MKINSTALLDIRS"; then MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" fi AC_SUBST(MKINSTALLDIRS) ]) # po.m4 serial 3 (gettext-0.14) dnl Copyright (C) 1995-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. dnl Checks for all prerequisites of the po subdirectory. AC_DEFUN([AM_PO_SUBDIRS], [ AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_MKINSTALLDIRS])dnl AC_REQUIRE([AM_NLS])dnl dnl Perform the following tests also if --disable-nls has been given, dnl because they are needed for "make dist" to work. dnl Search for GNU msgfmt in the PATH. dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. dnl The second test excludes FreeBSD msgfmt. AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, [$ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1 && (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) dnl Search for GNU xgettext 0.12 or newer in the PATH. dnl The first test excludes Solaris xgettext and early GNU xgettext versions. dnl The second test excludes FreeBSD xgettext. AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 && (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) dnl Remove leftover from FreeBSD xgettext call. rm -f messages.po dnl Search for GNU msgmerge 0.11 or newer in the PATH. AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, [$ac_dir/$ac_word --update -q /dev/null /dev/null >/dev/null 2>&1], :) dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. dnl Test whether we really found GNU msgfmt. if test "$GMSGFMT" != ":"; then dnl If it is no GNU msgfmt we define it as : so that the dnl Makefiles still can work. if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 && (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then : ; else GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'` AC_MSG_RESULT( [found $GMSGFMT program is not GNU msgfmt; ignore it]) GMSGFMT=":" fi fi dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. dnl Test whether we really found GNU xgettext. if test "$XGETTEXT" != ":"; then dnl If it is no GNU xgettext we define it as : so that the dnl Makefiles still can work. if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 && (if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then : ; else AC_MSG_RESULT( [found xgettext program is not GNU xgettext; ignore it]) XGETTEXT=":" fi dnl Remove leftover from FreeBSD xgettext call. rm -f messages.po fi AC_OUTPUT_COMMANDS([ for ac_file in $CONFIG_FILES; do # Support "outfile[:infile[:infile...]]" case "$ac_file" in *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; esac # PO directories have a Makefile.in generated from Makefile.in.in. case "$ac_file" in */Makefile.in) # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" POMAKEFILEDEPS="POTFILES.in" # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend # on $ac_dir but don't depend on user-specified configuration # parameters. if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then # The LINGUAS file contains the set of available languages. if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi ALL_LINGUAS_=`sed -e "/^#/d" "$ac_given_srcdir/$ac_dir/LINGUAS"` # Hide the ALL_LINGUAS assigment from automake. eval 'ALL_LINGUAS''=$ALL_LINGUAS_' POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) # Compute UPDATEPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) # Compute DUMMYPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) # Compute GMOFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) case "$ac_given_srcdir" in .) srcdirpre= ;; *) srcdirpre='$(srcdir)/' ;; esac POFILES= UPDATEPOFILES= DUMMYPOFILES= GMOFILES= for lang in $ALL_LINGUAS; do POFILES="$POFILES $srcdirpre$lang.po" UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" DUMMYPOFILES="$DUMMYPOFILES $lang.nop" GMOFILES="$GMOFILES $srcdirpre$lang.gmo" done # CATALOGS depends on both $ac_dir and the user's LINGUAS # environment variable. INST_LINGUAS= if test -n "$ALL_LINGUAS"; then for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "$LINGUAS"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then INST_LINGUAS="$INST_LINGUAS $presentlang" fi done fi CATALOGS= if test -n "$INST_LINGUAS"; then for lang in $INST_LINGUAS; do CATALOGS="$CATALOGS $lang.gmo" done fi test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do if test -f "$f"; then case "$f" in *.orig | *.bak | *~) ;; *) cat "$f" >> "$ac_dir/Makefile" ;; esac fi done fi ;; esac done], [# Capture the value of obsolete ALL_LINGUAS because we need it to compute # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it # from automake. eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" ]) ]) dnl Postprocesses a Makefile in a directory containing PO files. AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], [ # When this code is run, in config.status, two variables have already been # set: # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, # - LINGUAS is the value of the environment variable LINGUAS at configure # time. changequote(,)dnl # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Find a way to echo strings without interpreting backslash. if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then gt_echo='echo' else if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then gt_echo='printf %s\n' else echo_func () { cat < "$ac_file.tmp" if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` cat >> "$ac_file.tmp" < /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/_/-/g'` cat >> "$ac_file.tmp" <> "$ac_file.tmp" < #include /* The string "%2$d %1$d", with dollar characters protected from the shell's dollar expansion (possibly an autoconf bug). */ static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; static char buf[100]; int main () { sprintf (buf, format, 33, 55); return (strcmp (buf, "55 33") != 0); }], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, [ AC_EGREP_CPP(notposix, [ #if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ notposix #endif ], gt_cv_func_printf_posix="guessing no", gt_cv_func_printf_posix="guessing yes") ]) ]) case $gt_cv_func_printf_posix in *yes) AC_DEFINE(HAVE_POSIX_PRINTF, 1, [Define if your printf() function supports format strings with positions.]) ;; esac ]) # progtest.m4 serial 3 (gettext-0.12) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1996. # Search path for a program which passes the given test. dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) AC_DEFUN([AM_PATH_PROG_WITH_TEST], [ # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL(ac_cv_path_$1, [case "[$]$1" in [[\\/]]* | ?:[[\\/]]*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in ifelse([$5], , $PATH, [$5]); do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) fi AC_SUBST($1)dnl ]) # signed.m4 serial 1 (gettext-0.10.40) dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. AC_DEFUN([bh_C_SIGNED], [ AC_CACHE_CHECK([for signed], bh_cv_c_signed, [AC_TRY_COMPILE(, [signed char x;], bh_cv_c_signed=yes, bh_cv_c_signed=no)]) if test $bh_cv_c_signed = no; then AC_DEFINE(signed, , [Define to empty if the C compiler doesn't support this keyword.]) fi ]) # size_max.m4 serial 2 dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. AC_DEFUN([gl_SIZE_MAX], [ AC_CHECK_HEADERS(stdint.h) dnl First test whether the system already has SIZE_MAX. AC_MSG_CHECKING([for SIZE_MAX]) result= AC_EGREP_CPP([Found it], [ #include #if HAVE_STDINT_H #include #endif #ifdef SIZE_MAX Found it #endif ], result=yes) if test -z "$result"; then dnl Define it ourselves. Here we assume that the type 'size_t' is not wider dnl than the type 'unsigned long'. dnl The _AC_COMPUTE_INT macro works up to LONG_MAX, since it uses 'expr', dnl which is guaranteed to work from LONG_MIN to LONG_MAX. _AC_COMPUTE_INT([~(size_t)0 / 10], res_hi, [#include ], result=?) _AC_COMPUTE_INT([~(size_t)0 % 10], res_lo, [#include ], result=?) _AC_COMPUTE_INT([sizeof (size_t) <= sizeof (unsigned int)], fits_in_uint, [#include ], result=?) if test "$fits_in_uint" = 1; then dnl Even though SIZE_MAX fits in an unsigned int, it must be of type dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. AC_TRY_COMPILE([#include extern size_t foo; extern unsigned long foo; ], [], fits_in_uint=0) fi if test -z "$result"; then if test "$fits_in_uint" = 1; then result="$res_hi$res_lo"U else result="$res_hi$res_lo"UL fi else dnl Shouldn't happen, but who knows... result='~(size_t)0' fi fi AC_MSG_RESULT([$result]) if test "$result" != yes; then AC_DEFINE_UNQUOTED([SIZE_MAX], [$result], [Define as the maximum value of type 'size_t', if the system doesn't define it.]) fi ]) # stdint_h.m4 serial 3 (gettext-0.12) dnl Copyright (C) 1997-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Paul Eggert. # Define HAVE_STDINT_H_WITH_UINTMAX if exists, # doesn't clash with , and declares uintmax_t. AC_DEFUN([jm_AC_HEADER_STDINT_H], [ AC_CACHE_CHECK([for stdint.h], jm_ac_cv_header_stdint_h, [AC_TRY_COMPILE( [#include #include ], [uintmax_t i = (uintmax_t) -1;], jm_ac_cv_header_stdint_h=yes, jm_ac_cv_header_stdint_h=no)]) if test $jm_ac_cv_header_stdint_h = yes; then AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, [Define if exists, doesn't clash with , and declares uintmax_t. ]) fi ]) # uintmax_t.m4 serial 7 (gettext-0.12) dnl Copyright (C) 1997-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Paul Eggert. AC_PREREQ(2.13) # Define uintmax_t to 'unsigned long' or 'unsigned long long' # if it is not already defined in or . AC_DEFUN([jm_AC_TYPE_UINTMAX_T], [ AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) AC_REQUIRE([jm_AC_HEADER_STDINT_H]) if test $jm_ac_cv_header_inttypes_h = no && test $jm_ac_cv_header_stdint_h = no; then AC_REQUIRE([jm_AC_TYPE_UNSIGNED_LONG_LONG]) test $ac_cv_type_unsigned_long_long = yes \ && ac_type='unsigned long long' \ || ac_type='unsigned long' AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, [Define to unsigned long or unsigned long long if and don't define.]) else AC_DEFINE(HAVE_UINTMAX_T, 1, [Define if you have the 'uintmax_t' type in or .]) fi ]) # ulonglong.m4 serial 3 dnl Copyright (C) 1999-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Paul Eggert. # Define HAVE_UNSIGNED_LONG_LONG if 'unsigned long long' works. AC_DEFUN([jm_AC_TYPE_UNSIGNED_LONG_LONG], [ AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long, [AC_TRY_LINK([unsigned long long ull = 1ULL; int i = 63;], [unsigned long long ullmax = (unsigned long long) -1; return ull << i | ull >> i | ullmax / ull | ullmax % ull;], ac_cv_type_unsigned_long_long=yes, ac_cv_type_unsigned_long_long=no)]) if test $ac_cv_type_unsigned_long_long = yes; then AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, [Define if you have the 'unsigned long long' type.]) fi ]) # wchar_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl Test whether has the 'wchar_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WCHAR_T], [ AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, [AC_TRY_COMPILE([#include wchar_t foo = (wchar_t)'\0';], , gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) if test $gt_cv_c_wchar_t = yes; then AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) fi ]) # wint_t.m4 serial 1 (gettext-0.12) dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl Test whether has the 'wint_t' type. dnl Prerequisite: AC_PROG_CC AC_DEFUN([gt_TYPE_WINT_T], [ AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, [AC_TRY_COMPILE([#include wint_t foo = (wchar_t)'\0';], , gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) if test $gt_cv_c_wint_t = yes; then AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) fi ]) # xsize.m4 serial 2 dnl Copyright (C) 2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. AC_DEFUN([gl_XSIZE], [ dnl Prerequisites of lib/xsize.h. AC_REQUIRE([gl_SIZE_MAX]) AC_CHECK_HEADERS(stdint.h) ]) # lib-link.m4 serial 4 (gettext-0.12) dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, dnl hardcode_direct, hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib$1-prefix], [ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib$1-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/lib" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then found_dir="$additional_libdir" found_so="$additional_libdir/lib$name.$shlibext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then found_dir="$dir" found_so="$dir/lib$name.$shlibext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */lib | */lib/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/lib"; then haveit= if test "X$additional_libdir" = "X/usr/local/lib"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) # lib-prefix.m4 serial 3 (gettext-0.13) dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/lib" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/lib"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/lib"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) # lib-ld.m4 serial 3 (gettext-0.13) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General dnl Public License, this file may be distributed as part of a program dnl that contains a configuration script generated by Autoconf, under dnl the same distribution terms as the rest of that program. dnl Subroutines of libtool.m4, dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision dnl with libtool.m4. dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) BasiliskII/src/Unix/m4/gtk-2.0.m40000644000175000017500000001655410261155214016327 0ustar centriscentris# Configure paths for GTK+ # Owen Taylor 1997-2001 dnl AM_PATH_GTK_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GTK+, and define GTK_CFLAGS and GTK_LIBS, if gthread is specified in MODULES, dnl pass to pkg-config dnl AC_DEFUN([AM_PATH_GTK_2_0], [dnl dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(gtktest, [ --disable-gtktest do not try to compile and run a test GTK+ program], , enable_gtktest=yes) pkg_config_args=gtk+-2.0 for module in . $4 do case "$module" in gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done no_gtk="" AC_PATH_PROG(PKG_CONFIG, pkg-config, no) if test x$PKG_CONFIG != xno ; then if pkg-config --atleast-pkgconfig-version 0.7 ; then : else echo "*** pkg-config too old; version 0.7 or better required." no_gtk=yes PKG_CONFIG=no fi else no_gtk=yes fi min_gtk_version=ifelse([$1], ,2.0.0,$1) AC_MSG_CHECKING(for GTK+ - version >= $min_gtk_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" enable_gtktest=no fi if $PKG_CONFIG --atleast-version $min_gtk_version $pkg_config_args; then : else no_gtk=yes fi fi if test x"$no_gtk" = x ; then GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" dnl dnl Now check if the installed GTK+ is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.gtktest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.gtktest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_gtk_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'pkg-config --modversion gtk+-2.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then AC_MSG_RESULT(yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://pkgconfig.sourceforge.net" else if test -f conf.gtktest ; then : else echo "*** Could not run GTK+ test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" AC_TRY_LINK([ #include #include ], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK+ or finding the wrong" echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK+ is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) rm -f conf.gtktest ]) BasiliskII/src/Unix/m4/esd.m40000644000175000017500000001532610261155214016014 0ustar centriscentris# Configure paths for ESD # Manish Singh 98-9-30 # stolen back from Frank Belew # stolen from Manish Singh # Shamelessly stolen from Owen Taylor dnl AM_PATH_ESD([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) dnl Test for ESD, and define ESD_CFLAGS and ESD_LIBS dnl AC_DEFUN([AM_PATH_ESD], [dnl dnl Get the cflags and libraries from the esd-config script dnl AC_ARG_WITH(esd-prefix,[ --with-esd-prefix=PFX Prefix where ESD is installed (optional)], esd_prefix="$withval", esd_prefix="") AC_ARG_WITH(esd-exec-prefix,[ --with-esd-exec-prefix=PFX Exec prefix where ESD is installed (optional)], esd_exec_prefix="$withval", esd_exec_prefix="") AC_ARG_ENABLE(esdtest, [ --disable-esdtest Do not try to compile and run a test ESD program], , enable_esdtest=yes) if test x$esd_exec_prefix != x ; then esd_args="$esd_args --exec-prefix=$esd_exec_prefix" if test x${ESD_CONFIG+set} != xset ; then ESD_CONFIG=$esd_exec_prefix/bin/esd-config fi fi if test x$esd_prefix != x ; then esd_args="$esd_args --prefix=$esd_prefix" if test x${ESD_CONFIG+set} != xset ; then ESD_CONFIG=$esd_prefix/bin/esd-config fi fi AC_PATH_PROG(ESD_CONFIG, esd-config, no) min_esd_version=ifelse([$1], ,0.2.7,$1) AC_MSG_CHECKING(for ESD - version >= $min_esd_version) no_esd="" if test "$ESD_CONFIG" = "no" ; then no_esd=yes else AC_LANG_SAVE AC_LANG_C ESD_CFLAGS=`$ESD_CONFIG $esdconf_args --cflags` ESD_LIBS=`$ESD_CONFIG $esdconf_args --libs` esd_major_version=`$ESD_CONFIG $esd_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` esd_minor_version=`$ESD_CONFIG $esd_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` esd_micro_version=`$ESD_CONFIG $esd_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_esdtest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $ESD_CFLAGS" LIBS="$LIBS $ESD_LIBS" dnl dnl Now check if the installed ESD is sufficiently new. (Also sanity dnl checks the results of esd-config to some extent dnl rm -f conf.esdtest AC_TRY_RUN([ #include #include #include #include char* my_strdup (char *str) { char *new_str; if (str) { new_str = malloc ((strlen (str) + 1) * sizeof(char)); strcpy (new_str, str); } else new_str = NULL; return new_str; } int main () { int major, minor, micro; char *tmp_version; system ("touch conf.esdtest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = my_strdup("$min_esd_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_esd_version"); exit(1); } if (($esd_major_version > major) || (($esd_major_version == major) && ($esd_minor_version > minor)) || (($esd_major_version == major) && ($esd_minor_version == minor) && ($esd_micro_version >= micro))) { return 0; } else { printf("\n*** 'esd-config --version' returned %d.%d.%d, but the minimum version\n", $esd_major_version, $esd_minor_version, $esd_micro_version); printf("*** of ESD required is %d.%d.%d. If esd-config is correct, then it is\n", major, minor, micro); printf("*** best to upgrade to the required version.\n"); printf("*** If esd-config was wrong, set the environment variable ESD_CONFIG\n"); printf("*** to point to the correct copy of esd-config, and remove the file\n"); printf("*** config.cache before re-running configure\n"); return 1; } } ],, no_esd=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" AC_LANG_RESTORE fi fi if test "x$no_esd" = x ; then AC_MSG_RESULT(yes) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$ESD_CONFIG" = "no" ; then echo "*** The esd-config script installed by ESD could not be found" echo "*** If ESD was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the ESD_CONFIG environment variable to the" echo "*** full path to esd-config." else if test -f conf.esdtest ; then : else echo "*** Could not run ESD test program, checking why..." CFLAGS="$CFLAGS $ESD_CFLAGS" LIBS="$LIBS $ESD_LIBS" AC_LANG_SAVE AC_LANG_C AC_TRY_LINK([ #include #include ], [ return 0; ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding ESD or finding the wrong" echo "*** version of ESD. If it is not finding ESD, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means ESD was incorrectly installed" echo "*** or that you have moved ESD since it was installed. In the latter case, you" echo "*** may want to edit the esd-config script: $ESD_CONFIG" ]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" AC_LANG_RESTORE fi fi ESD_CFLAGS="" ESD_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(ESD_CFLAGS) AC_SUBST(ESD_LIBS) rm -f conf.esdtest ]) dnl AM_ESD_SUPPORTS_MULTIPLE_RECORD([ACTION-IF-SUPPORTS [, ACTION-IF-NOT-SUPPORTS]]) dnl Test, whether esd supports multiple recording clients (version >=0.2.21) dnl AC_DEFUN([AM_ESD_SUPPORTS_MULTIPLE_RECORD], [dnl AC_MSG_NOTICE([whether installed esd version supports multiple recording clients]) ac_save_ESD_CFLAGS="$ESD_CFLAGS" ac_save_ESD_LIBS="$ESD_LIBS" AM_PATH_ESD(0.2.21, ifelse([$1], , [ AM_CONDITIONAL(ESD_SUPPORTS_MULTIPLE_RECORD, true) AC_DEFINE(ESD_SUPPORTS_MULTIPLE_RECORD, 1, [Define if you have esound with support of multiple recording clients.])], [$1]), ifelse([$2], , [AM_CONDITIONAL(ESD_SUPPORTS_MULTIPLE_RECORD, false)], [$2]) if test "x$ac_save_ESD_CFLAGS" != x ; then ESD_CFLAGS="$ac_save_ESD_CFLAGS" fi if test "x$ac_save_ESD_LIBS" != x ; then ESD_LIBS="$ac_save_ESD_LIBS" fi ) ]) BasiliskII/src/Unix/m4/gtk.m40000644000175000017500000002013710426600252016022 0ustar centriscentris# Configure paths for GTK+ # Owen Taylor 97-11-3 dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS dnl AC_DEFUN([AM_PATH_GTK], [dnl dnl Get the cflags and libraries from the gtk-config script dnl AC_ARG_WITH(gtk-prefix,[ --with-gtk-prefix=PFX Prefix where GTK is installed (optional)], gtk_config_prefix="$withval", gtk_config_prefix="") AC_ARG_WITH(gtk-exec-prefix,[ --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)], gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="") AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], , enable_gtktest=yes) for module in . $4 do case "$module" in gthread) gtk_config_args="$gtk_config_args gthread" ;; esac done if test x$gtk_config_exec_prefix != x ; then gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" if test x${GTK_CONFIG+set} != xset ; then GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config fi fi if test x$gtk_config_prefix != x ; then gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" if test x${GTK_CONFIG+set} != xset ; then GTK_CONFIG=$gtk_config_prefix/bin/gtk-config fi fi AC_PATH_PROG(GTK_CONFIG, gtk-config, no) min_gtk_version=ifelse([$1], ,0.99.7,$1) AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) no_gtk="" if test "$GTK_CONFIG" = "no" ; then no_gtk=yes else GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" dnl dnl Now check if the installed GTK is sufficiently new. (Also sanity dnl checks the results of gtk-config to some extent dnl rm -f conf.gtktest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.gtktest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_gtk_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If gtk-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n"); printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); printf("*** before re-running configure\n"); } #if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION) else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } #endif /* defined (GTK_MAJOR_VERSION) ... */ else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the gtk-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); printf("*** correct copy of gtk-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then AC_MSG_RESULT(yes) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$GTK_CONFIG" = "no" ; then echo "*** The gtk-config script installed by GTK could not be found" echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" echo "*** your path, or set the GTK_CONFIG environment variable to the" echo "*** full path to gtk-config." else if test -f conf.gtktest ; then : else echo "*** Could not run GTK test program, checking why..." CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" AC_TRY_LINK([ #include #include ], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK or finding the wrong" echo "*** version of GTK. If it is not finding GTK, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" echo "***" echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" echo "*** came with the system with the command" echo "***" echo "*** rpm --erase --nodeps gtk gtk-devel" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK was incorrectly installed" echo "*** or that you have moved GTK since it was installed. In the latter case, you" echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) rm -f conf.gtktest ]) BasiliskII/src/Unix/m4/egrep.m40000644000175000017500000000070310261155214016334 0ustar centriscentris# AC_PROG_EGREP # ------------- # This is predefined starting with Autoconf 2.54, so this conditional # definition can be removed once we require Autoconf 2.54 or later. m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], [AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi]) EGREP=$ac_cv_prog_egrep AC_SUBST([EGREP]) ])]) BasiliskII/src/Unix/Irix/0000755000175000017500000000000011735674761015407 5ustar centriscentrisBasiliskII/src/Unix/Irix/README.networking0000644000175000017500000000724407522012126020440 0ustar centriscentrisREADME file for networking under IRIX by Brian J. Johnson 7/23/2002 version 1.0 ================================================== BasiliskII does not currently support networking natively on IRIX. That is, the emulated Ethernet card does not do anything. There's no reason one couldn't use raw domain sockets and the snoop(7p) facility to do networking, but so far no one has written the required glue code. However, it is possible to do TCP/IP networking with BasiliskII on IRIX via PPP, by connecting an emulated serial port to the IRIX PPP daemon. Here are the steps to set it up: Set up PPP on IRIX ------------------ You need root privileges to do this. First, make sure you have eoe.sw.ppp and eoe.sw.uucp installed: IRIS# versions eoe.sw.ppp eoe.sw.uucp I = Installed, R = Removed Name Date Description I eoe 07/22/2002 IRIX Execution Environment, 6.5.17m I eoe.sw 07/22/2002 IRIX Execution Environment Software I eoe.sw.ppp 07/22/2002 Point-to-Point Protocol Software I eoe.sw.uucp 07/22/2002 UUCP Utilities If they aren't installed, install them from your distribution CDs. Next, pick IP addresses for the IRIX and MacOS sides of the PPP connection. You may want to ask your local network administrator about this, but any two unused addresses on your local subnet should work. Edit /etc/ppp.conf and add these three lines: _NET_INCOMING remotehost= localhost= (Replace the angle brackets and the text in them with the appropriate IP addresses.) Next, make a script to set up the environment properly when invoking pppd from BasiliskII. You can name this whatever you want; I chose /usr/etc/ppp-b2: IRIS# whoami root IRIS# cat < /usr/etc/ppp-b2 #!/bin/sh export USER=_NET_INCOMING exec /usr/etc/ppp "$@" IRIS# chmod 4775 /usr/etc/ppp-b2 Rewrite this in perl or python or C or whatever if you don't like setuid shell scripts. The alternative is to run BasiliskII as root: pppd _must_ be run as root. Configure BasiliskII to start the PPP daemon -------------------------------------------- Start up BasiliskII, and in the serial devices tab, enter: |exec /usr/etc/ppp-b2 Supply the name you used for the script you created. Be sure to include the leading pipe symbol ("|"). The "exec" causes your PPP startup script to replace the shell BasiliskII runs to interpret the command. It's not strictly necessary, but cuts down on the number of extra processes hanging about. Install a PPP client on MacOS ----------------------------- The details of this step will vary depending on your PPP client software. Set it up for a "direct" connection, with no modem chatting or login scripting. For instance, with FreePPP I set the "Connect:" item on the "Edit..." screen under the "Accounts" tab to "Directly". Be sure to select the correct serial port. The serial port speed shouldn't matter (BasiliskII ignores it), but I set it to 115200 bps. Next, configure MacOS's TCP/IP stack. If you're using Open Transport, Open the TCP/IP control panel and select "Using PPP Server" under the "Configure" item. Copy IRIX's DNS client info. from /etc/resolv.conf to the control panel: the addresses from the "nameserver" lines go in the "Name server addr.:" box, and the domains from the "search" lines go in the "Search domains:" box. The steps should be similar for MacTCP. Now fire up PPP. Your PPP client should establish communication with the IRIX PPP daemon, and you're off and running. Disclaimer ---------- I haven't tried this procedure from scratch on a freshly installed system, so I might have missed a step somewhere. But it should get you close.... BasiliskII/src/Unix/Irix/unaligned.c0000644000175000017500000000272310177252266017514 0ustar centriscentris/* * Irix/unaligned.c - Optimized unaligned access for Irix * * Basilisk II (C) 1997-2005 Christian Bauer * * 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 */ #ifdef sgi #include "sysdeps.h" /* Tell the compiler to pack data on 1-byte boundaries * (i.e. arbitrary alignment). Requires SGI MIPSPro compilers. */ #pragma pack(1) typedef struct _ual32 { uae_u32 v; } ual32_t; typedef struct _ual16 { uae_u16 v; } ual16_t; #pragma pack(0) /* The compiler is smart enough to inline these when you build with "-ipa" */ uae_u32 do_get_mem_long(uae_u32 *a) {return ((ual32_t *)a)->v;} uae_u32 do_get_mem_word(uae_u16 *a) {return ((ual16_t *)a)->v;} void do_put_mem_long(uae_u32 *a, uae_u32 v) {((ual32_t *)a)->v = v;} void do_put_mem_word(uae_u16 *a, uae_u32 v) {((ual16_t *)a)->v = v;} #endif /* sgi */ BasiliskII/src/Unix/Irix/audio_irix.cpp0000644000175000017500000004210210736405221020225 0ustar centriscentris/* * audio_irix.cpp - Audio support, SGI Irix implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include #include #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "audio.h" #include "audio_defs.h" #define DEBUG 0 #include "debug.h" // The currently selected audio parameters (indices in audio_sample_rates[] // etc. vectors) static int audio_sample_rate_index = 0; static int audio_sample_size_index = 0; static int audio_channel_count_index = 0; // Global variables static int audio_fd = -1; // fd from audio library static sem_t audio_irq_done_sem; // Signal from interrupt to streaming thread: data block read static bool sem_inited = false; // Flag: audio_irq_done_sem initialized static int sound_buffer_size; // Size of sound buffer in bytes static int sound_buffer_fill_point; // Fill buffer when this many frames are empty static uint8 silence_byte = 0; // Byte value to use to fill sound buffers with silence static pthread_t stream_thread; // Audio streaming thread static pthread_attr_t stream_thread_attr; // Streaming thread attributes static bool stream_thread_active = false; // Flag: streaming thread installed static volatile bool stream_thread_cancel = false; // Flag: cancel streaming thread static bool current_main_mute = false; // Flag: output muted static bool current_speaker_mute = false; // Flag: speaker muted static uint32 current_main_volume = 0; // Output volume static uint32 current_speaker_volume = 0; // Speaker volume // IRIX libaudio control structures static ALconfig config; static ALport port; // Prototypes static void *stream_func(void *arg); static uint32 read_volume(void); static bool read_mute(void); static void set_mute(bool mute); /* * Initialization */ // Set AudioStatus to reflect current audio stream format static void set_audio_status_format(void) { AudioStatus.sample_rate = audio_sample_rates[audio_sample_rate_index]; AudioStatus.sample_size = audio_sample_sizes[audio_sample_size_index]; AudioStatus.channels = audio_channel_counts[audio_channel_count_index]; } bool open_audio(void) { ALpv pv[2]; printf("Using libaudio audio output\n"); // Get supported sample formats if (audio_sample_sizes.empty()) { // All sample sizes are supported audio_sample_sizes.push_back(8); audio_sample_sizes.push_back(16); // Assume at least two channels are supported. Some IRIX boxes // can do 4 or more... MacOS only handles up to 2. audio_channel_counts.push_back(1); audio_channel_counts.push_back(2); if (audio_sample_sizes.empty() || audio_channel_counts.empty()) { WarningAlert(GetString(STR_AUDIO_FORMAT_WARN)); alClosePort(port); audio_fd = -1; return false; } audio_sample_rates.push_back( 8000 << 16); audio_sample_rates.push_back(11025 << 16); audio_sample_rates.push_back(22050 << 16); audio_sample_rates.push_back(44100 << 16); // Default to highest supported values audio_sample_rate_index = audio_sample_rates.size() - 1; audio_sample_size_index = audio_sample_sizes.size() - 1; audio_channel_count_index = audio_channel_counts.size() - 1; } // Set the sample format D(bug("Size %d, channels %d, rate %d\n", audio_sample_sizes[audio_sample_size_index], audio_channel_counts[audio_channel_count_index], audio_sample_rates[audio_sample_rate_index] >> 16)); config = alNewConfig(); alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP); if (audio_sample_sizes[audio_sample_size_index] == 8) { alSetWidth(config, AL_SAMPLE_8); } else { alSetWidth(config, AL_SAMPLE_16); } alSetChannels(config, audio_channel_counts[audio_channel_count_index]); alSetDevice(config, AL_DEFAULT_OUTPUT); // Allow selecting via prefs? // Try to open the audio library port = alOpenPort("BasiliskII", "w", config); if (port == NULL) { fprintf(stderr, "ERROR: Cannot open audio port: %s\n", alGetErrorString(oserror())); WarningAlert(GetString(STR_NO_AUDIO_WARN)); return false; } // Set the sample rate pv[0].param = AL_RATE; pv[0].value.ll = alDoubleToFixed(audio_sample_rates[audio_sample_rate_index] >> 16); pv[1].param = AL_MASTER_CLOCK; pv[1].value.i = AL_CRYSTAL_MCLK_TYPE; if (alSetParams(AL_DEFAULT_OUTPUT, pv, 2) < 0) { fprintf(stderr, "ERROR: libaudio setparams failed: %s\n", alGetErrorString(oserror())); alClosePort(port); return false; } // Compute sound buffer size and libaudio refill point config = alGetConfig(port); audio_frames_per_block = alGetQueueSize(config); if (audio_frames_per_block < 0) { fprintf(stderr, "ERROR: couldn't get queue size: %s\n", alGetErrorString(oserror())); alClosePort(port); return false; } D(bug("alGetQueueSize %d, width %d, channels %d\n", audio_frames_per_block, alGetWidth(config), alGetChannels(config))); // Put a limit on the Mac sound buffer size, to decrease delay #define AUDIO_BUFFER_MSEC 50 // milliseconds of sound to buffer int target_frames_per_block = (audio_sample_rates[audio_sample_rate_index] >> 16) * AUDIO_BUFFER_MSEC / 1000; if (audio_frames_per_block > target_frames_per_block) audio_frames_per_block = target_frames_per_block; D(bug("frames per block %d\n", audio_frames_per_block)); alZeroFrames(port, audio_frames_per_block); // so we don't underflow // Try to keep the buffer pretty full sound_buffer_fill_point = alGetQueueSize(config) - 2 * audio_frames_per_block; if (sound_buffer_fill_point < 0) sound_buffer_fill_point = alGetQueueSize(config) / 3; D(bug("fill point %d\n", sound_buffer_fill_point)); sound_buffer_size = (audio_sample_sizes[audio_sample_size_index] >> 3) * audio_channel_counts[audio_channel_count_index] * audio_frames_per_block; set_audio_status_format(); // Get a file descriptor we can select() on audio_fd = alGetFD(port); if (audio_fd < 0) { fprintf(stderr, "ERROR: couldn't get libaudio file descriptor: %s\n", alGetErrorString(oserror())); alClosePort(port); return false; } // Initialize volume, mute settings current_main_volume = current_speaker_volume = read_volume(); current_main_mute = current_speaker_mute = read_mute(); // Start streaming thread Set_pthread_attr(&stream_thread_attr, 0); stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0); // Everything went fine audio_open = true; return true; } void AudioInit(void) { // Init audio status (reasonable defaults) and feature flags AudioStatus.sample_rate = 44100 << 16; AudioStatus.sample_size = 16; AudioStatus.channels = 2; AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; // Init semaphore if (sem_init(&audio_irq_done_sem, 0, 0) < 0) return; sem_inited = true; // Open and initialize audio device open_audio(); } /* * Deinitialization */ static void close_audio(void) { // Stop stream and delete semaphore if (stream_thread_active) { stream_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(stream_thread); #endif pthread_join(stream_thread, NULL); stream_thread_active = false; stream_thread_cancel = false; } // Close audio library alClosePort(port); audio_open = false; } void AudioExit(void) { // Close audio device close_audio(); // Delete semaphore if (sem_inited) { sem_destroy(&audio_irq_done_sem); sem_inited = false; } } /* * First source added, start audio stream */ void audio_enter_stream() { // Streaming thread is always running to avoid clicking noises } /* * Last source removed, stop audio stream */ void audio_exit_stream() { // Streaming thread is always running to avoid clicking noises } /* * Streaming function */ static void *stream_func(void *arg) { int32 *last_buffer = new int32[sound_buffer_size / 4]; fd_set audio_fdset; int numfds, was_error; numfds = audio_fd + 1; FD_ZERO(&audio_fdset); while (!stream_thread_cancel) { if (AudioStatus.num_sources) { // Trigger audio interrupt to get new buffer D(bug("stream: triggering irq\n")); SetInterruptFlag(INTFLAG_AUDIO); TriggerInterrupt(); D(bug("stream: waiting for ack\n")); sem_wait(&audio_irq_done_sem); D(bug("stream: ack received\n")); // Get size of audio data uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); if (!current_main_mute && !current_speaker_mute && apple_stream_info) { int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels; D(bug("stream: work_size %d\n", work_size)); if (work_size > sound_buffer_size) work_size = sound_buffer_size; if (work_size == 0) goto silence; // Send data to audio library. Convert 8-bit data // unsigned->signed, using same algorithm as audio_amiga.cpp. // It works fine for 8-bit mono, but not stereo. if (AudioStatus.sample_size == 8) { uint32 *p = (uint32 *)Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)); uint32 *q = (uint32 *)last_buffer; int r = work_size >> 2; // XXX not quite right.... while (r--) *q++ = *p++ ^ 0x80808080; if (work_size != sound_buffer_size) memset((uint8 *)last_buffer + work_size, silence_byte, sound_buffer_size - work_size); alWriteFrames(port, last_buffer, audio_frames_per_block); } else if (work_size == sound_buffer_size) alWriteFrames(port, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), audio_frames_per_block); else { // Last buffer Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size); memset((uint8 *)last_buffer + work_size, silence_byte, sound_buffer_size - work_size); alWriteFrames(port, last_buffer, audio_frames_per_block); } D(bug("stream: data written\n")); } else goto silence; } else { // Audio not active, play silence silence: // D(bug("stream: silence\n")); alZeroFrames(port, audio_frames_per_block); } // Wait for fill point to be reached (may be immediate) if (alSetFillPoint(port, sound_buffer_fill_point) < 0) { fprintf(stderr, "ERROR: alSetFillPoint failed: %s\n", alGetErrorString(oserror())); // Should stop the audio here.... } do { errno = 0; FD_SET(audio_fd, &audio_fdset); was_error = select(numfds, NULL, &audio_fdset, NULL, NULL); } while(was_error < 0 && (errno == EINTR)); if (was_error < 0) { fprintf(stderr, "ERROR: select returned %d, errno %d\n", was_error, errno); // Should stop audio here.... } } delete[] last_buffer; return NULL; } /* * Read or set the current output volume using the audio library */ static uint32 read_volume(void) { ALpv x[2]; ALfixed gain[8]; double maxgain, mingain; ALparamInfo pi; uint32 ret = 0x01000100; // default, maximum value int dev = alGetDevice(config); // Fetch the maximum and minimum gain settings alGetParamInfo(dev, AL_GAIN, &pi); maxgain = alFixedToDouble(pi.max.ll); mingain = alFixedToDouble(pi.min.ll); // printf("maxgain = %lf dB, mingain = %lf dB\n", maxgain, mingain); // Get the current gain values x[0].param = AL_GAIN; x[0].value.ptr = gain; x[0].sizeIn = sizeof(gain) / sizeof(gain[0]); x[1].param = AL_CHANNELS; if (alGetParams(dev, x, 2) < 0) { printf("alGetParams failed: %s\n", alGetErrorString(oserror())); } else { if (x[0].sizeOut < 0) { printf("AL_GAIN was an unrecognized parameter\n"); } else { double v; uint32 left, right; // Left v = alFixedToDouble(gain[0]); if (v < mingain) v = mingain; // handle gain == -inf v = (v - mingain) / (maxgain - mingain); // scale to 0..1 left = (uint32)(v * (double)256); // convert to 8.8 fixed point // Right if (x[0].sizeOut <= 1) { // handle a mono interface right = left; } else { v = alFixedToDouble(gain[1]); if (v < mingain) v = mingain; // handle gain == -inf v = (v - mingain) / (maxgain - mingain); // scale to 0..1 right = (uint32)(v * (double)256); // convert to 8.8 fixed point } ret = (left << 16) | right; } } return ret; } static void set_volume(uint32 vol) { ALpv x[1]; ALfixed gain[2]; // left and right double maxgain, mingain; ALparamInfo pi; int dev = alGetDevice(config); // Fetch the maximum and minimum gain settings alGetParamInfo(dev, AL_GAIN, &pi); maxgain = alFixedToDouble(pi.max.ll); mingain = alFixedToDouble(pi.min.ll); // Set the new gain values x[0].param = AL_GAIN; x[0].value.ptr = gain; x[0].sizeIn = sizeof(gain) / sizeof(gain[0]); uint32 left = vol >> 16; uint32 right = vol & 0xffff; double lv, rv; if (left == 0 && pi.specialVals & AL_NEG_INFINITY_BIT) { lv = AL_NEG_INFINITY; } else { lv = ((double)left / 256) * (maxgain - mingain) + mingain; } if (right == 0 && pi.specialVals & AL_NEG_INFINITY_BIT) { rv = AL_NEG_INFINITY; } else { rv = ((double)right / 256) * (maxgain - mingain) + mingain; } D(bug("set_volume: left=%lf dB, right=%lf dB\n", lv, rv)); gain[0] = alDoubleToFixed(lv); gain[1] = alDoubleToFixed(rv); if (alSetParams(dev, x, 1) < 0) { printf("alSetParams failed: %s\n", alGetErrorString(oserror())); } } /* * Read or set the mute setting using the audio library */ static bool read_mute(void) { bool ret; int dev = alGetDevice(config); ALpv x; x.param = AL_MUTE; if (alGetParams(dev, &x, 1) < 0) { printf("alSetParams failed: %s\n", alGetErrorString(oserror())); return current_main_mute; // Or just return false? } ret = x.value.i; D(bug("read_mute: mute=%d\n", ret)); return ret; } static void set_mute(bool mute) { D(bug("set_mute: mute=%ld\n", mute)); int dev = alGetDevice(config); ALpv x; x.param = AL_MUTE; x.value.i = mute; if (alSetParams(dev, &x, 1) < 0) { printf("alSetParams failed: %s\n", alGetErrorString(oserror())); } } /* * MacOS audio interrupt, read next data block */ void AudioInterrupt(void) { D(bug("AudioInterrupt\n")); // Get data from apple mixer if (AudioStatus.mixer) { M68kRegisters r; r.a[0] = audio_data + adatStreamInfo; r.a[1] = AudioStatus.mixer; Execute68k(audio_data + adatGetSourceData, &r); D(bug(" GetSourceData() returns %08lx\n", r.d[0])); } else WriteMacInt32(audio_data + adatStreamInfo, 0); // Signal stream function sem_post(&audio_irq_done_sem); D(bug("AudioInterrupt done\n")); } /* * Set sampling parameters * "index" is an index into the audio_sample_rates[] etc. vectors * It is guaranteed that AudioStatus.num_sources == 0 */ bool audio_set_sample_rate(int index) { close_audio(); audio_sample_rate_index = index; return open_audio(); } bool audio_set_sample_size(int index) { close_audio(); audio_sample_size_index = index; return open_audio(); } bool audio_set_channels(int index) { close_audio(); audio_channel_count_index = index; return open_audio(); } /* * Get/set volume controls (volume values received/returned have the left channel * volume in the upper 16 bits and the right channel volume in the lower 16 bits; * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume")) */ bool audio_get_main_mute(void) { D(bug("audio_get_main_mute: mute=%ld\n", current_main_mute)); return current_main_mute; } uint32 audio_get_main_volume(void) { uint32 ret = current_main_volume; D(bug("audio_get_main_volume: vol=0x%x\n", ret)); return ret; } bool audio_get_speaker_mute(void) { D(bug("audio_get_speaker_mute: mute=%ld\n", current_speaker_mute)); return current_speaker_mute; } uint32 audio_get_speaker_volume(void) { uint32 ret = current_speaker_volume; D(bug("audio_get_speaker_volume: vol=0x%x\n", ret)); return ret; } void audio_set_main_mute(bool mute) { D(bug("audio_set_main_mute: mute=%ld\n", mute)); if (mute != current_main_mute) { current_main_mute = mute; } set_mute(current_main_mute); } void audio_set_main_volume(uint32 vol) { D(bug("audio_set_main_volume: vol=%x\n", vol)); current_main_volume = vol; set_volume(vol); } void audio_set_speaker_mute(bool mute) { D(bug("audio_set_speaker_mute: mute=%ld\n", mute)); if (mute != current_speaker_mute) { current_speaker_mute = mute; } set_mute(current_speaker_mute); } void audio_set_speaker_volume(uint32 vol) { D(bug("audio_set_speaker_volume: vol=%x\n", vol)); current_speaker_volume = vol; set_volume(vol); } BasiliskII/src/Unix/Darwin/0000755000175000017500000000000011735674761015720 5ustar centriscentrisBasiliskII/src/Unix/Darwin/testlmem.sh0000755000175000017500000000253010177252266020100 0ustar centriscentris#!/bin/sh # testlmem.sh - test whether the Mach-O hack works # # Basilisk II (C) 1997-2005 Christian Bauer # # testlmem.sh Copyright (C) 2003 Michael Z. Sliczniak # # 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 PAGEZERO_SIZE=0x2000 [[ -n "$1" ]] && PAGEZERO_SIZE=$1 # You want all the output to go to stderr so that configure is quiet but # config.log is verbose. { echo 'building lowmem utility' && \ make -f /dev/null Darwin/lowmem && \ echo 'building pagezero test' && \ make -f /dev/null LDFLAGS="-pagezero_size $PAGEZERO_SIZE" Darwin/pagezero && \ echo 'enabling low memory globals in pagezero' && \ Darwin/lowmem Darwin/pagezero && \ echo 'running pagezero test' && \ Darwin/pagezero; } 1>&2 BasiliskII/src/Unix/Darwin/pagezero.c0000644000175000017500000000200707742354077017675 0ustar centriscentris/* * pagezero.c - test to see if low memory globals can be accessed * * Copyright (c) 2003 Michael Z. Sliczniak * * Basilisk II (C) 1997-2003 Christian Bauer * * 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 */ int main(int argc, const char *argv[]) { volatile char *pagezero = (void *)0; pagezero[0x1234] = pagezero[0x123]; return (0); } BasiliskII/src/Unix/Darwin/mkstandalone0000755000175000017500000000500210421537357020311 0ustar centriscentris#!/bin/sh # # mkstandalone - Make a standalone bundle with GTK runtime # # Basilisk II (C) 1997-2006 Christian Bauer # # mkstandalone Copyright (C) 2006 Gwenole Beauchesne # # 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 PROG="${1%.app}" [ -n "$PROG" ] || { echo "Usage: ${0##*/} " exit 1 } [ -d "$PROG.app" ] || { echo "ERROR: $PROG.app bundle does not exist" exit 1 } [ -x "$PROG.app/Contents/MacOS/$PROG" ] || { echo "ERROR: $PROG.app is not a properly formed bundle" exit 1 } echo "Processing bundle $PROG.app" FRAMEWORKS="GLib GDK GTK" rm -r -f $PROG.app/Contents/Frameworks mkdir -p $PROG.app/Contents/Frameworks int_args="" for fmk_path in `otool -L $PROG.app/Contents/MacOS/$PROG | \ sed -n '/ *\(\/.*\.framework\/.*\) ([^)]*)/s//\1/p'` do fmk_spath="${fmk_path%/Versions/*}" fmk="${fmk_spath%.framework}" fmk="${fmk##*/}" case " $FRAMEWORKS " in (*" $fmk "*) ;; (*) continue ;; esac echo " Linking in framework $fmk" fmk_dpath=$PROG.app/Contents/Frameworks/$fmk.framework rm -rf $fmk_dpath cp -Rf $fmk_spath $fmk_dpath find $fmk_dpath -name "*Headers*" | xargs rm -rf fmk_vpath="${fmk_path##*.framework/}" # change library dependency install_name_tool -change \ $fmk_spath/$fmk_vpath \ @executable_path/../Frameworks/$fmk.framework/$fmk_vpath \ $PROG.app/Contents/MacOS/$PROG # change shared library id name fmk_newid="@executable_path/../Frameworks/${fmk_path#*/Frameworks/}" install_name_tool -id $fmk_newid $fmk_dpath/$fmk_vpath # expand final install_name_tool args list int_args="$int_args -change $fmk_path $fmk_newid" # strip shared library strip -x $fmk_dpath/$fmk_vpath done # change remaining dependency libs names for f in $FRAMEWORKS; do install_name_tool $int_args $PROG.app/Contents/Frameworks/$f.framework/$f done exit 0 BasiliskII/src/Unix/Darwin/lowmem.c0000644000175000017500000001650111676431054017355 0ustar centriscentris/* * lowmem.c - enable access to low memory globals on Darwin * * Copyright (c) 2003 Michael Z. Sliczniak * * Basilisk II (C) 1997-2005 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #include #include #include static const char progname[] = "lowmem"; static const char *filename; static int do_swap = 0; static uint32_t target_uint32(uint32_t value) { if (do_swap) value = OSSwapInt32(value); return value; } void pagezero_32(struct mach_header *machhead) { struct segment_command *sc_cmd; if (target_uint32(machhead->filetype) != MH_EXECUTE) { (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n", progname, filename); exit(1); } if (machhead->ncmds == 0) { (void)fprintf(stderr, "%s: %s does not contain any load commands\n", progname, filename); exit(1); } sc_cmd = (void *)&machhead[1]; if (target_uint32(sc_cmd->cmd) != LC_SEGMENT){ (void)fprintf(stderr, "%s: load segment not first command in %s\n", progname, filename); exit(1); } if (strncmp(sc_cmd->segname, "__PAGEZERO", sizeof (*sc_cmd->segname))) { (void)fprintf(stderr, "%s: zero page not first segment in %s\n", progname, filename); exit(1); } /* change the permissions */ sc_cmd->maxprot = target_uint32(VM_PROT_ALL); sc_cmd->initprot = target_uint32(VM_PROT_ALL); } #if defined(MH_MAGIC_64) void pagezero_64(struct mach_header_64 *machhead) { struct segment_command_64 *sc_cmd; if (target_uint32(machhead->filetype) != MH_EXECUTE) { (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n", progname, filename); exit(1); } if (machhead->ncmds == 0) { (void)fprintf(stderr, "%s: %s does not contain any load commands\n", progname, filename); exit(1); } sc_cmd = (void *)&machhead[1]; if (target_uint32(sc_cmd->cmd) != LC_SEGMENT_64) { (void)fprintf(stderr, "%s: load segment not first command in %s\n", progname, filename); exit(1); } if (strncmp(sc_cmd->segname, "__PAGEZERO", sizeof(*sc_cmd->segname))) { (void)fprintf(stderr, "%s: zero page not first segment in %s\n", progname, filename); exit(1); } /* change the permissions */ sc_cmd->maxprot = target_uint32(VM_PROT_ALL); sc_cmd->initprot = target_uint32(VM_PROT_ALL); } #endif /* * Under Mach there is very little assumed about the memory map of object * files. It is the job of the loader to create the initial memory map of an * executable. In a Mach-O executable there will be numerous loader commands * that the loader must process. Some of these will create the initial memory * map used by the executable. Under Darwin the static object file linker, * ld, automatically adds the __PAGEZERO segment to all executables. The * default size of this segment is the page size of the target system and * the initial and maximum permissions are set to allow no access. This is so * that all programs fault on a NULL pointer dereference. Arguably this is * incorrect and the maximum permissions shoould be rwx so that programs can * change this default behavior. Then programs could be written that assume * a null string at the null address, which was the convention on some * systems. In our case we need to have 8K mapped at zero for the low memory * globals and this program modifies the segment load command in the * basiliskII executable so that it can be used for data. */ int main(int argc, const char *argv[]) { int fd; char *addr; off_t file_size; struct mach_header *machhead; #if defined(MH_MAGIC_64) struct mach_header_64 *machhead64; #endif struct fat_header *fathead; struct stat f; if (argc != 2) { (void)fprintf(stderr, "Usage: %s executable\n", progname); exit(1); } filename = argv[1]; if (stat(filename, &f)) { (void)fprintf(stderr, "%s: could not stat %s: %s\n", progname, filename, strerror(errno)); exit(1); } file_size = f.st_size; fd = open(filename, O_RDWR, 0); if (fd == -1) { (void)fprintf(stderr, "%s: could not open %s: %s\n", progname, filename, strerror(errno)); exit(1); } /* * Size does not really matter, it will be rounded-up to a multiple * of the page size automatically. */ addr = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (addr == NULL || addr == MAP_FAILED) { (void)fprintf(stderr, "%s: could not mmap %s: %s\n", progname, filename, strerror(errno)); exit(1); } /* * Check to see if the Mach-O magic bytes are in the header. */ machhead = (void *)addr; #if defined(MH_MAGIC_64) machhead64 = (void *)addr; #endif fathead = (void *)addr; #if defined(MH_MAGIC_64) do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM || machhead64->magic == MH_CIGAM_64; #else do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM; #endif if (target_uint32(machhead->magic) == MH_MAGIC) { pagezero_32(machhead); #if defined(MH_MAGIC_64) } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) { pagezero_64(machhead64); #endif } else if (target_uint32(fathead->magic) == FAT_MAGIC) { struct fat_arch *arch = (void *)&fathead[1]; int saved_swap = do_swap; int i; for (i = 0; i < target_uint32(fathead->nfat_arch); ++i, ++arch) { machhead = (void *)(addr + target_uint32(arch->offset)); #if defined(MH_MAGIC_64) machhead64 = (void *)(addr + target_uint32(arch->offset)); #endif #if defined(MH_MAGIC_64) do_swap = machhead->magic == MH_CIGAM || machhead64->magic == MH_CIGAM_64; #else do_swap = machhead->magic == MH_CIGAM; #endif if (target_uint32(machhead->magic) == MH_MAGIC) { pagezero_32(machhead); #if defined(MH_MAGIC_64) } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) { pagezero_64(machhead64); #endif } else { (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n", progname, filename); exit(1); } do_swap = saved_swap; } } else { (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n", progname, filename); exit(1); } /* * We do not make __PAGEZERO 8K in this program because then * all of the offsets would be wrong in the object file after * this segment. Instead we use the -pagezero_size option * to link the executable. */ if (msync(addr, file_size, MS_SYNC) == -1) { (void)fprintf(stderr, "%s: could not sync %s: %s\n", progname, filename, strerror(errno)); exit(1); } if (munmap(addr, file_size) == -1) { (void)fprintf(stderr, "%s: could not unmap %s: %s\n", progname, filename, strerror(errno)); exit(1); } (void)close(fd); exit(0); } BasiliskII/src/Unix/Darwin/gtk-osx.patch0000644000175000017500000001310610426564761020330 0ustar centriscentris2006-05-05 Gwenole Beauchesne * gtk/gtkaqua.c (gtk_aqua_draw_focus): Don't crash if "detail" is NULL. * gdk/MacCarbonEvents.c (mouse_motion_handler): Another NULL pointer check. 2006-04-17 Gwenole Beauchesne * glib-1.2.10/gmain.c (g_main_run): Don't block in RunApplicationEventLoop(), code inspired from Inside Mac technote. This patch only suits Basilisk II needs. i.e. this may not work for other programs. 2006-04-17 Gwenole Beauchesne * glib-1.2.10/glibconfig.h (G_VA_COPY): Don't redefine. --- gtk-osx-0.7/gdk/MacCarbonEvents.c Sat May 8 16:59:12 2004 +++ gtk-osx-0.7/gdk/MacCarbonEvents.c Fri May 5 07:48:45 2006 @@ -227,7 +227,7 @@ mouse_motion_handler (EventHandlerCallRe local_point.v = global_point.v; } - if (gdk_window != g_win_containing_mouse) + if (gdk_window && gdk_window != g_win_containing_mouse) { if(GDK_LEAVE_NOTIFY_MASK & ((GdkWindowPrivate*) g_win_containing_mouse)->event_mask) { --- gtk-osx-0.7/glib-1.2.10/glibconfig.h Thu Jan 2 05:29:18 2003 +++ gtk-osx-0.7/glib-1.2.10/glibconfig.h Mon Apr 17 21:12:34 2006 @@ -62,8 +62,9 @@ G_GNUC_EXTENSION typedef unsigned long l #define GLIB_MINOR_VERSION 2 #define GLIB_MICRO_VERSION 10 - +#ifndef G_VA_COPY #define G_VA_COPY __va_copy +#endif #ifdef __cplusplus #define G_HAVE_INLINE 1 --- gtk-osx-0.7/glib-1.2.10/gmain.c Sat Dec 27 22:23:06 2003 +++ gtk-osx-0.7/glib-1.2.10/gmain.c Mon Apr 17 22:12:15 2006 @@ -145,6 +145,7 @@ static gboolean g_idle_dispatch ( gpointer user_data); #ifdef MAC_CARBON_EVENTS +static void mac_run_application_event_loop (GMainLoop *loop); static void mac_handle_idle_action (EventLoopTimerRef timer_ref, EventLoopIdleTimerMessage state, void* user_data); @@ -1116,7 +1117,7 @@ g_main_run (GMainLoop *loop) loop->is_running = TRUE; #ifdef MAC_CARBON_EVENTS - RunApplicationEventLoop (); + mac_run_application_event_loop (loop); #else while (loop->is_running) g_main_iterate (TRUE, TRUE); @@ -1870,4 +1871,94 @@ mac_handle_g_main_iteration_action (Even #endif } -#endif /* MAC_CARBON_EVENTS */ \ No newline at end of file +static EventHandlerUPP g_quit_event_handler_upp; + +static pascal OSStatus QuitEventHandler(EventHandlerCallRef inHandlerCallRef, + EventRef inEvent, void *inUserData) +{ + OSStatus err; + + if ((err = CallNextEventHandler(inHandlerCallRef, inEvent)) == noErr) + *((Boolean *)inUserData) = TRUE; + + return err; +} + +static EventHandlerUPP g_event_loop_event_handler_upp; + +static pascal OSStatus EventLoopEventHandler(EventHandlerCallRef inHandlerCallRef, + EventRef inEvent, void *inUserData) +{ + OSStatus err; + OSStatus junk; + EventHandlerRef installedHandler; + EventTargetRef theTarget; + EventRef theEvent; + EventTimeout timeToWaitForEvent; + Boolean quitNow; + GMainLoop * loop = (GMainLoop *)inUserData; + static const EventTypeSpec eventSpec = {kEventClassApplication, kEventAppQuit}; + + quitNow = false; + + err = InstallEventHandler(GetApplicationEventTarget(), + g_quit_event_handler_upp, + 1, &eventSpec, &quitNow, &installedHandler); + if (err == noErr) { + theTarget = GetEventDispatcherTarget(); + do { + timeToWaitForEvent = kEventDurationNoWait; + err = ReceiveNextEvent(0, NULL, timeToWaitForEvent, + true, &theEvent); + if (err == noErr) { + SendEventToEventTarget(theEvent, theTarget); + ReleaseEvent(theEvent); + } + YieldToAnyThread(); + } while ( loop->is_running && ! quitNow ); + junk = RemoveEventHandler(installedHandler); + } + + return err; +} + +static void +mac_run_application_event_loop (GMainLoop *loop) +{ + static const EventTypeSpec eventSpec = {'KWIN', 'KWIN' }; + OSStatus err; + OSStatus junk; + EventHandlerRef installedHandler; + EventRef dummyEvent; + + dummyEvent = nil; + + err = noErr; + if (g_event_loop_event_handler_upp == nil) + g_event_loop_event_handler_upp = NewEventHandlerUPP(EventLoopEventHandler); + if (g_quit_event_handler_upp == nil) + g_quit_event_handler_upp = NewEventHandlerUPP(QuitEventHandler); + if (g_event_loop_event_handler_upp == nil || g_quit_event_handler_upp == nil) + err = memFullErr; + + if (err == noErr) { + err = InstallEventHandler(GetApplicationEventTarget(), + g_event_loop_event_handler_upp, + 1, &eventSpec, loop, &installedHandler); + if (err == noErr) { + err = MacCreateEvent(nil, 'KWIN', 'KWIN', GetCurrentEventTime(), + kEventAttributeNone, &dummyEvent); + if (err == noErr) + err = PostEventToQueue(GetMainEventQueue(), dummyEvent, + kEventPriorityHigh); + if (err == noErr) + RunApplicationEventLoop(); + + junk = RemoveEventHandler(installedHandler); + } + } + + if (dummyEvent != nil) + ReleaseEvent(dummyEvent); +} +#endif /* MAC_CARBON_EVENTS */ --- gtk-osx-0.7/gtk/gtkaqua.c Sat Dec 27 23:33:36 2003 +++ gtk-osx-0.7/gtk/gtkaqua.c Fri May 5 07:13:30 2006 @@ -2183,11 +2183,12 @@ gtk_aqua_draw_focus (GtkStyle *styl g_return_if_fail (window != NULL); // aqua button focus is not just a simple rectangle, so we don't draw anything here - if ( strcmp( detail, "button" ) == 0 ) { + if (detail) { + if ( strcmp( detail, "button" ) == 0 ) return; - } else if ( strcmp( detail, "checkbutton" ) == 0 ) { + else if ( strcmp( detail, "checkbutton" ) == 0 ) return; - } else if ( strcmp( detail, "togglebutton" ) == 0 ) { + else if ( strcmp( detail, "togglebutton" ) == 0 ) return; } BasiliskII/src/Unix/bincue_unix.cpp0000644000175000017500000004555011452741437017510 0ustar centriscentris/* * Copyright (C) 2002-2010 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. */ /* Geoffrey Brown 2010 * Includes ideas from dosbox src/dos/cdrom_image.cpp * * Limitations: 1) cue files must reference single bin file * 2) only supports raw mode1 data and audio * 3) no support for audio flags * 4) requires SDL audio or OS X core audio * 5) limited cue file keyword support * * Creating cue/bin files: * cdrdao read-cd --read-raw --paranoia 3 foo.toc * toc2cue foo.toc */ #include "sysdeps.h" #include #include #include #include #include #include #include #include #include #ifdef OSX_CORE_AUDIO #include "../MacOSX/MacOSX_sound_if.h" static int bincue_core_audio_callback(void); #endif #ifdef USE_SDL_AUDIO #include #include #endif #include "bincue_unix.h" #define DEBUG 0 #include "debug.h" #define MAXTRACK 100 #define MAXLINE 512 #define CD_FRAMES 75 #define RAW_SECTOR_SIZE 2352 #define COOKED_SECTOR_SIZE 2048 // Bits of Track Control Field -- These are standard for scsi cd players #define PREMPHASIS 0x1 #define COPY 0x2 #define DATA 0x4 #define AUDIO 0 #define FOURTRACK 0x8 // Audio status -- These are standard for scsi cd players #define CDROM_AUDIO_INVALID 0x00 #define CDROM_AUDIO_PLAY 0x11 #define CDROM_AUDIO_PAUSED 0x12 #define CDROM_AUDIO_COMPLETED 0x13 #define CDROM_AUDIO_ERROR 0x14 #define CDROM_AUDIO_NO_STATUS 0x15 typedef unsigned char uint8; // cuefiles can be challenging as some information is // implied. For example, there may a pregap (also postgap) // of silence that must be generated. Here we implement // only the pregap. typedef struct { int number; unsigned int start; // Track start in frames unsigned int length; // Track length in frames loff_t fileoffset; // Track frame start within file unsigned int pregap; // Silence in frames to generate unsigned char tcf; // Track control field } Track; typedef struct { char *binfile; // Binary file name unsigned int length; // file length in frames int binfh; // binary file handle int tcnt; // number of tracks Track tracks[MAXTRACK]; } CueSheet; typedef struct { CueSheet *cs; // cue sheet to play from int audiofh; // file handle for audio data unsigned int audioposition; // current position from audiostart (bytes) unsigned int audiostart; // start position if playing (frame) unsigned int audioend; // end position if playing (frames) unsigned int silence; // pregap (silence) bytes unsigned char audiostatus; // See defines above for status loff_t fileoffset; // offset from file beginning to audiostart #ifdef OSX_CORE_AUDIO OSXsoundOutput soundoutput; #endif } CDPlayer; // Minute,Second,Frame data type typedef struct { int m, s, f; // note size matters since we scan for %d ! } MSF; // Parser State static unsigned int totalPregap; static unsigned int prestart; // Audio System State static bool audio_enabled = false; static uint8 silence_byte; // CD Player state. Note only one player is supported ! static CDPlayer player; static void FramesToMSF(unsigned int frames, MSF *msf) { msf->m = frames/(60 * CD_FRAMES); frames = frames%(60 * CD_FRAMES); msf->s = frames/CD_FRAMES; msf->f = frames%CD_FRAMES; } static int MSFToFrames(MSF msf) { return (msf.m * 60 * CD_FRAMES) + (msf.s * CD_FRAMES) + msf.f; } static int PositionToTrack(CueSheet *cs, unsigned int position) { int i; MSF msf; FramesToMSF(position, &msf); for (i = 0; i < cs->tcnt; i++) { if ((position >= cs->tracks[i].start) && (position <= (cs->tracks[i].start + cs->tracks[i].length))) break; } return i; } static bool AddTrack(CueSheet *cs) { int skip = prestart; Track *prev; Track *curr = &(cs->tracks[cs->tcnt]); prestart = 0; if (skip > 0) { if (skip > curr->start) { D(bug("AddTrack: prestart > start\n")); return false; } } curr->fileoffset = curr->start * RAW_SECTOR_SIZE; // now we patch up the indicated time curr->start += totalPregap; // curr->pregap is supposed to be part of this track, but it // must be generated as silence totalPregap += curr->pregap; if (cs->tcnt == 0) { if (curr->number != 1) { D(bug("AddTrack: number != 1\n")); return false; } cs->tcnt++; return true; } prev = &(cs->tracks[cs->tcnt - 1]); if (prev->start < skip) prev->length = skip - prev->start - curr->pregap; else prev->length = curr->start - prev->start - curr->pregap; // error checks if (curr->number <= 1) { D(bug("Bad track number %d\n", curr->number)); return false; } if ((prev->number + 1 != curr->number) && (curr->number != 0xAA)) { D(bug("Bad track number %d\n", curr->number)); return false; } if (curr->start < prev->start + prev->length) { D(bug("unexpected start %d\n", curr->start)); return false; } cs->tcnt++; return true; } static bool ParseCueSheet(FILE *fh, CueSheet *cs, const char *cuefile) { bool seen1st = false; char line[MAXLINE]; unsigned int i_line=0; char *keyword; totalPregap = 0; prestart = 0; while (fgets(line, MAXLINE, fh) != NULL) { Track *curr = &cs->tracks[cs->tcnt]; // check for CUE file if (!i_line && (strncmp("FILE", line, 4) != 0)) { return false; } i_line++; // extract keyword if (NULL != (keyword = strtok(line, " \t\n\t"))) { if (!strcmp("FILE", keyword)) { char *filename; char *filetype; if (i_line > 1) { D(bug("More than one FILE token\n")); goto fail; } filename = strtok(NULL, "\"\t\n\r"); filetype = strtok(NULL, " \"\t\n\r"); if (strcmp("BINARY", filetype)) { D(bug("Not binary file %s", filetype)); goto fail; } else { char *tmp = strdup(cuefile); char *b = dirname(tmp); cs->binfile = (char *) malloc(strlen(b) + strlen(filename) + 2); sprintf(cs->binfile, "%s/%s", b, filename); free(tmp); } } else if (!strcmp("TRACK", keyword)) { char *field; int i_track; if (seen1st) { if (!AddTrack(cs)){ D(bug("AddTrack failed \n")); goto fail; } curr = &cs->tracks[cs->tcnt]; } seen1st = true; // parse track number field = strtok(NULL, " \t\n\r"); if (1 != sscanf(field, "%d", &i_track)) { D(bug("Expected track number\n")); goto fail; } curr->number = i_track; // parse track type field = strtok(NULL, " \t\n\r"); if (!strcmp("MODE1/2352", field)) { curr->tcf = DATA; } else if (!strcmp("AUDIO", field)) { curr->tcf = AUDIO; } else { D(bug("Unexpected track type %s", field)); goto fail; } } else if (!strcmp("INDEX", keyword)) { char *field; int i_index; MSF msf; // parse INDEX number field = strtok(NULL, " \t\n\r"); if (1 != sscanf(field, "%d", &i_index)) { D(bug("Expected index number")); goto fail; } // parse INDEX start field = strtok(NULL, " \t\n\r"); if (3 != sscanf(field, "%d:%d:%d", &msf.m, &msf.s, &msf.f)) { D(bug("Expected index start frame\n")); goto fail; } if (i_index == 1) curr->start = MSFToFrames(msf); else if (i_index == 0) prestart = MSFToFrames(msf); } else if (!strcmp("PREGAP", keyword)) { MSF msf; char *field = strtok(NULL, " \t\n\r"); if (3 != sscanf(field, "%d:%d:%d", &msf.m, &msf.s, &msf.f)) { D(bug("Expected pregap frame\n")); goto fail; } curr->pregap = MSFToFrames(msf); // Ignored directives } else if (!strcmp("TITLE", keyword)) { } else if (!strcmp("PERFORMER", keyword)) { } else if (!strcmp("REM", keyword)) { } else if (!strcmp("ISRC", keyword)) { } else if (!strcmp("SONGWRITER", keyword)) { } else { D(bug("Unexpected keyword %s\n", keyword)); goto fail; } } } AddTrack(cs); // add final track return true; fail: return false; } static bool LoadCueSheet(const char *cuefile, CueSheet *cs) { FILE *fh = NULL; int binfh = -1; struct stat buf; Track *tlast = NULL; if (cs) { bzero(cs, sizeof(*cs)); if (!(fh = fopen(cuefile, "r"))) return false; if (!ParseCueSheet(fh, cs, cuefile)) goto fail; // Open bin file and find length if ((binfh = open(cs->binfile,O_RDONLY)) < 0) { D(bug("Can't read bin file %s\n", cs->binfile)); goto fail; } if (fstat(binfh, &buf)) { D(bug("fstat returned error\n")); goto fail; } // compute length of final track tlast = &cs->tracks[cs->tcnt - 1]; tlast->length = buf.st_size/RAW_SECTOR_SIZE - tlast->start + totalPregap; if (tlast->length < 0) { D(bug("Binary file too short \n")); goto fail; } // save bin file length and pointer cs->length = buf.st_size/RAW_SECTOR_SIZE; cs->binfh = binfh; fclose(fh); return true; fail: if (binfh >= 0) close(binfh); fclose(fh); free(cs->binfile); return false; } return false; } void *open_bincue(const char *name) { CueSheet *cs; if (player.cs == NULL) { cs = (CueSheet *) malloc(sizeof(CueSheet)); if (!cs) { D(bug("malloc failed\n")); return NULL; } if (LoadCueSheet(name, cs)) { player.cs = cs; #ifdef OSX_CORE_AUDIO audio_enabled = true; #endif if (audio_enabled) player.audiostatus = CDROM_AUDIO_NO_STATUS; else player.audiostatus = CDROM_AUDIO_INVALID; player.audiofh = dup(cs->binfh); return cs; } else free(cs); } return NULL; } void close_bincue(void *fh) { } /* * File read (cooked) * Data are stored in raw sectors of which only COOKED_SECTOR_SIZE * bytes are valid -- the remaining include 16 bytes at the beginning * of each raw sector and RAW_SECTOR_SIZE - COOKED_SECTOR_SIZE - bytes * at the end * * We assume that a read request can land in the middle of * sector. We compute the byte address of that sector (sec) * and the offset of the first byte we want within that sector (secoff) * * Reading is performed one raw sector at a time, extracting as many * valid bytes as possible from that raw sector (available) */ size_t read_bincue(void *fh, void *b, loff_t offset, size_t len) { size_t bytes_read = 0; // bytes read so far unsigned char *buf = (unsigned char *) b; // target buffer unsigned char secbuf[RAW_SECTOR_SIZE]; // temporary buffer off_t sec = ((offset/COOKED_SECTOR_SIZE) * RAW_SECTOR_SIZE); off_t secoff = offset % COOKED_SECTOR_SIZE; // sec contains location (in bytes) of next raw sector to read // secoff contains offset within that sector at which to start // reading since we can request a read that starts in the middle // of a sector CueSheet *cs = (CueSheet *) fh; if (cs == NULL || lseek(cs->binfh, sec, SEEK_SET) < 0) { return -1; } while (len) { // bytes available in next raw sector or len (bytes) // we want whichever is less size_t available = COOKED_SECTOR_SIZE - secoff; available = (available > len) ? len : available; // read the next raw sector if (read(cs->binfh, secbuf, RAW_SECTOR_SIZE) != RAW_SECTOR_SIZE) { return bytes_read; } // copy cooked sector bytes (skip first 16) // we want out of those available bcopy(&secbuf[16+secoff], &buf[bytes_read], available); // next sector we start at the beginning secoff = 0; // increment running count decrement request bytes_read += available; len -= available; } return bytes_read; } loff_t size_bincue(void *fh) { if (fh) { return ((CueSheet *)fh)->length * COOKED_SECTOR_SIZE; } } bool readtoc_bincue(void *fh, unsigned char *toc) { CueSheet *cs = (CueSheet *) fh; if (cs) { MSF msf; unsigned char *p = toc + 2; *p++ = cs->tracks[0].number; *p++ = cs->tracks[cs->tcnt - 1].number; for (int i = 0; i < cs->tcnt; i++) { FramesToMSF(cs->tracks[i].start, &msf); *p++ = 0; *p++ = 0x10 | cs->tracks[i].tcf; *p++ = cs->tracks[i].number; *p++ = 0; *p++ = 0; *p++ = msf.m; *p++ = msf.s; *p++ = msf.f; } FramesToMSF(cs->length, &msf); *p++ = 0; *p++ = 0x14; *p++ = 0xAA; *p++ = 0; *p++ = 0; *p++ = msf.m; *p++ = msf.s; *p++ = msf.f; int toc_size = p - toc; *toc++ = toc_size >> 8; *toc++ = toc_size & 0xff; return true; } } bool GetPosition_bincue(void *fh, uint8 *pos) { CueSheet *cs = (CueSheet *) fh; if (cs && player.cs == cs) { MSF abs, rel; int fpos = player.audioposition / RAW_SECTOR_SIZE + player.audiostart; int trackno = PositionToTrack(cs, fpos); if (!audio_enabled) return false; FramesToMSF(fpos, &abs); if (trackno < cs->tcnt) { // compute position relative to start of frame unsigned int position = player.audioposition/RAW_SECTOR_SIZE + player.audiostart - player.cs->tracks[trackno].start; FramesToMSF(position, &rel); } else FramesToMSF(0, &rel); *pos++ = 0; *pos++ = player.audiostatus; *pos++ = 0; *pos++ = 12; // Sub-Q data length *pos++ = 0; if (trackno < cs->tcnt) *pos++ = 0x10 | cs->tracks[trackno].tcf; *pos++ = (trackno < cs->tcnt) ? cs->tracks[trackno].number : 0xAA; *pos++ = 1; // track index *pos++ = 0; *pos++ = abs.m; *pos++ = abs.s; *pos++ = abs.f; *pos++ = 0; *pos++ = rel.m; *pos++ = rel.s; *pos++ = rel.f; *pos++ = 0; // D(bug("CDROM position %02d:%02d:%02d track %02d\n", abs.m, abs.s, abs.f, trackno)); return true; } else return false; } bool CDPause_bincue(void *fh) { CueSheet *cs = (CueSheet *) fh; if (cs && cs == player.cs) { if (player.audiostatus == CDROM_AUDIO_PLAY) { player.audiostatus = CDROM_AUDIO_PAUSED; return true; } } return false; } bool CDStop_bincue(void *fh) { CueSheet *cs = (CueSheet *) fh; if (cs && cs == player.cs) { #ifdef OSX_CORE_AUDIO player.soundoutput.stop(); #endif if (player.audiostatus != CDROM_AUDIO_INVALID) player.audiostatus = CDROM_AUDIO_NO_STATUS; return true; } return false; } bool CDResume_bincue(void *fh) { CueSheet *cs = (CueSheet *) fh; if (cs && cs == player.cs) { if (player.audiostatus == CDROM_AUDIO_PAUSED) { player.audiostatus = CDROM_AUDIO_PLAY; return true; } } return false; } bool CDPlay_bincue(void *fh, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f) { CueSheet *cs = (CueSheet *)fh; if (cs && cs == player.cs) { int track; MSF msf; #ifdef USE_SDL_AUDIO SDL_LockAudio(); #endif player.audiostatus = CDROM_AUDIO_NO_STATUS; player.audiostart = (start_m * 60 * CD_FRAMES) + (start_s * CD_FRAMES) + start_f; player.audioend = (end_m * 60 * CD_FRAMES) + (end_s * CD_FRAMES) + end_f; track = PositionToTrack(player.cs, player.audiostart); if (track < player.cs->tcnt) { player.audioposition = 0; // here we need to compute silence if (player.audiostart - player.cs->tracks[track].start > player.cs->tracks[track].pregap) player.silence = 0; else player.silence = (player.cs->tracks[track].pregap - player.audiostart + player.cs->tracks[track].start) * RAW_SECTOR_SIZE; player.fileoffset = player.cs->tracks[track].fileoffset; D(bug("file offset %d\n", (unsigned int) player.fileoffset)); // fix up file offset if beyond the silence bytes if (!player.silence) // not at the beginning player.fileoffset += (player.audiostart - player.cs->tracks[track].start - player.cs->tracks[track].pregap) * RAW_SECTOR_SIZE; FramesToMSF(player.cs->tracks[track].start, &msf); D(bug("CDPlay_bincue track %02d start %02d:%02d:%02d silence %d", player.cs->tracks[track].number, msf.m, msf.s, msf.f, player.silence/RAW_SECTOR_SIZE)); D(bug(" Stop %02u:%02u:%02u\n", end_m, end_s, end_f)); } else D(bug("CDPlay_bincue: play beyond last track !\n")); #ifdef USE_SDL_AUDIO SDL_UnlockAudio(); #endif if (audio_enabled) { player.audiostatus = CDROM_AUDIO_PLAY; #ifdef OSX_CORE_AUDIO D(bug("starting os x sound")); player.soundoutput.setCallback(bincue_core_audio_callback); // should be from current track ! player.soundoutput.start(16, 2, 44100); #endif return true; } } return false; } static uint8 *fill_buffer(int stream_len) { static uint8 *buf = 0; static int bufsize = 0; int offset = 0; if (bufsize < stream_len) { free(buf); buf = (uint8 *) malloc(stream_len); if (buf) { bufsize = stream_len; } else { D(bug("malloc failed \n")); return NULL; } } memset(buf, silence_byte, stream_len); if (player.audiostatus == CDROM_AUDIO_PLAY) { int remaining_silence = player.silence - player.audioposition; if (player.audiostart + player.audioposition/RAW_SECTOR_SIZE >= player.audioend) { player.audiostatus = CDROM_AUDIO_COMPLETED; return buf; } if (remaining_silence >= stream_len) { player.audioposition += stream_len; return buf; } if (remaining_silence > 0) { offset += remaining_silence; player.audioposition += remaining_silence; } int ret = 0; int available = ((player.audioend - player.audiostart) * RAW_SECTOR_SIZE) - player.audioposition; if (available > (stream_len - offset)) available = stream_len - offset; if (lseek(player.audiofh, player.fileoffset + player.audioposition - player.silence, SEEK_SET) < 0) return NULL; if (available < 0) { player.audioposition += available; // correct end !; available = 0; } if ((ret = read(player.audiofh, &buf[offset], available)) >= 0) { player.audioposition += ret; offset += ret; available -= ret; } while (offset < stream_len) { buf[offset++] = silence_byte; if (available-- > 0){ player.audioposition++; } } } return buf; } #ifdef USE_SDL_AUDIO void MixAudio_bincue(uint8 *stream, int stream_len) { uint8 *buf; if (audio_enabled && (player.audiostatus == CDROM_AUDIO_PLAY)) { if (buf = fill_buffer(stream_len)) SDL_MixAudio(stream, buf, stream_len, SDL_MIX_MAXVOLUME); } } void OpenAudio_bincue(int freq, int format, int channels, uint8 silence) { if (freq == 44100 && format == AUDIO_S16MSB && channels == 2) { audio_enabled = true; silence_byte = silence; } else { D(bug("unexpected frequency %d , format %d, or channels %d\n", freq, format, channels)); } } #endif #ifdef OSX_CORE_AUDIO static int bincue_core_audio_callback(void) { int frames = player.soundoutput.bufferSizeFrames(); uint8 *buf = fill_buffer(frames*4); // D(bug("Audio request %d\n", stream_len)); player.soundoutput.sendAudioBuffer((void *) buf, (buf ? frames : 0)); return 1; } #endif BasiliskII/src/Unix/Linux/0000755000175000017500000000000011735674761015573 5ustar centriscentrisBasiliskII/src/Unix/Linux/NetDriver/0000755000175000017500000000000011735675027017471 5ustar centriscentrisBasiliskII/src/Unix/Linux/NetDriver/Makefile0000644000175000017500000000204611357252142021120 0ustar centriscentris# Linux makefile for sheep_net driver KERNEL_DIR = /lib/modules/$(shell uname -r) KERNEL_SOURCE = $(KERNEL_DIR)/build LV := $(shell test -f $(KERNEL_SOURCE)/Rules.make && echo 24 || echo 26) MP := $(shell test -f $(KERNEL_SOURCE)/Rules.make && echo "o" || echo "ko") ifeq ($(LV),26) # Kernel 2.6 KERNEL_DRIVER = $(KERNEL_DIR)/kernel/drivers obj-m = sheep_net.o sheep_net.ko: sheep_net.c $(MAKE) -C $(KERNEL_SOURCE) M=$$PWD modules clean: $(MAKE) -C $(KERNEL_SOURCE) M=$$PWD clean else # Kernel 2.4 ## System specific configuration CPPFLAGS = -I. -I$(KERNEL_SOURCE)/include CFLAGS = -O2 -Wall -D__KERNEL__ -DMODULE -D_LOOSE_KERNEL_NAMES ASFLAGS = LDFLAGS = LIBS = ## Files KERNEL_DRIVER = $(KERNEL_DIR) OBJS = sheep_net.o ## Rules sheep_net.o: sheep_net.c $(CC) -c $(CPPFLAGS) $(CFLAGS) sheep_net.c clean: -rm $(OBJS) dep depend: makedepend $(CPPFLAGS) -Y *.c endif dev: mknod /dev/sheep_net c 10 198 install: sheep_net.$(MP) install -d $(KERNEL_DRIVER)/misc install -m 644 sheep_net.$(MP) $(KERNEL_DRIVER)/misc depmod -a # DO NOT DELETE BasiliskII/src/Unix/Linux/NetDriver/sheep_net.c0000644000175000017500000004235111474046521021603 0ustar centriscentris/* * sheep_net.c - Linux driver for SheepShaver/Basilisk II networking (access to raw Ethernet packets) * * sheep_net (C) 1999-2004 Mar"c" Hellwig and Christian Bauer * * 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 */ /* modversions.h redefines kernel symbols. Now include other headers */ #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) #define LINUX_26_35 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) #define LINUX_26_36 #endif /* Compatibility glue */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) #define LINUX_26_30 #else /* determine whether to use checksummed versions of kernel symbols */ /*** #include ***/ #include "config.h" #include #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) #define MODVERSIONS #endif #if defined(MODVERSIONS) #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include MODULE_AUTHOR("Christian Bauer"); MODULE_DESCRIPTION("Pseudo ethernet device for emulators"); /* Compatibility glue */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #define LINUX_26 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #define LINUX_24 #else #define net_device device typedef struct wait_queue *wait_queue_head_t; #define init_waitqueue_head(x) *(x)=NULL #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) #define eth_hdr(skb) (skb)->mac.ethernet #define skb_mac_header(skb) (skb)->mac.raw #define ipip_hdr(skb) (skb)->h.ipiph #endif #ifdef LINUX_26 #define skt_set_dead(skt) do {} while(0) #define wmem_alloc sk_wmem_alloc #else #define skt_set_dead(skt) (skt)->dead = 1 #endif #define DEBUG 0 #define bug printk #if DEBUG #define D(x) (x); #else #define D(x) ; #endif /* Constants */ #define SHEEP_NET_MINOR 198 /* Driver minor number */ #define MAX_QUEUE 32 /* Maximum number of packets in queue */ #define PROT_MAGIC 1520 /* Our "magic" protocol type */ #define ETH_ADDR_MULTICAST 0x1 #define ETH_ADDR_LOCALLY_DEFINED 0x02 #define SIOC_MOL_GET_IPFILTER SIOCDEVPRIVATE #define SIOC_MOL_SET_IPFILTER (SIOCDEVPRIVATE + 1) /* Prototypes */ static int sheep_net_open(struct inode *inode, struct file *f); static int sheep_net_release(struct inode *inode, struct file *f); static ssize_t sheep_net_read(struct file *f, char *buf, size_t count, loff_t *off); static ssize_t sheep_net_write(struct file *f, const char *buf, size_t count, loff_t *off); static unsigned int sheep_net_poll(struct file *f, struct poll_table_struct *wait); #ifdef LINUX_26_36 static long sheep_net_ioctl(struct file *f, unsigned int code, unsigned long arg); #else static int sheep_net_ioctl(struct inode *inode, struct file *f, unsigned int code, unsigned long arg); #endif #ifdef LINUX_26 static int sheep_net_receiver(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *foo); #else static int sheep_net_receiver(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt); #endif /* * Driver private variables */ struct SheepVars { /* IMPORTANT: the packet_type struct must go first. It no longer (2.6) contains * a data field so we typecast to get the SheepVars struct */ struct packet_type pt; /* Receiver packet type */ struct net_device *ether; /* The Ethernet device we're attached to */ struct sock *skt; /* Socket for communication with Ethernet card */ struct sk_buff_head queue; /* Receiver packet queue */ wait_queue_head_t wait; /* Wait queue for blocking read operations */ u32 ipfilter; /* Only receive IP packets destined for this address (host byte order) */ char eth_addr[6]; /* Hardware address of the Ethernet card */ char fake_addr[6]; /* Local faked hardware address (what SheepShaver sees) */ }; /* * file_operations structure - has function pointers to the * various entry points for device operations */ static struct file_operations sheep_net_fops = { .owner = THIS_MODULE, .read = sheep_net_read, .write = sheep_net_write, .poll = sheep_net_poll, #ifdef LINUX_26_36 .unlocked_ioctl = sheep_net_ioctl, #else .ioctl = sheep_net_ioctl, #endif .open = sheep_net_open, .release = sheep_net_release, }; /* * miscdevice structure for driver initialization */ static struct miscdevice sheep_net_device = { .minor = SHEEP_NET_MINOR, /* minor number */ .name = "sheep_net", /* name */ .fops = &sheep_net_fops }; /* * fake protocol to use a common socket */ static struct proto sheep_proto = { .name = "SHEEP", .owner = THIS_MODULE, .obj_size = sizeof(struct sock), }; /* * Initialize module */ int init_module(void) { int ret; /* Register driver */ ret = misc_register(&sheep_net_device); D(bug("Sheep net driver installed\n")); return ret; } /* * Deinitialize module */ void cleanup_module(void) { /* Unregister driver */ misc_deregister(&sheep_net_device); D(bug("Sheep net driver removed\n")); } /* * Driver open() function */ static int sheep_net_open(struct inode *inode, struct file *f) { struct SheepVars *v; D(bug("sheep_net: open\n")); /* Must be opened with read permissions */ if ((f->f_flags & O_ACCMODE) == O_WRONLY) return -EPERM; /* Allocate private variables */ v = (struct SheepVars *)kmalloc(sizeof(struct SheepVars), GFP_USER); if (v == NULL) return -ENOMEM; #ifndef LINUX_26_30 lock_kernel(); #endif memset(v, 0, sizeof(struct SheepVars)); skb_queue_head_init(&v->queue); init_waitqueue_head(&v->wait); v->fake_addr[0] = 0xfe; v->fake_addr[1] = 0xfd; v->fake_addr[2] = 0xde; v->fake_addr[3] = 0xad; v->fake_addr[4] = 0xbe; v->fake_addr[5] = 0xef; /* Put our stuff where we will be able to find it later */ f->private_data = (void *)v; /* Yes, we're open */ #ifndef LINUX_26 MOD_INC_USE_COUNT; #endif #ifndef LINUX_26_30 unlock_kernel(); #endif return 0; } /* * Driver release() function */ static int sheep_net_release(struct inode *inode, struct file *f) { struct SheepVars *v = (struct SheepVars *)f->private_data; struct sk_buff *skb; D(bug("sheep_net: close\n")); /* Detach from Ethernet card */ if (v->ether) { dev_remove_pack(&v->pt); sk_free(v->skt); v->skt = NULL; #ifdef LINUX_24 dev_put( v->ether ); #endif v->ether = NULL; } /* Empty packet queue */ while ((skb = skb_dequeue(&v->queue)) != NULL) dev_kfree_skb(skb); /* Free private variables */ kfree(v); /* Sorry, we're closed */ #ifndef LINUX_26 MOD_DEC_USE_COUNT; #endif return 0; } /* * Check whether an Ethernet address is the local (attached) one or * the fake one */ static inline int is_local_addr(struct SheepVars *v, void *a) { return memcmp(a, v->eth_addr, 6) == 0; } static inline int is_fake_addr(struct SheepVars *v, void *a) { return memcmp(a, v->fake_addr, 6) == 0; } /* * Outgoing packet. Replace the fake enet addr with the real local one. */ static inline void do_demasq(struct SheepVars *v, u8 *p) { memcpy(p, v->eth_addr, 6); } static void demasquerade(struct SheepVars *v, struct sk_buff *skb) { u8 *p = skb_mac_header(skb); int proto = (p[12] << 8) | p[13]; do_demasq(v, p + 6); /* source address */ /* Need to fix ARP packets */ if (proto == ETH_P_ARP) { if (is_fake_addr(v, p + 14 + 8)) /* sender HW-addr */ do_demasq(v, p + 14 + 8); } /* ...and AARPs (snap code: 0x00,0x00,0x00,0x80,0xF3) */ if (p[17] == 0 && p[18] == 0 && p[19] == 0 && p[20] == 0x80 && p[21] == 0xf3) { /* XXX: we should perhaps look for the 802 frame too */ if (is_fake_addr(v, p + 30)) do_demasq(v, p + 30); /* sender HW-addr */ } } /* * Incoming packet. Replace the local enet addr with the fake one. */ static inline void do_masq(struct SheepVars *v, u8 *p) { memcpy(p, v->fake_addr, 6); } static void masquerade(struct SheepVars *v, struct sk_buff *skb) { u8 *p = skb_mac_header(skb); if (!(p[0] & ETH_ADDR_MULTICAST)) do_masq(v, p); /* destination address */ /* XXX: reverse ARP might need to be fixed */ } /* * Driver read() function */ static ssize_t sheep_net_read(struct file *f, char *buf, size_t count, loff_t *off) { struct SheepVars *v = (struct SheepVars *)f->private_data; struct sk_buff *skb; D(bug("sheep_net: read\n")); for (;;) { /* Get next packet from queue */ skb = skb_dequeue(&v->queue); if (skb != NULL || (f->f_flags & O_NONBLOCK)) break; /* No packet in queue and in blocking mode, so block */ interruptible_sleep_on(&v->wait); /* Signal received? Then bail out */ if (signal_pending(current)) return -EINTR; } if (skb == NULL) return -EAGAIN; /* Pass packet to caller */ if (count > skb->len) count = skb->len; if (copy_to_user(buf, skb->data, count)) count = -EFAULT; dev_kfree_skb(skb); return count; } /* * Driver write() function */ static ssize_t sheep_net_write(struct file *f, const char *buf, size_t count, loff_t *off) { struct SheepVars *v = (struct SheepVars *)f->private_data; struct sk_buff *skb; char *p; D(bug("sheep_net: write\n")); /* Check packet size */ if (count < sizeof(struct ethhdr)) return -EINVAL; if (count > 1514) { printk("sheep_net_write: packet size %ld > 1514\n", count); count = 1514; } /* Interface active? */ if (v->ether == NULL) return count; /* Allocate buffer for packet */ skb = dev_alloc_skb(count); if (skb == NULL) return -ENOBUFS; /* Stuff packet in buffer */ p = skb_put(skb, count); if (copy_from_user(p, buf, count)) { kfree_skb(skb); return -EFAULT; } /* Transmit packet */ atomic_add(skb->truesize, &v->skt->wmem_alloc); skb->sk = v->skt; skb->dev = v->ether; skb->priority = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) skb->nh.raw = skb->h.raw = skb->data + v->ether->hard_header_len; skb->mac.raw = skb->data; #else skb_reset_mac_header(skb); skb_set_transport_header(skb, v->ether->hard_header_len); skb_set_network_header(skb, v->ether->hard_header_len); #endif /* Base the IP-filtering on the IP address in any outgoing ARP packets */ if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) { u8 *p = &skb->data[14+14]; /* source IP address */ u32 ip = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; if (ip != v->ipfilter) { v->ipfilter = ip; printk("sheep_net: ipfilter set to %d.%d.%d.%d\n", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); } } /* Is this packet addressed solely to the local host? */ if (is_local_addr(v, skb->data) && !(skb->data[0] & ETH_ADDR_MULTICAST)) { skb->protocol = eth_type_trans(skb, v->ether); netif_rx(skb); return count; } if (skb->data[0] & ETH_ADDR_MULTICAST) { /* We can't clone the skb since we will manipulate the data below */ struct sk_buff *lskb = skb_copy(skb, GFP_ATOMIC); if (lskb) { lskb->protocol = eth_type_trans(lskb, v->ether); netif_rx(lskb); } } /* Outgoing packet (will be on the net) */ demasquerade(v, skb); skb->protocol = PROT_MAGIC; /* Magic value (we can recognize the packet in sheep_net_receiver) */ dev_queue_xmit(skb); return count; } /* * Driver poll() function */ static unsigned int sheep_net_poll(struct file *f, struct poll_table_struct *wait) { struct SheepVars *v = (struct SheepVars *)f->private_data; D(bug("sheep_net: poll\n")); /* Packets in queue? Then return */ if (!skb_queue_empty(&v->queue)) return POLLIN | POLLRDNORM; /* Otherwise wait for packet */ poll_wait(f, &v->wait, wait); if (!skb_queue_empty(&v->queue)) return POLLIN | POLLRDNORM; else return 0; } /* * Driver ioctl() function */ #ifdef LINUX_26_36 static long sheep_net_ioctl(struct file *f, unsigned int code, unsigned long arg) #else static int sheep_net_ioctl(struct inode *inode, struct file *f, unsigned int code, unsigned long arg) #endif { struct SheepVars *v = (struct SheepVars *)f->private_data; D(bug("sheep_net: ioctl %04x\n", code)); switch (code) { /* Attach to Ethernet card arg: pointer to name of Ethernet device (char[20]) */ case SIOCSIFLINK: { char name[20]; int err; /* Already attached? */ if (v->ether) return -EBUSY; /* Get Ethernet card name */ if (copy_from_user(name, (void *)arg, 20)) return -EFAULT; name[19] = 0; /* Find card */ #ifdef LINUX_26 v->ether = dev_get_by_name(&init_net, name); #elif defined(LINUX_24) v->ether = dev_get_by_name(name); #else dev_lock_list(); v->ether = dev_get(name); #endif if (v->ether == NULL) { err = -ENODEV; goto error; } /* Is it Ethernet? */ if (v->ether->type != ARPHRD_ETHER) { err = -EINVAL; goto error; } /* Remember the card's hardware address */ memcpy(v->eth_addr, v->ether->dev_addr, 6); /* Allocate socket */ #ifdef LINUX_26 v->skt = sk_alloc(dev_net(v->ether), GFP_USER, 1, &sheep_proto); #else v->skt = sk_alloc(0, GFP_USER, 1); #endif if (v->skt == NULL) { err = -ENOMEM; goto error; } skt_set_dead(v->skt); /* Attach packet handler */ v->pt.type = htons(ETH_P_ALL); v->pt.dev = v->ether; v->pt.func = sheep_net_receiver; dev_add_pack(&v->pt); #ifndef LINUX_24 dev_unlock_list(); #endif return 0; error: #ifdef LINUX_24 if (v->ether) dev_put(v->ether); #else dev_unlock_list(); #endif v->ether = NULL; return err; } /* Get hardware address of the sheep_net module arg: pointer to buffer (6 bytes) to store address */ case SIOCGIFADDR: if (copy_to_user((void *)arg, v->fake_addr, 6)) return -EFAULT; return 0; /* Set the hardware address of the sheep_net module arg: pointer to new address (6 bytes) */ case SIOCSIFADDR: if (copy_from_user(v->fake_addr, (void*)arg, 6)) return -EFAULT; return 0; /* Add multicast address arg: pointer to address (6 bytes) */ case SIOCADDMULTI: { char addr[6]; if (v->ether == NULL) return -ENODEV; if (copy_from_user(addr, (void *)arg, 6)) return -EFAULT; #ifdef LINUX_26_35 return dev_mc_add(v->ether, addr); #else return dev_mc_add(v->ether, addr, 6, 0); #endif } /* Remove multicast address arg: pointer to address (6 bytes) */ case SIOCDELMULTI: { char addr[6]; if (v->ether == NULL) return -ENODEV; if (copy_from_user(addr, (void *)arg, 6)) return -EFAULT; #ifdef LINUX_26_35 return dev_mc_del(v->ether, addr); #else return dev_mc_delete(v->ether, addr, 6, 0); #endif } /* Return size of first packet in queue */ case FIONREAD: { int count = 0; struct sk_buff *skb; #ifdef LINUX_24 unsigned long flags; spin_lock_irqsave(&v->queue.lock, flags); #else cli(); #endif skb = skb_peek(&v->queue); if (skb) count = skb->len; #ifdef LINUX_24 spin_unlock_irqrestore(&v->queue.lock, flags); #else sti(); #endif return put_user(count, (int *)arg); } case SIOC_MOL_GET_IPFILTER: return put_user(v->ipfilter, (int *)arg); case SIOC_MOL_SET_IPFILTER: v->ipfilter = arg; return 0; default: return -ENOIOCTLCMD; } } /* * Packet receiver function */ #ifdef LINUX_26 static int sheep_net_receiver(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *foo) #else static int sheep_net_receiver(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) #endif { struct SheepVars *v = (struct SheepVars *)pt; struct sk_buff *skb2; int fake; int multicast; D(bug("sheep_net: packet received\n")); multicast = (eth_hdr(skb)->h_dest[0] & ETH_ADDR_MULTICAST); fake = is_fake_addr(v, ð_hdr(skb)->h_dest); /* Packet sent by us? Then discard */ if (is_fake_addr(v, ð_hdr(skb)->h_source) || skb->protocol == PROT_MAGIC) goto drop; /* If the packet is not meant for this host, discard it */ if (!is_local_addr(v, ð_hdr(skb)->h_dest) && !multicast && !fake) goto drop; /* Discard packets if queue gets too full */ if (skb_queue_len(&v->queue) > MAX_QUEUE) goto drop; /* Apply any filters here (if fake is true, then we *know* we want this packet) */ if (!fake) { if ((skb->protocol == htons(ETH_P_IP)) && (!v->ipfilter || (ntohl(ipip_hdr(skb)->daddr) != v->ipfilter && !multicast))) goto drop; } /* Masquerade (we are typically a clone - best to make a real copy) */ skb2 = skb_copy(skb, GFP_ATOMIC); if (!skb2) goto drop; kfree_skb(skb); skb = skb2; masquerade(v, skb); /* We also want the Ethernet header */ skb_push(skb, skb->data - skb_mac_header(skb)); /* Enqueue packet */ skb_queue_tail(&v->queue, skb); /* Unblock blocked read */ wake_up(&v->wait); return 0; drop: kfree_skb(skb); return 0; } MODULE_LICENSE("GPL"); BasiliskII/src/Unix/Linux/scsi_linux.cpp0000644000175000017500000001457710736405221020454 0ustar centriscentris/* * scsi_linux.cpp - SCSI Manager, Linux specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include // workaround for broken RedHat 6.0 /usr/include/scsi #include #include #define DRIVER_SENSE 0x08 #include "main.h" #include "prefs.h" #include "user_strings.h" #include "scsi.h" #define DEBUG 0 #include "debug.h" // Global variables static int fds[8]; // fd's for 8 units static int fd; // Active fd (selected target) static uint32 buffer_size; // Size of data buffer static uint8 *buffer = NULL; // Pointer to data buffer static uint8 the_cmd[12]; // Active SCSI command static int the_cmd_len; /* * Initialization */ void SCSIInit(void) { int id; // Allocate buffer buffer = (uint8 *)malloc(buffer_size = 0x10000); // Open generic SCSI driver for all 8 units for (id=0; id<8; id++) { char prefs_name[16]; sprintf(prefs_name, "scsi%d", id); const char *str = PrefsFindString(prefs_name); if (str) { int fd = fds[id] = open(str, O_RDWR | O_EXCL); if (fd > 0) { // Is it really a Generic SCSI device? int timeout = ioctl(fd, SG_GET_TIMEOUT); if (timeout < 0) { // Error with SG_GET_TIMEOUT, doesn't seem to be a Generic SCSI device char msg[256]; sprintf(msg, GetString(STR_SCSI_DEVICE_NOT_SCSI_WARN), str); WarningAlert(msg); close(fd); fds[id] = -1; } else { // Flush unwanted garbage from previous use of device uint8 reply[256]; int old_fl = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, old_fl | O_NONBLOCK); while (read(fd, reply, sizeof(reply)) != -1 || errno != EAGAIN) ; fcntl(fd, F_SETFL, old_fl); } } else { char msg[256]; sprintf(msg, GetString(STR_SCSI_DEVICE_OPEN_WARN), str, strerror(errno)); WarningAlert(msg); } } } // Reset SCSI bus SCSIReset(); } /* * Deinitialization */ void SCSIExit(void) { // Close all devices for (int i=0; i<8; i++) { int fd = fds[i]; if (fd > 0) close(fd); } // Free buffer if (buffer) { free(buffer); buffer = NULL; } } /* * Check if requested data size fits into buffer, allocate new buffer if needed */ static bool try_buffer(uint32 size) { size += sizeof(sg_header) + 12; if (size <= buffer_size) return true; uint8 *new_buffer = (uint8 *)malloc(size); if (new_buffer == NULL) return false; free(buffer); buffer = new_buffer; buffer_size = size; return true; } /* * Set SCSI command to be sent by scsi_send_cmd() */ void scsi_set_cmd(int cmd_length, uint8 *cmd) { memcpy(the_cmd, cmd, the_cmd_len = cmd_length); } /* * Check for presence of SCSI target */ bool scsi_is_target_present(int id) { return fds[id] > 0; } /* * Set SCSI target (returns false on error) */ bool scsi_set_target(int id, int lun) { int new_fd = fds[id]; if (new_fd < 0) return false; if (new_fd != fd) { // New target, clear autosense data sg_header *h = (sg_header *)buffer; h->driver_status &= ~DRIVER_SENSE; } fd = new_fd; return true; } /* * Send SCSI command to active target (scsi_set_command() must have been called), * read/write data according to S/G table (returns false on error); timeout is in 1/60 sec */ bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout) { static int pack_id = 0; // Check if buffer is large enough, allocate new buffer if needed if (!try_buffer(data_length)) { char str[256]; sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length); ErrorAlert(str); return false; } // Process S/G table when writing if (!reading) { D(bug(" writing to buffer\n")); uint8 *buffer_ptr = buffer + sizeof(sg_header) + the_cmd_len; for (int i=0; itarget_status & DRIVER_SENSE)) { // Yes, fake command D(bug(" autosense\n")); memcpy(buffer + sizeof(sg_header), h->sense_buffer, 16); h->target_status &= ~DRIVER_SENSE; res = 0; *stat = 0; } else { // No, send regular command if (timeout) { int to = timeout * HZ / 60; ioctl(fd, SG_SET_TIMEOUT, &to); } ioctl(fd, SG_NEXT_CMD_LEN, &the_cmd_len); D(bug(" sending command, length %d\n", data_length)); int request_size, reply_size; if (reading) { h->pack_len = request_size = sizeof(sg_header) + the_cmd_len; h->reply_len = reply_size = sizeof(sg_header) + data_length; } else { h->pack_len = request_size = sizeof(sg_header) + the_cmd_len + data_length; h->reply_len = reply_size = sizeof(sg_header); } h->pack_id = pack_id++; h->result = 0; h->twelve_byte = (the_cmd_len == 12); h->target_status = 0; h->host_status = 0; h->driver_status = 0; h->other_flags = 0; memcpy(buffer + sizeof(sg_header), the_cmd, the_cmd_len); res = write(fd, buffer, request_size); D(bug(" request sent, actual %d, result %d\n", res, h->result)); if (res >= 0) { res = read(fd, buffer, reply_size); D(bug(" reply read, actual %d, result %d, status %02x\n", res, h->result, h->target_status << 1)); } *stat = h->target_status << 1; } // Process S/G table when reading if (reading && h->result == 0) { D(bug(" reading from buffer\n")); uint8 *buffer_ptr = buffer + sizeof(sg_header); for (int i=0; i= 0; } BasiliskII/src/Unix/sigsegv.cpp0000644000175000017500000031144511357251467016651 0ustar centriscentris/* * sigsegv.cpp - SIGSEGV signals support * * Derived from Bruno Haible's work on his SIGSEGV library for clisp * * * MacOS X support derived from the post by Timothy J. Wood to the * omnigroup macosx-dev list: * Mach Exception Handlers 101 (Was Re: ptrace, gdb) * tjw@omnigroup.com Sun, 4 Jun 2000 * www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "sigsegv.h" #ifndef NO_STD_NAMESPACE using std::list; #endif // Return value type of a signal handler (standard type if not defined) #ifndef RETSIGTYPE #define RETSIGTYPE void #endif // Size of an unsigned integer large enough to hold all bits of a pointer // NOTE: this can be different than SIGSEGV_REGISTER_TYPE. In // particular, on ILP32 systems with a 64-bit kernel (HP-UX/ia64?) #if defined(HAVE_WIN32_VM) // Windows is either ILP32 or LLP64 #include typedef UINT_PTR sigsegv_uintptr_t; #else // Other systems are sane enough to follow ILP32 or LP64 models typedef unsigned long sigsegv_uintptr_t; #endif // Type of the system signal handler typedef RETSIGTYPE (*signal_handler)(int); // User's SIGSEGV handler static sigsegv_fault_handler_t sigsegv_fault_handler = 0; // Function called to dump state if we can't handle the fault static sigsegv_state_dumper_t sigsegv_state_dumper = 0; // Actual SIGSEGV handler installer static bool sigsegv_do_install_handler(int sig); /* * Instruction decoding aids */ // Transfer type enum transfer_type_t { SIGSEGV_TRANSFER_UNKNOWN = 0, SIGSEGV_TRANSFER_LOAD = 1, SIGSEGV_TRANSFER_STORE = 2 }; // Transfer size enum transfer_size_t { SIZE_UNKNOWN, SIZE_BYTE, SIZE_WORD, // 2 bytes SIZE_LONG, // 4 bytes SIZE_QUAD // 8 bytes }; #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__)) // Addressing mode enum addressing_mode_t { MODE_UNKNOWN, MODE_NORM, MODE_U, MODE_X, MODE_UX }; // Decoded instruction struct instruction_t { transfer_type_t transfer_type; transfer_size_t transfer_size; addressing_mode_t addr_mode; unsigned int addr; char ra, rd; }; static void powerpc_decode_instruction(instruction_t *instruction, unsigned int nip, unsigned long * gpr) { // Get opcode and divide into fields unsigned int opcode = *((unsigned int *)(unsigned long)nip); unsigned int primop = opcode >> 26; unsigned int exop = (opcode >> 1) & 0x3ff; unsigned int ra = (opcode >> 16) & 0x1f; unsigned int rb = (opcode >> 11) & 0x1f; unsigned int rd = (opcode >> 21) & 0x1f; signed int imm = (signed short)(opcode & 0xffff); // Analyze opcode transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; transfer_size_t transfer_size = SIZE_UNKNOWN; addressing_mode_t addr_mode = MODE_UNKNOWN; switch (primop) { case 31: switch (exop) { case 23: // lwzx transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break; case 55: // lwzux transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break; case 87: // lbzx transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; case 119: // lbzux transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; case 151: // stwx transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break; case 183: // stwux transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break; case 215: // stbx transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break; case 247: // stbux transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break; case 279: // lhzx transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; case 311: // lhzux transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; case 343: // lhax transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; case 375: // lhaux transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; case 407: // sthx transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break; case 439: // sthux transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break; } break; case 32: // lwz transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break; case 33: // lwzu transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break; case 34: // lbz transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; case 35: // lbzu transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; case 36: // stw transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break; case 37: // stwu transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break; case 38: // stb transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break; case 39: // stbu transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break; case 40: // lhz transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; case 41: // lhzu transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; case 42: // lha transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; case 43: // lhau transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; case 44: // sth transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break; case 45: // sthu transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break; case 58: // ld, ldu, lwa transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_QUAD; addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM; imm &= ~3; break; case 62: // std, stdu, stq transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_QUAD; addr_mode = ((opcode & 3) == 1) ? MODE_U : MODE_NORM; imm &= ~3; break; } // Calculate effective address unsigned int addr = 0; switch (addr_mode) { case MODE_X: case MODE_UX: if (ra == 0) addr = gpr[rb]; else addr = gpr[ra] + gpr[rb]; break; case MODE_NORM: case MODE_U: if (ra == 0) addr = (signed int)(signed short)imm; else addr = gpr[ra] + (signed int)(signed short)imm; break; default: break; } // Commit decoded instruction instruction->addr = addr; instruction->addr_mode = addr_mode; instruction->transfer_type = transfer_type; instruction->transfer_size = transfer_size; instruction->ra = ra; instruction->rd = rd; } #endif /* * OS-dependant SIGSEGV signals support section */ #if HAVE_SIGINFO_T // Generic extended signal handler #if defined(__FreeBSD__) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS) #elif defined(__hpux) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS) #else #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #endif #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, siginfo_t *sip, void *scp #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 siginfo_t *sip, void *scp #define SIGSEGV_FAULT_HANDLER_ARGS sip, scp #define SIGSEGV_FAULT_ADDRESS sip->si_addr #if (defined(sgi) || defined(__sgi)) #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs) #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)SIGSEGV_CONTEXT_REGS[CTX_EPC] #if (defined(mips) || defined(__mips)) #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS[CTX_EPC], &SIGSEGV_CONTEXT_REGS[CTX_R0] #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction #endif #endif #if defined(__sun__) #if (defined(sparc) || defined(__sparc__)) #include #include #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[REG_PC] #define SIGSEGV_SPARC_GWINDOWS (((ucontext_t *)scp)->uc_mcontext.gwins) #define SIGSEGV_SPARC_RWINDOW (struct rwindow *)((char *)SIGSEGV_CONTEXT_REGS[REG_SP] + STACK_BIAS) #define SIGSEGV_REGISTER_FILE ((unsigned long *)SIGSEGV_CONTEXT_REGS), SIGSEGV_SPARC_GWINDOWS, SIGSEGV_SPARC_RWINDOW #define SIGSEGV_SKIP_INSTRUCTION sparc_skip_instruction #endif #if defined(__i386__) #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[EIP] #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) #if (defined(i386) || defined(__i386__)) #define SIGSEGV_FAULT_INSTRUCTION (((struct sigcontext *)scp)->sc_eip) #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&(((struct sigcontext *)scp)->sc_edi)) /* EDI is the first GPR (even below EIP) in sigcontext */ #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #endif #if defined(__NetBSD__) #if (defined(i386) || defined(__i386__)) #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_EIP] #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #if (defined(powerpc) || defined(__powerpc__)) #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.__gregs) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[_REG_PC] #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_PC], (unsigned long *)&SIGSEGV_CONTEXT_REGS[_REG_R0] #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction #endif #endif #if defined(__linux__) #if (defined(i386) || defined(__i386__)) #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[14] /* should use REG_EIP instead */ #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #if (defined(x86_64) || defined(__x86_64__)) #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.gregs) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS[16] /* should use REG_RIP instead */ #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)SIGSEGV_CONTEXT_REGS #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #if (defined(ia64) || defined(__ia64__)) #define SIGSEGV_CONTEXT_REGS ((struct sigcontext *)scp) #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->sc_ip & ~0x3ULL) /* slot number is in bits 0 and 1 */ #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS #define SIGSEGV_SKIP_INSTRUCTION ia64_skip_instruction #endif #if (defined(powerpc) || defined(__powerpc__)) #include #define SIGSEGV_CONTEXT_REGS (((ucontext_t *)scp)->uc_mcontext.regs) #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS->nip) #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIGSEGV_CONTEXT_REGS->nip, (unsigned long *)(SIGSEGV_CONTEXT_REGS->gpr) #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction #endif #if (defined(hppa) || defined(__hppa__)) #undef SIGSEGV_FAULT_ADDRESS #define SIGSEGV_FAULT_ADDRESS sip->si_ptr #endif #if (defined(arm) || defined(__arm__)) #include /* use kernel structure, glibc may not be in sync */ #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext) #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.arm_pc) #define SIGSEGV_REGISTER_FILE (&SIGSEGV_CONTEXT_REGS.arm_r0) #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction #endif #if (defined(mips) || defined(__mips__)) #include #define SIGSEGV_CONTEXT_REGS (((struct ucontext *)scp)->uc_mcontext) #define SIGSEGV_FAULT_INSTRUCTION (SIGSEGV_CONTEXT_REGS.pc) #define SIGSEGV_REGISTER_FILE &SIGSEGV_CONTEXT_REGS.pc, &SIGSEGV_CONTEXT_REGS.gregs[0] #define SIGSEGV_SKIP_INSTRUCTION mips_skip_instruction #endif #endif #if (defined(__hpux) || defined(__hpux__)) #if (defined(__hppa) || defined(__hppa__)) #define SIGSEGV_CONTEXT_REGS (&((ucontext_t *)scp)->uc_mcontext) #define SIGSEGV_FAULT_INSTRUCTION_32 (SIGSEGV_CONTEXT_REGS->ss_narrow.ss_pcoq_head & ~3ul) #define SIGSEGV_FAULT_INSTRUCTION_64 (SIGSEGV_CONTEXT_REGS->ss_wide.ss_64.ss_pcoq_head & ~3ull) #if defined(__LP64__) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_FAULT_INSTRUCTION_64 #else #define SIGSEGV_FAULT_INSTRUCTION ((SIGSEGV_CONTEXT_REGS->ss_flags & SS_WIDEREGS) ? \ (uint32_t)SIGSEGV_FAULT_INSTRUCTION_64 : \ SIGSEGV_FAULT_INSTRUCTION_32) #endif #endif #if (defined(__ia64) || defined(__ia64__)) #include #define SIGSEGV_CONTEXT_REGS ((ucontext_t *)scp) #define SIGSEGV_FAULT_INSTRUCTION get_fault_instruction(SIGSEGV_CONTEXT_REGS) #define SIGSEGV_REGISTER_FILE SIGSEGV_CONTEXT_REGS #define SIGSEGV_SKIP_INSTRUCTION ia64_skip_instruction #include static inline sigsegv_address_t get_fault_instruction(const ucontext_t *ucp) { uint64_t ip; if (__uc_get_ip(ucp, &ip) != 0) return SIGSEGV_INVALID_ADDRESS; return (sigsegv_address_t)(ip & ~3ULL); } #endif #endif #endif #if HAVE_SIGCONTEXT_SUBTERFUGE // Linux kernels prior to 2.4 ? #if defined(__linux__) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #if (defined(i386) || defined(__i386__)) #include #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext scs #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS &scs #define SIGSEGV_FAULT_ADDRESS scp->cr2 #define SIGSEGV_FAULT_INSTRUCTION scp->eip #define SIGSEGV_REGISTER_FILE (SIGSEGV_REGISTER_TYPE *)scp #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #if (defined(sparc) || defined(__sparc__)) #include #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr #define SIGSEGV_FAULT_ADDRESS addr #endif #if (defined(powerpc) || defined(__powerpc__)) #include #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, scp #define SIGSEGV_FAULT_ADDRESS scp->regs->dar #define SIGSEGV_FAULT_INSTRUCTION scp->regs->nip #define SIGSEGV_REGISTER_FILE (unsigned long *)&scp->regs->nip, (unsigned long *)(scp->regs->gpr) #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction #endif #if (defined(alpha) || defined(__alpha__)) #include #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp) #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc #endif #if (defined(arm) || defined(__arm__)) #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int r1, int r2, int r3, struct sigcontext sc #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS &sc #define SIGSEGV_FAULT_ADDRESS scp->fault_address #define SIGSEGV_FAULT_INSTRUCTION scp->arm_pc #define SIGSEGV_REGISTER_FILE &scp->arm_r0 #define SIGSEGV_SKIP_INSTRUCTION arm_skip_instruction #endif #endif // Irix 5 or 6 on MIPS #if (defined(sgi) || defined(__sgi)) && (defined(SYSTYPE_SVR4) || defined(_SYSTYPE_SVR4)) #include #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS (unsigned long)scp->sc_badvaddr #define SIGSEGV_FAULT_INSTRUCTION (unsigned long)scp->sc_pc #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #endif // HP-UX #if (defined(hpux) || defined(__hpux__)) #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS scp->sc_sl.sl_ss.ss_narrow.ss_cr21 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) FAULT_HANDLER(SIGBUS) #endif // OSF/1 on Alpha #if defined(__osf__) #include #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS scp->sc_traparg_a0 #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #endif // AIX #if defined(_AIX) #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS scp->sc_jmpbuf.jmp_context.o_vaddr #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #endif // NetBSD #if defined(__NetBSD__) #if (defined(m68k) || defined(__m68k__)) #include #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) // Use decoding scheme from BasiliskII/m68k native static sigsegv_address_t get_fault_address(struct sigcontext *scp) { struct sigstate { int ss_flags; struct frame ss_frame; }; struct sigstate *state = (struct sigstate *)scp->sc_ap; char *fault_addr; switch (state->ss_frame.f_format) { case 7: /* 68040 access error */ /* "code" is sometimes unreliable (i.e. contains NULL or a bogus address), reason unknown */ fault_addr = state->ss_frame.f_fmt7.f_fa; break; default: fault_addr = (char *)code; break; } return (sigsegv_address_t)fault_addr; } #endif #if (defined(alpha) || defined(__alpha__)) #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS) #endif #if (defined(i386) || defined(__i386__)) #error "FIXME: need to decode instruction and compute EA" #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #endif #endif #if defined(__FreeBSD__) #if (defined(i386) || defined(__i386__)) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS) #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct sigcontext *scp, char *addr #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp, addr #define SIGSEGV_FAULT_ADDRESS addr #define SIGSEGV_FAULT_INSTRUCTION scp->sc_eip #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&scp->sc_edi) #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #if (defined(alpha) || defined(__alpha__)) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGSEGV) #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, char *addr, struct sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, addr, scp #define SIGSEGV_FAULT_ADDRESS addr #define SIGSEGV_FAULT_INSTRUCTION scp->sc_pc #endif #endif // Extract fault address out of a sigcontext #if (defined(alpha) || defined(__alpha__)) // From Boehm's GC 6.0alpha8 static sigsegv_address_t get_fault_address(struct sigcontext *scp) { unsigned int instruction = *((unsigned int *)(scp->sc_pc)); unsigned long fault_address = scp->sc_regs[(instruction >> 16) & 0x1f]; fault_address += (signed long)(signed short)(instruction & 0xffff); return (sigsegv_address_t)fault_address; } #endif // MacOS X, not sure which version this works in. Under 10.1 // vm_protect does not appear to work from a signal handler. Under // 10.2 signal handlers get siginfo type arguments but the si_addr // field is the address of the faulting instruction and not the // address that caused the SIGBUS. Maybe this works in 10.0? In any // case with Mach exception handlers there is a way to do what this // was meant to do. #ifndef HAVE_MACH_EXCEPTIONS #if defined(__APPLE__) && defined(__MACH__) #if (defined(ppc) || defined(__ppc__)) #define SIGSEGV_FAULT_HANDLER_ARGLIST int sig, int code, struct __darwin_sigcontext *scp #define SIGSEGV_FAULT_HANDLER_ARGS sig, code, scp #define SIGSEGV_FAULT_ADDRESS get_fault_address(scp) #define SIGSEGV_FAULT_INSTRUCTION scp->MACH_FIELD_NAME(sc_ir) #define SIGSEGV_ALL_SIGNALS FAULT_HANDLER(SIGBUS) #define SIGSEGV_REGISTER_FILE (unsigned int *)&scp->sc_ir, &((unsigned int *) scp->sc_regs)[2] #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction // Use decoding scheme from SheepShaver static sigsegv_address_t get_fault_address(struct sigcontext *scp) { unsigned int nip = (unsigned int) scp->MACH_FIELD_NAME(sc_ir); unsigned int * gpr = &((unsigned int *) scp->MACH_FIELD_NAME(sc_regs))[2]; instruction_t instr; powerpc_decode_instruction(&instr, nip, (long unsigned int*)gpr); return (sigsegv_address_t)instr.addr; } #endif #endif #endif #endif #if HAVE_WIN32_EXCEPTIONS #define WIN32_LEAN_AND_MEAN /* avoid including junk */ #include #include #define SIGSEGV_FAULT_HANDLER_ARGLIST EXCEPTION_POINTERS *ExceptionInfo #define SIGSEGV_FAULT_HANDLER_ARGS ExceptionInfo #define SIGSEGV_FAULT_ADDRESS ExceptionInfo->ExceptionRecord->ExceptionInformation[1] #define SIGSEGV_CONTEXT_REGS ExceptionInfo->ContextRecord #if defined(_M_IX86) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Eip #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Edi) #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #if defined(_M_X64) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->Rip #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIGSEGV_CONTEXT_REGS->Rax) #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #endif #if defined(_M_IA64) #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_CONTEXT_REGS->StIIP #endif #endif #if HAVE_MACH_EXCEPTIONS // This can easily be extended to other Mach systems, but really who // uses HURD (oops GNU/HURD), Darwin/x86, NextStep, Rhapsody, or CMU // Mach 2.5/3.0? #if defined(__APPLE__) && defined(__MACH__) #include #include #include #include /* * If you are familiar with MIG then you will understand the frustration * that was necessary to get these embedded into C++ code by hand. */ extern "C" { #include #include #ifndef HAVE_MACH64_VM // Undefine this to prevent a preprocessor warning when compiling on a // 32-bit machine with Mac OS X 10.5. #undef MACH_EXCEPTION_CODES #define MACH_EXCEPTION_CODES 0 #define mach_exception_data_t exception_data_t #define mach_exception_data_type_t exception_data_type_t #define mach_exc_server exc_server #define catch_mach_exception_raise catch_exception_raise #define mach_exception_raise exception_raise #define mach_exception_raise_state exception_raise_state #define mach_exception_raise_state_identity exception_raise_state_identity #endif extern boolean_t mach_exc_server(mach_msg_header_t *, mach_msg_header_t *); extern kern_return_t catch_mach_exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t); extern kern_return_t catch_mach_exception_raise_state(mach_port_t exception_port, exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t code_count, int *flavor, thread_state_t old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t *new_state_count); extern kern_return_t catch_mach_exception_raise_state_identity(mach_port_t exception_port, mach_port_t thread_port, mach_port_t task_port, exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t code_count, int *flavor, thread_state_t old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t *new_state_count); extern kern_return_t mach_exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t); extern kern_return_t mach_exception_raise_state(mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *); extern kern_return_t mach_exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t, exception_type_t, mach_exception_data_t, mach_msg_type_number_t, thread_state_flavor_t *, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *); } // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE #define HANDLER_COUNT 64 // structure to tuck away existing exception handlers typedef struct _ExceptionPorts { mach_msg_type_number_t maskCount; exception_mask_t masks[HANDLER_COUNT]; exception_handler_t handlers[HANDLER_COUNT]; exception_behavior_t behaviors[HANDLER_COUNT]; thread_state_flavor_t flavors[HANDLER_COUNT]; } ExceptionPorts; // exception handler thread static pthread_t exc_thread; // place where old exception handler info is stored static ExceptionPorts ports; // our exception port static mach_port_t _exceptionPort = MACH_PORT_NULL; #define MACH_CHECK_ERROR(name,ret) \ if (ret != KERN_SUCCESS) { \ mach_error(#name, ret); \ exit (1); \ } #ifndef MACH_FIELD_NAME #define MACH_FIELD_NAME(X) X #endif // Since there can only be one exception thread running at any time // this is not a problem. #define MSG_SIZE 512 static char msgbuf[MSG_SIZE]; static char replybuf[MSG_SIZE]; /* * This is the entry point for the exception handler thread. The job * of this thread is to wait for exception messages on the exception * port that was setup beforehand and to pass them on to exc_server. * exc_server is a MIG generated function that is a part of Mach. * Its job is to decide what to do with the exception message. In our * case exc_server calls catch_exception_raise on our behalf. After * exc_server returns, it is our responsibility to send the reply. */ static void * handleExceptions(void *priv) { mach_msg_header_t *msg, *reply; kern_return_t krc; msg = (mach_msg_header_t *)msgbuf; reply = (mach_msg_header_t *)replybuf; for (;;) { krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE, _exceptionPort, 0, MACH_PORT_NULL); MACH_CHECK_ERROR(mach_msg, krc); if (!mach_exc_server(msg, reply)) { fprintf(stderr, "exc_server hated the message\n"); exit(1); } krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, msg->msgh_local_port, 0, MACH_PORT_NULL); if (krc != KERN_SUCCESS) { fprintf(stderr, "Error sending message to original reply port, krc = %d, %s", krc, mach_error_string(krc)); exit(1); } } } #endif #endif /* * Instruction skipping */ #ifndef SIGSEGV_REGISTER_TYPE #define SIGSEGV_REGISTER_TYPE sigsegv_uintptr_t #endif #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION // Decode and skip X86 instruction #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64)) #if defined(__linux__) enum { #if (defined(i386) || defined(__i386__)) X86_REG_EIP = 14, X86_REG_EAX = 11, X86_REG_ECX = 10, X86_REG_EDX = 9, X86_REG_EBX = 8, X86_REG_ESP = 7, X86_REG_EBP = 6, X86_REG_ESI = 5, X86_REG_EDI = 4 #endif #if defined(__x86_64__) X86_REG_R8 = 0, X86_REG_R9 = 1, X86_REG_R10 = 2, X86_REG_R11 = 3, X86_REG_R12 = 4, X86_REG_R13 = 5, X86_REG_R14 = 6, X86_REG_R15 = 7, X86_REG_EDI = 8, X86_REG_ESI = 9, X86_REG_EBP = 10, X86_REG_EBX = 11, X86_REG_EDX = 12, X86_REG_EAX = 13, X86_REG_ECX = 14, X86_REG_ESP = 15, X86_REG_EIP = 16 #endif }; #endif #if defined(__NetBSD__) enum { #if (defined(i386) || defined(__i386__)) X86_REG_EIP = _REG_EIP, X86_REG_EAX = _REG_EAX, X86_REG_ECX = _REG_ECX, X86_REG_EDX = _REG_EDX, X86_REG_EBX = _REG_EBX, X86_REG_ESP = _REG_ESP, X86_REG_EBP = _REG_EBP, X86_REG_ESI = _REG_ESI, X86_REG_EDI = _REG_EDI #endif }; #endif #if defined(__FreeBSD__) enum { #if (defined(i386) || defined(__i386__)) X86_REG_EIP = 10, X86_REG_EAX = 7, X86_REG_ECX = 6, X86_REG_EDX = 5, X86_REG_EBX = 4, X86_REG_ESP = 13, X86_REG_EBP = 2, X86_REG_ESI = 1, X86_REG_EDI = 0 #endif }; #endif #if defined(__OpenBSD__) enum { #if defined(__i386__) // EDI is the first register we consider #define OREG(REG) offsetof(struct sigcontext, sc_##REG) #define DREG(REG) ((OREG(REG) - OREG(edi)) / 4) X86_REG_EIP = DREG(eip), // 7 X86_REG_EAX = DREG(eax), // 6 X86_REG_ECX = DREG(ecx), // 5 X86_REG_EDX = DREG(edx), // 4 X86_REG_EBX = DREG(ebx), // 3 X86_REG_ESP = DREG(esp), // 10 X86_REG_EBP = DREG(ebp), // 2 X86_REG_ESI = DREG(esi), // 1 X86_REG_EDI = DREG(edi) // 0 #undef DREG #undef OREG #endif }; #endif #if defined(__sun__) // Same as for Linux, need to check for x86-64 enum { #if defined(__i386__) X86_REG_EIP = EIP, X86_REG_EAX = EAX, X86_REG_ECX = ECX, X86_REG_EDX = EDX, X86_REG_EBX = EBX, X86_REG_ESP = ESP, X86_REG_EBP = EBP, X86_REG_ESI = ESI, X86_REG_EDI = EDI #endif }; #endif #if defined(__APPLE__) && defined(__MACH__) enum { #if (defined(i386) || defined(__i386__)) #ifdef i386_SAVED_STATE // same as FreeBSD (in Open Darwin 8.0.1) X86_REG_EIP = 10, X86_REG_EAX = 7, X86_REG_ECX = 6, X86_REG_EDX = 5, X86_REG_EBX = 4, X86_REG_ESP = 13, X86_REG_EBP = 2, X86_REG_ESI = 1, X86_REG_EDI = 0 #else // new layout (MacOS X 10.4.4 for x86) X86_REG_EIP = 10, X86_REG_EAX = 0, X86_REG_ECX = 2, X86_REG_EDX = 3, X86_REG_EBX = 1, X86_REG_ESP = 7, X86_REG_EBP = 6, X86_REG_ESI = 5, X86_REG_EDI = 4 #endif #endif #if defined(__x86_64__) X86_REG_R8 = 8, X86_REG_R9 = 9, X86_REG_R10 = 10, X86_REG_R11 = 11, X86_REG_R12 = 12, X86_REG_R13 = 13, X86_REG_R14 = 14, X86_REG_R15 = 15, X86_REG_EDI = 4, X86_REG_ESI = 5, X86_REG_EBP = 6, X86_REG_EBX = 1, X86_REG_EDX = 3, X86_REG_EAX = 0, X86_REG_ECX = 2, X86_REG_ESP = 7, X86_REG_EIP = 16 #endif }; #endif #if defined(_WIN32) enum { #if defined(_M_IX86) X86_REG_EIP = 7, X86_REG_EAX = 5, X86_REG_ECX = 4, X86_REG_EDX = 3, X86_REG_EBX = 2, X86_REG_ESP = 10, X86_REG_EBP = 6, X86_REG_ESI = 1, X86_REG_EDI = 0 #endif #if defined(_M_X64) X86_REG_EAX = 0, X86_REG_ECX = 1, X86_REG_EDX = 2, X86_REG_EBX = 3, X86_REG_ESP = 4, X86_REG_EBP = 5, X86_REG_ESI = 6, X86_REG_EDI = 7, X86_REG_R8 = 8, X86_REG_R9 = 9, X86_REG_R10 = 10, X86_REG_R11 = 11, X86_REG_R12 = 12, X86_REG_R13 = 13, X86_REG_R14 = 14, X86_REG_R15 = 15, X86_REG_EIP = 16 #endif }; #endif // FIXME: this is partly redundant with the instruction decoding phase // to discover transfer type and register number static inline int ix86_step_over_modrm(unsigned char * p) { int mod = (p[0] >> 6) & 3; int rm = p[0] & 7; int offset = 0; // ModR/M Byte switch (mod) { case 0: // [reg] if (rm == 5) return 4; // disp32 break; case 1: // disp8[reg] offset = 1; break; case 2: // disp32[reg] offset = 4; break; case 3: // register return 0; } // SIB Byte if (rm == 4) { if (mod == 0 && (p[1] & 7) == 5) offset = 5; // disp32[index] else offset++; } return offset; } static bool ix86_skip_instruction(SIGSEGV_REGISTER_TYPE * regs) { unsigned char * eip = (unsigned char *)regs[X86_REG_EIP]; if (eip == 0) return false; #ifdef _WIN32 if (IsBadCodePtr((FARPROC)eip)) return false; #endif enum instruction_type_t { i_MOV, i_ADD }; transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; transfer_size_t transfer_size = SIZE_LONG; instruction_type_t instruction_type = i_MOV; int reg = -1; int len = 0; #if DEBUG printf("IP: %p [%02x %02x %02x %02x...]\n", eip, eip[0], eip[1], eip[2], eip[3]); #endif // Operand size prefix if (*eip == 0x66) { eip++; len++; transfer_size = SIZE_WORD; } // REX prefix #if defined(__x86_64__) || defined(_M_X64) struct rex_t { unsigned char W; unsigned char R; unsigned char X; unsigned char B; }; rex_t rex = { 0, 0, 0, 0 }; bool has_rex = false; if ((*eip & 0xf0) == 0x40) { has_rex = true; const unsigned char b = *eip; rex.W = b & (1 << 3); rex.R = b & (1 << 2); rex.X = b & (1 << 1); rex.B = b & (1 << 0); #if DEBUG printf("REX: %c,%c,%c,%c\n", rex.W ? 'W' : '_', rex.R ? 'R' : '_', rex.X ? 'X' : '_', rex.B ? 'B' : '_'); #endif eip++; len++; if (rex.W) transfer_size = SIZE_QUAD; } #else const bool has_rex = false; #endif // Decode instruction int op_len = 1; int target_size = SIZE_UNKNOWN; switch (eip[0]) { case 0x0f: target_size = transfer_size; switch (eip[1]) { case 0xbe: // MOVSX r32, r/m8 case 0xb6: // MOVZX r32, r/m8 transfer_size = SIZE_BYTE; goto do_mov_extend; case 0xbf: // MOVSX r32, r/m16 case 0xb7: // MOVZX r32, r/m16 transfer_size = SIZE_WORD; goto do_mov_extend; do_mov_extend: op_len = 2; goto do_transfer_load; } break; #if defined(__x86_64__) || defined(_M_X64) case 0x63: // MOVSXD r64, r/m32 if (has_rex && rex.W) { transfer_size = SIZE_LONG; target_size = SIZE_QUAD; } else if (transfer_size != SIZE_WORD) { transfer_size = SIZE_LONG; target_size = SIZE_QUAD; } goto do_transfer_load; #endif case 0x02: // ADD r8, r/m8 transfer_size = SIZE_BYTE; case 0x03: // ADD r32, r/m32 instruction_type = i_ADD; goto do_transfer_load; case 0x8a: // MOV r8, r/m8 transfer_size = SIZE_BYTE; case 0x8b: // MOV r32, r/m32 (or 16-bit operation) do_transfer_load: switch (eip[op_len] & 0xc0) { case 0x80: reg = (eip[op_len] >> 3) & 7; transfer_type = SIGSEGV_TRANSFER_LOAD; break; case 0x40: reg = (eip[op_len] >> 3) & 7; transfer_type = SIGSEGV_TRANSFER_LOAD; break; case 0x00: reg = (eip[op_len] >> 3) & 7; transfer_type = SIGSEGV_TRANSFER_LOAD; break; } len += 1 + op_len + ix86_step_over_modrm(eip + op_len); break; case 0x00: // ADD r/m8, r8 transfer_size = SIZE_BYTE; case 0x01: // ADD r/m32, r32 instruction_type = i_ADD; goto do_transfer_store; case 0x88: // MOV r/m8, r8 transfer_size = SIZE_BYTE; case 0x89: // MOV r/m32, r32 (or 16-bit operation) do_transfer_store: switch (eip[op_len] & 0xc0) { case 0x80: reg = (eip[op_len] >> 3) & 7; transfer_type = SIGSEGV_TRANSFER_STORE; break; case 0x40: reg = (eip[op_len] >> 3) & 7; transfer_type = SIGSEGV_TRANSFER_STORE; break; case 0x00: reg = (eip[op_len] >> 3) & 7; transfer_type = SIGSEGV_TRANSFER_STORE; break; } len += 1 + op_len + ix86_step_over_modrm(eip + op_len); break; } if (target_size == SIZE_UNKNOWN) target_size = transfer_size; if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) { // Unknown machine code, let it crash. Then patch the decoder return false; } #if defined(__x86_64__) || defined(_M_X64) if (rex.R) reg += 8; #endif if (instruction_type == i_MOV && transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) { static const int x86_reg_map[] = { X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX, X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI, #if defined(__x86_64__) || defined(_M_X64) X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11, X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15, #endif }; if (reg < 0 || reg >= (sizeof(x86_reg_map)/sizeof(x86_reg_map[0]) - 1)) return false; // Set 0 to the relevant register part // NOTE: this is only valid for MOV alike instructions int rloc = x86_reg_map[reg]; switch (target_size) { case SIZE_BYTE: if (has_rex || reg < 4) regs[rloc] = (regs[rloc] & ~0x00ffL); else { rloc = x86_reg_map[reg - 4]; regs[rloc] = (regs[rloc] & ~0xff00L); } break; case SIZE_WORD: regs[rloc] = (regs[rloc] & ~0xffffL); break; case SIZE_LONG: case SIZE_QUAD: // zero-extension regs[rloc] = 0; break; } } #if DEBUG printf("%p: %s %s access", (void *)regs[X86_REG_EIP], transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : transfer_size == SIZE_LONG ? "long" : transfer_size == SIZE_QUAD ? "quad" : "unknown", transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write"); if (reg != -1) { static const char * x86_byte_reg_str_map[] = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b", "ah", "ch", "dh", "bh", }; static const char * x86_word_reg_str_map[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w", }; static const char *x86_long_reg_str_map[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d", }; static const char *x86_quad_reg_str_map[] = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", }; const char * reg_str = NULL; switch (target_size) { case SIZE_BYTE: reg_str = x86_byte_reg_str_map[(!has_rex && reg >= 4 ? 12 : 0) + reg]; break; case SIZE_WORD: reg_str = x86_word_reg_str_map[reg]; break; case SIZE_LONG: reg_str = x86_long_reg_str_map[reg]; break; case SIZE_QUAD: reg_str = x86_quad_reg_str_map[reg]; break; } if (reg_str) printf(" %s register %%%s", transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from", reg_str); } printf(", %d bytes instruction\n", len); #endif regs[X86_REG_EIP] += len; return true; } #endif // Decode and skip IA-64 instruction #if defined(__ia64) || defined(__ia64__) typedef uint64_t ia64_bundle_t[2]; #if defined(__linux__) // We can directly patch the slot number #define IA64_CAN_PATCH_IP_SLOT 1 // Helper macros to access the machine context #define IA64_CONTEXT_TYPE struct sigcontext * #define IA64_CONTEXT scp #define IA64_GET_IP() (IA64_CONTEXT->sc_ip) #define IA64_SET_IP(V) (IA64_CONTEXT->sc_ip = (V)) #define IA64_GET_PR(P) ((IA64_CONTEXT->sc_pr >> (P)) & 1) #define IA64_GET_NAT(I) ((IA64_CONTEXT->sc_nat >> (I)) & 1) #define IA64_GET_GR(R) (IA64_CONTEXT->sc_gr[(R)]) #define _IA64_SET_GR(R,V) (IA64_CONTEXT->sc_gr[(R)] = (V)) #define _IA64_SET_NAT(I,V) (IA64_CONTEXT->sc_nat = (IA64_CONTEXT->sc_nat & ~(1ull << (I))) | (((uint64_t)!!(V)) << (I))) #define IA64_SET_GR(R,V,N) (_IA64_SET_GR(R,V), _IA64_SET_NAT(R,N)) // Load bundle (in little-endian) static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip) { uint64_t *ip = (uint64_t *)(raw_ip & ~3ull); bundle[0] = ip[0]; bundle[1] = ip[1]; } #endif #if defined(__hpux) || defined(__hpux__) // We can directly patch the slot number #define IA64_CAN_PATCH_IP_SLOT 1 // Helper macros to access the machine context #define IA64_CONTEXT_TYPE ucontext_t * #define IA64_CONTEXT ucp #define IA64_GET_IP() ia64_get_ip(IA64_CONTEXT) #define IA64_SET_IP(V) ia64_set_ip(IA64_CONTEXT, V) #define IA64_GET_PR(P) ia64_get_pr(IA64_CONTEXT, P) #define IA64_GET_NAT(I) ia64_get_nat(IA64_CONTEXT, I) #define IA64_GET_GR(R) ia64_get_gr(IA64_CONTEXT, R) #define IA64_SET_GR(R,V,N) ia64_set_gr(IA64_CONTEXT, R, V, N) #define UC_ACCESS(FUNC,ARGS) do { if (__uc_##FUNC ARGS != 0) abort(); } while (0) static inline uint64_t ia64_get_ip(IA64_CONTEXT_TYPE IA64_CONTEXT) { uint64_t v; UC_ACCESS(get_ip,(IA64_CONTEXT, &v)); return v; } static inline void ia64_set_ip(IA64_CONTEXT_TYPE IA64_CONTEXT, uint64_t v) { UC_ACCESS(set_ip,(IA64_CONTEXT, v)); } static inline unsigned int ia64_get_pr(IA64_CONTEXT_TYPE IA64_CONTEXT, int pr) { uint64_t v; UC_ACCESS(get_prs,(IA64_CONTEXT, &v)); return (v >> pr) & 1; } static inline unsigned int ia64_get_nat(IA64_CONTEXT_TYPE IA64_CONTEXT, int r) { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return (nat >> r) & 1; } static inline uint64_t ia64_get_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r) { uint64_t v; unsigned int nat; UC_ACCESS(get_grs,(IA64_CONTEXT, r, 1, &v, &nat)); return v; } static void ia64_set_gr(IA64_CONTEXT_TYPE IA64_CONTEXT, int r, uint64_t v, unsigned int nat) { if (r == 0) return; if (r > 0 && r < 32) UC_ACCESS(set_grs,(IA64_CONTEXT, r, 1, &v, (!!nat) << r)); else { uint64_t bsp, bspstore; UC_ACCESS(get_ar_bsp,(IA64_CONTEXT, &bsp)); UC_ACCESS(get_ar_bspstore,(IA64_CONTEXT, &bspstore)); abort(); /* XXX: use libunwind, this is not fun... */ } } // Byte-swapping #if defined(__GNUC__) #define BSWAP64(V) ({ uint64_t r; __asm__ __volatile__("mux1 %0=%1,@rev;;" : "=r" (r) : "r" (V)); r; }) #elif defined (__HP_aCC) #define BSWAP64(V) _Asm_mux1(_MBTYPE_REV, V) #else #error "Define byte-swap instruction" #endif // Load bundle (in little-endian) static inline void ia64_load_bundle(ia64_bundle_t bundle, uint64_t raw_ip) { uint64_t *ip = (uint64_t *)(raw_ip & ~3ull); bundle[0] = BSWAP64(ip[0]); bundle[1] = BSWAP64(ip[1]); } #endif // Instruction operations enum { IA64_INST_UNKNOWN = 0, IA64_INST_LD1, // ld1 op0=[op1] IA64_INST_LD1_UPDATE, // ld1 op0=[op1],op2 IA64_INST_LD2, // ld2 op0=[op1] IA64_INST_LD2_UPDATE, // ld2 op0=[op1],op2 IA64_INST_LD4, // ld4 op0=[op1] IA64_INST_LD4_UPDATE, // ld4 op0=[op1],op2 IA64_INST_LD8, // ld8 op0=[op1] IA64_INST_LD8_UPDATE, // ld8 op0=[op1],op2 IA64_INST_ST1, // st1 [op0]=op1 IA64_INST_ST1_UPDATE, // st1 [op0]=op1,op2 IA64_INST_ST2, // st2 [op0]=op1 IA64_INST_ST2_UPDATE, // st2 [op0]=op1,op2 IA64_INST_ST4, // st4 [op0]=op1 IA64_INST_ST4_UPDATE, // st4 [op0]=op1,op2 IA64_INST_ST8, // st8 [op0]=op1 IA64_INST_ST8_UPDATE, // st8 [op0]=op1,op2 IA64_INST_ADD, // add op0=op1,op2,op3 IA64_INST_SUB, // sub op0=op1,op2,op3 IA64_INST_SHLADD, // shladd op0=op1,op3,op2 IA64_INST_AND, // and op0=op1,op2 IA64_INST_ANDCM, // andcm op0=op1,op2 IA64_INST_OR, // or op0=op1,op2 IA64_INST_XOR, // xor op0=op1,op2 IA64_INST_SXT1, // sxt1 op0=op1 IA64_INST_SXT2, // sxt2 op0=op1 IA64_INST_SXT4, // sxt4 op0=op1 IA64_INST_ZXT1, // zxt1 op0=op1 IA64_INST_ZXT2, // zxt2 op0=op1 IA64_INST_ZXT4, // zxt4 op0=op1 IA64_INST_NOP // nop op0 }; const int IA64_N_OPERANDS = 4; // Decoded operand type struct ia64_operand_t { uint8_t commit; // commit result of operation to register file? uint8_t valid; // XXX: not really used, can be removed (debug) int8_t index; // index of GPR, or -1 if immediate value uint8_t nat; // NaT state before operation uint64_t value; // register contents or immediate value }; // Decoded instruction type struct ia64_instruction_t { uint8_t mnemo; // operation to perform uint8_t pred; // predicate register to check uint8_t no_memory; // used to emulated main fault instruction uint64_t inst; // the raw instruction bits (41-bit wide) ia64_operand_t operands[IA64_N_OPERANDS]; }; // Get immediate sign-bit static inline int ia64_inst_get_sbit(uint64_t inst) { return (inst >> 36) & 1; } // Get 8-bit immediate value (A3, A8, I27, M30) static inline uint64_t ia64_inst_get_imm8(uint64_t inst) { uint64_t value = (inst >> 13) & 0x7full; if (ia64_inst_get_sbit(inst)) value |= ~0x7full; return value; } // Get 9-bit immediate value (M3) static inline uint64_t ia64_inst_get_imm9b(uint64_t inst) { uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 13) & 0x7f); if (ia64_inst_get_sbit(inst)) value |= ~0xffull; return value; } // Get 9-bit immediate value (M5) static inline uint64_t ia64_inst_get_imm9a(uint64_t inst) { uint64_t value = (((inst >> 27) & 1) << 7) | ((inst >> 6) & 0x7f); if (ia64_inst_get_sbit(inst)) value |= ~0xffull; return value; } // Get 14-bit immediate value (A4) static inline uint64_t ia64_inst_get_imm14(uint64_t inst) { uint64_t value = (((inst >> 27) & 0x3f) << 7) | (inst & 0x7f); if (ia64_inst_get_sbit(inst)) value |= ~0x1ffull; return value; } // Get 22-bit immediate value (A5) static inline uint64_t ia64_inst_get_imm22(uint64_t inst) { uint64_t value = ((((inst >> 22) & 0x1f) << 16) | (((inst >> 27) & 0x1ff) << 7) | (inst & 0x7f)); if (ia64_inst_get_sbit(inst)) value |= ~0x1fffffull; return value; } // Get 21-bit immediate value (I19) static inline uint64_t ia64_inst_get_imm21(uint64_t inst) { return (((inst >> 36) & 1) << 20) | ((inst >> 6) & 0xfffff); } // Get 2-bit count value (A2) static inline int ia64_inst_get_count2(uint64_t inst) { return (inst >> 27) & 0x3; } // Get bundle template static inline unsigned int ia64_get_template(uint64_t ip) { ia64_bundle_t bundle; ia64_load_bundle(bundle, ip); return bundle[0] & 0x1f; } // Get specified instruction in bundle static uint64_t ia64_get_instruction(uint64_t ip, int slot) { uint64_t inst; ia64_bundle_t bundle; ia64_load_bundle(bundle, ip); #if DEBUG printf("Bundle: %016llx%016llx\n", bundle[1], bundle[0]); #endif switch (slot) { case 0: inst = (bundle[0] >> 5) & 0x1ffffffffffull; break; case 1: inst = ((bundle[1] & 0x7fffffull) << 18) | ((bundle[0] >> 46) & 0x3ffffull); break; case 2: inst = (bundle[1] >> 23) & 0x1ffffffffffull; break; case 3: fprintf(stderr, "ERROR: ia64_get_instruction(), invalid slot number %d\n", slot); abort(); break; } #if DEBUG printf(" Instruction %d: 0x%016llx\n", slot, inst); #endif return inst; } // Decode group 0 instructions static bool ia64_decode_instruction_0(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT) { const int r1 = (inst->inst >> 6) & 0x7f; const int r3 = (inst->inst >> 20) & 0x7f; const int x3 = (inst->inst >> 33) & 0x07; const int x6 = (inst->inst >> 27) & 0x3f; const int x2 = (inst->inst >> 31) & 0x03; const int x4 = (inst->inst >> 27) & 0x0f; if (x3 == 0) { switch (x6) { case 0x01: // nop.i (I19) inst->mnemo = IA64_INST_NOP; inst->operands[0].valid = true; inst->operands[0].index = -1; inst->operands[0].value = ia64_inst_get_imm21(inst->inst); return true; case 0x14: // sxt1 (I29) case 0x15: // sxt2 (I29) case 0x16: // sxt4 (I29) case 0x10: // zxt1 (I29) case 0x11: // zxt2 (I29) case 0x12: // zxt4 (I29) switch (x6) { case 0x14: inst->mnemo = IA64_INST_SXT1; break; case 0x15: inst->mnemo = IA64_INST_SXT2; break; case 0x16: inst->mnemo = IA64_INST_SXT4; break; case 0x10: inst->mnemo = IA64_INST_ZXT1; break; case 0x11: inst->mnemo = IA64_INST_ZXT2; break; case 0x12: inst->mnemo = IA64_INST_ZXT4; break; default: abort(); } inst->operands[0].valid = true; inst->operands[0].index = r1; inst->operands[1].valid = true; inst->operands[1].index = r3; inst->operands[1].value = IA64_GET_GR(r3); inst->operands[1].nat = IA64_GET_NAT(r3); return true; } } return false; } // Decode group 4 instructions (load/store instructions) static bool ia64_decode_instruction_4(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT) { const int r1 = (inst->inst >> 6) & 0x7f; const int r2 = (inst->inst >> 13) & 0x7f; const int r3 = (inst->inst >> 20) & 0x7f; const int m = (inst->inst >> 36) & 1; const int x = (inst->inst >> 27) & 1; const int x6 = (inst->inst >> 30) & 0x3f; switch (x6) { case 0x00: case 0x01: case 0x02: case 0x03: if (x == 0) { inst->operands[0].valid = true; inst->operands[0].index = r1; inst->operands[1].valid = true; inst->operands[1].index = r3; inst->operands[1].value = IA64_GET_GR(r3); inst->operands[1].nat = IA64_GET_NAT(r3); if (m == 0) { switch (x6) { case 0x00: inst->mnemo = IA64_INST_LD1; break; case 0x01: inst->mnemo = IA64_INST_LD2; break; case 0x02: inst->mnemo = IA64_INST_LD4; break; case 0x03: inst->mnemo = IA64_INST_LD8; break; } } else { inst->operands[2].valid = true; inst->operands[2].index = r2; inst->operands[2].value = IA64_GET_GR(r2); inst->operands[2].nat = IA64_GET_NAT(r2); switch (x6) { case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break; case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break; case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break; case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break; } } return true; } break; case 0x30: case 0x31: case 0x32: case 0x33: if (m == 0 && x == 0) { inst->operands[0].valid = true; inst->operands[0].index = r3; inst->operands[0].value = IA64_GET_GR(r3); inst->operands[0].nat = IA64_GET_NAT(r3); inst->operands[1].valid = true; inst->operands[1].index = r2; inst->operands[1].value = IA64_GET_GR(r2); inst->operands[1].nat = IA64_GET_NAT(r2); switch (x6) { case 0x30: inst->mnemo = IA64_INST_ST1; break; case 0x31: inst->mnemo = IA64_INST_ST2; break; case 0x32: inst->mnemo = IA64_INST_ST4; break; case 0x33: inst->mnemo = IA64_INST_ST8; break; } return true; } break; } return false; } // Decode group 5 instructions (load/store instructions) static bool ia64_decode_instruction_5(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT) { const int r1 = (inst->inst >> 6) & 0x7f; const int r2 = (inst->inst >> 13) & 0x7f; const int r3 = (inst->inst >> 20) & 0x7f; const int x6 = (inst->inst >> 30) & 0x3f; switch (x6) { case 0x00: case 0x01: case 0x02: case 0x03: inst->operands[0].valid = true; inst->operands[0].index = r1; inst->operands[1].valid = true; inst->operands[1].index = r3; inst->operands[1].value = IA64_GET_GR(r3); inst->operands[1].nat = IA64_GET_NAT(r3); inst->operands[2].valid = true; inst->operands[2].index = -1; inst->operands[2].value = ia64_inst_get_imm9b(inst->inst); inst->operands[2].nat = 0; switch (x6) { case 0x00: inst->mnemo = IA64_INST_LD1_UPDATE; break; case 0x01: inst->mnemo = IA64_INST_LD2_UPDATE; break; case 0x02: inst->mnemo = IA64_INST_LD4_UPDATE; break; case 0x03: inst->mnemo = IA64_INST_LD8_UPDATE; break; } return true; case 0x30: case 0x31: case 0x32: case 0x33: inst->operands[0].valid = true; inst->operands[0].index = r3; inst->operands[0].value = IA64_GET_GR(r3); inst->operands[0].nat = IA64_GET_NAT(r3); inst->operands[1].valid = true; inst->operands[1].index = r2; inst->operands[1].value = IA64_GET_GR(r2); inst->operands[1].nat = IA64_GET_NAT(r2); inst->operands[2].valid = true; inst->operands[2].index = -1; inst->operands[2].value = ia64_inst_get_imm9a(inst->inst); inst->operands[2].nat = 0; switch (x6) { case 0x30: inst->mnemo = IA64_INST_ST1_UPDATE; break; case 0x31: inst->mnemo = IA64_INST_ST2_UPDATE; break; case 0x32: inst->mnemo = IA64_INST_ST4_UPDATE; break; case 0x33: inst->mnemo = IA64_INST_ST8_UPDATE; break; } return true; } return false; } // Decode group 8 instructions (ALU integer) static bool ia64_decode_instruction_8(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT) { const int r1 = (inst->inst >> 6) & 0x7f; const int r2 = (inst->inst >> 13) & 0x7f; const int r3 = (inst->inst >> 20) & 0x7f; const int x2a = (inst->inst >> 34) & 0x3; const int x2b = (inst->inst >> 27) & 0x3; const int x4 = (inst->inst >> 29) & 0xf; const int ve = (inst->inst >> 33) & 0x1; // destination register (r1) is always valid in this group inst->operands[0].valid = true; inst->operands[0].index = r1; // source register (r3) is always valid in this group inst->operands[2].valid = true; inst->operands[2].index = r3; inst->operands[2].value = IA64_GET_GR(r3); inst->operands[2].nat = IA64_GET_NAT(r3); if (x2a == 0 && ve == 0) { inst->operands[1].valid = true; inst->operands[1].index = r2; inst->operands[1].value = IA64_GET_GR(r2); inst->operands[1].nat = IA64_GET_NAT(r2); switch (x4) { case 0x0: // add (A1) inst->mnemo = IA64_INST_ADD; inst->operands[3].valid = true; inst->operands[3].index = -1; inst->operands[3].value = x2b == 1; return true; case 0x1: // add (A1) inst->mnemo = IA64_INST_SUB; inst->operands[3].valid = true; inst->operands[3].index = -1; inst->operands[3].value = x2b == 0; return true; case 0x4: // shladd (A2) inst->mnemo = IA64_INST_SHLADD; inst->operands[3].valid = true; inst->operands[3].index = -1; inst->operands[3].value = ia64_inst_get_count2(inst->inst); return true; case 0x9: if (x2b == 1) { inst->mnemo = IA64_INST_SUB; inst->operands[1].index = -1; inst->operands[1].value = ia64_inst_get_imm8(inst->inst); inst->operands[1].nat = 0; return true; } break; case 0xb: inst->operands[1].index = -1; inst->operands[1].value = ia64_inst_get_imm8(inst->inst); inst->operands[1].nat = 0; // fall-through case 0x3: switch (x2b) { case 0: inst->mnemo = IA64_INST_AND; break; case 1: inst->mnemo = IA64_INST_ANDCM; break; case 2: inst->mnemo = IA64_INST_OR; break; case 3: inst->mnemo = IA64_INST_XOR; break; } return true; } } return false; } // Decode instruction static bool ia64_decode_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT) { const int major = (inst->inst >> 37) & 0xf; inst->mnemo = IA64_INST_UNKNOWN; inst->pred = inst->inst & 0x3f; memset(&inst->operands[0], 0, sizeof(inst->operands)); switch (major) { case 0x0: return ia64_decode_instruction_0(inst, IA64_CONTEXT); case 0x4: return ia64_decode_instruction_4(inst, IA64_CONTEXT); case 0x5: return ia64_decode_instruction_5(inst, IA64_CONTEXT); case 0x8: return ia64_decode_instruction_8(inst, IA64_CONTEXT); } return false; } static bool ia64_emulate_instruction(ia64_instruction_t *inst, IA64_CONTEXT_TYPE IA64_CONTEXT) { // XXX: handle Register NaT Consumption fault? // XXX: this simple emulator assumes instructions in a bundle // don't depend on effects of other instructions in the same // bundle. It probably would be simpler to JIT-generate code to be // executed natively but probably more costly (inject/extract CPU state) if (inst->mnemo == IA64_INST_UNKNOWN) return false; if (inst->pred && !IA64_GET_PR(inst->pred)) return true; uint8_t nat, nat2; uint64_t dst, dst2, src1, src2, src3; switch (inst->mnemo) { case IA64_INST_NOP: break; case IA64_INST_ADD: case IA64_INST_SUB: case IA64_INST_SHLADD: src3 = inst->operands[3].value; // fall-through case IA64_INST_AND: case IA64_INST_ANDCM: case IA64_INST_OR: case IA64_INST_XOR: src1 = inst->operands[1].value; src2 = inst->operands[2].value; switch (inst->mnemo) { case IA64_INST_ADD: dst = src1 + src2 + src3; break; case IA64_INST_SUB: dst = src1 - src2 - src3; break; case IA64_INST_SHLADD: dst = (src1 << src3) + src2; break; case IA64_INST_AND: dst = src1 & src2; break; case IA64_INST_ANDCM: dst = src1 &~ src2; break; case IA64_INST_OR: dst = src1 | src2; break; case IA64_INST_XOR: dst = src1 ^ src2; break; } inst->operands[0].commit = true; inst->operands[0].value = dst; inst->operands[0].nat = inst->operands[1].nat | inst->operands[2].nat; break; case IA64_INST_SXT1: case IA64_INST_SXT2: case IA64_INST_SXT4: case IA64_INST_ZXT1: case IA64_INST_ZXT2: case IA64_INST_ZXT4: src1 = inst->operands[1].value; switch (inst->mnemo) { case IA64_INST_SXT1: dst = (int64_t)(int8_t)src1; break; case IA64_INST_SXT2: dst = (int64_t)(int16_t)src1; break; case IA64_INST_SXT4: dst = (int64_t)(int32_t)src1; break; case IA64_INST_ZXT1: dst = (uint8_t)src1; break; case IA64_INST_ZXT2: dst = (uint16_t)src1; break; case IA64_INST_ZXT4: dst = (uint32_t)src1; break; } inst->operands[0].commit = true; inst->operands[0].value = dst; inst->operands[0].nat = inst->operands[1].nat; break; case IA64_INST_LD1_UPDATE: case IA64_INST_LD2_UPDATE: case IA64_INST_LD4_UPDATE: case IA64_INST_LD8_UPDATE: inst->operands[1].commit = true; dst2 = inst->operands[1].value + inst->operands[2].value; nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0; // fall-through case IA64_INST_LD1: case IA64_INST_LD2: case IA64_INST_LD4: case IA64_INST_LD8: src1 = inst->operands[1].value; if (inst->no_memory) dst = 0; else { switch (inst->mnemo) { case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: dst = *((uint8_t *)src1); break; case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: dst = *((uint16_t *)src1); break; case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: dst = *((uint32_t *)src1); break; case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: dst = *((uint64_t *)src1); break; } } inst->operands[0].commit = true; inst->operands[0].value = dst; inst->operands[0].nat = 0; inst->operands[1].value = dst2; inst->operands[1].nat = nat2; break; case IA64_INST_ST1_UPDATE: case IA64_INST_ST2_UPDATE: case IA64_INST_ST4_UPDATE: case IA64_INST_ST8_UPDATE: inst->operands[0].commit = 0; dst2 = inst->operands[0].value + inst->operands[2].value; nat2 = inst->operands[2].nat ? inst->operands[2].nat : 0; // fall-through case IA64_INST_ST1: case IA64_INST_ST2: case IA64_INST_ST4: case IA64_INST_ST8: dst = inst->operands[0].value; src1 = inst->operands[1].value; if (!inst->no_memory) { switch (inst->mnemo) { case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: *((uint8_t *)dst) = src1; break; case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: *((uint16_t *)dst) = src1; break; case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: *((uint32_t *)dst) = src1; break; case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: *((uint64_t *)dst) = src1; break; } } inst->operands[0].value = dst2; inst->operands[0].nat = nat2; break; default: return false; } for (int i = 0; i < IA64_N_OPERANDS; i++) { ia64_operand_t const & op = inst->operands[i]; if (!op.commit) continue; if (op.index == -1) return false; // XXX: internal error IA64_SET_GR(op.index, op.value, op.nat); } return true; } static bool ia64_emulate_instruction(uint64_t raw_inst, IA64_CONTEXT_TYPE IA64_CONTEXT) { ia64_instruction_t inst; memset(&inst, 0, sizeof(inst)); inst.inst = raw_inst; if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) return false; return ia64_emulate_instruction(&inst, IA64_CONTEXT); } static bool ia64_skip_instruction(IA64_CONTEXT_TYPE IA64_CONTEXT) { uint64_t ip = IA64_GET_IP(); #if DEBUG printf("IP: 0x%016llx\n", ip); #if 0 printf(" Template 0x%02x\n", ia64_get_template(ip)); ia64_get_instruction(ip, 0); ia64_get_instruction(ip, 1); ia64_get_instruction(ip, 2); #endif #endif // Select which decode switch to use ia64_instruction_t inst; inst.inst = ia64_get_instruction(ip, ip & 3); if (!ia64_decode_instruction(&inst, IA64_CONTEXT)) { fprintf(stderr, "ERROR: ia64_skip_instruction(): could not decode instruction\n"); return false; } transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; transfer_size_t transfer_size = SIZE_UNKNOWN; switch (inst.mnemo) { case IA64_INST_LD1: case IA64_INST_LD2: case IA64_INST_LD4: case IA64_INST_LD8: case IA64_INST_LD1_UPDATE: case IA64_INST_LD2_UPDATE: case IA64_INST_LD4_UPDATE: case IA64_INST_LD8_UPDATE: transfer_type = SIGSEGV_TRANSFER_LOAD; break; case IA64_INST_ST1: case IA64_INST_ST2: case IA64_INST_ST4: case IA64_INST_ST8: case IA64_INST_ST1_UPDATE: case IA64_INST_ST2_UPDATE: case IA64_INST_ST4_UPDATE: case IA64_INST_ST8_UPDATE: transfer_type = SIGSEGV_TRANSFER_STORE; break; } if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) { // Unknown machine code, let it crash. Then patch the decoder fprintf(stderr, "ERROR: ia64_skip_instruction(): not a load/store instruction\n"); return false; } switch (inst.mnemo) { case IA64_INST_LD1: case IA64_INST_LD1_UPDATE: case IA64_INST_ST1: case IA64_INST_ST1_UPDATE: transfer_size = SIZE_BYTE; break; case IA64_INST_LD2: case IA64_INST_LD2_UPDATE: case IA64_INST_ST2: case IA64_INST_ST2_UPDATE: transfer_size = SIZE_WORD; break; case IA64_INST_LD4: case IA64_INST_LD4_UPDATE: case IA64_INST_ST4: case IA64_INST_ST4_UPDATE: transfer_size = SIZE_LONG; break; case IA64_INST_LD8: case IA64_INST_LD8_UPDATE: case IA64_INST_ST8: case IA64_INST_ST8_UPDATE: transfer_size = SIZE_QUAD; break; } if (transfer_size == SIZE_UNKNOWN) { // Unknown machine code, let it crash. Then patch the decoder fprintf(stderr, "ERROR: ia64_skip_instruction(): unknown transfer size\n"); return false; } inst.no_memory = true; if (!ia64_emulate_instruction(&inst, IA64_CONTEXT)) { fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate fault instruction\n"); return false; } int slot = ip & 3; bool emulate_next = false; switch (slot) { case 0: switch (ia64_get_template(ip)) { case 0x2: // MI;I case 0x3: // MI;I; emulate_next = true; slot = 2; break; case 0xa: // M;MI case 0xb: // M;MI; emulate_next = true; slot = 1; break; } break; } if (emulate_next && !IA64_CAN_PATCH_IP_SLOT) { while (slot < 3) { if (!ia64_emulate_instruction(ia64_get_instruction(ip, slot), IA64_CONTEXT)) { fprintf(stderr, "ERROR: ia64_skip_instruction(): could not emulate instruction\n"); return false; } ++slot; } } #if IA64_CAN_PATCH_IP_SLOT if ((slot = ip & 3) < 2) IA64_SET_IP((ip & ~3ull) + (slot + 1)); else #endif IA64_SET_IP((ip & ~3ull) + 16); #if DEBUG printf("IP: 0x%016llx\n", IA64_GET_IP()); #endif return true; } #endif // Decode and skip PPC instruction #if (defined(powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__)) static bool powerpc_skip_instruction(unsigned long * nip_p, unsigned long * regs) { instruction_t instr; powerpc_decode_instruction(&instr, *nip_p, regs); if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) { // Unknown machine code, let it crash. Then patch the decoder return false; } #if DEBUG printf("%08x: %s %s access", *nip_p, instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : instr.transfer_size == SIZE_LONG ? "long" : "quad", instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write"); if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX) printf(" r%d (ra = %08x)\n", instr.ra, instr.addr); if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD) printf(" r%d (rd = 0)\n", instr.rd); #endif if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX) regs[instr.ra] = instr.addr; if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD) regs[instr.rd] = 0; *nip_p += 4; return true; } #endif // Decode and skip MIPS instruction #if (defined(mips) || defined(__mips)) static bool mips_skip_instruction(greg_t * pc_p, greg_t * regs) { unsigned int * epc = (unsigned int *)(unsigned long)*pc_p; if (epc == 0) return false; #if DEBUG printf("IP: %p [%08x]\n", epc, epc[0]); #endif transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; transfer_size_t transfer_size = SIZE_LONG; int direction = 0; const unsigned int opcode = epc[0]; switch (opcode >> 26) { case 32: // Load Byte case 36: // Load Byte Unsigned transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; break; case 33: // Load Halfword case 37: // Load Halfword Unsigned transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; break; case 35: // Load Word case 39: // Load Word Unsigned transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; break; case 34: // Load Word Left transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; direction = -1; break; case 38: // Load Word Right transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; direction = 1; break; case 55: // Load Doubleword transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_QUAD; break; case 26: // Load Doubleword Left transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_QUAD; direction = -1; break; case 27: // Load Doubleword Right transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_QUAD; direction = 1; break; case 40: // Store Byte transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; break; case 41: // Store Halfword transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; break; case 43: // Store Word case 42: // Store Word Left case 46: // Store Word Right transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; break; case 63: // Store Doubleword case 44: // Store Doubleword Left case 45: // Store Doubleword Right transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_QUAD; break; /* Misc instructions unlikely to be used within CPU emulators */ case 48: // Load Linked Word transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; break; case 52: // Load Linked Doubleword transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_QUAD; break; case 56: // Store Conditional Word transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; break; case 60: // Store Conditional Doubleword transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_QUAD; break; } if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) { // Unknown machine code, let it crash. Then patch the decoder return false; } // Zero target register in case of a load operation const int reg = (opcode >> 16) & 0x1f; if (transfer_type == SIGSEGV_TRANSFER_LOAD) { if (direction == 0) regs[reg] = 0; else { // FIXME: untested code unsigned long ea = regs[(opcode >> 21) & 0x1f]; ea += (signed long)(signed int)(signed short)(opcode & 0xffff); const int offset = ea & (transfer_size == SIZE_LONG ? 3 : 7); unsigned long value; if (direction > 0) { const unsigned long rmask = ~((1L << ((offset + 1) * 8)) - 1); value = regs[reg] & rmask; } else { const unsigned long lmask = (1L << (offset * 8)) - 1; value = regs[reg] & lmask; } // restore most significant bits if (transfer_size == SIZE_LONG) value = (signed long)(signed int)value; regs[reg] = value; } } #if DEBUG #if (defined(_ABIN32) || defined(_ABI64)) static const char * mips_gpr_names[32] = { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" }; #else static const char * mips_gpr_names[32] = { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra" }; #endif printf("%s %s register %s\n", transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : transfer_size == SIZE_LONG ? "long" : transfer_size == SIZE_QUAD ? "quad" : "unknown", transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from", mips_gpr_names[reg]); #endif *pc_p += 4; return true; } #endif // Decode and skip SPARC instruction #if (defined(sparc) || defined(__sparc__)) enum { #if (defined(__sun__)) SPARC_REG_G1 = REG_G1, SPARC_REG_O0 = REG_O0, SPARC_REG_PC = REG_PC, SPARC_REG_nPC = REG_nPC #endif }; static bool sparc_skip_instruction(unsigned long * regs, gwindows_t * gwins, struct rwindow * rwin) { unsigned int * pc = (unsigned int *)regs[SPARC_REG_PC]; if (pc == 0) return false; #if DEBUG printf("IP: %p [%08x]\n", pc, pc[0]); #endif transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; transfer_size_t transfer_size = SIZE_LONG; bool register_pair = false; const unsigned int opcode = pc[0]; if ((opcode >> 30) != 3) return false; switch ((opcode >> 19) & 0x3f) { case 9: // Load Signed Byte case 1: // Load Unsigned Byte transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; break; case 10:// Load Signed Halfword case 2: // Load Unsigned Word transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; break; case 8: // Load Word case 0: // Load Unsigned Word transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; break; case 11:// Load Extended Word transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_QUAD; break; case 3: // Load Doubleword transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; register_pair = true; break; case 5: // Store Byte transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; break; case 6: // Store Halfword transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; break; case 4: // Store Word transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; break; case 14:// Store Extended Word transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_QUAD; break; case 7: // Store Doubleword transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; register_pair = true; break; } if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) { // Unknown machine code, let it crash. Then patch the decoder return false; } const int reg = (opcode >> 25) & 0x1f; #if DEBUG static const char * reg_names[] = { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7" }; printf("%s %s register %s\n", transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : transfer_size == SIZE_LONG ? "long" : transfer_size == SIZE_QUAD ? "quad" : "unknown", transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from", reg_names[reg]); #endif // Zero target register in case of a load operation if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != 0) { // FIXME: code to handle local & input registers is not tested if (reg >= 1 && reg < 8) { // global registers regs[reg - 1 + SPARC_REG_G1] = 0; } else if (reg >= 8 && reg < 16) { // output registers regs[reg - 8 + SPARC_REG_O0] = 0; } else if (reg >= 16 && reg < 24) { // local registers (in register windows) if (gwins) gwins->wbuf->rw_local[reg - 16] = 0; else rwin->rw_local[reg - 16] = 0; } else { // input registers (in register windows) if (gwins) gwins->wbuf->rw_in[reg - 24] = 0; else rwin->rw_in[reg - 24] = 0; } } regs[SPARC_REG_PC] += 4; regs[SPARC_REG_nPC] += 4; return true; } #endif #endif // Decode and skip ARM instruction #if (defined(arm) || defined(__arm__)) enum { #if (defined(__linux__)) ARM_REG_PC = 15, ARM_REG_CPSR = 16 #endif }; static bool arm_skip_instruction(unsigned long * regs) { unsigned int * pc = (unsigned int *)regs[ARM_REG_PC]; if (pc == 0) return false; #if DEBUG printf("IP: %p [%08x]\n", pc, pc[0]); #endif transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN; transfer_size_t transfer_size = SIZE_UNKNOWN; enum { op_sdt = 1, op_sdth = 2 }; int op = 0; // Handle load/store instructions only const unsigned int opcode = pc[0]; switch ((opcode >> 25) & 7) { case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH) op = op_sdth; // Determine transfer size (S/H bits) switch ((opcode >> 5) & 3) { case 0: // SWP instruction break; case 1: // Unsigned halfwords case 3: // Signed halfwords transfer_size = SIZE_WORD; break; case 2: // Signed byte transfer_size = SIZE_BYTE; break; } break; case 2: case 3: // Single Data Transfer (LDR, STR) op = op_sdt; // Determine transfer size (B bit) if (((opcode >> 22) & 1) == 1) transfer_size = SIZE_BYTE; else transfer_size = SIZE_LONG; break; default: // FIXME: support load/store mutliple? return false; } // Check for invalid transfer size (SWP instruction?) if (transfer_size == SIZE_UNKNOWN) return false; // Determine transfer type (L bit) if (((opcode >> 20) & 1) == 1) transfer_type = SIGSEGV_TRANSFER_LOAD; else transfer_type = SIGSEGV_TRANSFER_STORE; // Compute offset int offset; if (((opcode >> 25) & 1) == 0) { if (op == op_sdt) offset = opcode & 0xfff; else if (op == op_sdth) { int rm = opcode & 0xf; if (((opcode >> 22) & 1) == 0) { // register offset offset = regs[rm]; } else { // immediate offset offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f); } } } else { const int rm = opcode & 0xf; const int sh = (opcode >> 7) & 0x1f; if (((opcode >> 4) & 1) == 1) { // we expect only legal load/store instructions printf("FATAL: invalid shift operand\n"); return false; } const unsigned int v = regs[rm]; switch ((opcode >> 5) & 3) { case 0: // logical shift left offset = sh ? v << sh : v; break; case 1: // logical shift right offset = sh ? v >> sh : 0; break; case 2: // arithmetic shift right if (sh) offset = ((signed int)v) >> sh; else offset = (v & 0x80000000) ? 0xffffffff : 0; break; case 3: // rotate right if (sh) offset = (v >> sh) | (v << (32 - sh)); else offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000); break; } } if (((opcode >> 23) & 1) == 0) offset = -offset; int rd = (opcode >> 12) & 0xf; int rn = (opcode >> 16) & 0xf; #if DEBUG static const char * reg_names[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }; printf("%s %s register %s\n", transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : transfer_size == SIZE_LONG ? "long" : "unknown", transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from", reg_names[rd]); #endif unsigned int base = regs[rn]; if (((opcode >> 24) & 1) == 1) base += offset; if (transfer_type == SIGSEGV_TRANSFER_LOAD) regs[rd] = 0; if (((opcode >> 24) & 1) == 0) // post-index addressing regs[rn] += offset; else if (((opcode >> 21) & 1) == 1) // write-back address into base regs[rn] = base; regs[ARM_REG_PC] += 4; return true; } #endif // Fallbacks #ifndef SIGSEGV_FAULT_ADDRESS_FAST #define SIGSEGV_FAULT_ADDRESS_FAST SIGSEGV_FAULT_ADDRESS #endif #ifndef SIGSEGV_FAULT_INSTRUCTION_FAST #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_FAULT_INSTRUCTION #endif #ifndef SIGSEGV_FAULT_INSTRUCTION #define SIGSEGV_FAULT_INSTRUCTION SIGSEGV_INVALID_ADDRESS #endif #ifndef SIGSEGV_FAULT_HANDLER_ARGLIST_1 #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 SIGSEGV_FAULT_HANDLER_ARGLIST #endif #ifndef SIGSEGV_FAULT_HANDLER_INVOKE #define SIGSEGV_FAULT_HANDLER_INVOKE(P) sigsegv_fault_handler(P) #endif // SIGSEGV recovery supported ? #if defined(SIGSEGV_ALL_SIGNALS) && defined(SIGSEGV_FAULT_HANDLER_ARGLIST) && defined(SIGSEGV_FAULT_ADDRESS) #define HAVE_SIGSEGV_RECOVERY #endif /* * SIGSEGV global handler */ #ifdef HAVE_MACH_EXCEPTIONS static void mach_get_exception_state(sigsegv_info_t *SIP) { SIP->exc_state_count = SIGSEGV_EXCEPTION_STATE_COUNT; kern_return_t krc = thread_get_state(SIP->thread, SIGSEGV_EXCEPTION_STATE_FLAVOR, (natural_t *)&SIP->exc_state, &SIP->exc_state_count); MACH_CHECK_ERROR(thread_get_state, krc); SIP->has_exc_state = true; } static void mach_get_thread_state(sigsegv_info_t *SIP) { SIP->thr_state_count = SIGSEGV_THREAD_STATE_COUNT; kern_return_t krc = thread_get_state(SIP->thread, SIGSEGV_THREAD_STATE_FLAVOR, (natural_t *)&SIP->thr_state, &SIP->thr_state_count); MACH_CHECK_ERROR(thread_get_state, krc); SIP->has_thr_state = true; } static void mach_set_thread_state(sigsegv_info_t *SIP) { kern_return_t krc = thread_set_state(SIP->thread, SIGSEGV_THREAD_STATE_FLAVOR, (natural_t *)&SIP->thr_state, SIP->thr_state_count); MACH_CHECK_ERROR(thread_set_state, krc); } #endif // Return the address of the invalid memory reference sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *SIP) { #ifdef HAVE_MACH_EXCEPTIONS #ifdef EMULATED_PPC static int use_fast_path = -1; if (use_fast_path != 1 && !SIP->has_exc_state) { mach_get_exception_state(SIP); sigsegv_address_t addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS; if (use_fast_path < 0) { const char *machfault = getenv("SIGSEGV_MACH_FAULT"); if (machfault) { if (strcmp(machfault, "fast") == 0) use_fast_path = 1; else if (strcmp(machfault, "slow") == 0) use_fast_path = 0; } if (use_fast_path < 0) use_fast_path = addr == SIP->addr; } SIP->addr = addr; } #endif #endif return SIP->addr; } // Return the address of the instruction that caused the fault, or // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *SIP) { #ifdef HAVE_MACH_EXCEPTIONS #ifdef EMULATED_PPC if (!SIP->has_thr_state) { mach_get_thread_state(SIP); SIP->pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION; } #endif #endif return SIP->pc; } // This function handles the badaccess to memory. // It is called from the signal handler or the exception handler. static bool handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGLIST_1) { sigsegv_info_t SI; SI.addr = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS_FAST; SI.pc = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION_FAST; #ifdef HAVE_MACH_EXCEPTIONS SI.thread = thread; SI.has_exc_state = false; SI.has_thr_state = false; #endif sigsegv_info_t * const SIP = &SI; // Call user's handler and reinstall the global handler, if required switch (SIGSEGV_FAULT_HANDLER_INVOKE(SIP)) { case SIGSEGV_RETURN_SUCCESS: return true; #if HAVE_SIGSEGV_SKIP_INSTRUCTION case SIGSEGV_RETURN_SKIP_INSTRUCTION: // Call the instruction skipper with the register file // available #ifdef HAVE_MACH_EXCEPTIONS if (!SIP->has_thr_state) mach_get_thread_state(SIP); #endif if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE)) { #ifdef HAVE_MACH_EXCEPTIONS // Unlike UNIX signals where the thread state // is modified off of the stack, in Mach we // need to actually call thread_set_state to // have the register values updated. mach_set_thread_state(SIP); #endif return true; } break; #endif case SIGSEGV_RETURN_FAILURE: // We can't do anything with the fault_address, dump state? if (sigsegv_state_dumper != 0) sigsegv_state_dumper(SIP); break; } return false; } /* * There are two mechanisms for handling a bad memory access, * Mach exceptions and UNIX signals. The implementation specific * code appears below. Its reponsibility is to call handle_badaccess * which is the routine that handles the fault in an implementation * agnostic manner. The implementation specific code below is then * reponsible for checking whether handle_badaccess was able * to handle the memory access error and perform any implementation * specific tasks necessary afterwards. */ #ifdef HAVE_MACH_EXCEPTIONS /* * We need to forward all exceptions that we do not handle. * This is important, there are many exceptions that may be * handled by other exception handlers. For example debuggers * use exceptions and the exception hander is in another * process in such a case. (Timothy J. Wood states in his * message to the list that he based this code on that from * gdb for Darwin.) */ static inline kern_return_t forward_exception(mach_port_t thread_port, mach_port_t task_port, exception_type_t exception_type, mach_exception_data_t exception_data, mach_msg_type_number_t data_count, ExceptionPorts *oldExceptionPorts) { kern_return_t kret; unsigned int portIndex; mach_port_t port; exception_behavior_t behavior; thread_state_flavor_t flavor; thread_state_data_t thread_state; mach_msg_type_number_t thread_state_count; for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) { if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) { // This handler wants the exception break; } } if (portIndex >= oldExceptionPorts->maskCount) { fprintf(stderr, "No handler for exception_type = %d. Not fowarding\n", exception_type); return KERN_FAILURE; } port = oldExceptionPorts->handlers[portIndex]; behavior = oldExceptionPorts->behaviors[portIndex]; flavor = oldExceptionPorts->flavors[portIndex]; if (!VALID_THREAD_STATE_FLAVOR(flavor)) { fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor); return KERN_FAILURE; } /* fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor); */ if (behavior != EXCEPTION_DEFAULT) { thread_state_count = THREAD_STATE_MAX; kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state, &thread_state_count); MACH_CHECK_ERROR (thread_get_state, kret); } switch (behavior) { case EXCEPTION_DEFAULT: // fprintf(stderr, "forwarding to exception_raise\n"); kret = mach_exception_raise(port, thread_port, task_port, exception_type, exception_data, data_count); MACH_CHECK_ERROR (mach_exception_raise, kret); break; case EXCEPTION_STATE: // fprintf(stderr, "forwarding to exception_raise_state\n"); kret = mach_exception_raise_state(port, exception_type, exception_data, data_count, &flavor, (natural_t *)&thread_state, thread_state_count, (natural_t *)&thread_state, &thread_state_count); MACH_CHECK_ERROR (mach_exception_raise_state, kret); break; case EXCEPTION_STATE_IDENTITY: // fprintf(stderr, "forwarding to exception_raise_state_identity\n"); kret = mach_exception_raise_state_identity(port, thread_port, task_port, exception_type, exception_data, data_count, &flavor, (natural_t *)&thread_state, thread_state_count, (natural_t *)&thread_state, &thread_state_count); MACH_CHECK_ERROR (mach_exception_raise_state_identity, kret); break; default: fprintf(stderr, "forward_exception got unknown behavior\n"); kret = KERN_FAILURE; break; } if (behavior != EXCEPTION_DEFAULT) { kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state, thread_state_count); MACH_CHECK_ERROR (thread_set_state, kret); } return kret; } /* * This is the code that actually handles the exception. * It is called by exc_server. For Darwin 5 Apple changed * this a bit from how this family of functions worked in * Mach. If you are familiar with that it is a little * different. The main variation that concerns us here is * that code is an array of exception specific codes and * codeCount is a count of the number of codes in the code * array. In typical Mach all exceptions have a code * and sub-code. It happens to be the case that for a * EXC_BAD_ACCESS exception the first entry is the type of * bad access that occurred and the second entry is the * faulting address so these entries correspond exactly to * how the code and sub-code are used on Mach. * * This is a MIG interface. No code in Basilisk II should * call this directley. This has to have external C * linkage because that is what exc_server expects. */ kern_return_t catch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, mach_port_t task, exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t code_count) { kern_return_t krc; if (exception == EXC_BAD_ACCESS) { switch (code[0]) { case KERN_PROTECTION_FAILURE: case KERN_INVALID_ADDRESS: if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) return KERN_SUCCESS; break; } } // In Mach we do not need to remove the exception handler. // If we forward the exception, eventually some exception handler // will take care of this exception. krc = forward_exception(thread, task, exception, code, code_count, &ports); return krc; } /* XXX: borrowed from launchd and gdb */ kern_return_t catch_mach_exception_raise_state(mach_port_t exception_port, exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t code_count, int *flavor, thread_state_t old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t *new_state_count) { memcpy(new_state, old_state, old_state_count * sizeof(old_state[0])); *new_state_count = old_state_count; return KERN_SUCCESS; } /* XXX: borrowed from launchd and gdb */ kern_return_t catch_mach_exception_raise_state_identity(mach_port_t exception_port, mach_port_t thread_port, mach_port_t task_port, exception_type_t exception, mach_exception_data_t code, mach_msg_type_number_t code_count, int *flavor, thread_state_t old_state, mach_msg_type_number_t old_state_count, thread_state_t new_state, mach_msg_type_number_t *new_state_count) { kern_return_t kret; memcpy(new_state, old_state, old_state_count * sizeof(old_state[0])); *new_state_count = old_state_count; kret = mach_port_deallocate(mach_task_self(), task_port); MACH_CHECK_ERROR(mach_port_deallocate, kret); kret = mach_port_deallocate(mach_task_self(), thread_port); MACH_CHECK_ERROR(mach_port_deallocate, kret); return KERN_SUCCESS; } #endif #ifdef HAVE_SIGSEGV_RECOVERY // Handle bad memory accesses with signal handler static void sigsegv_handler(SIGSEGV_FAULT_HANDLER_ARGLIST) { // Call handler and reinstall the global handler, if required if (handle_badaccess(SIGSEGV_FAULT_HANDLER_ARGS)) { #if (defined(HAVE_SIGACTION) ? defined(SIGACTION_NEED_REINSTALL) : defined(SIGNAL_NEED_REINSTALL)) sigsegv_do_install_handler(sig); #endif return; } // Failure: reinstall default handler for "safe" crash #define FAULT_HANDLER(sig) signal(sig, SIG_DFL); SIGSEGV_ALL_SIGNALS #undef FAULT_HANDLER } #endif /* * SIGSEGV handler initialization */ #if defined(HAVE_SIGINFO_T) static bool sigsegv_do_install_handler(int sig) { // Setup SIGSEGV handler to process writes to frame buffer #ifdef HAVE_SIGACTION struct sigaction sigsegv_sa; sigemptyset(&sigsegv_sa.sa_mask); sigsegv_sa.sa_sigaction = sigsegv_handler; sigsegv_sa.sa_flags = SA_SIGINFO; return (sigaction(sig, &sigsegv_sa, 0) == 0); #else return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR); #endif } #endif #if defined(HAVE_SIGCONTEXT_SUBTERFUGE) static bool sigsegv_do_install_handler(int sig) { // Setup SIGSEGV handler to process writes to frame buffer #ifdef HAVE_SIGACTION struct sigaction sigsegv_sa; sigemptyset(&sigsegv_sa.sa_mask); sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler; sigsegv_sa.sa_flags = 0; #if !EMULATED_68K && defined(__NetBSD__) sigaddset(&sigsegv_sa.sa_mask, SIGALRM); sigsegv_sa.sa_flags |= SA_ONSTACK; #endif return (sigaction(sig, &sigsegv_sa, 0) == 0); #else return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR); #endif } #endif #if defined(HAVE_MACH_EXCEPTIONS) static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler) { /* * Except for the exception port functions, this should be * pretty much stock Mach. If later you choose to support * other Mach's besides Darwin, just check for __MACH__ * here and __APPLE__ where the actual differences are. */ #if defined(__APPLE__) && defined(__MACH__) if (sigsegv_fault_handler != NULL) { sigsegv_fault_handler = handler; return true; } kern_return_t krc; // create the the exception port krc = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &_exceptionPort); if (krc != KERN_SUCCESS) { mach_error("mach_port_allocate", krc); return false; } // add a port send right krc = mach_port_insert_right(mach_task_self(), _exceptionPort, _exceptionPort, MACH_MSG_TYPE_MAKE_SEND); if (krc != KERN_SUCCESS) { mach_error("mach_port_insert_right", krc); return false; } // get the old exception ports ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]); krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks, &ports.maskCount, ports.handlers, ports.behaviors, ports.flavors); if (krc != KERN_SUCCESS) { mach_error("thread_get_exception_ports", krc); return false; } // set the new exception port // // We could have used EXCEPTION_STATE_IDENTITY instead of // EXCEPTION_DEFAULT to get the thread state in the initial // message, but it turns out that in the common case this is not // neccessary. If we need it we can later ask for it from the // suspended thread. // // Even with THREAD_STATE_NONE, Darwin provides the program // counter in the thread state. The comments in the header file // seem to imply that you can count on the GPR's on an exception // as well but just to be safe I use MACHINE_THREAD_STATE because // you have to ask for all of the GPR's anyway just to get the // program counter. In any case because of update effective // address from immediate and update address from effective // addresses of ra and rb modes (as good an name as any for these // addressing modes) used in PPC instructions, you will need the // GPR state anyway. krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, SIGSEGV_THREAD_STATE_FLAVOR); if (krc != KERN_SUCCESS) { mach_error("thread_set_exception_ports", krc); return false; } // create the exception handler thread if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) { (void)fprintf(stderr, "creation of exception thread failed\n"); return false; } // do not care about the exception thread any longer, let is run standalone (void)pthread_detach(exc_thread); sigsegv_fault_handler = handler; return true; #else return false; #endif } #endif #ifdef HAVE_WIN32_EXCEPTIONS static LONG WINAPI main_exception_filter(EXCEPTION_POINTERS *ExceptionInfo) { if (sigsegv_fault_handler != NULL && ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && ExceptionInfo->ExceptionRecord->NumberParameters >= 2 && handle_badaccess(ExceptionInfo)) return EXCEPTION_CONTINUE_EXECUTION; return EXCEPTION_CONTINUE_SEARCH; } #if defined __CYGWIN__ && defined __i386__ /* In Cygwin programs, SetUnhandledExceptionFilter has no effect because Cygwin installs a global exception handler. We have to dig deep in order to install our main_exception_filter. */ /* Data structures for the current thread's exception handler chain. On the x86 Windows uses register fs, offset 0 to point to the current exception handler; Cygwin mucks with it, so we must do the same... :-/ */ /* Magic taken from winsup/cygwin/include/exceptions.h. */ struct exception_list { struct exception_list *prev; int (*handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *); }; typedef struct exception_list exception_list; /* Magic taken from winsup/cygwin/exceptions.cc. */ __asm__ (".equ __except_list,0"); extern exception_list *_except_list __asm__ ("%fs:__except_list"); /* For debugging. _except_list is not otherwise accessible from gdb. */ static exception_list * debug_get_except_list () { return _except_list; } /* Cygwin's original exception handler. */ static int (*cygwin_exception_handler) (EXCEPTION_RECORD *, void *, CONTEXT *, void *); /* Our exception handler. */ static int libsigsegv_exception_handler (EXCEPTION_RECORD *exception, void *frame, CONTEXT *context, void *dispatch) { EXCEPTION_POINTERS ExceptionInfo; ExceptionInfo.ExceptionRecord = exception; ExceptionInfo.ContextRecord = context; if (main_exception_filter (&ExceptionInfo) == EXCEPTION_CONTINUE_SEARCH) return cygwin_exception_handler (exception, frame, context, dispatch); else return 0; } static void do_install_main_exception_filter () { /* We cannot insert any handler into the chain, because such handlers must lie on the stack (?). Instead, we have to replace(!) Cygwin's global exception handler. */ cygwin_exception_handler = _except_list->handler; _except_list->handler = libsigsegv_exception_handler; } #else static void do_install_main_exception_filter () { SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) &main_exception_filter); } #endif static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler) { static bool main_exception_filter_installed = false; if (!main_exception_filter_installed) { do_install_main_exception_filter(); main_exception_filter_installed = true; } sigsegv_fault_handler = handler; return true; } #endif bool sigsegv_install_handler(sigsegv_fault_handler_t handler) { #if defined(HAVE_SIGSEGV_RECOVERY) bool success = true; #define FAULT_HANDLER(sig) success = success && sigsegv_do_install_handler(sig); SIGSEGV_ALL_SIGNALS #undef FAULT_HANDLER if (success) sigsegv_fault_handler = handler; return success; #elif defined(HAVE_MACH_EXCEPTIONS) || defined(HAVE_WIN32_EXCEPTIONS) return sigsegv_do_install_handler(handler); #else // FAIL: no siginfo_t nor sigcontext subterfuge is available return false; #endif } /* * SIGSEGV handler deinitialization */ void sigsegv_deinstall_handler(void) { // We do nothing for Mach exceptions, the thread would need to be // suspended if not already so, and we might mess with other // exception handlers that came after we registered ours. There is // no need to remove the exception handler, in fact this function is // not called anywhere in Basilisk II. #ifdef HAVE_SIGSEGV_RECOVERY sigsegv_fault_handler = 0; #define FAULT_HANDLER(sig) signal(sig, SIG_DFL); SIGSEGV_ALL_SIGNALS #undef FAULT_HANDLER #endif #ifdef HAVE_WIN32_EXCEPTIONS sigsegv_fault_handler = NULL; #endif } /* * Set callback function when we cannot handle the fault */ void sigsegv_set_dump_state(sigsegv_state_dumper_t handler) { sigsegv_state_dumper = handler; } /* * Test program used for configure/test */ #ifdef CONFIGURE_TEST_SIGSEGV_RECOVERY #include #include #include #ifdef HAVE_SYS_MMAN_H #include #endif #include "vm_alloc.h" const int REF_INDEX = 123; const int REF_VALUE = 45; static sigsegv_uintptr_t page_size; static volatile char * page = 0; static volatile int handler_called = 0; /* Barriers */ #ifdef __GNUC__ #define BARRIER() asm volatile ("" : : : "memory") #else #define BARRIER() /* nothing */ #endif #ifdef __GNUC__ // Code range where we expect the fault to come from static void *b_region, *e_region; #endif static sigsegv_return_t sigsegv_test_handler(sigsegv_info_t *sip) { const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip); const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip); #if DEBUG printf("sigsegv_test_handler(%p, %p)\n", fault_address, instruction_address); printf("expected fault at %p\n", page + REF_INDEX); #ifdef __GNUC__ printf("expected instruction address range: %p-%p\n", b_region, e_region); #endif #endif handler_called++; if ((fault_address - REF_INDEX) != page) exit(10); #ifdef __GNUC__ // Make sure reported fault instruction address falls into // expected code range if (instruction_address != SIGSEGV_INVALID_ADDRESS && ((instruction_address < (sigsegv_address_t)b_region) || (instruction_address >= (sigsegv_address_t)e_region))) exit(11); #endif if (vm_protect((char *)((sigsegv_uintptr_t)fault_address & -page_size), page_size, VM_PAGE_READ | VM_PAGE_WRITE) != 0) exit(12); return SIGSEGV_RETURN_SUCCESS; } #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION static sigsegv_return_t sigsegv_insn_handler(sigsegv_info_t *sip) { const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip); const sigsegv_address_t instruction_address = sigsegv_get_fault_instruction_address(sip); #if DEBUG printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address); printf("expected instruction address range: %p-%p\n", b_region, e_region); #endif if (((sigsegv_uintptr_t)fault_address - (sigsegv_uintptr_t)page) < page_size) { #ifdef __GNUC__ // Make sure reported fault instruction address falls into // expected code range if (instruction_address != SIGSEGV_INVALID_ADDRESS && ((instruction_address < (sigsegv_address_t)b_region) || (instruction_address >= (sigsegv_address_t)e_region))) return SIGSEGV_RETURN_FAILURE; #endif return SIGSEGV_RETURN_SKIP_INSTRUCTION; } return SIGSEGV_RETURN_FAILURE; } // More sophisticated tests for instruction skipper static bool arch_insn_skipper_tests() { #if (defined(i386) || defined(__i386__)) || (defined(__x86_64__) || defined(_M_X64)) static const unsigned char code[] = { 0x8a, 0x00, // mov (%eax),%al 0x8a, 0x2c, 0x18, // mov (%eax,%ebx,1),%ch 0x88, 0x20, // mov %ah,(%eax) 0x88, 0x08, // mov %cl,(%eax) 0x66, 0x8b, 0x00, // mov (%eax),%ax 0x66, 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%cx 0x66, 0x89, 0x00, // mov %ax,(%eax) 0x66, 0x89, 0x0c, 0x18, // mov %cx,(%eax,%ebx,1) 0x8b, 0x00, // mov (%eax),%eax 0x8b, 0x0c, 0x18, // mov (%eax,%ebx,1),%ecx 0x89, 0x00, // mov %eax,(%eax) 0x89, 0x0c, 0x18, // mov %ecx,(%eax,%ebx,1) #if defined(__x86_64__) || defined(_M_X64) 0x44, 0x8a, 0x00, // mov (%rax),%r8b 0x44, 0x8a, 0x20, // mov (%rax),%r12b 0x42, 0x8a, 0x3c, 0x10, // mov (%rax,%r10,1),%dil 0x44, 0x88, 0x00, // mov %r8b,(%rax) 0x44, 0x88, 0x20, // mov %r12b,(%rax) 0x42, 0x88, 0x3c, 0x10, // mov %dil,(%rax,%r10,1) 0x66, 0x44, 0x8b, 0x00, // mov (%rax),%r8w 0x66, 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%cx 0x66, 0x44, 0x89, 0x00, // mov %r8w,(%rax) 0x66, 0x42, 0x89, 0x0c, 0x10, // mov %cx,(%rax,%r10,1) 0x44, 0x8b, 0x00, // mov (%rax),%r8d 0x42, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%ecx 0x44, 0x89, 0x00, // mov %r8d,(%rax) 0x42, 0x89, 0x0c, 0x10, // mov %ecx,(%rax,%r10,1) 0x48, 0x8b, 0x08, // mov (%rax),%rcx 0x4c, 0x8b, 0x18, // mov (%rax),%r11 0x4a, 0x8b, 0x0c, 0x10, // mov (%rax,%r10,1),%rcx 0x4e, 0x8b, 0x1c, 0x10, // mov (%rax,%r10,1),%r11 0x48, 0x89, 0x08, // mov %rcx,(%rax) 0x4c, 0x89, 0x18, // mov %r11,(%rax) 0x4a, 0x89, 0x0c, 0x10, // mov %rcx,(%rax,%r10,1) 0x4e, 0x89, 0x1c, 0x10, // mov %r11,(%rax,%r10,1) 0x63, 0x47, 0x04, // movslq 4(%rdi),%eax 0x48, 0x63, 0x47, 0x04, // movslq 4(%rdi),%rax #endif 0 // end }; const int N_REGS = 20; SIGSEGV_REGISTER_TYPE regs[N_REGS]; for (int i = 0; i < N_REGS; i++) regs[i] = i; const sigsegv_uintptr_t start_code = (sigsegv_uintptr_t)&code; regs[X86_REG_EIP] = start_code; while ((regs[X86_REG_EIP] - start_code) < (sizeof(code) - 1) && ix86_skip_instruction(regs)) ; /* simply iterate */ return (regs[X86_REG_EIP] - start_code) == (sizeof(code) - 1); #endif return true; } #endif int main(void) { if (vm_init() < 0) return 1; page_size = vm_get_page_size(); if ((page = (char *)vm_acquire(page_size)) == VM_MAP_FAILED) return 2; memset((void *)page, 0, page_size); if (vm_protect((char *)page, page_size, VM_PAGE_READ) < 0) return 3; if (!sigsegv_install_handler(sigsegv_test_handler)) return 4; #ifdef __GNUC__ b_region = &&L_b_region1; e_region = &&L_e_region1; #endif /* This is a really awful hack but otherwise gcc is smart enough * (or bug'ous enough?) to optimize the labels and place them * e.g. at the "main" entry point, which is wrong. */ volatile int label_hack = 3; switch (label_hack) { case 3: L_b_region1: page[REF_INDEX] = REF_VALUE; if (page[REF_INDEX] != REF_VALUE) exit(20); page[REF_INDEX] = REF_VALUE; BARRIER(); // fall-through case 2: L_e_region1: BARRIER(); break; } if (handler_called != 1) return 5; #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION if (!sigsegv_install_handler(sigsegv_insn_handler)) return 6; if (vm_protect((char *)page, page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0) return 7; for (int i = 0; i < page_size; i++) page[i] = (i + 1) % page_size; if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0) return 8; #define TEST_SKIP_INSTRUCTION(TYPE) do { \ const unsigned long TAG = 0x12345678 | \ (sizeof(long) == 8 ? 0x9abcdef0UL << 31 : 0); \ TYPE data = *((TYPE *)(page + sizeof(TYPE))); \ volatile unsigned long effect = data + TAG; \ if (effect != TAG) \ return 9; \ } while (0) #ifdef __GNUC__ b_region = &&L_b_region2; e_region = &&L_e_region2; #ifdef DEBUG printf("switch footage : \n"); printf(" 4 : %p\n", &&L_b_4_region2); printf(" 5 : %p\n", &&L_b_5_region2); printf(" 8 : %p\n", &&L_b_8_region2); printf(" 6 : %p\n", &&L_b_6_region2); printf(" 7 : %p\n", &&L_b_7_region2); printf(" 9 : %p\n", &&L_b_9_region2); printf(" 1 : %p\n", &&L_b_1_region2); #endif #endif switch (label_hack) { case 3: L_b_region2: TEST_SKIP_INSTRUCTION(unsigned char); BARRIER(); case 4: L_b_4_region2: TEST_SKIP_INSTRUCTION(unsigned short); BARRIER(); case 5: L_b_5_region2: TEST_SKIP_INSTRUCTION(unsigned int); BARRIER(); case 8: L_b_8_region2: TEST_SKIP_INSTRUCTION(unsigned long); BARRIER(); case 6: L_b_6_region2: TEST_SKIP_INSTRUCTION(signed char); BARRIER(); case 7: L_b_7_region2: TEST_SKIP_INSTRUCTION(signed short); BARRIER(); case 9: L_b_9_region2: TEST_SKIP_INSTRUCTION(signed int); BARRIER(); case 1: L_b_1_region2: TEST_SKIP_INSTRUCTION(signed long); BARRIER(); // fall-through case 2: L_e_region2: BARRIER(); break; } if (!arch_insn_skipper_tests()) return 20; #endif vm_exit(); return 0; } #endif BasiliskII/src/Unix/rpc.h0000644000175000017500000001007210736405221015410 0ustar centriscentris/* * rpc.h - Remote Procedure Calls * * Basilisk II (C) 1997-2008 Christian Bauer * Contributed by Gwenole Beauchesne * * 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 */ #ifndef RPC_H #define RPC_H // Error Types enum { RPC_ERROR_NO_ERROR = 0, RPC_ERROR_GENERIC = -1000, RPC_ERROR_ERRNO_SET = -1001, RPC_ERROR_NO_MEMORY = -1002, RPC_ERROR_CONNECTION_NULL = -1003, RPC_ERROR_CONNECTION_TYPE_MISMATCH = -1004, RPC_ERROR_MESSAGE_TRUNCATED = -1005, RPC_ERROR_MESSAGE_ARGUMENT_MISMATCH = -1006, RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN = -1007, }; // Connection Handling typedef struct rpc_connection_t rpc_connection_t; extern rpc_connection_t *rpc_init_server(const char *ident); extern rpc_connection_t *rpc_init_client(const char *ident); extern int rpc_exit(rpc_connection_t *connection); extern int rpc_listen_socket(rpc_connection_t *connection); extern int rpc_listen(rpc_connection_t *connection); extern int rpc_dispatch(rpc_connection_t *connection); extern int rpc_wait_dispatch(rpc_connection_t *connection, int timeout); extern int rpc_connection_busy(rpc_connection_t *connection); // Message Passing enum { RPC_TYPE_INVALID = 0, RPC_TYPE_CHAR = -2000, RPC_TYPE_BOOLEAN = -2001, RPC_TYPE_INT32 = -2002, RPC_TYPE_UINT32 = -2003, RPC_TYPE_STRING = -2004, RPC_TYPE_ARRAY = -2005, }; typedef struct rpc_message_t rpc_message_t; extern int rpc_message_send_char(rpc_message_t *message, char c); extern int rpc_message_send_int32(rpc_message_t *message, int32_t value); extern int rpc_message_send_uint32(rpc_message_t *message, uint32_t value); extern int rpc_message_send_string(rpc_message_t *message, const char *str); extern int rpc_message_send_bytes(rpc_message_t *message, unsigned char *bytes, int count); extern int rpc_message_recv_char(rpc_message_t *message, char *ret); extern int rpc_message_recv_int32(rpc_message_t *message, int32_t *ret); extern int rpc_message_recv_uint32(rpc_message_t *message, uint32_t *ret); extern int rpc_message_recv_string(rpc_message_t *message, char **ret); extern int rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count); typedef int (*rpc_message_callback_t)(rpc_message_t *message, void *p_value); typedef struct { int id; int size; rpc_message_callback_t send_callback; rpc_message_callback_t recv_callback; } rpc_message_descriptor_t; extern int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs); // Method Callbacks Handling typedef int (*rpc_method_callback_t)(rpc_connection_t *connection); typedef struct { int id; rpc_method_callback_t callback; } rpc_method_descriptor_t; extern int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs); extern int rpc_method_remove_callback_id(rpc_connection_t *connection, int id); extern int rpc_method_remove_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs); // Remote Procedure Call (method invocation) extern int rpc_method_invoke(rpc_connection_t *connection, int method, ...); extern int rpc_method_wait_for_reply(rpc_connection_t *connection, ...); extern int rpc_method_get_args(rpc_connection_t *connection, ...); extern int rpc_method_send_reply(rpc_connection_t *connection, ...); // Message Protocol enum { RPC_METHOD_ERROR_ALERT = 1, RPC_METHOD_WARNING_ALERT, RPC_METHOD_EXIT }; #endif /* RPC_H */ BasiliskII/src/Unix/strlcpy.c0000644000175000017500000000477307522012126016327 0ustar centriscentris/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``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 * THE AUTHOR 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. */ #include "config.h" #ifndef HAVE_STRLCPY #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include #include "strlcpy.h" /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(dst, src, siz) char *dst; const char *src; size_t siz; { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif /* !HAVE_STRLCPY */ BasiliskII/src/Unix/strlcpy.h0000644000175000017500000000043307522012126016321 0ustar centriscentris/* $Id: strlcpy.h,v 1.1 2002/07/31 16:46:14 cebix Exp $ */ #ifndef _BSD_STRLCPY_H #define _BSD_STRLCPY_H #include "config.h" #ifndef HAVE_STRLCPY #include size_t strlcpy(char *dst, const char *src, size_t siz); #endif /* !HAVE_STRLCPY */ #endif /* _BSD_STRLCPY_H */ BasiliskII/src/Unix/NetBSD/0000755000175000017500000000000011735674761015553 5ustar centriscentrisBasiliskII/src/Unix/posix_sem.cpp0000644000175000017500000000536510736405221017176 0ustar centriscentris/* * posix_sem.cpp - POSIX.4 semaphores "emulation" * Copyright (C) 1999 Orlando Bassotto * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * OK, I had really big problems with SysV semaphores :/ * I rewrote those one giving a look to the source of linuxthreads * with mutex. Seems to be working correctly now. */ #include #include #include #include #include #include "semaphore.h" extern "C" { int sem_init(sem_t* sem, int pshared, unsigned int value) { if(sem==NULL||value>SEM_VALUE_MAX) { errno = EINVAL; return -1; } if(pshared) { errno = ENOSYS; return -1; } pthread_mutex_init(&sem->sem_lock, NULL); sem->sem_value = value; sem->sem_waiting = 0; return 0; } int sem_destroy(sem_t* sem) { if(sem==NULL) { errno = EINVAL; return -1; } if(sem->sem_waiting) { errno = EBUSY; return -1; } pthread_mutex_destroy(&sem->sem_lock); sem->sem_waiting = 0; sem->sem_value = 0; return 0; } sem_t sem_open(const char* name, int oflag, ...) { errno = ENOSYS; return *(sem_t*)NULL; } int sem_close(sem_t* sem) { errno = ENOSYS; return -1; } int sem_unlink(const char* name) { errno = ENOSYS; return -1; } int sem_wait(sem_t* sem) { struct timespec req = { 1, 0 }; if(sem==NULL) { errno = EINVAL; return -1; } pthread_mutex_lock(&sem->sem_lock); sem->sem_waiting++; if(sem->sem_value > 0) { --sem->sem_value; return 0; } while(!sem->sem_value) nanosleep(NULL, &req); pthread_mutex_unlock(&sem->sem_lock); return 0; } int sem_trywait(sem_t* sem) { errno = ENOSYS; return -1; } int sem_post(sem_t* sem) { if(sem==NULL) { errno = EINVAL; return -1; } if(!sem->sem_waiting) { if(sem->sem_value >= SEM_VALUE_MAX) { errno = ERANGE; pthread_mutex_unlock(&sem->sem_lock); return -1; } ++sem->sem_value; pthread_mutex_unlock(&sem->sem_lock); } else { sem->sem_waiting--; ++sem->sem_value; // pthread_mutex_unlock(&sem->sem_lock); } return 0; } int sem_getvalue(sem_t* sem, int* sval) { errno = ENOSYS; return -1; } } BasiliskII/src/Unix/sys_unix.cpp0000644000175000017500000010077011723575015017053 0ustar centriscentris/* * sys_unix.cpp - System dependent routines, Unix implementation * * Basilisk II (C) Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #ifdef HAVE_AVAILABILITYMACROS_H #include #endif #ifdef __linux__ #include #include #include #include #include #include #include #endif #if defined(__FreeBSD__) || defined(__NetBSD__) #include #endif #if defined __APPLE__ && defined __MACH__ #include #if (defined AQUA || defined HAVE_FRAMEWORK_COREFOUNDATION) #ifndef __MACOSX__ #define __MACOSX__ MAC_OS_X_VERSION_MIN_REQUIRED #endif #endif #endif #include "main.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "sys.h" #if defined(BINCUE) #include "bincue_unix.h" #endif #if defined(HAVE_LIBVHD) #include "vhd_unix.h" #endif #define DEBUG 0 #include "debug.h" // File handles are pointers to these structures struct mac_file_handle { char *name; // Copy of device/file name int fd; bool is_file; // Flag: plain file or /dev/something? bool is_floppy; // Flag: floppy device bool is_cdrom; // Flag: CD-ROM device bool read_only; // Copy of Sys_open() flag loff_t start_byte; // Size of file header (if any) loff_t file_size; // Size of file data (only valid if is_file is true) bool is_media_present; // Flag: media is inserted and available #if defined(__linux__) int cdrom_cap; // CD-ROM capability flags (only valid if is_cdrom is true) #elif defined(__FreeBSD__) struct ioc_capability cdrom_cap; #elif defined(__APPLE__) && defined(__MACH__) char *ioctl_name; // For CDs on OS X - a device for special ioctls int ioctl_fd; #endif #if defined(BINCUE) bool is_bincue; // Flag: BIN CUE file void *bincue_fd; #endif #if defined(HAVE_LIBVHD) bool is_vhd; // Flag: VHD file void *vhd_fd; #endif }; // Open file handles struct open_mac_file_handle { mac_file_handle *fh; open_mac_file_handle *next; }; static open_mac_file_handle *open_mac_file_handles = NULL; // File handle of first floppy drive (for SysMountFirstFloppy()) static mac_file_handle *first_floppy = NULL; // Prototypes static void cdrom_close(mac_file_handle *fh); static bool cdrom_open(mac_file_handle *fh, const char *path = NULL); /* * Initialization */ void SysInit(void) { #if defined __MACOSX__ extern void DarwinSysInit(void); DarwinSysInit(); #endif } /* * Deinitialization */ void SysExit(void) { #if defined __MACOSX__ extern void DarwinSysExit(void); DarwinSysExit(); #endif } /* * Manage open file handles */ static void sys_add_mac_file_handle(mac_file_handle *fh) { open_mac_file_handle *p = new open_mac_file_handle; p->fh = fh; p->next = open_mac_file_handles; open_mac_file_handles = p; } static void sys_remove_mac_file_handle(mac_file_handle *fh) { open_mac_file_handle *p = open_mac_file_handles; open_mac_file_handle *q = NULL; while (p) { if (p->fh == fh) { if (q) q->next = p->next; else open_mac_file_handles = p->next; delete p; break; } q = p; p = p->next; } } /* * Account for media that has just arrived */ void SysMediaArrived(const char *path, int type) { // Replace the "cdrom" entry (we are polling, it's unique) if (type == MEDIA_CD && !PrefsFindBool("nocdrom")) PrefsReplaceString("cdrom", path); // Wait for media to be available for reading if (open_mac_file_handles) { const int MAX_WAIT = 5; for (int i = 0; i < MAX_WAIT; i++) { if (access(path, R_OK) == 0) break; switch (errno) { case ENOENT: // Unlikely case EACCES: // MacOS X is mounting the media sleep(1); continue; } printf("WARNING: Cannot access %s (%s)\n", path, strerror(errno)); return; } } for (open_mac_file_handle *p = open_mac_file_handles; p != NULL; p = p->next) { mac_file_handle * const fh = p->fh; // Re-open CD-ROM device if (fh->is_cdrom && type == MEDIA_CD) { cdrom_close(fh); if (cdrom_open(fh, path)) { fh->is_media_present = true; MountVolume(fh); } } } } /* * Account for media that has just been removed */ void SysMediaRemoved(const char *path, int type) { if ((type & MEDIA_REMOVABLE) != MEDIA_CD) return; for (open_mac_file_handle *p = open_mac_file_handles; p != NULL; p = p->next) { mac_file_handle * const fh = p->fh; // Mark media as not available if (!fh->is_cdrom || !fh->is_media_present) continue; if (fh->name && strcmp(fh->name, path) == 0) { fh->is_media_present = false; break; } #if defined __MACOSX__ if (fh->ioctl_name && strcmp(fh->ioctl_name, path) == 0) { fh->is_media_present = false; break; } #endif } } /* * Mount first floppy disk */ void SysMountFirstFloppy(void) { if (first_floppy) MountVolume(first_floppy); } /* * This gets called when no "floppy" prefs items are found * It scans for available floppy drives and adds appropriate prefs items */ void SysAddFloppyPrefs(void) { #if defined(__linux__) DIR *fd_dir = opendir("/dev/floppy"); if (fd_dir) { struct dirent *floppy_dev; while ((floppy_dev = readdir(fd_dir)) != NULL) { if (strstr(floppy_dev->d_name, "u1440") != NULL) { char fd_dev[20]; sprintf(fd_dev, "/dev/floppy/%s", floppy_dev->d_name); PrefsAddString("floppy", fd_dev); } } closedir(fd_dir); } else { PrefsAddString("floppy", "/dev/fd0"); PrefsAddString("floppy", "/dev/fd1"); } #elif defined(__NetBSD__) PrefsAddString("floppy", "/dev/fd0a"); PrefsAddString("floppy", "/dev/fd1a"); #elif defined(__APPLE__) && defined(__MACH__) #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION) extern void DarwinAddFloppyPrefs(void); DarwinAddFloppyPrefs(); #else // Until I can convince the other guys that my Darwin code is useful, // we just add something safe (a non-existant device): PrefsAddString("floppy", "/dev/null"); #endif #else PrefsAddString("floppy", "/dev/fd0"); PrefsAddString("floppy", "/dev/fd1"); #endif } /* * This gets called when no "disk" prefs items are found * It scans for available HFS volumes and adds appropriate prefs items * On OS X, we could do the same, but on an OS X machine I think it is * very unlikely that any mounted volumes would contain a system which * is old enough to boot a 68k Mac, so we just do nothing here for now. */ void SysAddDiskPrefs(void) { #ifdef __linux__ FILE *f = fopen("/etc/fstab", "r"); if (f) { char line[256]; while(fgets(line, 255, f)) { // Read line int len = strlen(line); if (len == 0 || line[0] == '#') continue; line[len-1] = 0; // Parse line char *dev, *mnt_point, *fstype; if (sscanf(line, "%as %as %as", &dev, &mnt_point, &fstype) == 3) { if (strcmp(fstype, "hfs") == 0) PrefsAddString("disk", dev); } free(dev); free(mnt_point); free(fstype); } fclose(f); } #endif } /* * This gets called when no "cdrom" prefs items are found * It scans for available CD-ROM drives and adds appropriate prefs items */ void SysAddCDROMPrefs(void) { // Don't scan for drives if nocdrom option given if (PrefsFindBool("nocdrom")) return; #if defined(__linux__) if (access("/dev/.devfsd", F_OK) < 0) PrefsAddString("cdrom", "/dev/cdrom"); else { DIR *cd_dir = opendir("/dev/cdroms"); if (cd_dir) { struct dirent *cdrom_dev; while ((cdrom_dev = readdir(cd_dir)) != NULL) { if (strcmp(cdrom_dev->d_name, ".") != 0 && strcmp(cdrom_dev->d_name, "..") != 0) { char cd_dev[20]; sprintf(cd_dev, "/dev/cdroms/%s", cdrom_dev->d_name); PrefsAddString("cdrom", cd_dev); } } closedir(cd_dir); } } #elif defined __MACOSX__ // There is no predefined path for CD-ROMs on MacOS X. Rather, we // define a single fake CD-ROM entry for the emulated MacOS. // XXX this means we handle only CD-ROM drive at a time, wherever // the disk is, the latest one is used. PrefsAddString("cdrom", "/dev/poll/cdrom"); #elif defined(__FreeBSD__) || defined(__NetBSD__) PrefsAddString("cdrom", "/dev/cd0c"); #endif } /* * Add default serial prefs (must be added, even if no ports present) */ void SysAddSerialPrefs(void) { #if defined(__linux__) if (access("/dev/.devfsd", F_OK) < 0) { PrefsAddString("seriala", "/dev/ttyS0"); PrefsAddString("serialb", "/dev/ttyS1"); } else { PrefsAddString("seriala", "/dev/tts/0"); PrefsAddString("serialb", "/dev/tts/1"); } #elif defined(__FreeBSD__) PrefsAddString("seriala", "/dev/cuaa0"); PrefsAddString("serialb", "/dev/cuaa1"); #elif defined(__NetBSD__) PrefsAddString("seriala", "/dev/tty00"); PrefsAddString("serialb", "/dev/tty01"); #elif defined(__APPLE__) && defined(__MACH__) #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION) extern void DarwinAddSerialPrefs(void); DarwinAddSerialPrefs(); #else // Until I can convince the other guys that my Darwin code is useful, // we just add something safe (non-existant devices): PrefsAddString("seriala", "/dev/null"); PrefsAddString("serialb", "/dev/null"); #endif #endif } /* * Open CD-ROM device and initialize internal data */ static bool cdrom_open_1(mac_file_handle *fh) { #if defined __MACOSX__ // In OS X, the device name is OK for sending ioctls to, // but not for reading raw CDROM data from. // (it seems to have extra data padded in) // // So, we keep the already opened file handle, // and open a slightly different file for CDROM data // fh->ioctl_fd = fh->fd; fh->ioctl_name = fh->name; fh->fd = -1; fh->name = (char *)malloc(strlen(fh->ioctl_name) + 3); if (fh->name) { strcpy(fh->name, fh->ioctl_name); strcat(fh->name, "s1"); fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK); } if (fh->ioctl_fd < 0) return false; #endif return true; } bool cdrom_open(mac_file_handle *fh, const char *path) { if (path) fh->name = strdup(path); fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK); fh->start_byte = 0; if (!cdrom_open_1(fh)) return false; return fh->fd >= 0; } /* * Close a CD-ROM device */ void cdrom_close(mac_file_handle *fh) { if (fh->fd >= 0) { close(fh->fd); fh->fd = -1; } if (fh->name) { free(fh->name); fh->name = NULL; } #if defined __MACOSX__ if (fh->ioctl_fd >= 0) { close(fh->ioctl_fd); fh->ioctl_fd = -1; } if (fh->ioctl_name) { free(fh->ioctl_name); fh->ioctl_name = NULL; } #endif } /* * Check if device is a mounted HFS volume, get mount name */ static bool is_drive_mounted(const char *dev_name, char *mount_name) { #ifdef __linux__ FILE *f = fopen("/proc/mounts", "r"); if (f) { char line[256]; while(fgets(line, 255, f)) { // Read line int len = strlen(line); if (len == 0) continue; line[len-1] = 0; // Parse line if (strncmp(line, dev_name, strlen(dev_name)) == 0) { mount_name[0] = 0; char *dummy; sscanf(line, "%as %s", &dummy, mount_name); free(dummy); fclose(f); return true; } } fclose(f); } #endif return false; } /* * Open file/device, create new file handle (returns NULL on error) */ static mac_file_handle *open_filehandle(const char *name) { mac_file_handle *fh = new mac_file_handle; memset(fh, 0, sizeof(mac_file_handle)); fh->name = strdup(name); fh->fd = -1; #if defined __MACOSX__ fh->ioctl_fd = -1; fh->ioctl_name = NULL; #endif return fh; } void *Sys_open(const char *name, bool read_only) { bool is_file = strncmp(name, "/dev/", 5) != 0; #if defined(__FreeBSD__) // SCSI IDE bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0 || strncmp(name, "/dev/acd", 8) == 0; #else bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0; #endif bool is_floppy = strncmp(name, "/dev/fd", 7) == 0; bool is_polled_media = strncmp(name, "/dev/poll/", 10) == 0; if (is_floppy) // Floppy open fails if there's no disk inserted is_polled_media = true; #if defined __MACOSX__ // There is no set filename in /dev which is the cdrom, // so we have to see if it is any of the devices that we found earlier { int index = 0; const char *str; while ((str = PrefsFindString("cdrom", index++)) != NULL) { if (is_polled_media || strcmp(str, name) == 0) { is_cdrom = true; read_only = true; break; } } } #endif D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write")); // Check if write access is allowed, set read-only flag if not if (!read_only && access(name, W_OK)) read_only = true; // Print warning message and eventually unmount drive when this is an HFS volume mounted under Linux (double mounting will corrupt the volume) char mount_name[256]; if (!is_file && !read_only && is_drive_mounted(name, mount_name)) { char str[512]; sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name); WarningAlert(str); sprintf(str, "umount %s", mount_name); if (system(str)) { sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name, strerror(errno)); WarningAlert(str); return NULL; } } // Open file/device #if defined(BINCUE) void *binfd = open_bincue(name); if (binfd) { mac_file_handle *fh = open_filehandle(name); D(bug("opening %s as bincue\n", name)); fh->bincue_fd = binfd; fh->is_bincue = true; fh->read_only = true; fh->is_media_present = true; sys_add_mac_file_handle(fh); return fh; } #endif #if defined(HAVE_LIBVHD) int vhdsize; void *vhdfd = vhd_unix_open(name, &vhdsize, read_only); if (vhdfd) { mac_file_handle *fh = open_filehandle(name); D(bug("opening %s as vnd\n", name)); fh->is_vhd = true; fh->vhd_fd = vhdfd; fh->read_only = read_only; fh->file_size = vhdsize; fh->is_media_present = true; sys_add_mac_file_handle(fh); return fh; } #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__) int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0)); #else int fd = open(name, read_only ? O_RDONLY : O_RDWR); #endif if (fd < 0 && !read_only) { // Read-write failed, try read-only read_only = true; fd = open(name, O_RDONLY); } if (fd >= 0 || is_polled_media) { mac_file_handle *fh = open_filehandle(name); fh->fd = fd; fh->is_file = is_file; fh->read_only = read_only; fh->is_floppy = is_floppy; fh->is_cdrom = is_cdrom; if (fh->is_file) { fh->is_media_present = true; // Detect disk image file layout loff_t size = 0; size = lseek(fd, 0, SEEK_END); uint8 data[256]; lseek(fd, 0, SEEK_SET); read(fd, data, 256); FileDiskLayout(size, data, fh->start_byte, fh->file_size); } else { struct stat st; if (fstat(fd, &st) == 0) { fh->is_media_present = true; if (S_ISBLK(st.st_mode)) { fh->is_cdrom = is_cdrom; #if defined(__linux__) fh->is_floppy = (MAJOR(st.st_rdev) == FLOPPY_MAJOR); #ifdef CDROM_GET_CAPABILITY if (is_cdrom) { fh->cdrom_cap = ioctl(fh->fd, CDROM_GET_CAPABILITY); if (fh->cdrom_cap < 0) fh->cdrom_cap = 0; } #endif #elif defined(__FreeBSD__) fh->is_floppy = ((st.st_rdev >> 16) == 2); #ifdef CDIOCCAPABILITY if (is_cdrom) { if (ioctl(fh->fd, CDIOCCAPABILITY, &fh->cdrom_cap) < 0) memset(&fh->cdrom_cap, 0, sizeof(fh->cdrom_cap)); } #endif #elif defined(__NetBSD__) fh->is_floppy = ((st.st_rdev >> 16) == 2); #endif } #if defined __MACOSX__ if (is_cdrom) { fh->is_cdrom = true; fh->is_floppy = false; if (cdrom_open_1(fh)) fh->is_media_present = true; } #endif } } if (fh->is_floppy && first_floppy == NULL) first_floppy = fh; sys_add_mac_file_handle(fh); return fh; } else { printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno)); return NULL; } } /* * Close file/device, delete file handle */ void Sys_close(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return; sys_remove_mac_file_handle(fh); #if defined(HAVE_LIBVHD) if (fh->is_vhd) vhd_unix_close(fh->vhd_fd); #endif #if defined(BINCUE) if (fh->is_bincue) close_bincue(fh->bincue_fd); #endif if (fh->is_cdrom) cdrom_close(fh); if (fh->fd >= 0) close(fh->fd); if (fh->name) free(fh->name); delete fh; } /* * Read "length" bytes from file/device, starting at "offset", to "buffer", * returns number of bytes read (or 0) */ size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return 0; #if defined(BINCUE) if (fh->is_bincue) return read_bincue(fh->bincue_fd, buffer, offset, length); #endif #if defined(HAVE_LIBVHD) if (fh->is_vhd) return vhd_unix_read(fh->vhd_fd, buffer, offset, length); #endif // Seek to position if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) return 0; // Read data return read(fh->fd, buffer, length); } /* * Write "length" bytes from "buffer" to file/device, starting at "offset", * returns number of bytes written (or 0) */ size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return 0; #if defined(HAVE_LIBVHD) if (fh->is_vhd) return vhd_unix_write(fh->vhd_fd, buffer, offset, length); #endif // Seek to position if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0) return 0; // Write data return write(fh->fd, buffer, length); } /* * Return size of file/device (minus header) */ loff_t SysGetFileSize(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return true; #if defined(BINCUE) if (fh->is_bincue) return size_bincue(fh->bincue_fd); #endif #if defined(HAVE_LIBVHD) if (fh->is_vhd) return fh->file_size; #endif if (fh->is_file) return fh->file_size; else { #if defined(__linux__) long blocks; if (ioctl(fh->fd, BLKGETSIZE, &blocks) < 0) return 0; D(bug(" BLKGETSIZE returns %d blocks\n", blocks)); return (loff_t)blocks * 512; #elif defined __MACOSX__ uint32 block_size; if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKSIZE, &block_size) < 0) return 0; D(bug(" DKIOCGETBLOCKSIZE returns %lu bytes\n", (unsigned long)block_size)); uint64 block_count; if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKCOUNT, &block_count) < 0) return 0; D(bug(" DKIOCGETBLOCKCOUNT returns %llu blocks\n", (unsigned long long)block_count)); return block_count * block_size; #else return lseek(fh->fd, 0, SEEK_END) - fh->start_byte; #endif } } /* * Eject volume (if applicable) */ void SysEject(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return; #if defined(__linux__) if (fh->is_floppy) { if (fh->fd >= 0) { fsync(fh->fd); ioctl(fh->fd, FDFLUSH); ioctl(fh->fd, FDEJECT); close(fh->fd); // Close and reopen so the driver will see the media change } fh->fd = open(fh->name, fh->read_only ? O_RDONLY : O_RDWR); } else if (fh->is_cdrom) { ioctl(fh->fd, CDROMEJECT); close(fh->fd); // Close and reopen so the driver will see the media change fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK); } #elif defined(__FreeBSD__) || defined(__NetBSD__) if (fh->is_floppy) { fsync(fh->fd); } else if (fh->is_cdrom) { ioctl(fh->fd, CDIOCEJECT); close(fh->fd); // Close and reopen so the driver will see the media change fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK); } #elif defined(__APPLE__) && defined(__MACH__) if (fh->is_cdrom && fh->is_media_present) { close(fh->fd); fh->fd = -1; if (ioctl(fh->ioctl_fd, DKIOCEJECT) < 0) { D(bug(" DKIOCEJECT failed on file %s: %s\n", fh->ioctl_name, strerror(errno))); // If we are running MacOS X, the device may be in busy // state because the Finder has mounted the disk close(fh->ioctl_fd); fh->ioctl_fd = -1; // Try to use "diskutil eject" but it can take up to 5 // seconds to complete static const char eject_cmd[] = "/usr/sbin/diskutil eject %s 2>&1 >/dev/null"; char *cmd = (char *)alloca(strlen(eject_cmd) + strlen(fh->ioctl_name) + 1); sprintf(cmd, eject_cmd, fh->ioctl_name); system(cmd); } fh->is_media_present = false; } #endif } /* * Format volume (if applicable) */ bool SysFormat(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; //!! return true; } /* * Check if file/device is read-only (this includes the read-only flag on Sys_open()) */ bool SysIsReadOnly(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return true; #if defined(__linux__) if (fh->is_floppy) { if (fh->fd >= 0) { struct floppy_drive_struct stat; ioctl(fh->fd, FDGETDRVSTAT, &stat); return !(stat.flags & FD_DISK_WRITABLE); } else return true; } else #endif return fh->read_only; } /* * Check if the given file handle refers to a fixed or a removable disk */ bool SysIsFixedDisk(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return true; #if defined(HAVE_LIBVHD) if (fh->is_vhd) return true; #endif if (fh->is_file) return true; else if (fh->is_floppy || fh->is_cdrom) return false; else return true; } /* * Check if a disk is inserted in the drive (always true for files) */ bool SysIsDiskInserted(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; #if defined(HAVE_LIBVHD) if (fh->is_vhd) return true; #endif if (fh->is_file) { return true; #if defined(__linux__) } else if (fh->is_floppy) { char block[512]; lseek(fh->fd, 0, SEEK_SET); ssize_t actual = read(fh->fd, block, 512); if (actual < 0) { close(fh->fd); // Close and reopen so the driver will see the media change fh->fd = open(fh->name, fh->read_only ? O_RDONLY : O_RDWR); actual = read(fh->fd, block, 512); } return actual == 512; } else if (fh->is_cdrom) { #ifdef CDROM_MEDIA_CHANGED if (fh->cdrom_cap & CDC_MEDIA_CHANGED) { // If we don't do this, all attempts to read from a disc fail // once the tray has been opened (altough the TOC reads fine). // Can somebody explain this to me? if (ioctl(fh->fd, CDROM_MEDIA_CHANGED) == 1) { close(fh->fd); fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK); } } #endif #ifdef CDROM_DRIVE_STATUS if (fh->cdrom_cap & CDC_DRIVE_STATUS) { return ioctl(fh->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK; } #endif cdrom_tochdr header; return ioctl(fh->fd, CDROMREADTOCHDR, &header) == 0; #elif defined(__FreeBSD__) || defined(__NetBSD__) } else if (fh->is_floppy) { return false; //!! } else if (fh->is_cdrom) { struct ioc_toc_header header; return ioctl(fh->fd, CDIOREADTOCHEADER, &header) == 0; #elif defined __MACOSX__ } else if (fh->is_cdrom || fh->is_floppy) { return fh->is_media_present; #endif } else return true; } /* * Prevent medium removal (if applicable) */ void SysPreventRemoval(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return; #if defined(__linux__) && defined(CDROM_LOCKDOOR) if (fh->is_cdrom) ioctl(fh->fd, CDROM_LOCKDOOR, 1); #endif } /* * Allow medium removal (if applicable) */ void SysAllowRemoval(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return; #if defined(__linux__) && defined(CDROM_LOCKDOOR) if (fh->is_cdrom) ioctl(fh->fd, CDROM_LOCKDOOR, 0); #endif } /* * Read CD-ROM TOC (binary MSF format, 804 bytes max.) */ bool SysCDReadTOC(void *arg, uint8 *toc) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; #if defined(BINCUE) if (fh->is_bincue) return readtoc_bincue(fh->bincue_fd, toc); #endif if (fh->is_cdrom) { #if defined(__linux__) uint8 *p = toc + 2; // Header cdrom_tochdr header; if (ioctl(fh->fd, CDROMREADTOCHDR, &header) < 0) return false; *p++ = header.cdth_trk0; *p++ = header.cdth_trk1; // Tracks cdrom_tocentry entry; for (int i=header.cdth_trk0; i<=header.cdth_trk1; i++) { entry.cdte_track = i; entry.cdte_format = CDROM_MSF; if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0) return false; *p++ = 0; *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl; *p++ = entry.cdte_track; *p++ = 0; *p++ = 0; *p++ = entry.cdte_addr.msf.minute; *p++ = entry.cdte_addr.msf.second; *p++ = entry.cdte_addr.msf.frame; } // Leadout track entry.cdte_track = CDROM_LEADOUT; entry.cdte_format = CDROM_MSF; if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0) return false; *p++ = 0; *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl; *p++ = entry.cdte_track; *p++ = 0; *p++ = 0; *p++ = entry.cdte_addr.msf.minute; *p++ = entry.cdte_addr.msf.second; *p++ = entry.cdte_addr.msf.frame; // TOC size int toc_size = p - toc; *toc++ = toc_size >> 8; *toc++ = toc_size & 0xff; return true; #elif defined __MACOSX__ && defined MAC_OS_X_VERSION_10_2 if (fh->is_media_present) { extern bool DarwinCDReadTOC(char *name, uint8 *toc); return DarwinCDReadTOC(fh->name, toc); } return false; #elif defined(__FreeBSD__) uint8 *p = toc + 2; // Header struct ioc_toc_header header; if (ioctl(fh->fd, CDIOREADTOCHEADER, &header) < 0) return false; *p++ = header.starting_track; *p++ = header.ending_track; // Tracks struct ioc_read_toc_single_entry entry; for (int i=header.starting_track; i<=header.ending_track; i++) { entry.track = i; entry.address_format = CD_MSF_FORMAT; if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0) return false; *p++ = 0; *p++ = (entry.entry.addr_type << 4) | entry.entry.control; *p++ = entry.entry.track; *p++ = 0; *p++ = 0; *p++ = entry.entry.addr.msf.minute; *p++ = entry.entry.addr.msf.second; *p++ = entry.entry.addr.msf.frame; } // Leadout track entry.track = CD_TRACK_INFO; entry.address_format = CD_MSF_FORMAT; if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0) return false; *p++ = 0; *p++ = (entry.entry.addr_type << 4) | entry.entry.control; *p++ = entry.entry.track; *p++ = 0; *p++ = 0; *p++ = entry.entry.addr.msf.minute; *p++ = entry.entry.addr.msf.second; *p++ = entry.entry.addr.msf.frame; // TOC size int toc_size = p - toc; *toc++ = toc_size >> 8; *toc++ = toc_size & 0xff; return true; #elif defined(__NetBSD__) uint8 *p = toc + 2; // Header struct ioc_toc_header header; if (ioctl(fh->fd, CDIOREADTOCHEADER, &header) < 0) return false; *p++ = header.starting_track; *p++ = header.ending_track; // Tracks (this is nice... :-) struct ioc_read_toc_entry entries; entries.address_format = CD_MSF_FORMAT; entries.starting_track = 1; entries.data_len = 800; entries.data = (cd_toc_entry *)p; if (ioctl(fh->fd, CDIOREADTOCENTRIES, &entries) < 0) return false; // TOC size int toc_size = p - toc; *toc++ = toc_size >> 8; *toc++ = toc_size & 0xff; return true; #else return false; #endif } else return false; } /* * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard) */ bool SysCDGetPosition(void *arg, uint8 *pos) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; #if defined(BINCUE) if (fh->is_bincue) return GetPosition_bincue(fh->bincue_fd, pos); #endif if (fh->is_cdrom) { #if defined(__linux__) cdrom_subchnl chan; chan.cdsc_format = CDROM_MSF; if (ioctl(fh->fd, CDROMSUBCHNL, &chan) < 0) return false; *pos++ = 0; *pos++ = chan.cdsc_audiostatus; *pos++ = 0; *pos++ = 12; // Sub-Q data length *pos++ = 0; *pos++ = (chan.cdsc_adr << 4) | chan.cdsc_ctrl; *pos++ = chan.cdsc_trk; *pos++ = chan.cdsc_ind; *pos++ = 0; *pos++ = chan.cdsc_absaddr.msf.minute; *pos++ = chan.cdsc_absaddr.msf.second; *pos++ = chan.cdsc_absaddr.msf.frame; *pos++ = 0; *pos++ = chan.cdsc_reladdr.msf.minute; *pos++ = chan.cdsc_reladdr.msf.second; *pos++ = chan.cdsc_reladdr.msf.frame; return true; #elif defined(__FreeBSD__) || defined(__NetBSD__) struct ioc_read_subchannel chan; chan.data_format = CD_MSF_FORMAT; chan.address_format = CD_MSF_FORMAT; chan.track = CD_CURRENT_POSITION; if (ioctl(fh->fd, CDIOCREADSUBCHANNEL, &chan) < 0) return false; *pos++ = 0; *pos++ = chan.data->header.audio_status; *pos++ = 0; *pos++ = 12; // Sub-Q data length *pos++ = 0; *pos++ = (chan.data->what.position.addr_type << 4) | chan.data->what.position.control; *pos++ = chan.data->what.position.track_number; *pos++ = chan.data->what.position.index_number; *pos++ = 0; *pos++ = chan.data->what.position.absaddr.msf.minute; *pos++ = chan.data->what.position.absaddr.msf.second; *pos++ = chan.data->what.position.absaddr.msf.frame; *pos++ = 0; *pos++ = chan.data->what.position.reladdr.msf.minute; *pos++ = chan.data->what.position.reladdr.msf.second; *pos++ = chan.data->what.position.reladdr.msf.frame; return true; #else return false; #endif } else return false; } /* * Play CD audio */ bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; #if defined(BINCUE) if (fh->is_bincue) return CDPlay_bincue(fh->bincue_fd, start_m, start_s, start_f, end_m, end_s, end_f); #endif if (fh->is_cdrom) { #if defined(__linux__) cdrom_msf play; play.cdmsf_min0 = start_m; play.cdmsf_sec0 = start_s; play.cdmsf_frame0 = start_f; play.cdmsf_min1 = end_m; play.cdmsf_sec1 = end_s; play.cdmsf_frame1 = end_f; return ioctl(fh->fd, CDROMPLAYMSF, &play) == 0; #elif defined(__FreeBSD__) || defined(__NetBSD__) struct ioc_play_msf play; play.start_m = start_m; play.start_s = start_s; play.start_f = start_f; play.end_m = end_m; play.end_s = end_s; play.end_f = end_f; return ioctl(fh->fd, CDIOCPLAYMSF, &play) == 0; #else return false; #endif } else return false; } /* * Pause CD audio */ bool SysCDPause(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; #if defined(BINCUE) if (fh->is_bincue) return CDPause_bincue(fh->bincue_fd); #endif if (fh->is_cdrom) { #if defined(__linux__) return ioctl(fh->fd, CDROMPAUSE) == 0; #elif defined(__FreeBSD__) || defined(__NetBSD__) return ioctl(fh->fd, CDIOCPAUSE) == 0; #else return false; #endif } else return false; } /* * Resume paused CD audio */ bool SysCDResume(void *arg) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; #if defined(BINCUE) if (fh->is_bincue) return CDResume_bincue(fh->bincue_fd); #endif if (fh->is_cdrom) { #if defined(__linux__) return ioctl(fh->fd, CDROMRESUME) == 0; #elif defined(__FreeBSD__) || defined(__NetBSD__) return ioctl(fh->fd, CDIOCRESUME) == 0; #else return false; #endif } else return false; } /* * Stop CD audio */ bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; #if defined(BINCUE) if (fh->is_bincue) return CDStop_bincue(fh->bincue_fd); #endif if (fh->is_cdrom) { #if defined(__linux__) return ioctl(fh->fd, CDROMSTOP) == 0; #elif defined(__FreeBSD__) || defined(__NetBSD__) return ioctl(fh->fd, CDIOCSTOP) == 0; #else return false; #endif } else return false; } /* * Perform CD audio fast-forward/fast-reverse operation starting from specified address */ bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return false; // Not supported under Linux return false; } /* * Set CD audio volume (0..255 each channel) */ void SysCDSetVolume(void *arg, uint8 left, uint8 right) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return; if (fh->is_cdrom) { #if defined(__linux__) cdrom_volctrl vol; vol.channel0 = vol.channel2 = left; vol.channel1 = vol.channel3 = right; ioctl(fh->fd, CDROMVOLCTRL, &vol); #elif defined(__FreeBSD__) || defined(__NetBSD__) struct ioc_vol vol; vol.vol[0] = vol.vol[2] = left; vol.vol[1] = vol.vol[3] = right; ioctl(fh->fd, CDIOCSETVOL, &vol); #endif } } /* * Get CD audio volume (0..255 each channel) */ void SysCDGetVolume(void *arg, uint8 &left, uint8 &right) { mac_file_handle *fh = (mac_file_handle *)arg; if (!fh) return; left = right = 0; if (fh->is_cdrom) { #if defined(__linux__) cdrom_volctrl vol; ioctl(fh->fd, CDROMVOLREAD, &vol); left = vol.channel0; right = vol.channel1; #elif defined(__FreeBSD__) || defined(__NetBSD__) struct ioc_vol vol; ioctl(fh->fd, CDIOCGETVOL, &vol); left = vol.vol[0]; right = vol.vol[1]; #endif } } BasiliskII/src/Unix/sysdeps.h0000644000175000017500000003224711242340262016322 0ustar centriscentris/* * sysdeps.h - System dependent definitions for Unix * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SYSDEPS_H #define SYSDEPS_H #ifndef __STDC__ #error "Your compiler is not ANSI. Get a real one." #endif #include "config.h" #include "user_strings_unix.h" #ifndef STDC_HEADERS #error "You don't have ANSI C header files." #endif #ifdef HAVE_UNISTD_H # include # include #endif #include #include #include #include #include #ifdef HAVE_PTHREADS # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #if defined(__MACH__) #include #endif #ifdef ENABLE_NATIVE_M68K /* Mac and host address space are the same */ #define REAL_ADDRESSING 1 /* Using 68k natively */ #define EMULATED_68K 0 /* Mac ROM is not write protected */ #define ROM_IS_WRITE_PROTECTED 0 #define USE_SCRATCHMEM_SUBTERFUGE 1 #else /* Mac and host address space are distinct */ #ifndef REAL_ADDRESSING #define REAL_ADDRESSING 0 #endif /* Using 68k emulator */ #define EMULATED_68K 1 /* The m68k emulator uses a prefetch buffer ? */ #define USE_PREFETCH_BUFFER 0 /* Mac ROM is write protected when banked memory is used */ #if REAL_ADDRESSING || DIRECT_ADDRESSING # define ROM_IS_WRITE_PROTECTED 0 # define USE_SCRATCHMEM_SUBTERFUGE 1 #else # define ROM_IS_WRITE_PROTECTED 1 #endif #endif /* Direct Addressing requires Video on SEGV signals in plain X11 mode */ #if DIRECT_ADDRESSING && (!ENABLE_VOSF && !USE_SDL_VIDEO) # undef ENABLE_VOSF # define ENABLE_VOSF 1 #endif /* ExtFS is supported */ #define SUPPORTS_EXTFS 1 /* BSD socket API supported */ #define SUPPORTS_UDP_TUNNEL 1 /* Use the CPU emulator to check for periodic tasks? */ #ifdef HAVE_PTHREADS #define USE_PTHREADS_SERVICES #endif #if EMULATED_68K #if defined(__NetBSD__) #define USE_CPU_EMUL_SERVICES #endif #endif #ifdef USE_CPU_EMUL_SERVICES #undef USE_PTHREADS_SERVICES #endif /* Data types */ typedef unsigned char uint8; typedef signed char int8; #if SIZEOF_SHORT == 2 typedef unsigned short uint16; typedef short int16; #elif SIZEOF_INT == 2 typedef unsigned int uint16; typedef int int16; #else #error "No 2 byte type, you lose." #endif #if SIZEOF_INT == 4 typedef unsigned int uint32; typedef int int32; #elif SIZEOF_LONG == 4 typedef unsigned long uint32; typedef long int32; #else #error "No 4 byte type, you lose." #endif #if SIZEOF_LONG == 8 typedef unsigned long uint64; typedef long int64; #define VAL64(a) (a ## l) #define UVAL64(a) (a ## ul) #elif SIZEOF_LONG_LONG == 8 typedef unsigned long long uint64; typedef long long int64; #define VAL64(a) (a ## LL) #define UVAL64(a) (a ## uLL) #else #error "No 8 byte type, you lose." #endif #if SIZEOF_VOID_P == 4 typedef uint32 uintptr; typedef int32 intptr; #elif SIZEOF_VOID_P == 8 typedef uint64 uintptr; typedef int64 intptr; #else #error "Unsupported size of pointer" #endif #ifndef HAVE_LOFF_T typedef off_t loff_t; #endif #ifndef HAVE_CADDR_T typedef char * caddr_t; #endif /* Time data type for Time Manager emulation */ #ifdef HAVE_CLOCK_GETTIME typedef struct timespec tm_time_t; #elif defined(__MACH__) typedef mach_timespec_t tm_time_t; #else typedef struct timeval tm_time_t; #endif /* Define codes for all the float formats that we know of. * Though we only handle IEEE format. */ #define UNKNOWN_FLOAT_FORMAT 0 #define IEEE_FLOAT_FORMAT 1 #define VAX_FLOAT_FORMAT 2 #define IBM_FLOAT_FORMAT 3 #define C4X_FLOAT_FORMAT 4 /* UAE CPU data types */ #define uae_s8 int8 #define uae_u8 uint8 #define uae_s16 int16 #define uae_u16 uint16 #define uae_s32 int32 #define uae_u32 uint32 #define uae_s64 int64 #define uae_u64 uint64 typedef uae_u32 uaecptr; /* Alignment restrictions */ #if defined(__i386__) || defined(__powerpc__) || defined(__m68k__) || defined(__x86_64__) # define CPU_CAN_ACCESS_UNALIGNED #endif /* Timing functions */ extern uint64 GetTicks_usec(void); extern void Delay_usec(uint32 usec); /* Spinlocks */ #ifdef __GNUC__ #if defined(__powerpc__) || defined(__ppc__) #define HAVE_TEST_AND_SET 1 static inline int testandset(volatile int *p) { int ret; __asm__ __volatile__("0: lwarx %0,0,%1\n" " xor. %0,%3,%0\n" " bne 1f\n" " stwcx. %2,0,%1\n" " bne- 0b\n" "1: " : "=&r" (ret) : "r" (p), "r" (1), "r" (0) : "cr0", "memory"); return ret; } #endif /* FIXME: SheepShaver occasionnally hangs with those locks */ #if 0 && (defined(__i386__) || defined(__x86_64__)) #define HAVE_TEST_AND_SET 1 static inline int testandset(volatile int *p) { long int ret; /* Note: the "xchg" instruction does not need a "lock" prefix */ __asm__ __volatile__("xchgl %k0, %1" : "=r" (ret), "=m" (*p) : "0" (1), "m" (*p) : "memory"); return ret; } #endif #ifdef __s390__ #define HAVE_TEST_AND_SET 1 static inline int testandset(volatile int *p) { int ret; __asm__ __volatile__("0: cs %0,%1,0(%2)\n" " jl 0b" : "=&d" (ret) : "r" (1), "a" (p), "0" (*p) : "cc", "memory" ); return ret; } #endif #ifdef __alpha__ #define HAVE_TEST_AND_SET 1 static inline int testandset(volatile int *p) { int ret; unsigned long one; __asm__ __volatile__("0: mov 1,%2\n" " ldl_l %0,%1\n" " stl_c %2,%1\n" " beq %2,1f\n" ".subsection 2\n" "1: br 0b\n" ".previous" : "=r" (ret), "=m" (*p), "=r" (one) : "m" (*p)); return ret; } #endif #ifdef __sparc__ #define HAVE_TEST_AND_SET 1 static inline int testandset(volatile int *p) { int ret; __asm__ __volatile__("ldstub [%1], %0" : "=r" (ret) : "r" (p) : "memory"); return (ret ? 1 : 0); } #endif #ifdef __arm__ #define HAVE_TEST_AND_SET 1 static inline int testandset(volatile int *p) { register unsigned int ret; __asm__ __volatile__("swp %0, %1, [%2]" : "=r"(ret) : "0"(1), "r"(p)); return ret; } #endif #endif /* __GNUC__ */ typedef volatile int spinlock_t; static const spinlock_t SPIN_LOCK_UNLOCKED = 0; #if HAVE_TEST_AND_SET #define HAVE_SPINLOCKS 1 static inline void spin_lock(spinlock_t *lock) { while (testandset(lock)); } static inline void spin_unlock(spinlock_t *lock) { *lock = 0; } static inline int spin_trylock(spinlock_t *lock) { return !testandset(lock); } #else static inline void spin_lock(spinlock_t *lock) { } static inline void spin_unlock(spinlock_t *lock) { } static inline int spin_trylock(spinlock_t *lock) { return 1; } #endif /* X11 display fast locks */ #ifdef HAVE_SPINLOCKS #define X11_LOCK_TYPE spinlock_t #define X11_LOCK_INIT SPIN_LOCK_UNLOCKED #define XDisplayLock() spin_lock(&x_display_lock) #define XDisplayUnlock() spin_unlock(&x_display_lock) #elif defined(HAVE_PTHREADS) #define X11_LOCK_TYPE pthread_mutex_t #define X11_LOCK_INIT PTHREAD_MUTEX_INITIALIZER #define XDisplayLock() pthread_mutex_lock(&x_display_lock); #define XDisplayUnlock() pthread_mutex_unlock(&x_display_lock); #else #define XDisplayLock() #define XDisplayUnlock() #endif #ifdef X11_LOCK_TYPE extern X11_LOCK_TYPE x_display_lock; #endif #ifdef HAVE_PTHREADS /* Centralized pthread attribute setup */ void Set_pthread_attr(pthread_attr_t *attr, int priority); #endif /* UAE CPU defines */ #ifdef WORDS_BIGENDIAN #ifdef CPU_CAN_ACCESS_UNALIGNED /* Big-endian CPUs which can do unaligned accesses */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {return *a;} static inline uae_u32 do_get_mem_word(uae_u16 *a) {return *a;} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {*a = v;} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {*a = v;} #else /* CPU_CAN_ACCESS_UNALIGNED */ #ifdef sgi /* The SGI MIPSPro compilers can do unaligned accesses given enough hints. * They will automatically inline these routines. */ #ifdef __cplusplus extern "C" { /* only the C compiler does unaligned accesses */ #endif extern uae_u32 do_get_mem_long(uae_u32 *a); extern uae_u32 do_get_mem_word(uae_u16 *a); extern void do_put_mem_long(uae_u32 *a, uae_u32 v); extern void do_put_mem_word(uae_u16 *a, uae_u32 v); #ifdef __cplusplus } #endif #else /* sgi */ /* Big-endian CPUs which can not do unaligned accesses (this is not the most efficient way to do this...) */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint8 *b = (uint8 *)a; return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];} static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint8 *b = (uint8 *)a; return (b[0] << 8) | b[1];} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 24; b[1] = v >> 16; b[2] = v >> 8; b[3] = v;} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 8; b[1] = v;} #endif /* sgi */ #endif /* CPU_CAN_ACCESS_UNALIGNED */ #else /* WORDS_BIGENDIAN */ #if defined(__i386__) || defined(__x86_64__) /* Intel x86 */ #define X86_PPRO_OPT static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 retval; __asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc"); return retval;} #ifdef X86_PPRO_OPT static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswapl %k0\n" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #else static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #endif #define HAVE_GET_WORD_UNSWAPPED #define do_get_mem_word_unswapped(a) ((uae_u32)*((uae_u16 *)(a))) static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #ifdef X86_PPRO_OPT static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); *a = v;} #else static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #endif #define HAVE_OPTIMIZED_BYTESWAP_32 /* bswap doesn't affect condition codes */ static inline uae_u32 do_byteswap_32(uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v)); return v;} #define HAVE_OPTIMIZED_BYTESWAP_16 #ifdef X86_PPRO_OPT static inline uae_u32 do_byteswap_16(uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); return v;} #else static inline uae_u32 do_byteswap_16(uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); return v;} #endif #elif defined(CPU_CAN_ACCESS_UNALIGNED) /* Other little-endian CPUs which can do unaligned accesses */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 x = *a; return (x >> 24) | (x >> 8) & 0xff00 | (x << 8) & 0xff0000 | (x << 24);} static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint16 x = *a; return (x >> 8) | (x << 8);} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {*a = (v >> 24) | (v >> 8) & 0xff00 | (v << 8) & 0xff0000 | (v << 24);} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {*a = (v >> 8) | (v << 8);} #else /* CPU_CAN_ACCESS_UNALIGNED */ /* Other little-endian CPUs which can not do unaligned accesses (this needs optimization) */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint8 *b = (uint8 *)a; return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];} static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint8 *b = (uint8 *)a; return (b[0] << 8) | b[1];} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 24; b[1] = v >> 16; b[2] = v >> 8; b[3] = v;} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 8; b[1] = v;} #endif /* CPU_CAN_ACCESS_UNALIGNED */ #endif /* WORDS_BIGENDIAN */ #ifndef HAVE_OPTIMIZED_BYTESWAP_32 static inline uae_u32 do_byteswap_32(uae_u32 v) { return (((v >> 24) & 0xff) | ((v >> 8) & 0xff00) | ((v & 0xff) << 24) | ((v & 0xff00) << 8)); } #endif #ifndef HAVE_OPTIMIZED_BYTESWAP_16 static inline uae_u32 do_byteswap_16(uae_u32 v) { return (((v >> 8) & 0xff) | ((v & 0xff) << 8)); } #endif #define do_get_mem_byte(a) ((uae_u32)*((uae_u8 *)(a))) #define do_put_mem_byte(a, v) (*(uae_u8 *)(a) = (v)) #define call_mem_get_func(func, addr) ((*func)(addr)) #define call_mem_put_func(func, addr, v) ((*func)(addr, v)) #define __inline__ inline #define CPU_EMU_SIZE 0 #undef NO_INLINE_MEMORY_ACCESS #undef MD_HAVE_MEM_1_FUNCS #define ENUMDECL typedef enum #define ENUMNAME(name) name #define write_log printf #if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY) #define ASM_SYM_FOR_FUNC(a) __asm__(a) #else #define ASM_SYM_FOR_FUNC(a) #endif #ifndef REGPARAM # define REGPARAM #endif #define REGPARAM2 #endif BasiliskII/src/Unix/vm_alloc.cpp0000644000175000017500000003422011700157370016755 0ustar centriscentris/* * vm_alloc.cpp - Wrapper to various virtual memory allocation schemes * (supports mmap, vm_allocate or fallbacks to malloc) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_WIN32_VM #define WIN32_LEAN_AND_MEAN /* avoid including junk */ #include #endif #include #include #include #include #include #include "vm_alloc.h" #if defined(__APPLE__) && defined(__MACH__) #include #endif #ifdef HAVE_MACH_VM #ifndef HAVE_MACH_TASK_SELF #ifdef HAVE_TASK_SELF #define mach_task_self task_self #else #error "No task_self(), you lose." #endif #endif #endif #ifdef HAVE_WIN32_VM /* Windows is either ILP32 or LLP64 */ typedef UINT_PTR vm_uintptr_t; #else /* Other systems are sane as they are either ILP32 or LP64 */ typedef unsigned long vm_uintptr_t; #endif /* We want MAP_32BIT, if available, for SheepShaver and BasiliskII because the emulated target is 32-bit and this helps to allocate memory so that branches could be resolved more easily (32-bit displacement to code in .text), on AMD64 for example. */ #if defined(__hpux) #define MAP_32BIT MAP_ADDR32 #endif #ifndef MAP_32BIT #define MAP_32BIT 0 #endif #ifndef MAP_ANON #define MAP_ANON 0 #endif #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS 0 #endif #define MAP_EXTRA_FLAGS (MAP_32BIT) #ifdef HAVE_MMAP_VM #if (defined(__linux__) && defined(__i386__)) || HAVE_LINKER_SCRIPT /* Force a reasonnable address below 0x80000000 on x86 so that we don't get addresses above when the program is run on AMD64. NOTE: this is empirically determined on Linux/x86. */ #define MAP_BASE 0x10000000 #else #define MAP_BASE 0x00000000 #endif static char * next_address = (char *)MAP_BASE; #ifdef HAVE_MMAP_ANON #define map_flags (MAP_ANON | MAP_EXTRA_FLAGS) #define zero_fd -1 #else #ifdef HAVE_MMAP_ANONYMOUS #define map_flags (MAP_ANONYMOUS | MAP_EXTRA_FLAGS) #define zero_fd -1 #else #define map_flags (MAP_EXTRA_FLAGS) static int zero_fd = -1; #endif #endif #endif /* Translate generic VM map flags to host values. */ #ifdef HAVE_MMAP_VM static int translate_map_flags(int vm_flags) { int flags = 0; if (vm_flags & VM_MAP_SHARED) flags |= MAP_SHARED; if (vm_flags & VM_MAP_PRIVATE) flags |= MAP_PRIVATE; if (vm_flags & VM_MAP_FIXED) flags |= MAP_FIXED; if (vm_flags & VM_MAP_32BIT) flags |= MAP_32BIT; return flags; } #endif /* Align ADDR and SIZE to 64K boundaries. */ #ifdef HAVE_WIN32_VM static inline LPVOID align_addr_segment(LPVOID addr) { return (LPVOID)(((vm_uintptr_t)addr) & -((vm_uintptr_t)65536)); } static inline DWORD align_size_segment(LPVOID addr, DWORD size) { return size + ((vm_uintptr_t)addr - (vm_uintptr_t)align_addr_segment(addr)); } #endif /* Translate generic VM prot flags to host values. */ #ifdef HAVE_WIN32_VM static int translate_prot_flags(int prot_flags) { int prot = PAGE_READWRITE; if (prot_flags == (VM_PAGE_EXECUTE | VM_PAGE_READ | VM_PAGE_WRITE)) prot = PAGE_EXECUTE_READWRITE; else if (prot_flags == (VM_PAGE_EXECUTE | VM_PAGE_READ)) prot = PAGE_EXECUTE_READ; else if (prot_flags == (VM_PAGE_READ | VM_PAGE_WRITE)) prot = PAGE_READWRITE; else if (prot_flags == VM_PAGE_READ) prot = PAGE_READONLY; else if (prot_flags == 0) prot = PAGE_NOACCESS; return prot; } #endif /* Translate Mach return codes to POSIX errno values. */ #ifdef HAVE_MACH_VM static int vm_error(kern_return_t ret_code) { switch (ret_code) { case KERN_SUCCESS: return 0; case KERN_INVALID_ADDRESS: case KERN_NO_SPACE: return ENOMEM; case KERN_PROTECTION_FAILURE: return EACCES; default: return EINVAL; } } #endif /* Initialize the VM system. Returns 0 if successful, -1 for errors. */ int vm_init(void) { #ifdef HAVE_MMAP_VM #ifndef zero_fd zero_fd = open("/dev/zero", O_RDWR); if (zero_fd < 0) return -1; #endif #endif // On 10.4 and earlier, reset CrashReporter's task signal handler to // avoid having it show up for signals that get handled. #if defined(__APPLE__) && defined(__MACH__) struct utsname info; if (!uname(&info) && atoi(info.release) <= 8) { task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC, MACH_PORT_NULL, EXCEPTION_STATE_IDENTITY, MACHINE_THREAD_STATE); } #endif return 0; } /* Deallocate all internal data used to wrap virtual memory allocators. */ void vm_exit(void) { #ifdef HAVE_MMAP_VM #ifndef zero_fd if (zero_fd != -1) { close(zero_fd); zero_fd = -1; } #endif #endif } /* Allocate zero-filled memory of SIZE bytes. The mapping is private and default protection bits are read / write. The return value is the actual mapping address chosen or VM_MAP_FAILED for errors. */ void * vm_acquire(size_t size, int options) { void * addr; errno = 0; // VM_MAP_FIXED are to be used with vm_acquire_fixed() only if (options & VM_MAP_FIXED) return VM_MAP_FAILED; #ifndef HAVE_VM_WRITE_WATCH if (options & VM_MAP_WRITE_WATCH) return VM_MAP_FAILED; #endif #if defined(HAVE_MACH_VM) // vm_allocate() returns a zero-filled memory region kern_return_t ret_code = vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, TRUE); if (ret_code != KERN_SUCCESS) { errno = vm_error(ret_code); return VM_MAP_FAILED; } #elif defined(HAVE_MMAP_VM) int fd = zero_fd; int the_map_flags = translate_map_flags(options) | map_flags; if ((addr = mmap((caddr_t)next_address, size, VM_PAGE_DEFAULT, the_map_flags, fd, 0)) == (void *)MAP_FAILED) return VM_MAP_FAILED; // Sanity checks for 64-bit platforms if (sizeof(void *) == 8 && (options & VM_MAP_32BIT) && !((char *)addr <= (char *)0xffffffff)) return VM_MAP_FAILED; next_address = (char *)addr + size; #elif defined(HAVE_WIN32_VM) int alloc_type = MEM_RESERVE | MEM_COMMIT; if (options & VM_MAP_WRITE_WATCH) alloc_type |= MEM_WRITE_WATCH; if ((addr = VirtualAlloc(NULL, size, alloc_type, PAGE_EXECUTE_READWRITE)) == NULL) return VM_MAP_FAILED; #else if ((addr = calloc(size, 1)) == 0) return VM_MAP_FAILED; // Omit changes for protections because they are not supported in this mode return addr; #endif // Explicitely protect the newly mapped region here because on some systems, // say MacOS X, mmap() doesn't honour the requested protection flags. if (vm_protect(addr, size, VM_PAGE_DEFAULT) != 0) return VM_MAP_FAILED; return addr; } /* Allocate zero-filled memory at exactly ADDR (which must be page-aligned). Retuns 0 if successful, -1 on errors. */ int vm_acquire_fixed(void * addr, size_t size, int options) { errno = 0; // Fixed mappings are required to be private if (options & VM_MAP_SHARED) return -1; #ifndef HAVE_VM_WRITE_WATCH if (options & VM_MAP_WRITE_WATCH) return -1; #endif #if defined(HAVE_MACH_VM) // vm_allocate() returns a zero-filled memory region kern_return_t ret_code = vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, 0); if (ret_code != KERN_SUCCESS) { errno = vm_error(ret_code); return -1; } #elif defined(HAVE_MMAP_VM) int fd = zero_fd; int the_map_flags = translate_map_flags(options) | map_flags | MAP_FIXED; if (mmap((caddr_t)addr, size, VM_PAGE_DEFAULT, the_map_flags, fd, 0) == (void *)MAP_FAILED) return -1; #elif defined(HAVE_WIN32_VM) // Windows cannot allocate Low Memory if (addr == NULL) return -1; int alloc_type = MEM_RESERVE | MEM_COMMIT; if (options & VM_MAP_WRITE_WATCH) alloc_type |= MEM_WRITE_WATCH; // Allocate a possibly offset region to align on 64K boundaries LPVOID req_addr = align_addr_segment(addr); DWORD req_size = align_size_segment(addr, size); LPVOID ret_addr = VirtualAlloc(req_addr, req_size, alloc_type, PAGE_EXECUTE_READWRITE); if (ret_addr != req_addr) return -1; #else // Unsupported return -1; #endif // Explicitely protect the newly mapped region here because on some systems, // say MacOS X, mmap() doesn't honour the requested protection flags. if (vm_protect(addr, size, VM_PAGE_DEFAULT) != 0) return -1; return 0; } /* Deallocate any mapping for the region starting at ADDR and extending LEN bytes. Returns 0 if successful, -1 on errors. */ int vm_release(void * addr, size_t size) { // Safety check: don't try to release memory that was not allocated if (addr == VM_MAP_FAILED) return 0; #ifdef HAVE_MACH_VM if (vm_deallocate(mach_task_self(), (vm_address_t)addr, size) != KERN_SUCCESS) return -1; #else #ifdef HAVE_MMAP_VM if (munmap((caddr_t)addr, size) != 0) return -1; #else #ifdef HAVE_WIN32_VM if (VirtualFree(align_addr_segment(addr), 0, MEM_RELEASE) == 0) return -1; #else free(addr); #endif #endif #endif return 0; } /* Change the memory protection of the region starting at ADDR and extending LEN bytes to PROT. Returns 0 if successful, -1 for errors. */ int vm_protect(void * addr, size_t size, int prot) { #ifdef HAVE_MACH_VM int ret_code = vm_protect(mach_task_self(), (vm_address_t)addr, size, 0, prot); return ret_code == KERN_SUCCESS ? 0 : -1; #else #ifdef HAVE_MMAP_VM int ret_code = mprotect((caddr_t)addr, size, prot); return ret_code == 0 ? 0 : -1; #else #ifdef HAVE_WIN32_VM DWORD old_prot; int ret_code = VirtualProtect(addr, size, translate_prot_flags(prot), &old_prot); return ret_code != 0 ? 0 : -1; #else // Unsupported return -1; #endif #endif #endif } /* Return the addresses of the pages that got modified in the specified range [ ADDR, ADDR + SIZE [ since the last reset of the watch bits. Returns 0 if successful, -1 for errors. */ int vm_get_write_watch(void * addr, size_t size, void ** pages, unsigned int * n_pages, int options) { #ifdef HAVE_VM_WRITE_WATCH #ifdef HAVE_WIN32_VM DWORD flags = 0; if (options & VM_WRITE_WATCH_RESET) flags |= WRITE_WATCH_FLAG_RESET; ULONG page_size; ULONG_PTR count = *n_pages; int ret_code = GetWriteWatch(flags, addr, size, pages, &count, &page_size); if (ret_code != 0) return -1; *n_pages = count; return 0; #endif #endif // Unsupported return -1; } /* Reset the write-tracking state for the specified range [ ADDR, ADDR + SIZE [. Returns 0 if successful, -1 for errors. */ int vm_reset_write_watch(void * addr, size_t size) { #ifdef HAVE_VM_WRITE_WATCH #ifdef HAVE_WIN32_VM int ret_code = ResetWriteWatch(addr, size); return ret_code == 0 ? 0 : -1; #endif #endif // Unsupported return -1; } /* Returns the size of a page. */ int vm_get_page_size(void) { #ifdef HAVE_WIN32_VM static vm_uintptr_t page_size = 0; if (page_size == 0) { SYSTEM_INFO si; GetSystemInfo(&si); page_size = si.dwAllocationGranularity; } return page_size; #else return getpagesize(); #endif } #ifdef CONFIGURE_TEST_VM_WRITE_WATCH int main(void) { int i, j; vm_init(); vm_uintptr_t page_size = vm_get_page_size(); char *area; const int n_pages = 7; const int area_size = n_pages * page_size; const int map_options = VM_MAP_DEFAULT | VM_MAP_WRITE_WATCH; if ((area = (char *)vm_acquire(area_size, map_options)) == VM_MAP_FAILED) return 1; unsigned int n_modified_pages_expected = 0; static const int touch_page[n_pages] = { 0, 1, 1, 0, 1, 0, 1 }; for (i = 0; i < n_pages; i++) { if (touch_page[i]) { area[i * page_size] = 1; ++n_modified_pages_expected; } } char *modified_pages[n_pages]; unsigned int n_modified_pages = n_pages; if (vm_get_write_watch(area, area_size, (void **)modified_pages, &n_modified_pages) < 0) return 2; if (n_modified_pages != n_modified_pages_expected) return 3; for (i = 0, j = 0; i < n_pages; i++) { char v = area[i * page_size]; if ((touch_page[i] && !v) || (!touch_page[i] && v)) return 4; if (!touch_page[i]) continue; if (modified_pages[j] != (area + i * page_size)) return 5; ++j; } vm_release(area, area_size); return 0; } #endif #ifdef CONFIGURE_TEST_VM_MAP #include #include static void fault_handler(int sig) { exit(1); } /* Tests covered here: - TEST_VM_PROT_* program slices actually succeeds when a crash occurs - TEST_VM_MAP_ANON* program slices succeeds when it could be compiled */ int main(void) { vm_init(); signal(SIGSEGV, fault_handler); #ifdef SIGBUS signal(SIGBUS, fault_handler); #endif #define page_align(address) ((char *)((vm_uintptr_t)(address) & -page_size)) vm_uintptr_t page_size = vm_get_page_size(); const int area_size = 6 * page_size; volatile char * area = (volatile char *) vm_acquire(area_size); volatile char * fault_address = area + (page_size * 7) / 2; #if defined(TEST_VM_MMAP_ANON) || defined(TEST_VM_MMAP_ANONYMOUS) if (area == VM_MAP_FAILED) return 1; if (vm_release((char *)area, area_size) < 0) return 1; return 0; #endif #if defined(TEST_VM_PROT_NONE_READ) || defined(TEST_VM_PROT_NONE_WRITE) if (area == VM_MAP_FAILED) return 0; if (vm_protect(page_align(fault_address), page_size, VM_PAGE_NOACCESS) < 0) return 0; #endif #if defined(TEST_VM_PROT_RDWR_WRITE) if (area == VM_MAP_FAILED) return 1; if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0) return 1; if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0) return 1; #endif #if defined(TEST_VM_PROT_READ_WRITE) if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0) return 0; #endif #if defined(TEST_VM_PROT_NONE_READ) // this should cause a core dump char foo = *fault_address; return 0; #endif #if defined(TEST_VM_PROT_NONE_WRITE) || defined(TEST_VM_PROT_READ_WRITE) // this should cause a core dump *fault_address = 'z'; return 0; #endif #if defined(TEST_VM_PROT_RDWR_WRITE) // this should not cause a core dump *fault_address = 'z'; return 0; #endif } #endif BasiliskII/src/Unix/main_unix.cpp0000644000175000017500000011373611340220131017144 0ustar centriscentris/* * main_unix.cpp - Startup code for Unix * * Basilisk II (C) Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #ifdef USE_SDL # include #endif #ifndef USE_SDL_VIDEO # include #endif #ifdef HAVE_PTHREADS # include #endif #if REAL_ADDRESSING || DIRECT_ADDRESSING # include #endif #if !EMULATED_68K && defined(__NetBSD__) # include # include # include # include struct sigstate { int ss_flags; struct frame ss_frame; struct fpframe ss_fpstate; }; # define SS_FPSTATE 0x02 # define SS_USERREGS 0x04 #endif #ifdef ENABLE_GTK # include # include # ifdef HAVE_GNOMEUI # include # endif #endif #ifdef ENABLE_XF86_DGA # include # include #endif #include using std::string; #include "cpu_emulation.h" #include "sys.h" #include "rom_patches.h" #include "xpram.h" #include "timer.h" #include "video.h" #include "emul_op.h" #include "prefs.h" #include "prefs_editor.h" #include "macos_util.h" #include "user_strings.h" #include "version.h" #include "main.h" #include "vm_alloc.h" #include "sigsegv.h" #include "rpc.h" #if USE_JIT extern void flush_icache_range(uint8 *start, uint32 size); // from compemu_support.cpp #endif #ifdef ENABLE_MON # include "mon.h" #endif #define DEBUG 0 #include "debug.h" // Constants const char ROM_FILE_NAME[] = "ROM"; #if !EMULATED_68K const int SIG_STACK_SIZE = SIGSTKSZ; // Size of signal stack #endif const int SCRATCH_MEM_SIZE = 0x10000; // Size of scratch memory area #if !EMULATED_68K // RAM and ROM pointers uint32 RAMBaseMac; // RAM base (Mac address space) uint8 *RAMBaseHost; // RAM base (host address space) uint32 RAMSize; // Size of RAM uint32 ROMBaseMac; // ROM base (Mac address space) uint8 *ROMBaseHost; // ROM base (host address space) uint32 ROMSize; // Size of ROM #endif // CPU and FPU type, addressing mode int CPUType; bool CPUIs68060; int FPUType; bool TwentyFourBitAddressing; // Global variables #ifndef USE_SDL_VIDEO extern char *x_display_name; // X11 display name extern Display *x_display; // X11 display handle #ifdef X11_LOCK_TYPE X11_LOCK_TYPE x_display_lock = X11_LOCK_INIT; // X11 display lock #endif #endif static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes #ifdef HAVE_PTHREADS #if !EMULATED_68K static pthread_t emul_thread; // Handle of MacOS emulation thread (main thread) #endif static bool xpram_thread_active = false; // Flag: XPRAM watchdog installed static volatile bool xpram_thread_cancel = false; // Flag: Cancel XPRAM thread static pthread_t xpram_thread; // XPRAM watchdog static bool tick_thread_active = false; // Flag: 60Hz thread installed static volatile bool tick_thread_cancel = false; // Flag: Cancel 60Hz thread static pthread_t tick_thread; // 60Hz thread static pthread_attr_t tick_thread_attr; // 60Hz thread attributes static pthread_mutex_t intflag_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect InterruptFlags #define LOCK_INTFLAGS pthread_mutex_lock(&intflag_lock) #define UNLOCK_INTFLAGS pthread_mutex_unlock(&intflag_lock) #else #define LOCK_INTFLAGS #define UNLOCK_INTFLAGS #endif #if !EMULATED_68K #define SIG_IRQ SIGUSR1 static struct sigaction sigirq_sa; // Virtual 68k interrupt signal static struct sigaction sigill_sa; // Illegal instruction static void *sig_stack = NULL; // Stack for signal handlers uint16 EmulatedSR; // Emulated bits of SR (supervisor bit and interrupt mask) #endif #if USE_SCRATCHMEM_SUBTERFUGE uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes #endif #if !defined(HAVE_PTHREADS) static struct sigaction timer_sa; // sigaction used for timer #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) #define SIG_TIMER SIGRTMIN static timer_t timer; // 60Hz timer #endif #endif // !HAVE_PTHREADS #ifdef ENABLE_MON static struct sigaction sigint_sa; // sigaction for SIGINT handler static void sigint_handler(...); #endif #if REAL_ADDRESSING static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped #endif static rpc_connection_t *gui_connection = NULL; // RPC connection to the GUI static const char *gui_connection_path = NULL; // GUI connection identifier // Prototypes static void *xpram_func(void *arg); static void *tick_func(void *arg); static void one_tick(...); #if !EMULATED_68K static void sigirq_handler(int sig, int code, struct sigcontext *scp); static void sigill_handler(int sig, int code, struct sigcontext *scp); extern "C" void EmulOpTrampoline(void); #endif /* * Ersatz functions */ extern "C" { #ifndef HAVE_STRDUP char *strdup(const char *s) { char *n = (char *)malloc(strlen(s) + 1); strcpy(n, s); return n; } #endif } /* * Helpers to map memory that can be accessed from the Mac side */ // NOTE: VM_MAP_32BIT is only used when compiling a 64-bit JIT on specific platforms void *vm_acquire_mac(size_t size) { return vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT); } static int vm_acquire_mac_fixed(void *addr, size_t size) { return vm_acquire_fixed(addr, size, VM_MAP_DEFAULT | VM_MAP_32BIT); } /* * SIGSEGV handler */ static sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip) { const uintptr fault_address = (uintptr)sigsegv_get_fault_address(sip); #if ENABLE_VOSF // Handle screen fault extern bool Screen_fault_handler(sigsegv_info_t *sip); if (Screen_fault_handler(sip)) return SIGSEGV_RETURN_SUCCESS; #endif #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION // Ignore writes to ROM if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // Ignore all other faults, if requested if (PrefsFindBool("ignoresegv")) return SIGSEGV_RETURN_SKIP_INSTRUCTION; #endif return SIGSEGV_RETURN_FAILURE; } /* * Dump state when everything went wrong after a SEGV */ static void sigsegv_dump_state(sigsegv_info_t *sip) { const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip); const sigsegv_address_t fault_instruction = sigsegv_get_fault_instruction_address(sip); fprintf(stderr, "Caught SIGSEGV at address %p", fault_address); if (fault_instruction != SIGSEGV_INVALID_ADDRESS) fprintf(stderr, " [IP=%p]", fault_instruction); fprintf(stderr, "\n"); #if EMULATED_68K uaecptr nextpc; extern void m68k_dumpstate(uaecptr *nextpc); m68k_dumpstate(&nextpc); #endif #if USE_JIT && JIT_DEBUG extern void compiler_dumpstate(void); compiler_dumpstate(); #endif VideoQuitFullScreen(); #ifdef ENABLE_MON const char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); #endif QuitEmulator(); } /* * Update virtual clock and trigger interrupts if necessary */ #ifdef USE_CPU_EMUL_SERVICES static uint64 n_check_ticks = 0; static uint64 emulated_ticks_start = 0; static uint64 emulated_ticks_count = 0; static int64 emulated_ticks_current = 0; static int32 emulated_ticks_quantum = 1000; int32 emulated_ticks = emulated_ticks_quantum; void cpu_do_check_ticks(void) { #if DEBUG n_check_ticks++; #endif uint64 now; static uint64 next = 0; if (next == 0) next = emulated_ticks_start = GetTicks_usec(); // Update total instructions count if (emulated_ticks <= 0) { emulated_ticks_current += (emulated_ticks_quantum - emulated_ticks); // XXX: can you really have a machine fast enough to overflow // a 63-bit m68k instruction counter within 16 ms? if (emulated_ticks_current < 0) { printf("WARNING: Overflowed 63-bit m68k instruction counter in less than 16 ms!\n"); goto recalibrate_quantum; } } // Check for interrupt opportunity now = GetTicks_usec(); if (next < now) { one_tick(); do { next += 16625; } while (next < now); emulated_ticks_count++; // Recalibrate 1000 Hz quantum every 10 ticks static uint64 last = 0; if (last == 0) last = now; else if (now - last > 166250) { recalibrate_quantum: emulated_ticks_quantum = ((uint64)emulated_ticks_current * 1000) / (now - last); emulated_ticks_current = 0; last = now; } } // Update countdown if (emulated_ticks <= 0) emulated_ticks += emulated_ticks_quantum; } #endif /* * Main program */ static void usage(const char *prg_name) { printf( "Usage: %s [OPTION...]\n" "\nUnix options:\n" " --config FILE\n read/write configuration from/to FILE\n" " --display STRING\n X display to use\n" " --break ADDRESS\n set ROM breakpoint\n" " --rominfo\n dump ROM information\n", prg_name ); LoadPrefs(NULL); // read the prefs file so PrefsPrintUsage() will print the correct default values PrefsPrintUsage(); exit(0); } int main(int argc, char **argv) { const char *vmdir = NULL; char str[256]; // Initialize variables RAMBaseHost = NULL; ROMBaseHost = NULL; srand(time(NULL)); tzset(); // Print some info printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); printf(" %s\n", GetString(STR_ABOUT_TEXT2)); // Parse command line arguments for (int i=1; i i) { k -= i; for (int j=i+k; j 1023*1024*1024) // Cap to 1023MB (APD crashes at 1GB) RAMSize = 1023*1024*1024; #if REAL_ADDRESSING || DIRECT_ADDRESSING RAMSize = RAMSize & -getpagesize(); // Round down to page boundary #endif // Initialize VM system vm_init(); #if REAL_ADDRESSING // Flag: RAM and ROM are contigously allocated from address 0 bool memory_mapped_from_zero = false; // Make sure to map RAM & ROM at address 0 only on platforms that // supports linker scripts to relocate the Basilisk II executable // above 0x70000000 #if HAVE_LINKER_SCRIPT const bool can_map_all_memory = true; #else const bool can_map_all_memory = false; #endif // Try to allocate all memory from 0x0000, if it is not known to crash if (can_map_all_memory && (vm_acquire_mac_fixed(0, RAMSize + 0x100000) == 0)) { D(bug("Could allocate RAM and ROM from 0x0000\n")); memory_mapped_from_zero = true; } #ifndef PAGEZERO_HACK // Otherwise, just create the Low Memory area (0x0000..0x2000) else if (vm_acquire_mac_fixed(0, 0x2000) == 0) { D(bug("Could allocate the Low Memory globals\n")); lm_area_mapped = true; } // Exit on failure else { sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno)); ErrorAlert(str); QuitEmulator(); } #endif #endif /* REAL_ADDRESSING */ // Create areas for Mac RAM and ROM #if REAL_ADDRESSING if (memory_mapped_from_zero) { RAMBaseHost = (uint8 *)0; ROMBaseHost = RAMBaseHost + RAMSize; } else #endif { uint8 *ram_rom_area = (uint8 *)vm_acquire_mac(RAMSize + 0x100000); if (ram_rom_area == VM_MAP_FAILED) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } RAMBaseHost = ram_rom_area; ROMBaseHost = RAMBaseHost + RAMSize; } #if USE_SCRATCHMEM_SUBTERFUGE // Allocate scratch memory ScratchMem = (uint8 *)vm_acquire_mac(SCRATCH_MEM_SIZE); if (ScratchMem == VM_MAP_FAILED) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block #endif #if DIRECT_ADDRESSING // RAMBaseMac shall always be zero MEMBaseDiff = (uintptr)RAMBaseHost; RAMBaseMac = 0; ROMBaseMac = Host2MacAddr(ROMBaseHost); #endif #if REAL_ADDRESSING RAMBaseMac = Host2MacAddr(RAMBaseHost); ROMBaseMac = Host2MacAddr(ROMBaseHost); #endif D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac)); D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac)); // Get rom file path from preferences const char *rom_path = PrefsFindString("rom"); // Load Mac ROM int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY); if (rom_fd < 0) { ErrorAlert(STR_NO_ROM_FILE_ERR); QuitEmulator(); } printf(GetString(STR_READING_ROM_FILE)); ROMSize = lseek(rom_fd, 0, SEEK_END); if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) { ErrorAlert(STR_ROM_SIZE_ERR); close(rom_fd); QuitEmulator(); } lseek(rom_fd, 0, SEEK_SET); if (read(rom_fd, ROMBaseHost, ROMSize) != (ssize_t)ROMSize) { ErrorAlert(STR_ROM_FILE_READ_ERR); close(rom_fd); QuitEmulator(); } #if !EMULATED_68K // Get CPU model int mib[2] = {CTL_HW, HW_MODEL}; char *model; size_t model_len; sysctl(mib, 2, NULL, &model_len, NULL, 0); model = (char *)malloc(model_len); sysctl(mib, 2, model, &model_len, NULL, 0); D(bug("Model: %s\n", model)); // Set CPU and FPU type CPUIs68060 = false; if (strstr(model, "020")) CPUType = 2; else if (strstr(model, "030")) CPUType = 3; else if (strstr(model, "040")) CPUType = 4; else if (strstr(model, "060")) { CPUType = 4; CPUIs68060 = true; } else { printf("WARNING: Cannot detect CPU type, assuming 68020\n"); CPUType = 2; } FPUType = 1; // NetBSD has an FPU emulation, so the FPU ought to be available at all times TwentyFourBitAddressing = false; #endif // Initialize everything if (!InitAll(vmdir)) QuitEmulator(); D(bug("Initialization complete\n")); #if !EMULATED_68K // (Virtual) supervisor mode, disable interrupts EmulatedSR = 0x2700; #ifdef HAVE_PTHREADS // Get handle of main thread emul_thread = pthread_self(); #endif // Create and install stack for signal handlers sig_stack = malloc(SIG_STACK_SIZE); D(bug("Signal stack at %p\n", sig_stack)); if (sig_stack == NULL) { ErrorAlert(STR_NOT_ENOUGH_MEMORY_ERR); QuitEmulator(); } stack_t new_stack; new_stack.ss_sp = sig_stack; new_stack.ss_flags = 0; new_stack.ss_size = SIG_STACK_SIZE; if (sigaltstack(&new_stack, NULL) < 0) { sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno)); ErrorAlert(str); QuitEmulator(); } // Install SIGILL handler for emulating privileged instructions and // executing A-Trap and EMUL_OP opcodes sigemptyset(&sigill_sa.sa_mask); // Block virtual 68k interrupts during SIGILL handling sigaddset(&sigill_sa.sa_mask, SIG_IRQ); sigaddset(&sigill_sa.sa_mask, SIGALRM); sigill_sa.sa_handler = (void (*)(int))sigill_handler; sigill_sa.sa_flags = SA_ONSTACK; if (sigaction(SIGILL, &sigill_sa, NULL) < 0) { sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGILL", strerror(errno)); ErrorAlert(str); QuitEmulator(); } // Install virtual 68k interrupt signal handler sigemptyset(&sigirq_sa.sa_mask); sigaddset(&sigirq_sa.sa_mask, SIGALRM); sigirq_sa.sa_handler = (void (*)(int))sigirq_handler; sigirq_sa.sa_flags = SA_ONSTACK | SA_RESTART; if (sigaction(SIG_IRQ, &sigirq_sa, NULL) < 0) { sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIG_IRQ", strerror(errno)); ErrorAlert(str); QuitEmulator(); } #endif #ifdef ENABLE_MON // Setup SIGINT handler to enter mon sigemptyset(&sigint_sa.sa_mask); sigint_sa.sa_handler = (void (*)(int))sigint_handler; sigint_sa.sa_flags = 0; sigaction(SIGINT, &sigint_sa, NULL); #endif #ifndef USE_CPU_EMUL_SERVICES #if defined(HAVE_PTHREADS) // POSIX threads available, start 60Hz thread Set_pthread_attr(&tick_thread_attr, 0); tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0); if (!tick_thread_active) { sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno)); ErrorAlert(str); QuitEmulator(); } D(bug("60Hz thread started\n")); #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) // POSIX.4 timers and real-time signals available, start 60Hz timer sigemptyset(&timer_sa.sa_mask); timer_sa.sa_sigaction = (void (*)(int, siginfo_t *, void *))one_tick; timer_sa.sa_flags = SA_SIGINFO | SA_RESTART; if (sigaction(SIG_TIMER, &timer_sa, NULL) < 0) { sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIG_TIMER", strerror(errno)); ErrorAlert(str); QuitEmulator(); } struct sigevent timer_event; timer_event.sigev_notify = SIGEV_SIGNAL; timer_event.sigev_signo = SIG_TIMER; if (timer_create(CLOCK_REALTIME, &timer_event, &timer) < 0) { sprintf(str, GetString(STR_TIMER_CREATE_ERR), strerror(errno)); ErrorAlert(str); QuitEmulator(); } struct itimerspec req; req.it_value.tv_sec = 0; req.it_value.tv_nsec = 16625000; req.it_interval.tv_sec = 0; req.it_interval.tv_nsec = 16625000; if (timer_settime(timer, 0, &req, NULL) < 0) { sprintf(str, GetString(STR_TIMER_SETTIME_ERR), strerror(errno)); ErrorAlert(str); QuitEmulator(); } D(bug("60Hz timer started\n")); #else // Start 60Hz timer sigemptyset(&timer_sa.sa_mask); // Block virtual 68k interrupts during SIGARLM handling #if !EMULATED_68K sigaddset(&timer_sa.sa_mask, SIG_IRQ); #endif timer_sa.sa_handler = one_tick; timer_sa.sa_flags = SA_ONSTACK | SA_RESTART; if (sigaction(SIGALRM, &timer_sa, NULL) < 0) { sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGALRM", strerror(errno)); ErrorAlert(str); QuitEmulator(); } struct itimerval req; req.it_interval.tv_sec = req.it_value.tv_sec = 0; req.it_interval.tv_usec = req.it_value.tv_usec = 16625; setitimer(ITIMER_REAL, &req, NULL); #endif #endif #ifdef USE_PTHREADS_SERVICES // Start XPRAM watchdog thread memcpy(last_xpram, XPRAM, XPRAM_SIZE); xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0); D(bug("XPRAM thread started\n")); #endif // Start 68k and jump to ROM boot routine D(bug("Starting emulation...\n")); Start680x0(); QuitEmulator(); return 0; } /* * Quit emulator */ void QuitEmulator(void) { D(bug("QuitEmulator\n")); #if EMULATED_68K // Exit 680x0 emulation Exit680x0(); #endif #if defined(USE_CPU_EMUL_SERVICES) // Show statistics uint64 emulated_ticks_end = GetTicks_usec(); D(bug("%ld ticks in %ld usec = %f ticks/sec [%ld tick checks]\n", (long)emulated_ticks_count, (long)(emulated_ticks_end - emulated_ticks_start), emulated_ticks_count * 1000000.0 / (emulated_ticks_end - emulated_ticks_start), (long)n_check_ticks)); #elif defined(USE_PTHREADS_SERVICES) // Stop 60Hz thread if (tick_thread_active) { tick_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(tick_thread); #endif pthread_join(tick_thread, NULL); } #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) // Stop 60Hz timer timer_delete(timer); #else struct itimerval req; req.it_interval.tv_sec = req.it_value.tv_sec = 0; req.it_interval.tv_usec = req.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &req, NULL); #endif #ifdef USE_PTHREADS_SERVICES // Stop XPRAM watchdog thread if (xpram_thread_active) { xpram_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(xpram_thread); #endif pthread_join(xpram_thread, NULL); } #endif // Deinitialize everything ExitAll(); // Free ROM/RAM areas if (RAMBaseHost != VM_MAP_FAILED) { vm_release(RAMBaseHost, RAMSize + 0x100000); RAMBaseHost = NULL; ROMBaseHost = NULL; } #if USE_SCRATCHMEM_SUBTERFUGE // Delete scratch memory area if (ScratchMem != (uint8 *)VM_MAP_FAILED) { vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE); ScratchMem = NULL; } #endif #if REAL_ADDRESSING // Delete Low Memory area if (lm_area_mapped) vm_release(0, 0x2000); #endif // Exit VM wrappers vm_exit(); // Exit system routines SysExit(); // Exit preferences PrefsExit(); // Close X11 server connection #ifndef USE_SDL_VIDEO if (x_display) XCloseDisplay(x_display); #endif // Notify GUI we are about to leave if (gui_connection) { if (rpc_method_invoke(gui_connection, RPC_METHOD_EXIT, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR) rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID); } exit(0); } /* * Code was patched, flush caches if neccessary (i.e. when using a real 680x0 * or a dynamically recompiling emulator) */ void FlushCodeCache(void *start, uint32 size) { #if USE_JIT if (UseJIT) flush_icache_range((uint8 *)start, size); #endif #if !EMULATED_68K && defined(__NetBSD__) m68k_sync_icache(start, size); #endif } /* * SIGINT handler, enters mon */ #ifdef ENABLE_MON static void sigint_handler(...) { #if EMULATED_68K uaecptr nextpc; extern void m68k_dumpstate(uaecptr *nextpc); m68k_dumpstate(&nextpc); #endif VideoQuitFullScreen(); const char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); QuitEmulator(); } #endif #ifdef HAVE_PTHREADS /* * Pthread configuration */ void Set_pthread_attr(pthread_attr_t *attr, int priority) { pthread_attr_init(attr); #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) // Some of these only work for superuser if (geteuid() == 0) { pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(attr, SCHED_FIFO); struct sched_param fifo_param; fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2 + priority); pthread_attr_setschedparam(attr, &fifo_param); } if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) { #ifdef PTHREAD_SCOPE_BOUND_NP // If system scope is not available (eg. we're not running // with CAP_SCHED_MGT capability on an SGI box), try bound // scope. It exposes pthread scheduling to the kernel, // without setting realtime priority. pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP); #endif } #endif } #endif // HAVE_PTHREADS /* * Mutexes */ #ifdef HAVE_PTHREADS struct B2_mutex { B2_mutex() { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); // Initialize the mutex for priority inheritance -- // required for accurate timing. #if defined(HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL) && !defined(__CYGWIN__) pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); #endif #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); #endif #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); #endif pthread_mutex_init(&m, &attr); pthread_mutexattr_destroy(&attr); } ~B2_mutex() { pthread_mutex_trylock(&m); // Make sure it's locked before pthread_mutex_unlock(&m); // unlocking it. pthread_mutex_destroy(&m); } pthread_mutex_t m; }; B2_mutex *B2_create_mutex(void) { return new B2_mutex; } void B2_lock_mutex(B2_mutex *mutex) { pthread_mutex_lock(&mutex->m); } void B2_unlock_mutex(B2_mutex *mutex) { pthread_mutex_unlock(&mutex->m); } void B2_delete_mutex(B2_mutex *mutex) { delete mutex; } #else struct B2_mutex { int dummy; }; B2_mutex *B2_create_mutex(void) { return new B2_mutex; } void B2_lock_mutex(B2_mutex *mutex) { } void B2_unlock_mutex(B2_mutex *mutex) { } void B2_delete_mutex(B2_mutex *mutex) { delete mutex; } #endif /* * Interrupt flags (must be handled atomically!) */ uint32 InterruptFlags = 0; #if EMULATED_68K void SetInterruptFlag(uint32 flag) { LOCK_INTFLAGS; InterruptFlags |= flag; UNLOCK_INTFLAGS; } void ClearInterruptFlag(uint32 flag) { LOCK_INTFLAGS; InterruptFlags &= ~flag; UNLOCK_INTFLAGS; } #endif #if !EMULATED_68K void TriggerInterrupt(void) { #if defined(HAVE_PTHREADS) pthread_kill(emul_thread, SIG_IRQ); #else raise(SIG_IRQ); #endif } void TriggerNMI(void) { // not yet supported } #endif /* * XPRAM watchdog thread (saves XPRAM every minute) */ static void xpram_watchdog(void) { if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) { memcpy(last_xpram, XPRAM, XPRAM_SIZE); SaveXPRAM(); } } #ifdef USE_PTHREADS_SERVICES static void *xpram_func(void *arg) { while (!xpram_thread_cancel) { for (int i=0; i<60 && !xpram_thread_cancel; i++) Delay_usec(999999); // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true xpram_watchdog(); } return NULL; } #endif /* * 60Hz thread (really 60.15Hz) */ static void one_second(void) { // Pseudo Mac 1Hz interrupt, update local time WriteMacInt32(0x20c, TimerDateTime()); SetInterruptFlag(INTFLAG_1HZ); TriggerInterrupt(); #ifndef USE_PTHREADS_SERVICES static int second_counter = 0; if (++second_counter > 60) { second_counter = 0; xpram_watchdog(); } #endif } static void one_tick(...) { static int tick_counter = 0; if (++tick_counter > 60) { tick_counter = 0; one_second(); } #ifndef USE_PTHREADS_SERVICES // Threads not used to trigger interrupts, perform video refresh from here VideoRefresh(); #endif #ifndef HAVE_PTHREADS // No threads available, perform networking from here SetInterruptFlag(INTFLAG_ETHER); #endif // Trigger 60Hz interrupt if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) { SetInterruptFlag(INTFLAG_60HZ); TriggerInterrupt(); } } #ifdef USE_PTHREADS_SERVICES static void *tick_func(void *arg) { uint64 start = GetTicks_usec(); int64 ticks = 0; uint64 next = GetTicks_usec(); while (!tick_thread_cancel) { one_tick(); next += 16625; int64 delay = next - GetTicks_usec(); if (delay > 0) Delay_usec(delay); else if (delay < -16625) next = GetTicks_usec(); ticks++; } uint64 end = GetTicks_usec(); D(bug("%lld ticks in %lld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); return NULL; } #endif #if !EMULATED_68K /* * Virtual 68k interrupt handler */ static void sigirq_handler(int sig, int code, struct sigcontext *scp) { // Interrupts disabled? Then do nothing if (EmulatedSR & 0x0700) return; struct sigstate *state = (struct sigstate *)scp->sc_ap; M68kRegisters *regs = (M68kRegisters *)&state->ss_frame; // Set up interrupt frame on stack uint32 a7 = regs->a[7]; a7 -= 2; WriteMacInt16(a7, 0x64); a7 -= 4; WriteMacInt32(a7, scp->sc_pc); a7 -= 2; WriteMacInt16(a7, scp->sc_ps | EmulatedSR); scp->sc_sp = regs->a[7] = a7; // Set interrupt level EmulatedSR |= 0x2100; // Jump to MacOS interrupt handler on return scp->sc_pc = ReadMacInt32(0x64); } /* * SIGILL handler, for emulation of privileged instructions and executing * A-Trap and EMUL_OP opcodes */ static void sigill_handler(int sig, int code, struct sigcontext *scp) { struct sigstate *state = (struct sigstate *)scp->sc_ap; uint16 *pc = (uint16 *)scp->sc_pc; uint16 opcode = *pc; M68kRegisters *regs = (M68kRegisters *)&state->ss_frame; #define INC_PC(n) scp->sc_pc += (n) #define GET_SR (scp->sc_ps | EmulatedSR) #define STORE_SR(v) \ scp->sc_ps = (v) & 0xff; \ EmulatedSR = (v) & 0xe700; \ if (((v) & 0x0700) == 0 && InterruptFlags) \ TriggerInterrupt(); //printf("opcode %04x at %p, sr %04x, emul_sr %04x\n", opcode, pc, scp->sc_ps, EmulatedSR); if ((opcode & 0xf000) == 0xa000) { // A-Line instruction, set up A-Line trap frame on stack uint32 a7 = regs->a[7]; a7 -= 2; WriteMacInt16(a7, 0x28); a7 -= 4; WriteMacInt32(a7, (uint32)pc); a7 -= 2; WriteMacInt16(a7, GET_SR); scp->sc_sp = regs->a[7] = a7; // Jump to MacOS A-Line handler on return scp->sc_pc = ReadMacInt32(0x28); } else if ((opcode & 0xff00) == 0x7100) { // Extended opcode, push registers on user stack uint32 a7 = regs->a[7]; a7 -= 4; WriteMacInt32(a7, (uint32)pc); a7 -= 2; WriteMacInt16(a7, scp->sc_ps); for (int i=7; i>=0; i--) { a7 -= 4; WriteMacInt32(a7, regs->a[i]); } for (int i=7; i>=0; i--) { a7 -= 4; WriteMacInt32(a7, regs->d[i]); } scp->sc_sp = regs->a[7] = a7; // Jump to EmulOp trampoline code on return scp->sc_pc = (uint32)EmulOpTrampoline; } else switch (opcode) { // Emulate privileged instructions case 0x40e7: // move sr,-(sp) regs->a[7] -= 2; WriteMacInt16(regs->a[7], GET_SR); scp->sc_sp = regs->a[7]; INC_PC(2); break; case 0x46df: { // move (sp)+,sr uint16 sr = ReadMacInt16(regs->a[7]); STORE_SR(sr); regs->a[7] += 2; scp->sc_sp = regs->a[7]; INC_PC(2); break; } case 0x007c: { // ori #xxxx,sr uint16 sr = GET_SR | pc[1]; scp->sc_ps = sr & 0xff; // oring bits into the sr can't enable interrupts, so we don't need to call STORE_SR EmulatedSR = sr & 0xe700; INC_PC(4); break; } case 0x027c: { // andi #xxxx,sr uint16 sr = GET_SR & pc[1]; STORE_SR(sr); INC_PC(4); break; } case 0x46fc: // move #xxxx,sr STORE_SR(pc[1]); INC_PC(4); break; case 0x46ef: { // move (xxxx,sp),sr uint16 sr = ReadMacInt16(regs->a[7] + (int32)(int16)pc[1]); STORE_SR(sr); INC_PC(4); break; } case 0x46d8: // move (a0)+,sr case 0x46d9: { // move (a1)+,sr uint16 sr = ReadMacInt16(regs->a[opcode & 7]); STORE_SR(sr); regs->a[opcode & 7] += 2; INC_PC(2); break; } case 0x40f8: // move sr,xxxx.w WriteMacInt16(pc[1], GET_SR); INC_PC(4); break; case 0x40d0: // move sr,(a0) case 0x40d1: // move sr,(a1) case 0x40d2: // move sr,(a2) case 0x40d3: // move sr,(a3) case 0x40d4: // move sr,(a4) case 0x40d5: // move sr,(a5) case 0x40d6: // move sr,(a6) case 0x40d7: // move sr,(sp) WriteMacInt16(regs->a[opcode & 7], GET_SR); INC_PC(2); break; case 0x40c0: // move sr,d0 case 0x40c1: // move sr,d1 case 0x40c2: // move sr,d2 case 0x40c3: // move sr,d3 case 0x40c4: // move sr,d4 case 0x40c5: // move sr,d5 case 0x40c6: // move sr,d6 case 0x40c7: // move sr,d7 regs->d[opcode & 7] = GET_SR; INC_PC(2); break; case 0x46c0: // move d0,sr case 0x46c1: // move d1,sr case 0x46c2: // move d2,sr case 0x46c3: // move d3,sr case 0x46c4: // move d4,sr case 0x46c5: // move d5,sr case 0x46c6: // move d6,sr case 0x46c7: { // move d7,sr uint16 sr = regs->d[opcode & 7]; STORE_SR(sr); INC_PC(2); break; } case 0xf327: // fsave -(sp) regs->a[7] -= 4; WriteMacInt32(regs->a[7], 0x41000000); // Idle frame scp->sc_sp = regs->a[7]; INC_PC(2); break; case 0xf35f: // frestore (sp)+ regs->a[7] += 4; scp->sc_sp = regs->a[7]; INC_PC(2); break; case 0x4e73: { // rte uint32 a7 = regs->a[7]; uint16 sr = ReadMacInt16(a7); a7 += 2; scp->sc_ps = sr & 0xff; EmulatedSR = sr & 0xe700; scp->sc_pc = ReadMacInt32(a7); a7 += 4; uint16 format = ReadMacInt16(a7) >> 12; a7 += 2; static const int frame_adj[16] = { 0, 0, 4, 4, 8, 0, 0, 52, 50, 12, 24, 84, 16, 0, 0, 0 }; scp->sc_sp = regs->a[7] = a7 + frame_adj[format]; break; } case 0x4e7a: // movec cr,x switch (pc[1]) { case 0x0002: // movec cacr,d0 regs->d[0] = 0x3111; break; case 0x1002: // movec cacr,d1 regs->d[1] = 0x3111; break; case 0x0003: // movec tc,d0 case 0x0004: // movec itt0,d0 case 0x0005: // movec itt1,d0 case 0x0006: // movec dtt0,d0 case 0x0007: // movec dtt1,d0 case 0x0806: // movec urp,d0 case 0x0807: // movec srp,d0 regs->d[0] = 0; break; case 0x1000: // movec sfc,d1 case 0x1001: // movec dfc,d1 case 0x1003: // movec tc,d1 case 0x1801: // movec vbr,d1 regs->d[1] = 0; break; case 0x8801: // movec vbr,a0 regs->a[0] = 0; break; case 0x9801: // movec vbr,a1 regs->a[1] = 0; break; default: goto ill; } INC_PC(4); break; case 0x4e7b: // movec x,cr switch (pc[1]) { case 0x1000: // movec d1,sfc case 0x1001: // movec d1,dfc case 0x0801: // movec d0,vbr case 0x1801: // movec d1,vbr break; case 0x0002: // movec d0,cacr case 0x1002: // movec d1,cacr FlushCodeCache(NULL, 0); break; default: goto ill; } INC_PC(4); break; case 0xf478: // cpusha dc case 0xf4f8: // cpusha dc/ic FlushCodeCache(NULL, 0); INC_PC(2); break; default: ill: printf("SIGILL num %d, code %d\n", sig, code); printf(" context %p:\n", scp); printf(" onstack %08x\n", scp->sc_onstack); printf(" sp %08x\n", scp->sc_sp); printf(" fp %08x\n", scp->sc_fp); printf(" pc %08x\n", scp->sc_pc); printf(" opcode %04x\n", opcode); printf(" sr %08x\n", scp->sc_ps); printf(" state %p:\n", state); printf(" flags %d\n", state->ss_flags); for (int i=0; i<8; i++) printf(" d%d %08x\n", i, state->ss_frame.f_regs[i]); for (int i=0; i<8; i++) printf(" a%d %08x\n", i, state->ss_frame.f_regs[i+8]); VideoQuitFullScreen(); #ifdef ENABLE_MON char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); #endif QuitEmulator(); break; } } #endif /* * Display alert */ #ifdef ENABLE_GTK static void dl_destroyed(void) { gtk_main_quit(); } static void dl_quit(GtkWidget *dialog) { gtk_widget_destroy(dialog); } void display_alert(int title_id, int prefix_id, int button_id, const char *text) { char str[256]; sprintf(str, GetString(prefix_id), text); GtkWidget *dialog = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id)); gtk_container_border_width(GTK_CONTAINER(dialog), 5); gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150); gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL); GtkWidget *label = gtk_label_new(str); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0); GtkWidget *button = gtk_button_new_with_label(GetString(button_id)); gtk_widget_show(button); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show(dialog); gtk_main(); } #endif /* * Display error alert */ void ErrorAlert(const char *text) { if (gui_connection) { if (rpc_method_invoke(gui_connection, RPC_METHOD_ERROR_ALERT, RPC_TYPE_STRING, text, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR && rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR) return; } #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO) if (PrefsFindBool("nogui") || x_display == NULL) { printf(GetString(STR_SHELL_ERROR_PREFIX), text); return; } VideoQuitFullScreen(); display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text); #else printf(GetString(STR_SHELL_ERROR_PREFIX), text); #endif } /* * Display warning alert */ void WarningAlert(const char *text) { if (gui_connection) { if (rpc_method_invoke(gui_connection, RPC_METHOD_WARNING_ALERT, RPC_TYPE_STRING, text, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR && rpc_method_wait_for_reply(gui_connection, RPC_TYPE_INVALID) == RPC_ERROR_NO_ERROR) return; } #if defined(ENABLE_GTK) && !defined(USE_SDL_VIDEO) if (PrefsFindBool("nogui") || x_display == NULL) { printf(GetString(STR_SHELL_WARNING_PREFIX), text); return; } display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text); #else printf(GetString(STR_SHELL_WARNING_PREFIX), text); #endif } /* * Display choice alert */ bool ChoiceAlert(const char *text, const char *pos, const char *neg) { printf(GetString(STR_SHELL_WARNING_PREFIX), text); return false; //!! } BasiliskII/src/Unix/video_blit.cpp0000644000175000017500000004554111446772651017325 0ustar centriscentris/* * video_blit.cpp - Video/graphics emulation, blitters * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "video.h" #include "video_blit.h" #include #include // Format of the target visual static VisualFormat visualFormat; // This holds the pixels values of the palette colors for 8->16/32-bit expansion uint32 ExpandMap[256]; // Mark video_blit.h for specialization #define DEFINE_VIDEO_BLITTERS 1 /* -------------------------------------------------------------------------- */ /* --- Raw Copy / No conversion required --- */ /* -------------------------------------------------------------------------- */ static void Blit_Copy_Raw(uint8 * dest, const uint8 * source, uint32 length) { // This function is likely to be inlined and/or highly optimized memcpy(dest, source, length); } /* -------------------------------------------------------------------------- */ /* --- RGB 555 --- */ /* -------------------------------------------------------------------------- */ #ifdef WORDS_BIGENDIAN # define FB_FUNC_NAME Blit_RGB555_OBO #else # define FB_FUNC_NAME Blit_RGB555_NBO #endif #define FB_BLIT_1(dst, src) \ (dst = (((src) >> 8) & 0xff) | (((src) & 0xff) << 8)) #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 8) & 0x00ff00ff) | (((src) & 0x00ff00ff) << 8)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 8) & UVAL64(0x00ff00ff00ff00ff)) | \ (((src) & UVAL64(0x00ff00ff00ff00ff)) << 8)) #define FB_DEPTH 15 #include "video_blit.h" /* -------------------------------------------------------------------------- */ /* --- BGR 555 --- */ /* -------------------------------------------------------------------------- */ #ifdef WORDS_BIGENDIAN // Native byte order #define FB_BLIT_1(dst, src) \ (dst = (((src) >> 10) & 0x001f) | ((src) & 0x03e0) | (((src) << 10) & 0x7c00)) #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 10) & 0x001f001f) | ((src) & 0x03e003e0) | (((src) << 10) & 0x7c007c00)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 10) & UVAL64(0x001f001f001f001f)) | \ ( (src) & UVAL64(0x03e003e003e003e0)) | \ (((src) << 10) & UVAL64(0x7c007c007c007c00))) #define FB_DEPTH 15 #define FB_FUNC_NAME Blit_BGR555_NBO #include "video_blit.h" // Opposite byte order (untested) #define FB_BLIT_1(dst, src) \ (dst = (((src) >> 2) & 0x1f00) | (((src) >> 8) & 3) | (((src) << 8) & 0xe000) | (((src) << 2) & 0x7c)) #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 2) & 0x1f001f00) | (((src) >> 8) & 0x30003) | (((src) << 8) & 0xe000e000) | (((src) << 2) & 0x7c007c)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 2) & UVAL64(0x1f001f001f001f00)) | \ (((src) >> 8) & UVAL64(0x0003000300030003)) | \ (((src) << 8) & UVAL64(0xe000e000e000e000)) | \ (((src) << 2) & UVAL64(0x007c007c007c007c))) #define FB_DEPTH 15 #define FB_FUNC_NAME Blit_BGR555_OBO #include "video_blit.h" #else // Native byte order (untested) #define FB_BLIT_1(dst, src) \ (dst = (((src) >> 2) & 0x1f) | (((src) >> 8) & 0xe0) | (((src) << 8) & 0x0300) | (((src) << 2) & 0x7c00)) #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 2) & 0x1f001f) | (((src) >> 8) & 0xe000e0) | (((src) << 8) & 0x03000300) | (((src) << 2) & 0x7c007c00)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 2) & UVAL64(0x001f001f001f001f)) | \ (((src) >> 8) & UVAL64(0x00e000e000e000e0)) | \ (((src) << 8) & UVAL64(0x0300030003000300)) | \ (((src) << 2) & UVAL64(0x7c007c007c007c00))) #define FB_DEPTH 15 #define FB_FUNC_NAME Blit_BGR555_NBO #include "video_blit.h" // Opposite byte order (untested) #define FB_BLIT_1(dst, src) \ (dst = (((src) << 6) & 0x1f00) | ((src) & 0xe003) | (((src) >> 6) & 0x7c)) #define FB_BLIT_2(dst, src) \ (dst = (((src) << 6) & 0x1f001f00) | ((src) & 0xe003e003) | (((src) >> 6) & 0x7c007c)) #define FB_BLIT_4(dst, src) \ (dst = (((src) << 6) & UVAL64(0x1f001f001f001f00)) | \ ( (src) & UVAL64(0xe003e003e003e003)) | \ (((src) >> 6) & UVAL64(0x007c007c007c007c))) #define FB_DEPTH 15 #define FB_FUNC_NAME Blit_BGR555_OBO #include "video_blit.h" #endif /* -------------------------------------------------------------------------- */ /* --- RGB 565 --- */ /* -------------------------------------------------------------------------- */ #ifdef WORDS_BIGENDIAN // Native byte order #define FB_BLIT_1(dst, src) \ (dst = (((src) & 0x1f) | (((src) << 1) & 0xffc0))) #define FB_BLIT_2(dst, src) \ (dst = (((src) & 0x001f001f) | (((src) << 1) & 0xffc0ffc0))) #define FB_BLIT_4(dst, src) \ (dst = (((src) & UVAL64(0x001f001f001f001f)) | \ (((src) << 1) & UVAL64(0xffc0ffc0ffc0ffc0)))) #define FB_DEPTH 16 #define FB_FUNC_NAME Blit_RGB565_NBO #include "video_blit.h" // Opposite byte order #define FB_BLIT_1(dst, src) \ (dst = ((((src) >> 7) & 0xff) | (((src) << 9) & 0xc000) | (((src) << 8) & 0x1f00))) #define FB_BLIT_2(dst, src) \ (dst = ((((src) >> 7) & 0x00ff00ff) | (((src) << 9) & 0xc000c000) | (((src) << 8) & 0x1f001f00))) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 7) & UVAL64(0x00ff00ff00ff00ff)) | \ (((src) << 9) & UVAL64(0xc000c000c000c000)) | \ (((src) << 8) & UVAL64(0x1f001f001f001f00))) #define FB_DEPTH 16 #define FB_FUNC_NAME Blit_RGB565_OBO #include "video_blit.h" #else // Native byte order #define FB_BLIT_1(dst, src) \ (dst = (((src) >> 8) & 0x001f) | (((src) << 9) & 0xfe00) | (((src) >> 7) & 0x01c0)) #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 8) & 0x001f001f) | (((src) << 9) & 0xfe00fe00) | (((src) >> 7) & 0x01c001c0)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 8) & UVAL64(0x001f001f001f001f)) | \ (((src) << 9) & UVAL64(0xfe00fe00fe00fe00)) | \ (((src) >> 7) & UVAL64(0x01c001c001c001c0))) #define FB_DEPTH 16 #define FB_FUNC_NAME Blit_RGB565_NBO #include "video_blit.h" // Opposite byte order (untested) #define FB_BLIT_1(dst, src) \ (dst = (((src) & 0x1f00) | (((src) << 1) & 0xe0fe) | (((src) >> 15) & 1))) #define FB_BLIT_2(dst, src) \ (dst = (((src) & 0x1f001f00) | (((src) << 1) & 0xe0fee0fe) | (((src) >> 15) & 0x10001))) #define FB_BLIT_4(dst, src) \ (dst = (((src) & UVAL64(0x1f001f001f001f00)) | \ (((src) << 1) & UVAL64(0xe0fee0fee0fee0fe)) | \ (((src) >> 15) & UVAL64(0x0001000100010001)))) #define FB_DEPTH 16 #define FB_FUNC_NAME Blit_RGB565_OBO #include "video_blit.h" #endif /* -------------------------------------------------------------------------- */ /* --- RGB 888 --- */ /* -------------------------------------------------------------------------- */ #ifdef WORDS_BIGENDIAN # define FB_FUNC_NAME Blit_RGB888_OBO #else # define FB_FUNC_NAME Blit_RGB888_NBO #endif #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 24) & 0xff) | (((src) >> 8) & 0xff00) | (((src) & 0xff00) << 8) | (((src) & 0xff) << 24)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 24) & UVAL64(0x000000ff000000ff)) | \ (((src) >> 8) & UVAL64(0x0000ff000000ff00)) | \ (((src) & UVAL64(0x0000ff000000ff00)) << 8) | \ (((src) & UVAL64(0x000000ff000000ff)) << 24)) #define FB_DEPTH 24 #include "video_blit.h" /* -------------------------------------------------------------------------- */ /* --- BGR 888 --- */ /* -------------------------------------------------------------------------- */ // Native byte order [BE] (untested) #ifdef WORDS_BIGENDIAN #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 16) & 0xff) | ((src) & 0xff00) | (((src) & 0xff) << 16)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 16) & UVAL64(0x000000ff000000ff)) | \ ( (src) & UVAL64(0x0000ff000000ff00)) | \ (((src) & UVAL64(0x000000ff000000ff)) << 16)) #define FB_FUNC_NAME Blit_BGR888_NBO #define FB_DEPTH 24 #include "video_blit.h" #else // Opposite byte order [LE] (untested) #define FB_BLIT_2(dst, src) \ (dst = (((src) >> 16) & 0xff) | ((src) & 0xff0000) | (((src) & 0xff) << 16)) #define FB_BLIT_4(dst, src) \ (dst = (((src) >> 16) & UVAL64(0x000000ff000000ff)) | \ ( (src) & UVAL64(0x00ff000000ff0000)) | \ (((src) & UVAL64(0x000000ff000000ff)) << 16)) #define FB_FUNC_NAME Blit_BGR888_OBO #define FB_DEPTH 24 #include "video_blit.h" #endif // Opposite byte order [BE] (untested) / Native byte order [LE] (untested) #ifdef WORDS_BIGENDIAN # define FB_FUNC_NAME Blit_BGR888_OBO #else # define FB_FUNC_NAME Blit_BGR888_NBO #endif #define FB_BLIT_2(dst, src) \ (dst = ((src) & 0xff00ff) | (((src) & 0xff00) << 16)) #define FB_BLIT_4(dst, src) \ (dst = ((src) & UVAL64(0x00ff00ff00ff00ff)) | (((src) & UVAL64(0x0000ff000000ff00)) << 16)) #define FB_DEPTH 24 #include "video_blit.h" /* -------------------------------------------------------------------------- */ /* --- 1/2/4-bit indexed to 8-bit mode conversion --- */ /* -------------------------------------------------------------------------- */ static void Blit_Expand_1_To_8(uint8 * dest, const uint8 * p, uint32 length) { uint8 *q = (uint8 *)dest; for (uint32 i=0; i> 7; *q++ = (c >> 6) & 1; *q++ = (c >> 5) & 1; *q++ = (c >> 4) & 1; *q++ = (c >> 3) & 1; *q++ = (c >> 2) & 1; *q++ = (c >> 1) & 1; *q++ = c & 1; } } static void Blit_Expand_2_To_8(uint8 * dest, const uint8 * p, uint32 length) { uint8 *q = (uint8 *)dest; for (uint32 i=0; i> 6; *q++ = (c >> 4) & 3; *q++ = (c >> 2) & 3; *q++ = c & 3; } } static void Blit_Expand_4_To_8(uint8 * dest, const uint8 * p, uint32 length) { uint8 *q = (uint8 *)dest; for (uint32 i=0; i> 4; *q++ = c & 0x0f; } } /* -------------------------------------------------------------------------- */ /* --- 1/2/4/8-bit indexed to 16-bit mode color expansion --- */ /* -------------------------------------------------------------------------- */ static void Blit_Expand_1_To_16(uint8 * dest, const uint8 * p, uint32 length) { uint16 *q = (uint16 *)dest; for (uint32 i=0; i> 7); *q++ = -((c >> 6) & 1); *q++ = -((c >> 5) & 1); *q++ = -((c >> 4) & 1); *q++ = -((c >> 3) & 1); *q++ = -((c >> 2) & 1); *q++ = -((c >> 1) & 1); *q++ = -(c & 1); } } static void Blit_Expand_2_To_16(uint8 * dest, const uint8 * p, uint32 length) { uint16 *q = (uint16 *)dest; for (uint32 i=0; i> 6]; *q++ = ExpandMap[c >> 4]; *q++ = ExpandMap[c >> 2]; *q++ = ExpandMap[c]; } } static void Blit_Expand_4_To_16(uint8 * dest, const uint8 * p, uint32 length) { uint16 *q = (uint16 *)dest; for (uint32 i=0; i> 4]; *q++ = ExpandMap[c]; } } static void Blit_Expand_8_To_16(uint8 * dest, const uint8 * p, uint32 length) { uint16 *q = (uint16 *)dest; for (uint32 i=0; i> 7); *q++ = -((c >> 6) & 1); *q++ = -((c >> 5) & 1); *q++ = -((c >> 4) & 1); *q++ = -((c >> 3) & 1); *q++ = -((c >> 2) & 1); *q++ = -((c >> 1) & 1); *q++ = -(c & 1); } } static void Blit_Expand_2_To_32(uint8 * dest, const uint8 * p, uint32 length) { uint32 *q = (uint32 *)dest; for (uint32 i=0; i> 6]; *q++ = ExpandMap[c >> 4]; *q++ = ExpandMap[c >> 2]; *q++ = ExpandMap[c]; } } static void Blit_Expand_4_To_32(uint8 * dest, const uint8 * p, uint32 length) { uint32 *q = (uint32 *)dest; for (uint32 i=0; i> 4]; *q++ = ExpandMap[c]; } } static void Blit_Expand_8_To_32(uint8 * dest, const uint8 * p, uint32 length) { uint32 *q = (uint32 *)dest; for (uint32 i=0; i Shall be initialized only through the Screen_blitter_init() function typedef void (*Screen_blit_func)(uint8 * dest, const uint8 * source, uint32 length); Screen_blit_func Screen_blit = 0; // Structure used to match the adequate framebuffer update function struct Screen_blit_func_info { int depth; // Screen depth uint32 Rmask; // Red mask uint32 Gmask; // Green mask uint32 Bmask; // Blue mask Screen_blit_func handler_nbo; // Update function (native byte order) Screen_blit_func handler_obo; // Update function (opposite byte order) }; // Table of visual formats supported and their respective handler static Screen_blit_func_info Screen_blitters[] = { #ifdef WORDS_BIGENDIAN { 1, 0x000000, 0x000000, 0x000000, Blit_Copy_Raw , Blit_Copy_Raw }, // NT { 8, 0x000000, 0x000000, 0x000000, Blit_Copy_Raw , Blit_Copy_Raw }, // OK (NBO) { 15, 0x007c00, 0x0003e0, 0x00001f, Blit_Copy_Raw , Blit_RGB555_OBO }, // OK (OBO) { 15, 0x00001f, 0x0003e0, 0x007c00, Blit_BGR555_NBO , Blit_BGR555_OBO }, // NT { 16, 0x007c00, 0x0003e0, 0x00001f, Blit_Copy_Raw , Blit_RGB555_OBO }, // OK (OBO) { 16, 0x00f800, 0x0007e0, 0x00001f, Blit_RGB565_NBO , Blit_RGB565_OBO }, // OK (OBO) { 24, 0xff0000, 0x00ff00, 0x0000ff, Blit_Copy_Raw , Blit_RGB888_OBO }, // OK (OBO) { 24, 0x0000ff, 0x00ff00, 0xff0000, Blit_BGR888_NBO , Blit_BGR888_OBO }, // NT { 32, 0xff0000, 0x00ff00, 0x0000ff, Blit_Copy_Raw , Blit_RGB888_OBO }, // OK { 32, 0x0000ff, 0x00ff00, 0xff0000, Blit_BGR888_NBO , Blit_BGR888_OBO }, // OK #else { 1, 0x000000, 0x000000, 0x000000, Blit_Copy_Raw , Blit_Copy_Raw }, // NT { 8, 0x000000, 0x000000, 0x000000, Blit_Copy_Raw , Blit_Copy_Raw }, // OK (NBO) { 15, 0x007c00, 0x0003e0, 0x00001f, Blit_RGB555_NBO , Blit_Copy_Raw }, // OK (NBO) { 15, 0x00001f, 0x0003e0, 0x007c00, Blit_BGR555_NBO , Blit_BGR555_OBO }, // NT { 16, 0x007c00, 0x0003e0, 0x00001f, Blit_RGB555_NBO , Blit_Copy_Raw }, // OK (NBO) { 16, 0x00f800, 0x0007e0, 0x00001f, Blit_RGB565_NBO , Blit_RGB565_OBO }, // OK (NBO) { 24, 0xff0000, 0x00ff00, 0x0000ff, Blit_RGB888_NBO , Blit_Copy_Raw }, // OK (NBO) { 24, 0x0000ff, 0x00ff00, 0xff0000, Blit_BGR888_NBO , Blit_BGR888_OBO }, // NT { 32, 0xff0000, 0x00ff00, 0x0000ff, Blit_RGB888_NBO , Blit_Copy_Raw }, // OK (NBO) { 32, 0x0000ff, 0x00ff00, 0xff0000, Blit_BGR888_NBO , Blit_BGR888_OBO }, // NT #endif { 32, 0xff00, 0xff0000, 0xff000000, Blit_Copy_Raw , Blit_Copy_Raw } // OK }; // Initialize the framebuffer update function // Returns FALSE, if the function was to be reduced to a simple memcpy() // --> In that case, VOSF is not necessary bool Screen_blitter_init(VisualFormat const & visual_format, bool native_byte_order, int mac_depth) { #if USE_SDL_VIDEO const bool use_sdl_video = true; #else const bool use_sdl_video = false; #endif #if REAL_ADDRESSING || DIRECT_ADDRESSING if (mac_depth == 1 && !use_sdl_video && !visual_format.fullscreen) { // Windowed 1-bit mode uses a 1-bit X image, so there's no need for special blitting routines Screen_blit = Blit_Copy_Raw; } else { // Compute RGB shift values visualFormat = visual_format; visualFormat.Rshift = 0; for (uint32 Rmask = visualFormat.Rmask; Rmask && ((Rmask & 1) != 1); Rmask >>= 1) ++visualFormat.Rshift; visualFormat.Gshift = 0; for (uint32 Gmask = visualFormat.Gmask; Gmask && ((Gmask & 1) != 1); Gmask >>= 1) ++visualFormat.Gshift; visualFormat.Bshift = 0; for (uint32 Bmask = visualFormat.Bmask; Bmask && ((Bmask & 1) != 1); Bmask >>= 1) ++visualFormat.Bshift; // 1/2/4/8-bit mode on 8/16/32-bit screen? Screen_blit = NULL; switch (visualFormat.depth) { case 8: switch (mac_depth) { case 1: Screen_blit = Blit_Expand_1_To_8; break; case 2: Screen_blit = Blit_Expand_2_To_8; break; case 4: Screen_blit = Blit_Expand_4_To_8; break; } break; case 15: case 16: switch (mac_depth) { case 1: Screen_blit = Blit_Expand_1_To_16; break; case 2: Screen_blit = Blit_Expand_2_To_16; break; case 4: Screen_blit = Blit_Expand_4_To_16; break; case 8: Screen_blit = Blit_Expand_8_To_16; break; } break; case 24: case 32: switch (mac_depth) { case 1: Screen_blit = Blit_Expand_1_To_32; break; case 2: Screen_blit = Blit_Expand_2_To_32; break; case 4: Screen_blit = Blit_Expand_4_To_32; break; case 8: Screen_blit = Blit_Expand_8_To_32; break; } break; } bool blitter_found = (Screen_blit != NULL); // Search for an adequate blit function const int blitters_count = sizeof(Screen_blitters)/sizeof(Screen_blitters[0]); for (int i = 0; !blitter_found && (i < blitters_count); i++) { if ( (visualFormat.depth == Screen_blitters[i].depth) && (visualFormat.Rmask == Screen_blitters[i].Rmask) && (visualFormat.Gmask == Screen_blitters[i].Gmask) && (visualFormat.Bmask == Screen_blitters[i].Bmask) ) { blitter_found = true; Screen_blit = native_byte_order ? Screen_blitters[i].handler_nbo : Screen_blitters[i].handler_obo ; } } // No appropriate blitter found, dump RGB mask values and abort() if (!blitter_found) { fprintf(stderr, "### No appropriate blitter found\n"); fprintf(stderr, "\tR/G/B mask values : 0x%06x, 0x%06x, 0x%06x (depth = %d)\n", visualFormat.Rmask, visualFormat.Gmask, visualFormat.Bmask, visualFormat.depth); fprintf(stderr, "\tR/G/B shift values : %d/%d/%d\n", visualFormat.Rshift, visualFormat.Gshift, visualFormat.Bshift); abort(); } } #else // The UAE memory handlers will blit correctly // --> no need for specialised blitters here Screen_blit = Blit_Copy_Raw; #endif // If the blitter simply reduces to a copy, we don't need VOSF in DGA mode // --> In that case, we return FALSE return (Screen_blit != Blit_Copy_Raw); } BasiliskII/src/Unix/serial_unix.cpp0000644000175000017500000004554411457210314017513 0ustar centriscentris/* * serial_unix.cpp - Serial device driver, Unix specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include #include #ifdef __linux__ #include #include #include #endif #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "serial.h" #include "serial_defs.h" extern "C" { #include "sshpty.h" } #define DEBUG 0 #include "debug.h" #define MONITOR 0 // IRIX missing or unsupported defines #ifdef sgi #ifndef CRTSCTS #define CRTSCTS CNEW_RTSCTS #endif #ifndef B230400 #define B230400 B115200 #endif #endif // Missing functions #ifndef HAVE_CFMAKERAW static int cfmakeraw(struct termios *termios_p) { termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); termios_p->c_oflag &= ~OPOST; termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); termios_p->c_cflag &= ~(CSIZE|PARENB); termios_p->c_cflag |= CS8; return 0; } #endif // Driver private variables class XSERDPort : public SERDPort { public: XSERDPort(const char *dev) { device_name = dev; protocol = serial; fd = -1; pid = 0; input_thread_active = output_thread_active = false; Set_pthread_attr(&thread_attr, 2); } virtual ~XSERDPort() { if (input_thread_active) { input_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(input_thread); #endif pthread_join(input_thread, NULL); sem_destroy(&input_signal); input_thread_active = false; } if (output_thread_active) { output_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(output_thread); #endif pthread_join(output_thread, NULL); sem_destroy(&output_signal); output_thread_active = false; } } virtual int16 open(uint16 config); virtual int16 prime_in(uint32 pb, uint32 dce); virtual int16 prime_out(uint32 pb, uint32 dce); virtual int16 control(uint32 pb, uint32 dce, uint16 code); virtual int16 status(uint32 pb, uint32 dce, uint16 code); virtual int16 close(void); private: bool open_pty(void); bool configure(uint16 config); void set_handshake(uint32 s, bool with_dtr); static void *input_func(void *arg); static void *output_func(void *arg); const char *device_name; // Device name enum {serial, parallel, pty, midi} protocol; // Type of device int fd; // FD of device pid_t pid; // PID of child process bool io_killed; // Flag: KillIO called, I/O threads must not call deferred tasks bool quitting; // Flag: Quit threads pthread_attr_t thread_attr; // Input/output thread attributes bool input_thread_active; // Flag: Input thread installed volatile bool input_thread_cancel; // Flag: Cancel input thread pthread_t input_thread; // Data input thread sem_t input_signal; // Signal for input thread: execute command uint32 input_pb; // Command parameter for input thread bool output_thread_active; // Flag: Output thread installed volatile bool output_thread_cancel; // Flag: Cancel output thread pthread_t output_thread; // Data output thread sem_t output_signal; // Signal for output thread: execute command uint32 output_pb; // Command parameter for output thread struct termios mode; // Terminal configuration }; /* * Initialization */ void SerialInit(void) { // Read serial preferences and create structs for both ports the_serd_port[0] = new XSERDPort(PrefsFindString("seriala")); the_serd_port[1] = new XSERDPort(PrefsFindString("serialb")); } /* * Deinitialization */ void SerialExit(void) { delete (XSERDPort *)the_serd_port[0]; delete (XSERDPort *)the_serd_port[1]; } /* * Open serial port */ int16 XSERDPort::open(uint16 config) { // Don't open NULL name devices if (device_name == NULL) return openErr; // Init variables io_killed = false; quitting = false; // Open port, according to the syntax of the path if (device_name[0] == '|') { // Open a process via ptys if (!open_pty()) goto open_error; } else if (!strcmp(device_name, "midi")) { // MIDI: not yet implemented return openErr; } else { // Device special file fd = ::open(device_name, O_RDWR); if (fd < 0) goto open_error; #if defined(__linux__) // Parallel port? struct stat st; if (fstat(fd, &st) == 0) if (S_ISCHR(st.st_mode)) protocol = ((MAJOR(st.st_rdev) == LP_MAJOR) ? parallel : serial); #elif defined(__FreeBSD__) || defined(__NetBSD__) // Parallel port? struct stat st; if (fstat(fd, &st) == 0) if (S_ISCHR(st.st_mode)) protocol = (((st.st_rdev >> 16) == 16) ? parallel : serial); #endif } // Configure port for raw mode if (protocol == serial) { if (tcgetattr(fd, &mode) < 0) goto open_error; cfmakeraw(&mode); mode.c_cflag |= HUPCL; mode.c_cc[VMIN] = 1; mode.c_cc[VTIME] = 0; tcsetattr(fd, TCSAFLUSH, &mode); } configure(config); // Start input/output threads input_thread_cancel = false; output_thread_cancel = false; if (sem_init(&input_signal, 0, 0) < 0) goto open_error; if (sem_init(&output_signal, 0, 0) < 0) goto open_error; input_thread_active = (pthread_create(&input_thread, &thread_attr, input_func, this) == 0); output_thread_active = (pthread_create(&output_thread, &thread_attr, output_func, this) == 0); if (!input_thread_active || !output_thread_active) goto open_error; return noErr; open_error: if (input_thread_active) { input_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(input_thread); #endif pthread_join(input_thread, NULL); sem_destroy(&input_signal); input_thread_active = false; } if (output_thread_active) { output_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(output_thread); #endif pthread_join(output_thread, NULL); sem_destroy(&output_signal); output_thread_active = false; } if (fd > 0) { ::close(fd); fd = -1; } return openErr; } /* * Read data from port */ int16 XSERDPort::prime_in(uint32 pb, uint32 dce) { // Send input command to input_thread read_done = false; read_pending = true; input_pb = pb; WriteMacInt32(input_dt + serdtDCE, dce); sem_post(&input_signal); return 1; // Command in progress } /* * Write data to port */ int16 XSERDPort::prime_out(uint32 pb, uint32 dce) { // Send output command to output_thread write_done = false; write_pending = true; output_pb = pb; WriteMacInt32(output_dt + serdtDCE, dce); sem_post(&output_signal); return 1; // Command in progress } /* * Control calls */ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code) { switch (code) { case 1: // KillIO io_killed = true; if (protocol == serial) tcflush(fd, TCIOFLUSH); while (read_pending || write_pending) usleep(10000); io_killed = false; return noErr; case kSERDConfiguration: if (configure(ReadMacInt16(pb + csParam))) return noErr; else return paramErr; case kSERDInputBuffer: return noErr; // Not supported under Unix case kSERDSerHShake: set_handshake(pb + csParam, false); return noErr; case kSERDSetBreak: if (protocol == serial) tcsendbreak(fd, 0); return noErr; case kSERDClearBreak: return noErr; case kSERDBaudRate: { if (protocol != serial) return noErr; uint16 rate = ReadMacInt16(pb + csParam); speed_t baud_rate; if (rate <= 50) { rate = 50; baud_rate = B50; } else if (rate <= 75) { rate = 75; baud_rate = B75; } else if (rate <= 110) { rate = 110; baud_rate = B110; } else if (rate <= 134) { rate = 134; baud_rate = B134; } else if (rate <= 150) { rate = 150; baud_rate = B150; } else if (rate <= 200) { rate = 200; baud_rate = B200; } else if (rate <= 300) { rate = 300; baud_rate = B300; } else if (rate <= 600) { rate = 600; baud_rate = B600; } else if (rate <= 1200) { rate = 1200; baud_rate = B1200; } else if (rate <= 1800) { rate = 1800; baud_rate = B1800; } else if (rate <= 2400) { rate = 2400; baud_rate = B2400; } else if (rate <= 4800) { rate = 4800; baud_rate = B4800; } else if (rate <= 9600) { rate = 9600; baud_rate = B9600; } else if (rate <= 19200) { rate = 19200; baud_rate = B19200; } else if (rate <= 38400) { rate = 38400; baud_rate = B38400; } else if (rate <= 57600) { rate = 57600; baud_rate = B57600; } else { // Just for safety in case someone wants a rate between 57600 and 65535 rate = 57600; baud_rate = B57600; } WriteMacInt16(pb + csParam, rate); cfsetispeed(&mode, baud_rate); cfsetospeed(&mode, baud_rate); tcsetattr(fd, TCSANOW, &mode); return noErr; } case kSERDHandshake: case kSERDHandshakeRS232: set_handshake(pb + csParam, true); return noErr; case kSERDMiscOptions: if (protocol != serial) return noErr; if (ReadMacInt8(pb + csParam) & kOptionPreserveDTR) mode.c_cflag &= ~HUPCL; else mode.c_cflag |= HUPCL; tcsetattr(fd, TCSANOW, &mode); return noErr; case kSERDAssertDTR: { if (protocol != serial) return noErr; unsigned int status = TIOCM_DTR; ioctl(fd, TIOCMBIS, &status); return noErr; } case kSERDNegateDTR: { if (protocol != serial) return noErr; unsigned int status = TIOCM_DTR; ioctl(fd, TIOCMBIC, &status); return noErr; } case kSERDSetPEChar: case kSERDSetPEAltChar: return noErr; // Not supported under Unix case kSERDResetChannel: if (protocol == serial) tcflush(fd, TCIOFLUSH); return noErr; case kSERDAssertRTS: { if (protocol != serial) return noErr; unsigned int status = TIOCM_RTS; ioctl(fd, TIOCMBIS, &status); return noErr; } case kSERDNegateRTS: { if (protocol != serial) return noErr; unsigned int status = TIOCM_RTS; ioctl(fd, TIOCMBIC, &status); return noErr; } case kSERD115KBaud: if (protocol != serial) return noErr; cfsetispeed(&mode, B115200); cfsetospeed(&mode, B115200); tcsetattr(fd, TCSANOW, &mode); return noErr; case kSERD230KBaud: case kSERDSetHighSpeed: if (protocol != serial) return noErr; cfsetispeed(&mode, B230400); cfsetospeed(&mode, B230400); tcsetattr(fd, TCSANOW, &mode); return noErr; default: printf("WARNING: SerialControl(): unimplemented control code %d\n", code); return controlErr; } } /* * Status calls */ int16 XSERDPort::status(uint32 pb, uint32 dce, uint16 code) { switch (code) { case kSERDInputCount: { int num; ioctl(fd, FIONREAD, &num); WriteMacInt32(pb + csParam, num); return noErr; } case kSERDStatus: { uint32 p = pb + csParam; WriteMacInt8(p + staCumErrs, cum_errors); cum_errors = 0; WriteMacInt8(p + staXOffSent, 0); WriteMacInt8(p + staXOffHold, 0); WriteMacInt8(p + staRdPend, read_pending); WriteMacInt8(p + staWrPend, write_pending); if (protocol != serial) { WriteMacInt8(p + staCtsHold, 0); WriteMacInt8(p + staDsrHold, 0); WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent); } else { unsigned int status; ioctl(fd, TIOCMGET, &status); WriteMacInt8(p + staCtsHold, status & TIOCM_CTS ? 0 : 1); WriteMacInt8(p + staDsrHold, status & TIOCM_DTR ? 0 : 1); WriteMacInt8(p + staModemStatus, (status & TIOCM_DSR ? dsrEvent : 0) | (status & TIOCM_RI ? riEvent : 0) | (status & TIOCM_CD ? dcdEvent : 0) | (status & TIOCM_CTS ? ctsEvent : 0)); } return noErr; } default: printf("WARNING: SerialStatus(): unimplemented status code %d\n", code); return statusErr; } } /* * Close serial port */ int16 XSERDPort::close() { // Kill threads if (input_thread_active) { quitting = true; sem_post(&input_signal); pthread_join(input_thread, NULL); input_thread_active = false; sem_destroy(&input_signal); } if (output_thread_active) { quitting = true; sem_post(&output_signal); pthread_join(output_thread, NULL); output_thread_active = false; sem_destroy(&output_signal); } // Close port if (fd > 0) ::close(fd); fd = -1; // Wait for the subprocess to exit if (pid) waitpid(pid, NULL, 0); pid = 0; return noErr; } /* * Open a process via ptys */ bool XSERDPort::open_pty(void) { // Talk to a process via a pty char slave[128]; int slavefd; protocol = pty; if (!pty_allocate(&fd, &slavefd, slave, sizeof(slave))) return false; fflush(stdout); fflush(stderr); switch (pid = fork()) { case -1: // error return false; break; case 0: // child ::close(fd); /* Make the pseudo tty our controlling tty. */ pty_make_controlling_tty(&slavefd, slave); ::close(0); dup(slavefd); // Use the slave fd for stdin, ::close(1); dup(slavefd); // stdout, ::close(2); dup(slavefd); // and stderr. // // // Let the shell do the dirty work execlp("/bin/sh", "/bin/sh", "-c", ++device_name, (char *)NULL); // exec failed! printf("serial_open: could not exec %s: %s\n", "/bin/sh", strerror(errno)); exit(1); break; default: // parent // Pid was stored above break; } return true; } /* * Configure serial port with MacOS config word */ bool XSERDPort::configure(uint16 config) { D(bug(" configure %04x\n", config)); if (protocol != serial) return true; // Set number of stop bits switch (config & 0xc000) { case stop10: mode.c_cflag &= ~CSTOPB; break; case stop20: mode.c_cflag |= CSTOPB; break; default: return false; } // Set parity mode switch (config & 0x3000) { case noParity: mode.c_iflag &= ~INPCK; mode.c_oflag &= ~PARENB; break; case oddParity: mode.c_iflag |= INPCK; mode.c_oflag |= PARENB; mode.c_oflag |= PARODD; break; case evenParity: mode.c_iflag |= INPCK; mode.c_oflag |= PARENB; mode.c_oflag &= ~PARODD; break; default: return false; } // Set number of data bits switch (config & 0x0c00) { case data5: mode.c_cflag = mode.c_cflag & ~CSIZE | CS5; break; case data6: mode.c_cflag = mode.c_cflag & ~CSIZE | CS6; break; case data7: mode.c_cflag = mode.c_cflag & ~CSIZE | CS7; break; case data8: mode.c_cflag = mode.c_cflag & ~CSIZE | CS8; break; } // Set baud rate speed_t baud_rate; switch (config & 0x03ff) { case baud150: baud_rate = B150; break; case baud300: baud_rate = B300; break; case baud600: baud_rate = B600; break; case baud1200: baud_rate = B1200; break; case baud1800: baud_rate = B1800; break; case baud2400: baud_rate = B2400; break; case baud4800: baud_rate = B4800; break; case baud9600: baud_rate = B9600; break; case baud19200: baud_rate = B19200; break; case baud38400: baud_rate = B38400; break; case baud57600: baud_rate = B57600; break; default: return false; } cfsetispeed(&mode, baud_rate); cfsetospeed(&mode, baud_rate); tcsetattr(fd, TCSANOW, &mode); return true; } /* * Set serial handshaking */ void XSERDPort::set_handshake(uint32 s, bool with_dtr) { D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n", ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3), ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7))); if (protocol != serial) return; if (with_dtr) { if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR)) mode.c_cflag |= CRTSCTS; else mode.c_cflag &= ~CRTSCTS; } else { if (ReadMacInt8(s + shkFCTS)) mode.c_cflag |= CRTSCTS; else mode.c_cflag &= ~CRTSCTS; } D(bug(" %sware flow control\n", mode.c_cflag & CRTSCTS ? "hard" : "soft")); tcsetattr(fd, TCSANOW, &mode); } /* * Data input thread */ void *XSERDPort::input_func(void *arg) { XSERDPort *s = (XSERDPort *)arg; while (!s->input_thread_cancel) { // Wait for commands sem_wait(&s->input_signal); if (s->quitting) break; // Execute command void *buf = Mac2HostAddr(ReadMacInt32(s->input_pb + ioBuffer)); uint32 length = ReadMacInt32(s->input_pb + ioReqCount); D(bug("input_func waiting for %ld bytes of data...\n", length)); int32 actual = read(s->fd, buf, length); D(bug(" %ld bytes received\n", actual)); #if MONITOR bug("Receiving serial data:\n"); uint8 *adr = (uint8 *)buf; for (int i=0; iio_killed) { WriteMacInt16(s->input_pb + ioResult, uint16(abortErr)); WriteMacInt32(s->input_pb + ioActCount, 0); s->read_pending = s->read_done = false; } else { // Set error code if (actual >= 0) { WriteMacInt32(s->input_pb + ioActCount, actual); WriteMacInt32(s->input_dt + serdtResult, noErr); } else { WriteMacInt32(s->input_pb + ioActCount, 0); WriteMacInt32(s->input_dt + serdtResult, uint16(readErr)); } // Trigger serial interrupt D(bug(" triggering serial interrupt\n")); s->read_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } return NULL; } /* * Data output thread */ void *XSERDPort::output_func(void *arg) { XSERDPort *s = (XSERDPort *)arg; while (!s->output_thread_cancel) { // Wait for commands sem_wait(&s->output_signal); if (s->quitting) break; // Execute command void *buf = Mac2HostAddr(ReadMacInt32(s->output_pb + ioBuffer)); uint32 length = ReadMacInt32(s->output_pb + ioReqCount); D(bug("output_func transmitting %ld bytes of data...\n", length)); #if MONITOR bug("Sending serial data:\n"); uint8 *adr = (uint8 *)buf; for (int i=0; ifd, buf, length); D(bug(" %ld bytes transmitted\n", actual)); // KillIO called? Then simply return if (s->io_killed) { WriteMacInt16(s->output_pb + ioResult, uint16(abortErr)); WriteMacInt32(s->output_pb + ioActCount, 0); s->write_pending = s->write_done = false; } else { // Set error code if (actual >= 0) { WriteMacInt32(s->output_pb + ioActCount, actual); WriteMacInt32(s->output_dt + serdtResult, noErr); } else { WriteMacInt32(s->output_pb + ioActCount, 0); WriteMacInt32(s->output_dt + serdtResult, uint16(writErr)); } // Trigger serial interrupt D(bug(" triggering serial interrupt\n")); s->write_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } return NULL; } BasiliskII/src/Unix/prefs_editor_gtk.cpp0000644000175000017500000015255611323745233020532 0ustar centriscentris/* * prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include #include #ifdef HAVE_GNOMEUI #include #endif #include "user_strings.h" #include "version.h" #include "cdrom.h" #include "xpram.h" #include "prefs.h" #include "prefs_editor.h" #define DEBUG 0 #include "debug.h" // Global variables static GtkWidget *win; // Preferences window static bool start_clicked = false; // Return value of PrefsEditor() function // Prototypes static void create_volumes_pane(GtkWidget *top); static void create_scsi_pane(GtkWidget *top); static void create_graphics_pane(GtkWidget *top); static void create_input_pane(GtkWidget *top); static void create_serial_pane(GtkWidget *top); static void create_memory_pane(GtkWidget *top); static void create_jit_pane(GtkWidget *top); static void read_settings(void); /* * Utility functions */ #if ! GLIB_CHECK_VERSION(2,0,0) #define G_OBJECT(obj) GTK_OBJECT(obj) #define g_object_get_data(obj, key) gtk_object_get_data((obj), (key)) #define g_object_set_data(obj, key, data) gtk_object_set_data((obj), (key), (data)) #endif struct opt_desc { int label_id; GtkSignalFunc func; }; struct combo_desc { int label_id; }; struct file_req_assoc { file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {} GtkWidget *req; GtkWidget *entry; }; static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc) { gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); gtk_entry_set_text(GTK_ENTRY(assoc->entry), file); gtk_widget_destroy(assoc->req); delete assoc; } static void cb_browse(GtkWidget *widget, void *user_data) { GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE)); gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(cb_browse_ok), new file_req_assoc(req, (GtkWidget *)user_data)); gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_widget_show(req); } static GtkWidget *make_browse_button(GtkWidget *entry) { GtkWidget *button; button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL)); gtk_widget_show(button); gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry); return button; } static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func) { GtkWidget *item = gtk_menu_item_new_with_label(GetString(label_id)); gtk_widget_show(item); gtk_signal_connect(GTK_OBJECT(item), "activate", func, NULL); gtk_menu_append(GTK_MENU(menu), item); } static GtkWidget *make_pane(GtkWidget *notebook, int title_id) { GtkWidget *frame, *label, *box; frame = gtk_frame_new(NULL); gtk_container_set_border_width(GTK_CONTAINER(frame), 4); box = gtk_vbox_new(FALSE, 4); gtk_container_set_border_width(GTK_CONTAINER(box), 4); gtk_container_add(GTK_CONTAINER(frame), box); gtk_widget_show_all(frame); label = gtk_label_new(GetString(title_id)); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); return box; } static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons) { GtkWidget *bb, *button; bb = gtk_hbutton_box_new(); gtk_widget_show(bb); gtk_container_set_border_width(GTK_CONTAINER(bb), border); gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE); gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4); gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0); while (buttons->label_id) { button = gtk_button_new_with_label(GetString(buttons->label_id)); gtk_widget_show(button); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL); gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0); buttons++; } return bb; } static GtkWidget *make_separator(GtkWidget *top) { GtkWidget *sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0); gtk_widget_show(sep); return sep; } static GtkWidget *make_table(GtkWidget *top, int x, int y) { GtkWidget *table = gtk_table_new(x, y, FALSE); gtk_widget_show(table); gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0); return table; } static GtkWidget *table_make_option_menu(GtkWidget *table, int row, int label_id, const opt_desc *options, int active) { GtkWidget *label, *opt, *menu; label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); opt = gtk_option_menu_new(); gtk_widget_show(opt); menu = gtk_menu_new(); while (options->label_id) { add_menu_item(menu, options->label_id, options->func); options++; } gtk_menu_set_active(GTK_MENU(menu), active); gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); gtk_table_attach(GTK_TABLE(table), opt, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); return menu; } static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, GList *glist) { GtkWidget *label, *combo; char str[32]; label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); combo = gtk_combo_new(); gtk_widget_show(combo); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); return combo; } static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, const combo_desc *options) { GList *glist = NULL; while (options->label_id) { glist = g_list_append(glist, (void *)GetString(options->label_id)); options++; } return table_make_combobox(table, row, label_id, default_value, glist); } static GtkWidget *table_make_file_entry(GtkWidget *table, int row, int label_id, const char *prefs_item, bool only_dirs = false) { GtkWidget *box, *label, *entry, *button; label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); const char *str = PrefsFindString(prefs_item); if (str == NULL) str = ""; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_table_attach(GTK_TABLE(table), box, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), str); gtk_widget_show(entry); gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); button = make_browse_button(entry); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); g_object_set_data(G_OBJECT(entry), "chooser_button", button); return entry; } static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active) { GtkWidget *box, *label, *opt, *menu; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); opt = gtk_option_menu_new(); gtk_widget_show(opt); menu = gtk_menu_new(); while (options->label_id) { add_menu_item(menu, options->label_id, options->func); options++; } gtk_menu_set_active(GTK_MENU(menu), active); gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0); return menu; } static GtkWidget *make_file_entry(GtkWidget *top, int label_id, const char *prefs_item, bool only_dirs = false) { GtkWidget *box, *label, *entry; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); const char *str = PrefsFindString(prefs_item); if (str == NULL) str = ""; #ifdef HAVE_GNOMEUI entry = gnome_file_entry_new(NULL, GetString(label_id)); if (only_dirs) gnome_file_entry_set_directory(GNOME_FILE_ENTRY(entry), true); gtk_entry_set_text(GTK_ENTRY(gnome_file_entry_gtk_entry(GNOME_FILE_ENTRY(entry))), str); #else entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), str); #endif gtk_widget_show(entry); gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); return entry; } static const gchar *get_file_entry_path(GtkWidget *entry) { #ifdef HAVE_GNOMEUI return gnome_file_entry_get_full_path(GNOME_FILE_ENTRY(entry), false); #else return gtk_entry_get_text(GTK_ENTRY(entry)); #endif } static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func) { GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id)); gtk_widget_show(button); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item)); gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button); gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0); return button; } static GtkWidget *make_combobox(GtkWidget *top, int label_id, const char *prefs_item, const combo_desc *options) { GtkWidget *box, *label, *combo; char str[32]; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); GList *glist = NULL; while (options->label_id) { glist = g_list_append(glist, (void *)GetString(options->label_id)); options++; } combo = gtk_combo_new(); gtk_widget_show(combo); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); sprintf(str, "%d", PrefsFindInt32(prefs_item)); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0); return combo; } /* * Show preferences editor * Returns true when user clicked on "Start", false otherwise */ // Window closed static gint window_closed(void) { return FALSE; } // Window destroyed static void window_destroyed(void) { gtk_main_quit(); } // "Start" button clicked static void cb_start(...) { start_clicked = true; read_settings(); SavePrefs(); gtk_widget_destroy(win); } // "Quit" button clicked static void cb_quit(...) { start_clicked = false; gtk_widget_destroy(win); } // "OK" button of "About" dialog clicked static void dl_quit(GtkWidget *dialog) { gtk_widget_destroy(dialog); } // "About" selected static void mn_about(...) { GtkWidget *dialog; #ifdef HAVE_GNOMEUI char version[32]; sprintf(version, "Version %d.%d", VERSION_MAJOR, VERSION_MINOR); const char *authors[] = { "Christian Bauer", "Orlando Bassotto", "Gwenolé Beauchesne", "Marc Chabanas", "Marc Hellwig", "Biill Huey", "Brian J. Johnson", "Jürgen Lachmann", "Samuel Lander", "David Lawrence", "Lauri Pesonen", "Bernd Schmidt", "and others", NULL }; dialog = gnome_about_new( "Basilisk II", version, "Copyright (C) 1997-2008 Christian Bauer", authors, "Basilisk II comes with ABSOLUTELY NO WARRANTY." "This is free software, and you are welcome to redistribute it" "under the terms of the GNU General Public License.", NULL ); gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(win)); #else GtkWidget *label, *button; char str[512]; sprintf(str, "Basilisk II\nVersion %d.%d\n\n" "Copyright (C) 1997-2008 Christian Bauer et al.\n" "E-mail: Christian.Bauer@uni-mainz.de\n" "http://www.uni-mainz.de/~bauec002/B2Main.html\n\n" "Basilisk II comes with ABSOLUTELY NO\n" "WARRANTY. This is free software, and\n" "you are welcome to redistribute it\n" "under the terms of the GNU General\n" "Public License.\n", VERSION_MAJOR, VERSION_MINOR ); dialog = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE)); gtk_container_border_width(GTK_CONTAINER(dialog), 5); gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150); label = gtk_label_new(str); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0); button = gtk_button_new_with_label(GetString(STR_OK_BUTTON)); gtk_widget_show(button); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_grab_default(button); #endif gtk_widget_show(dialog); } // "Zap PRAM" selected static void mn_zap_pram(...) { ZapPRAM(); } // Menu item descriptions static GtkItemFactoryEntry menu_items[] = { {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, ""}, {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "S", GTK_SIGNAL_FUNC(cb_start), 0, NULL}, {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(mn_zap_pram), 0, NULL}, {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, ""}, {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL}, {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, ""}, {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), NULL, GTK_SIGNAL_FUNC(mn_about), 0, NULL} }; bool PrefsEditor(void) { // Create window win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE)); gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL); gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL); // Create window contents GtkWidget *box = gtk_vbox_new(FALSE, 4); gtk_widget_show(box); gtk_container_add(GTK_CONTAINER(win), box); GtkAccelGroup *accel_group = gtk_accel_group_new(); GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "
", accel_group); gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL); #if GTK_CHECK_VERSION(1,3,15) gtk_window_add_accel_group(GTK_WINDOW(win), accel_group); #else gtk_accel_group_attach(accel_group, GTK_OBJECT(win)); #endif GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "
"); gtk_widget_show(menu_bar); gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0); GtkWidget *notebook = gtk_notebook_new(); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP); gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE); gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0); gtk_widget_realize(notebook); create_volumes_pane(notebook); create_scsi_pane(notebook); create_graphics_pane(notebook); create_input_pane(notebook); create_serial_pane(notebook); create_memory_pane(notebook); create_jit_pane(notebook); gtk_widget_show(notebook); static const opt_desc buttons[] = { {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)}, {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)}, {0, NULL} }; make_button_box(box, 4, buttons); // Show window and enter main loop gtk_widget_show(win); gtk_main(); return start_clicked; } /* * "Volumes" pane */ static GtkWidget *volume_list, *w_extfs; static int selected_volume; // Volume in list selected static void cl_selected(GtkWidget *list, int row, int column) { selected_volume = row; } // Volume selected for addition static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc) { gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); gtk_clist_append(GTK_CLIST(volume_list), &file); gtk_widget_destroy(assoc->req); delete assoc; } // Volume selected for creation static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc) { gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry)); int size = atoi(str); char cmd[1024]; sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", file, size); int ret = system(cmd); if (ret == 0) gtk_clist_append(GTK_CLIST(volume_list), &file); gtk_widget_destroy(GTK_WIDGET(assoc->req)); delete assoc; } // "Add Volume" button clicked static void cb_add_volume(...) { GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE)); gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL)); gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_widget_show(req); } // "Create Hardfile" button clicked static void cb_create_volume(...) { GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE)); GtkWidget *box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL)); gtk_widget_show(label); GtkWidget *entry = gtk_entry_new(); gtk_widget_show(entry); char str[32]; sprintf(str, "%d", 40); gtk_entry_set_text(GTK_ENTRY(entry), str); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0); gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry)); gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_widget_show(req); } // "Remove Volume" button clicked static void cb_remove_volume(...) { gtk_clist_remove(GTK_CLIST(volume_list), selected_volume); } // "Boot From" selected static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);} static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);} // "No CD-ROM Driver" button toggled static void tb_nocdrom(GtkWidget *widget) { PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active); } // Read settings from widgets and set preferences static void read_volumes_settings(void) { while (PrefsFindString("disk")) PrefsRemoveItem("disk"); for (int i=0; irows; i++) { char *str; gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str); PrefsAddString("disk", str); } PrefsReplaceString("extfs", get_file_entry_path(w_extfs)); } // Create "Volumes" pane static void create_volumes_pane(GtkWidget *top) { GtkWidget *box, *scroll, *menu; box = make_pane(top, STR_VOLUMES_PANE_TITLE); scroll = gtk_scrolled_window_new(NULL, NULL); gtk_widget_show(scroll); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); volume_list = gtk_clist_new(1); gtk_widget_show(volume_list); gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE); gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE); gtk_clist_set_reorderable(GTK_CLIST(volume_list), true); gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL); char *str; int32 index = 0; while ((str = const_cast(PrefsFindString("disk", index++))) != NULL) gtk_clist_append(GTK_CLIST(volume_list), &str); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list); gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0); selected_volume = 0; static const opt_desc buttons[] = { {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)}, {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)}, {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)}, {0, NULL}, }; make_button_box(box, 0, buttons); make_separator(box); w_extfs = make_file_entry(box, STR_EXTFS_CTRL, "extfs", true); static const opt_desc options[] = { {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)}, {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)}, {0, NULL} }; int bootdriver = PrefsFindInt32("bootdriver"), active = 0; switch (bootdriver) { case 0: active = 0; break; case CDROMRefNum: active = 1; break; } menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active); make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom)); } /* * "JIT Compiler" pane */ static GtkWidget *w_jit_fpu; static GtkWidget *w_jit_atraps; static GtkWidget *w_jit_cache_size; static GtkWidget *w_jit_lazy_flush; static GtkWidget *w_jit_follow_const_jumps; // Are we running a JIT capable CPU? static bool is_jit_capable(void) { #if USE_JIT && (defined __i386__ || defined __x86_64__) return true; #elif defined __APPLE__ && defined __MACH__ // XXX run-time detect so that we can use a PPC GUI prefs editor static char cpu[10]; if (cpu[0] == 0) { FILE *fp = popen("uname -p", "r"); if (fp == NULL) return false; fgets(cpu, sizeof(cpu) - 1, fp); fclose(fp); } if (cpu[0] == 'i' && cpu[2] == '8' && cpu[3] == '6') // XXX assuming i?86 return true; #endif return false; } // Set sensitivity of widgets static void set_jit_sensitive(void) { const bool jit_enabled = PrefsFindBool("jit"); gtk_widget_set_sensitive(w_jit_fpu, jit_enabled); gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled); gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled); gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled); } // "Use JIT Compiler" button toggled static void tb_jit(GtkWidget *widget) { PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active); set_jit_sensitive(); } // "Compile FPU Instructions" button toggled static void tb_jit_fpu(GtkWidget *widget) { PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active); } // "Lazy translation cache invalidation" button toggled static void tb_jit_lazy_flush(GtkWidget *widget) { PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active); } // "Translate through constant jumps (inline blocks)" button toggled static void tb_jit_follow_const_jumps(GtkWidget *widget) { PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active); } // Read settings from widgets and set preferences static void read_jit_settings(void) { bool jit_enabled = is_jit_capable() && PrefsFindBool("jit"); if (jit_enabled) { const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry)); PrefsReplaceInt32("jitcachesize", atoi(str)); } } // Create "JIT Compiler" pane static void create_jit_pane(GtkWidget *top) { if (!is_jit_capable()) return; GtkWidget *box, *table, *label, *menu; char str[32]; box = make_pane(top, STR_JIT_PANE_TITLE); make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit)); w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu)); // Translation cache size static const combo_desc options[] = { STR_JIT_CACHE_SIZE_2MB_LAB, STR_JIT_CACHE_SIZE_4MB_LAB, STR_JIT_CACHE_SIZE_8MB_LAB, STR_JIT_CACHE_SIZE_16MB_LAB, 0 }; w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, "jitcachesize", options); // Lazy translation cache invalidation w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush)); // Follow constant jumps (inline basic blocks) w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps)); set_jit_sensitive(); } /* * "SCSI" pane */ static GtkWidget *w_scsi[7]; // Read settings from widgets and set preferences static void read_scsi_settings(void) { for (int id=0; id<7; id++) { char prefs_name[32]; sprintf(prefs_name, "scsi%d", id); const char *str = get_file_entry_path(w_scsi[id]); if (str && strlen(str)) PrefsReplaceString(prefs_name, str); else PrefsRemoveItem(prefs_name); } } // Create "SCSI" pane static void create_scsi_pane(GtkWidget *top) { GtkWidget *box; box = make_pane(top, STR_SCSI_PANE_TITLE); for (int id=0; id<7; id++) { char prefs_name[32]; sprintf(prefs_name, "scsi%d", id); w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name); } } /* * "Graphics/Sound" pane */ // Display types enum { DISPLAY_WINDOW, DISPLAY_SCREEN }; static GtkWidget *w_frameskip, *w_display_x, *w_display_y; static GtkWidget *l_frameskip, *l_display_x, *l_display_y; static int display_type; static int dis_width, dis_height; #ifdef ENABLE_FBDEV_DGA static GtkWidget *w_fbdev_name, *w_fbdevice_file; static GtkWidget *l_fbdev_name, *l_fbdevice_file; static char fbdev_name[256]; #endif static GtkWidget *w_dspdevice_file, *w_mixerdevice_file; // Hide/show graphics widgets static void hide_show_graphics_widgets(void) { switch (display_type) { case DISPLAY_WINDOW: gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip); #ifdef ENABLE_FBDEV_DGA gtk_widget_show(w_display_x); gtk_widget_show(l_display_x); gtk_widget_show(w_display_y); gtk_widget_show(l_display_y); gtk_widget_hide(w_fbdev_name); gtk_widget_hide(l_fbdev_name); #endif break; case DISPLAY_SCREEN: gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip); #ifdef ENABLE_FBDEV_DGA gtk_widget_hide(w_display_x); gtk_widget_hide(l_display_x); gtk_widget_hide(w_display_y); gtk_widget_hide(l_display_y); gtk_widget_show(w_fbdev_name); gtk_widget_show(l_fbdev_name); #endif break; } } // "Window" video type selected static void mn_window(...) { display_type = DISPLAY_WINDOW; hide_show_graphics_widgets(); } // "Fullscreen" video type selected static void mn_fullscreen(...) { display_type = DISPLAY_SCREEN; hide_show_graphics_widgets(); } // "5 Hz".."60Hz" selected static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);} static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);} static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);} static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);} static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);} static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);} static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);} // Set sensitivity of widgets static void set_graphics_sensitive(void) { const bool sound_enabled = !PrefsFindBool("nosound"); gtk_widget_set_sensitive(w_dspdevice_file, sound_enabled); gtk_widget_set_sensitive(w_mixerdevice_file, sound_enabled); } // "Disable Sound Output" button toggled static void tb_nosound(GtkWidget *widget) { PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active); set_graphics_sensitive(); } // Read graphics preferences static void parse_graphics_prefs(void) { display_type = DISPLAY_WINDOW; dis_width = 512; dis_height = 384; #ifdef ENABLE_FBDEV_DGA fbdev_name[0] = 0; #endif const char *str = PrefsFindString("screen"); if (str) { if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2) display_type = DISPLAY_WINDOW; #ifdef ENABLE_FBDEV_DGA else if (sscanf(str, "dga/%255s", fbdev_name) == 1) #else else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2) #endif display_type = DISPLAY_SCREEN; } } // Read settings from widgets and set preferences static void read_graphics_settings(void) { const char *str; str = gtk_entry_get_text(GTK_ENTRY(w_display_x)); dis_width = atoi(str); str = gtk_entry_get_text(GTK_ENTRY(w_display_y)); dis_height = atoi(str); char pref[256]; switch (display_type) { case DISPLAY_WINDOW: sprintf(pref, "win/%d/%d", dis_width, dis_height); break; case DISPLAY_SCREEN: #ifdef ENABLE_FBDEV_DGA str = gtk_entry_get_text(GTK_ENTRY(w_fbdev_name)); sprintf(pref, "dga/%s", str); #else sprintf(pref, "dga/%d/%d", dis_width, dis_height); #endif break; default: PrefsRemoveItem("screen"); return; } PrefsReplaceString("screen", pref); #ifdef ENABLE_FBDEV_DGA str = get_file_entry_path(w_fbdevice_file); if (str && strlen(str)) PrefsReplaceString("fbdevicefile", str); else PrefsRemoveItem("fbdevicefile"); #endif PrefsReplaceString("dsp", get_file_entry_path(w_dspdevice_file)); PrefsReplaceString("mixer", get_file_entry_path(w_mixerdevice_file)); } // Create "Graphics/Sound" pane static void create_graphics_pane(GtkWidget *top) { GtkWidget *box, *table, *label, *opt, *menu, *combo; char str[32]; parse_graphics_prefs(); box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE); table = make_table(box, 2, 5); label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); opt = gtk_option_menu_new(); gtk_widget_show(opt); menu = gtk_menu_new(); add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window)); add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen)); switch (display_type) { case DISPLAY_WINDOW: gtk_menu_set_active(GTK_MENU(menu), 0); break; case DISPLAY_SCREEN: gtk_menu_set_active(GTK_MENU(menu), 1); break; } gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL)); gtk_widget_show(l_frameskip); gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); w_frameskip = gtk_option_menu_new(); gtk_widget_show(w_frameskip); menu = gtk_menu_new(); add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz)); add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz)); add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz)); add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz)); add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz)); add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz)); add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic)); int frameskip = PrefsFindInt32("frameskip"); int item = -1; switch (frameskip) { case 12: item = 0; break; case 8: item = 1; break; case 6: item = 2; break; case 4: item = 3; break; case 2: item = 4; break; case 1: item = 5; break; case 0: item = 6; break; } if (item >= 0) gtk_menu_set_active(GTK_MENU(menu), item); gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu); gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL)); gtk_widget_show(l_display_x); gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); combo = gtk_combo_new(); gtk_widget_show(combo); GList *glist1 = NULL; glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB)); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1); if (dis_width) sprintf(str, "%d", dis_width); else strcpy(str, GetString(STR_SIZE_MAX_LAB)); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); w_display_x = GTK_COMBO(combo)->entry; l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL)); gtk_widget_show(l_display_y); gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); combo = gtk_combo_new(); gtk_widget_show(combo); GList *glist2 = NULL; glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB)); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2); if (dis_height) sprintf(str, "%d", dis_height); else strcpy(str, GetString(STR_SIZE_MAX_LAB)); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); w_display_y = GTK_COMBO(combo)->entry; #ifdef ENABLE_FBDEV_DGA l_fbdev_name = gtk_label_new(GetString(STR_FBDEV_NAME_CTRL)); gtk_widget_show(l_fbdev_name); gtk_table_attach(GTK_TABLE(table), l_fbdev_name, 0, 1, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); w_fbdev_name = gtk_entry_new(); gtk_widget_show(w_fbdev_name); gtk_entry_set_text(GTK_ENTRY(w_fbdev_name), fbdev_name); gtk_table_attach(GTK_TABLE(table), w_fbdev_name, 1, 2, 4, 5, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); w_fbdevice_file = make_file_entry(box, STR_FBDEVICE_FILE_CTRL, "fbdevicefile"); #endif make_separator(box); make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound)); w_dspdevice_file = make_file_entry(box, STR_DSPDEVICE_FILE_CTRL, "dsp"); w_mixerdevice_file = make_file_entry(box, STR_MIXERDEVICE_FILE_CTRL, "mixer"); set_graphics_sensitive(); hide_show_graphics_widgets(); } /* * "Input" pane */ static GtkWidget *w_keycode_file; static GtkWidget *w_mouse_wheel_lines; // Set sensitivity of widgets static void set_input_sensitive(void) { const bool use_keycodes = PrefsFindBool("keycodes"); gtk_widget_set_sensitive(w_keycode_file, use_keycodes); gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes); gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1); } // "Use Raw Keycodes" button toggled static void tb_keycodes(GtkWidget *widget) { PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active); set_input_sensitive(); } // "Mouse Wheel Mode" selected static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();} static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();} // Read settings from widgets and set preferences static void read_input_settings(void) { const char *str = get_file_entry_path(w_keycode_file); if (str && strlen(str)) PrefsReplaceString("keycodefile", str); else PrefsRemoveItem("keycodefile"); PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines))); } // Create "Input" pane static void create_input_pane(GtkWidget *top) { GtkWidget *box, *hbox, *menu, *label, *button; GtkObject *adj; box = make_pane(top, STR_INPUT_PANE_TITLE); make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes)); hbox = gtk_hbox_new(FALSE, 4); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); label = gtk_label_new(GetString(STR_KEYCODES_CTRL)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); const char *str = PrefsFindString("keycodefile"); if (str == NULL) str = ""; w_keycode_file = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str); gtk_widget_show(w_keycode_file); gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0); button = make_browse_button(w_keycode_file); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button); make_separator(box); static const opt_desc options[] = { {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)}, {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)}, {0, NULL} }; int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0; switch (wheelmode) { case 0: active = 0; break; case 1: active = 1; break; } menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active); hbox = gtk_hbox_new(FALSE, 4); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0); w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0); gtk_widget_show(w_mouse_wheel_lines); gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0); set_input_sensitive(); } /* * "Serial/Network" pane */ static GtkWidget *w_seriala, *w_serialb, *w_ether, *w_udp_port; // Set sensitivity of widgets static void set_serial_sensitive(void) { #if SUPPORTS_UDP_TUNNEL gtk_widget_set_sensitive(w_ether, !PrefsFindBool("udptunnel")); gtk_widget_set_sensitive(w_udp_port, PrefsFindBool("udptunnel")); #endif } // "Tunnel AppleTalk over IP" button toggled static void tb_udptunnel(GtkWidget *widget) { PrefsReplaceBool("udptunnel", GTK_TOGGLE_BUTTON(widget)->active); set_serial_sensitive(); } // Read settings from widgets and set preferences static void read_serial_settings(void) { const char *str; str = gtk_entry_get_text(GTK_ENTRY(w_seriala)); PrefsReplaceString("seriala", str); str = gtk_entry_get_text(GTK_ENTRY(w_serialb)); PrefsReplaceString("serialb", str); str = gtk_entry_get_text(GTK_ENTRY(w_ether)); if (str && strlen(str)) PrefsReplaceString("ether", str); else PrefsRemoveItem("ether"); #if SUPPORTS_UDP_TUNNEL PrefsReplaceInt32("udpport", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_udp_port))); #endif } // Add names of serial devices static gint gl_str_cmp(gconstpointer a, gconstpointer b) { return strcmp((char *)a, (char *)b); } static GList *add_serial_names(void) { GList *glist = NULL; // Search /dev for ttyS* and lp* DIR *d = opendir("/dev"); if (d) { struct dirent *de; while ((de = readdir(d)) != NULL) { #if defined(__linux__) if (strncmp(de->d_name, "ttyS", 4) == 0 || strncmp(de->d_name, "lp", 2) == 0) { #elif defined(__FreeBSD__) if (strncmp(de->d_name, "cuaa", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) { #elif defined(__NetBSD__) if (strncmp(de->d_name, "tty0", 4) == 0 || strncmp(de->d_name, "lpt", 3) == 0) { #elif defined(sgi) if (strncmp(de->d_name, "ttyf", 4) == 0 || strncmp(de->d_name, "plp", 3) == 0) { #else if (false) { #endif char *str = new char[64]; sprintf(str, "/dev/%s", de->d_name); glist = g_list_append(glist, str); } } closedir(d); } if (glist) g_list_sort(glist, gl_str_cmp); else glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB)); return glist; } // Add names of ethernet interfaces static GList *add_ether_names(void) { GList *glist = NULL; // Get list of all Ethernet interfaces int s = socket(PF_INET, SOCK_DGRAM, 0); if (s >= 0) { char inbuf[8192]; struct ifconf ifc; ifc.ifc_len = sizeof(inbuf); ifc.ifc_buf = inbuf; if (ioctl(s, SIOCGIFCONF, &ifc) == 0) { struct ifreq req, *ifr = ifc.ifc_req; for (int i=0; iifr_name, 63); glist = g_list_append(glist, str); } } } close(s); } #ifdef HAVE_SLIRP static char s_slirp[] = "slirp"; glist = g_list_append(glist, s_slirp); #endif if (glist) g_list_sort(glist, gl_str_cmp); else glist = g_list_append(glist, (void *)GetString(STR_NONE_LAB)); return glist; } // Create "Serial/Network" pane static void create_serial_pane(GtkWidget *top) { GtkWidget *box, *hbox, *table, *label, *combo, *sep; GtkObject *adj; box = make_pane(top, STR_SERIAL_NETWORK_PANE_TITLE); table = make_table(box, 2, 4); label = gtk_label_new(GetString(STR_SERIALA_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); GList *glist = add_serial_names(); combo = gtk_combo_new(); gtk_widget_show(combo); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); const char *str = PrefsFindString("seriala"); if (str == NULL) str = ""; gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); w_seriala = GTK_COMBO(combo)->entry; label = gtk_label_new(GetString(STR_SERIALB_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); combo = gtk_combo_new(); gtk_widget_show(combo); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); str = PrefsFindString("serialb"); if (str == NULL) str = ""; gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 1, 2, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); w_serialb = GTK_COMBO(combo)->entry; sep = gtk_hseparator_new(); gtk_widget_show(sep); gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); glist = add_ether_names(); combo = gtk_combo_new(); gtk_widget_show(combo); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); str = PrefsFindString("ether"); if (str == NULL) str = ""; gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); w_ether = GTK_COMBO(combo)->entry; #if SUPPORTS_UDP_TUNNEL make_checkbox(box, STR_UDPTUNNEL_CTRL, "udptunnel", GTK_SIGNAL_FUNC(tb_udptunnel)); hbox = gtk_hbox_new(FALSE, 4); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); label = gtk_label_new(GetString(STR_UDPPORT_CTRL)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); adj = gtk_adjustment_new(PrefsFindInt32("udpport"), 1, 65535, 1, 5, 0); w_udp_port = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0); gtk_widget_show(w_udp_port); gtk_box_pack_start(GTK_BOX(hbox), w_udp_port, FALSE, FALSE, 0); #endif set_serial_sensitive(); } /* * "Memory/Misc" pane */ static GtkWidget *w_ramsize; static GtkWidget *w_rom_file; // Don't use CPU when idle? static void tb_idlewait(GtkWidget *widget) { PrefsReplaceBool("idlewait", GTK_TOGGLE_BUTTON(widget)->active); } // "Ignore SEGV" button toggled #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION static void tb_ignoresegv(GtkWidget *widget) { PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active); } #endif // Model ID selected static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);} static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);} // CPU/FPU type static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);} static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);} static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);} static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);} static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);} // Read settings from widgets and set preferences static void read_memory_settings(void) { const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry)); PrefsReplaceInt32("ramsize", atoi(str) << 20); str = get_file_entry_path(w_rom_file); if (str && strlen(str)) PrefsReplaceString("rom", str); else PrefsRemoveItem("rom"); } // Create "Memory/Misc" pane static void create_memory_pane(GtkWidget *top) { GtkWidget *box, *hbox, *table, *label, *menu; box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE); table = make_table(box, 2, 5); static const combo_desc options[] = { STR_RAMSIZE_2MB_LAB, STR_RAMSIZE_4MB_LAB, STR_RAMSIZE_8MB_LAB, STR_RAMSIZE_16MB_LAB, STR_RAMSIZE_32MB_LAB, STR_RAMSIZE_64MB_LAB, STR_RAMSIZE_128MB_LAB, STR_RAMSIZE_256MB_LAB, STR_RAMSIZE_512MB_LAB, STR_RAMSIZE_1024MB_LAB, 0 }; char default_ramsize[10]; sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20); w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options); static const opt_desc model_options[] = { {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)}, {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)}, {0, NULL} }; int modelid = PrefsFindInt32("modelid"), active = 0; switch (modelid) { case 5: active = 0; break; case 14: active = 1; break; } table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active); #if EMULATED_68K static const opt_desc cpu_options[] = { {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)}, {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)}, {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)}, {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)}, {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)}, {0, NULL} }; int cpu = PrefsFindInt32("cpu"); bool fpu = PrefsFindBool("fpu"); active = 0; switch (cpu) { case 2: active = fpu ? 1 : 0; break; case 3: active = fpu ? 3 : 2; break; case 4: active = 4; } table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active); #endif w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom"); make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait)); #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv)); #endif } /* * Read settings from widgets and set preferences */ static void read_settings(void) { read_volumes_settings(); read_scsi_settings(); read_graphics_settings(); read_input_settings(); read_serial_settings(); read_memory_settings(); read_jit_settings(); } #ifdef STANDALONE_GUI #include #include #include "rpc.h" /* * Fake unused data and functions */ uint8 XPRAM[XPRAM_SIZE]; void MountVolume(void *fh) { } void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { } #if defined __APPLE__ && defined __MACH__ void DarwinSysInit(void) { } void DarwinSysExit(void) { } void DarwinAddFloppyPrefs(void) { } void DarwinAddSerialPrefs(void) { } bool DarwinCDReadTOC(char *, uint8 *) { } #endif /* * Display alert */ static void dl_destroyed(void) { gtk_main_quit(); } static void display_alert(int title_id, int prefix_id, int button_id, const char *text) { char str[256]; sprintf(str, GetString(prefix_id), text); GtkWidget *dialog = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id)); gtk_container_border_width(GTK_CONTAINER(dialog), 5); gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150); gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL); GtkWidget *label = gtk_label_new(str); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0); GtkWidget *button = gtk_button_new_with_label(GetString(button_id)); gtk_widget_show(button); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show(dialog); gtk_main(); } /* * Display error alert */ void ErrorAlert(const char *text) { display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text); } /* * Display warning alert */ void WarningAlert(const char *text) { display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text); } /* * RPC handlers */ static GMainLoop *g_gui_loop; static int handle_ErrorAlert(rpc_connection_t *connection) { D(bug("handle_ErrorAlert\n")); int error; char *str; if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0) return error; ErrorAlert(str); free(str); return RPC_ERROR_NO_ERROR; } static int handle_WarningAlert(rpc_connection_t *connection) { D(bug("handle_WarningAlert\n")); int error; char *str; if ((error = rpc_method_get_args(connection, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID)) < 0) return error; WarningAlert(str); free(str); return RPC_ERROR_NO_ERROR; } static int handle_Exit(rpc_connection_t *connection) { D(bug("handle_Exit\n")); g_main_quit(g_gui_loop); return RPC_ERROR_NO_ERROR; } /* * SIGCHLD handler */ static char g_app_path[PATH_MAX]; static rpc_connection_t *g_gui_connection = NULL; static void sigchld_handler(int sig, siginfo_t *sip, void *) { D(bug("Child %d exitted with status = %x\n", sip->si_pid, sip->si_status)); // XXX perform a new wait because sip->si_status is sometimes not // the exit _value_ on MacOS X but rather the usual status field // from waitpid() -- we could arrange this code in some other way... int status; if (waitpid(sip->si_pid, &status, 0) < 0) status = sip->si_status; if (WIFEXITED(status)) status = WEXITSTATUS(status); if (status & 0x80) status |= -1 ^0xff; if (status < 0) { // negative -> execlp/-errno char str[256]; sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(-status)); ErrorAlert(str); status = 1; } if (status != 0) { if (g_gui_connection) rpc_exit(g_gui_connection); exit(status); } } /* * Start standalone GUI */ int main(int argc, char *argv[]) { #ifdef HAVE_GNOMEUI // Init GNOME/GTK char version[16]; sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR); gnome_init("Basilisk II", version, argc, argv); #else // Init GTK gtk_set_locale(); gtk_init(&argc, &argv); #endif // Read preferences PrefsInit(NULL, argc, argv); // Show preferences editor bool start = PrefsEditor(); // Exit preferences PrefsExit(); // Transfer control to the executable if (start) { char gui_connection_path[64]; sprintf(gui_connection_path, "/org/BasiliskII/GUI/%d", getpid()); // Catch exits from the child process struct sigaction sigchld_sa, old_sigchld_sa; sigemptyset(&sigchld_sa.sa_mask); sigchld_sa.sa_sigaction = sigchld_handler; sigchld_sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; if (sigaction(SIGCHLD, &sigchld_sa, &old_sigchld_sa) < 0) { char str[256]; sprintf(str, GetString(STR_SIG_INSTALL_ERR), SIGCHLD, strerror(errno)); ErrorAlert(str); return 1; } // Search and run the BasiliskII executable char *p; strcpy(g_app_path, argv[0]); if ((p = strstr(g_app_path, "BasiliskIIGUI.app/Contents/MacOS")) != NULL) { strcpy(p, "BasiliskII.app/Contents/MacOS/BasiliskII"); if (access(g_app_path, X_OK) < 0) { char str[256]; sprintf(str, GetString(STR_NO_B2_EXE_FOUND), g_app_path, strerror(errno)); WarningAlert(str); strcpy(g_app_path, "/Applications/BasiliskII.app/Contents/MacOS/BasiliskII"); } } else { p = strrchr(g_app_path, '/'); p = p ? p + 1 : g_app_path; strcpy(p, "BasiliskII"); } int pid = fork(); if (pid == 0) { D(bug("Trying to execute %s\n", g_app_path)); execlp(g_app_path, g_app_path, "--gui-connection", gui_connection_path, (char *)NULL); #ifdef _POSIX_PRIORITY_SCHEDULING // XXX get a chance to run the parent process so that to not confuse/upset GTK... sched_yield(); #endif _exit(-errno); } // Establish a connection to Basilisk II if ((g_gui_connection = rpc_init_server(gui_connection_path)) == NULL) { printf("ERROR: failed to initialize GUI-side RPC server connection\n"); return 1; } static const rpc_method_descriptor_t vtable[] = { { RPC_METHOD_ERROR_ALERT, handle_ErrorAlert }, { RPC_METHOD_WARNING_ALERT, handle_WarningAlert }, { RPC_METHOD_EXIT, handle_Exit } }; if (rpc_method_add_callbacks(g_gui_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) { printf("ERROR: failed to setup GUI method callbacks\n"); return 1; } int socket; if ((socket = rpc_listen_socket(g_gui_connection)) < 0) { printf("ERROR: failed to initialize RPC server thread\n"); return 1; } g_gui_loop = g_main_new(TRUE); while (g_main_is_running(g_gui_loop)) { // Process a few events pending const int N_EVENTS_DISPATCH = 10; for (int i = 0; i < N_EVENTS_DISPATCH; i++) { if (!g_main_iteration(FALSE)) break; } // Check for RPC events (100 ms timeout) int ret = rpc_wait_dispatch(g_gui_connection, 100000); if (ret == 0) continue; if (ret < 0) break; rpc_dispatch(g_gui_connection); } rpc_exit(g_gui_connection); return 0; } return 0; } #endif BasiliskII/src/Unix/extfs_unix.cpp0000644000175000017500000002601110736405221017353 0ustar centriscentris/* * extfs_unix.cpp - MacOS file system for access native file system access, Unix specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include "sysdeps.h" #include "extfs.h" #include "extfs_defs.h" #define DEBUG 0 #include "debug.h" // Default Finder flags const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; /* * Initialization */ void extfs_init(void) { } /* * Deinitialization */ void extfs_exit(void) { } /* * Add component to path name */ void add_path_component(char *path, const char *component) { int l = strlen(path); if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') { path[l] = '/'; path[l+1] = 0; } strncat(path, component, MAX_PATH_LENGTH-1); } /* * Finder info and resource forks are kept in helper files * * Finder info: * /path/.finf/file * Resource fork: * /path/.rsrc/file * * The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo * (16+16 bytes) */ static void make_helper_path(const char *src, char *dest, const char *add, bool only_dir = false) { dest[0] = 0; // Get pointer to last component of path const char *last_part = strrchr(src, '/'); if (last_part) last_part++; else last_part = src; // Copy everything before strncpy(dest, src, last_part-src); dest[last_part-src] = 0; // Add additional component strncat(dest, add, MAX_PATH_LENGTH-1); // Add last component if (!only_dir) strncat(dest, last_part, MAX_PATH_LENGTH-1); } static int create_helper_dir(const char *path, const char *add) { char helper_dir[MAX_PATH_LENGTH]; make_helper_path(path, helper_dir, add, true); if (helper_dir[strlen(helper_dir) - 1] == '/') // Remove trailing "/" helper_dir[strlen(helper_dir) - 1] = 0; return mkdir(helper_dir, 0777); } static int open_helper(const char *path, const char *add, int flag) { char helper_path[MAX_PATH_LENGTH]; make_helper_path(path, helper_path, add); if ((flag & O_ACCMODE) == O_RDWR || (flag & O_ACCMODE) == O_WRONLY) flag |= O_CREAT; int fd = open(helper_path, flag, 0666); if (fd < 0) { if (errno == ENOENT && (flag & O_CREAT)) { // One path component was missing, probably the helper // directory. Try to create it and re-open the file. int ret = create_helper_dir(path, add); if (ret < 0) return ret; fd = open(helper_path, flag, 0666); } } return fd; } static int open_finf(const char *path, int flag) { return open_helper(path, ".finf/", flag); } static int open_rsrc(const char *path, int flag) { return open_helper(path, ".rsrc/", flag); } /* * Get/set finder info for file/directory specified by full path */ struct ext2type { const char *ext; uint32 type; uint32 creator; }; static const ext2type e2t_translation[] = { {".Z", FOURCC('Z','I','V','M'), FOURCC('L','Z','I','V')}, {".gz", FOURCC('G','z','i','p'), FOURCC('G','z','i','p')}, {".hqx", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".bin", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".pdf", FOURCC('P','D','F',' '), FOURCC('C','A','R','O')}, {".ps", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".sit", FOURCC('S','I','T','!'), FOURCC('S','I','T','x')}, {".tar", FOURCC('T','A','R','F'), FOURCC('T','A','R',' ')}, {".uu", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".uue", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".zip", FOURCC('Z','I','P',' '), FOURCC('Z','I','P',' ')}, {".8svx", FOURCC('8','S','V','X'), FOURCC('S','N','D','M')}, {".aifc", FOURCC('A','I','F','C'), FOURCC('T','V','O','D')}, {".aiff", FOURCC('A','I','F','F'), FOURCC('T','V','O','D')}, {".au", FOURCC('U','L','A','W'), FOURCC('T','V','O','D')}, {".mid", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".midi", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".mp2", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".mp3", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".wav", FOURCC('W','A','V','E'), FOURCC('T','V','O','D')}, {".bmp", FOURCC('B','M','P','f'), FOURCC('o','g','l','e')}, {".gif", FOURCC('G','I','F','f'), FOURCC('o','g','l','e')}, {".lbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".ilbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".jpg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".jpeg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".pict", FOURCC('P','I','C','T'), FOURCC('o','g','l','e')}, {".png", FOURCC('P','N','G','f'), FOURCC('o','g','l','e')}, {".sgi", FOURCC('.','S','G','I'), FOURCC('o','g','l','e')}, {".tga", FOURCC('T','P','I','C'), FOURCC('o','g','l','e')}, {".tif", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".tiff", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".htm", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".html", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".txt", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".rtf", FOURCC('T','E','X','T'), FOURCC('M','S','W','D')}, {".c", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".C", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cc", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".h", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hh", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".s", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".S", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".i", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".mpg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mpeg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mov", FOURCC('M','o','o','V'), FOURCC('T','V','O','D')}, {".fli", FOURCC('F','L','I',' '), FOURCC('T','V','O','D')}, {".avi", FOURCC('V','f','W',' '), FOURCC('T','V','O','D')}, {".qxd", FOURCC('X','D','O','C'), FOURCC('X','P','R','3')}, {".hfv", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".dsk", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".img", FOURCC('r','o','h','d'), FOURCC('d','d','s','k')}, {NULL, 0, 0} // End marker }; void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Read Finder info file int fd = open_finf(path, O_RDONLY); if (fd >= 0) { ssize_t actual = read(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) actual += read(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); if (actual >= SIZEOF_FInfo) return; } // No Finder info file, translate file name extension to MacOS type/creator if (!is_dir) { int path_len = strlen(path); for (int i=0; e2t_translation[i].ext; i++) { int ext_len = strlen(e2t_translation[i].ext); if (path_len < ext_len) continue; if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) { WriteMacInt32(finfo + fdType, e2t_translation[i].type); WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator); break; } } } } void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Open Finder info file int fd = open_finf(path, O_RDWR); if (fd < 0) return; // Write file write(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) write(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); } /* * Resource fork emulation functions */ uint32 get_rfork_size(const char *path) { // Open resource file int fd = open_rsrc(path, O_RDONLY); if (fd < 0) return 0; // Get size off_t size = lseek(fd, 0, SEEK_END); // Close file and return size close(fd); return size < 0 ? 0 : size; } int open_rfork(const char *path, int flag) { return open_rsrc(path, flag); } void close_rfork(const char *path, int fd) { close(fd); } /* * Read "length" bytes from file to "buffer", * returns number of bytes read (or -1 on error) */ ssize_t extfs_read(int fd, void *buffer, size_t length) { return read(fd, buffer, length); } /* * Write "length" bytes from "buffer" to file, * returns number of bytes written (or -1 on error) */ ssize_t extfs_write(int fd, void *buffer, size_t length) { return write(fd, buffer, length); } /* * Remove file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_remove(const char *path) { // Remove helpers first, don't complain if this fails char helper_path[MAX_PATH_LENGTH]; make_helper_path(path, helper_path, ".finf/", false); remove(helper_path); make_helper_path(path, helper_path, ".rsrc/", false); remove(helper_path); // Now remove file or directory (and helper directories in the directory) if (remove(path) < 0) { if (errno == EISDIR || errno == ENOTEMPTY) { helper_path[0] = 0; strncpy(helper_path, path, MAX_PATH_LENGTH-1); add_path_component(helper_path, ".finf"); rmdir(helper_path); helper_path[0] = 0; strncpy(helper_path, path, MAX_PATH_LENGTH-1); add_path_component(helper_path, ".rsrc"); rmdir(helper_path); return rmdir(path) == 0; } else return false; } return true; } /* * Rename/move file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_rename(const char *old_path, const char *new_path) { // Rename helpers first, don't complain if this fails char old_helper_path[MAX_PATH_LENGTH], new_helper_path[MAX_PATH_LENGTH]; make_helper_path(old_path, old_helper_path, ".finf/", false); make_helper_path(new_path, new_helper_path, ".finf/", false); create_helper_dir(new_path, ".finf/"); rename(old_helper_path, new_helper_path); make_helper_path(old_path, old_helper_path, ".rsrc/", false); make_helper_path(new_path, new_helper_path, ".rsrc/", false); create_helper_dir(new_path, ".rsrc/"); rename(old_helper_path, new_helper_path); // Now rename file return rename(old_path, new_path) == 0; } // Convert from the host OS filename encoding to MacRoman const char *host_encoding_to_macroman(const char *filename) { return filename; } // Convert from MacRoman to host OS filename encoding const char *macroman_to_host_encoding(const char *filename) { return filename; } BasiliskII/src/Unix/semaphore.h0000644000175000017500000000233110241433107016601 0ustar centriscentris#ifndef __SEMAPHORE_H #define __SEMAPHORE_H #define SEM_VALUE_MAX 64 #if defined(c_plusplus) || defined(__cplusplus) extern "C" { #endif /* c_plusplus || __cplusplus */ /* MacOS X doesn't implement unnamed POSIX semaphores, event though the libc defines them! */ #if (defined(__MACH__) && defined(__APPLE__)) #include #include #include #define sem_t semaphore_t #define sem_init(SEM,UNUSED,VALUE) semaphore_create(current_task(), (SEM), SYNC_POLICY_FIFO, (VALUE)) #define sem_destroy(SEM) semaphore_destroy(current_task(), *(SEM)) #define sem_wait(SEM) semaphore_wait(*(SEM)) #define sem_post(SEM) semaphore_signal(*(SEM)) #else typedef struct psem { pthread_mutex_t sem_lock; int sem_value; int sem_waiting; } sem_t; int sem_init(sem_t* sem, int pshared, unsigned int value); int sem_destroy(sem_t* sem); sem_t sem_open(const char* name, int oflag, ...); int sem_close(sem_t* sem); int sem_unlink(const char* name); int sem_wait(sem_t* sem); int sem_trywait(sem_t* sem); int sem_post(sem_t* sem); int sem_getvalue(sem_t* sem, int* sval); #endif #if defined(c_plusplus) || defined(__cplusplus) }; #endif /* c_plusplus || __cplusplus */ #endif /* __SEMAPHORE_H */ BasiliskII/src/Unix/vhd_unix.cpp0000644000175000017500000000613011457207320017004 0ustar centriscentris/* * vhd_unix.cpp -- support for disk images in vhd format * * (C) 2010 Geoffrey Brown * * 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 */ #include "sysdeps.h" #include "vhd_unix.h" #include #include #include #include extern "C" { #include } // libvhd.h defines DEBUG #undef DEBUG #define DEBUG 0 #include "debug.h" void *vhd_unix_open(const char *name, int *size, bool read_only) { int amode = read_only ? R_OK : (R_OK | W_OK); int fid; vhd_context_t *vhd; D(bug("vhd open %s\n", name)); if (access(name, amode)) { D(bug("vhd open -- incorrect permissions %s\n", name)); return NULL; } if (! (fid = open(name, O_RDONLY))) { D(bug("vhd open -- couldn't open file %s\n", name)); return NULL; } else { char buf[9]; read(fid, buf, sizeof(buf)-1); buf[8] = 0; close(fid); if (strcmp("conectix", buf) != 0) { D(bug("vhd open -- not vhd magic = %s\n", buf)); return NULL; } if (vhd = (vhd_context_t *) malloc(sizeof(vhd_context_t))) { int err; if (err = vhd_open(vhd, name, read_only ? VHD_OPEN_RDONLY : VHD_OPEN_RDWR)) { D(bug("vhd_open failed (%d)\n", err)); free(vhd); return NULL; } else { *size = (int) vhd->footer.curr_size; printf("VHD Open %s\n", name); return (void *) vhd; } } else { D(bug("vhd open -- malloc failed\n")); return NULL; } } } int vhd_unix_read(void *arg, void *buffer, loff_t offset, size_t length) { vhd_context_t *ctx = (vhd_context_t *) arg; int err; if ((offset % VHD_SECTOR_SIZE) || (length % VHD_SECTOR_SIZE)) { printf("vhd read only supported on sector boundaries (%d)\n", VHD_SECTOR_SIZE); return 0; } if (err = vhd_io_read(ctx, (char *) buffer, offset / VHD_SECTOR_SIZE, length / VHD_SECTOR_SIZE)){ D(bug("vhd read error %d\n", err)); return err; } else return length; } int vhd_unix_write(void *arg, void *buffer, loff_t offset, size_t length) { int err; vhd_context_t *ctx = (vhd_context_t *) arg; if ((offset % VHD_SECTOR_SIZE) || (length % VHD_SECTOR_SIZE)) { printf("vhd write only supported on sector boundaries (%d)\n", VHD_SECTOR_SIZE); return 0; } if (err = vhd_io_write(ctx, (char *) buffer, offset/VHD_SECTOR_SIZE, length/VHD_SECTOR_SIZE)) { D(bug("vhd write error %d\n", err)); return err; } else return length; } void vhd_unix_close(void *arg) { D(bug("vhd close\n")); vhd_close((vhd_context_t *) arg); free(arg); } BasiliskII/src/Unix/configure.ac0000644000175000017500000015374411677014372016767 0ustar centriscentrisdnl Process this file with autoconf to produce a configure script. dnl Written in 2002 by Christian Bauer et al. AC_INIT([Basilisk II], 1.0, [Christian.Bauer@uni-mainz.de], BasiliskII) AC_CONFIG_SRCDIR(main_unix.cpp) AC_PREREQ(2.52) AC_CONFIG_HEADER(config.h) dnl Aliases for PACKAGE and VERSION macros. AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE_NAME", [Define this program name.]) AC_DEFINE_UNQUOTED(VERSION, "$PACKAGE_VERSION", [Define this program version.]) dnl Some systems do not put corefiles in the currect directory, avoid saving dnl cores for the configure tests since some are intended to dump core. ulimit -c 0 AC_ARG_ENABLE(standalone-gui,[ --enable-standalone-gui enable a standalone GUI prefs editor [default=no]], [WANT_STANDALONE_GUI=$enableval], [WANT_STANDALONE_GUI=no]) dnl Video options. AC_ARG_ENABLE(xf86-dga, [ --enable-xf86-dga use the XFree86 DGA extension [default=yes]], [WANT_XF86_DGA=$enableval], [WANT_XF86_DGA=yes]) AC_ARG_ENABLE(xf86-vidmode, [ --enable-xf86-vidmode use the XFree86 VidMode extension [default=yes]], [WANT_XF86_VIDMODE=$enableval], [WANT_XF86_VIDMODE=yes]) AC_ARG_ENABLE(fbdev-dga, [ --enable-fbdev-dga use direct frame buffer access via /dev/fb [default=yes]], [WANT_FBDEV_DGA=$enableval], [WANT_FBDEV_DGA=yes]) AC_ARG_ENABLE(vosf, [ --enable-vosf enable video on SEGV signals [default=yes]], [WANT_VOSF=$enableval], [WANT_VOSF=yes]) dnl SDL options. AC_ARG_ENABLE(sdl-static, [ --enable-sdl-static use SDL static libraries for linking [default=no]], [WANT_SDL_STATIC=$enableval], [WANT_SDL_STATIC=no]) AC_ARG_ENABLE(sdl-video, [ --enable-sdl-video use SDL for video graphics [default=no]], [WANT_SDL_VIDEO=$enableval], [WANT_SDL_VIDEO=no]) AC_ARG_ENABLE(sdl-audio, [ --enable-sdl-audio use SDL for audio [default=no]], [WANT_SDL_AUDIO=$enableval], [WANT_SDL_AUDIO=no]) AC_ARG_ENABLE(sdl-framework, [ --enable-sdl-framework use SDL framework [default=no]], [WANT_SDL_FRAMEWORK=$enableval], [WANT_SDL_FRAMEWORK=no]) AC_ARG_ENABLE(sdl-framework-prefix, [ --enable-sdl-framework-prefix=PFX default=/Library/Frameworks], [SDL_FRAMEWORK="$enableval"], [SDL_FRAMEWORK=/Library/Frameworks]) dnl JIT compiler options. AC_ARG_ENABLE(jit-compiler, [ --enable-jit-compiler enable JIT compiler [default=no]], [WANT_JIT=$enableval], [WANT_JIT=no]) AC_ARG_ENABLE(jit-debug, [ --enable-jit-debug activate native code disassemblers [default=no]], [WANT_JIT_DEBUG=$enableval], [WANT_JIT_DEBUG=no]) dnl FPU emulation core. AC_ARG_ENABLE(fpe, [ --enable-fpe=FPE specify which fpu emulator to use [default=auto]], [ case "$enableval" in dnl default is always ieee, if architecture has this fp format auto) FPE_CORE_TEST_ORDER="ieee uae";; ieee) FPE_CORE_TEST_ORDER="ieee";; uae) FPE_CORE_TEST_ORDER="uae";; x86) FPE_CORE_TEST_ORDER="x86";; *) AC_MSG_ERROR([--enable-fpe takes only one of the following values: auto, x86, ieee, uae]);; esac ], [ FPE_CORE_TEST_ORDER="ieee uae" ]) dnl Addressing modes. AC_ARG_ENABLE(addressing, [ --enable-addressing=AM specify the addressing mode to use [default=fastest]], [ case "$enableval" in real) ADDRESSING_TEST_ORDER="real";; direct) ADDRESSING_TEST_ORDER="direct";; banks) ADDRESSING_TEST_ORDER="banks";; fastest)ADDRESSING_TEST_ORDER="direct banks";; *) AC_MSG_ERROR([--enable-addressing takes only one of the following values: fastest, real, direct, banks]);; esac ], [ ADDRESSING_TEST_ORDER="direct banks" ]) dnl External packages. AC_ARG_WITH(esd, [ --with-esd support ESD for sound under Linux/FreeBSD [default=yes]], [WANT_ESD=$withval], [WANT_ESD=yes]) AC_ARG_WITH(gtk, [ --with-gtk use GTK user interface [default=yes]], [case "$withval" in gtk1) WANT_GTK="gtk";; gtk|gtk2) WANT_GTK="$withval";; yes) WANT_GTK="gtk2 gtk";; *) WANT_GTK="no";; esac], [WANT_GTK="gtk2 gtk"]) AC_ARG_WITH(mon, [ --with-mon use mon as debugger [default=yes]], [WANT_MON=$withval], [WANT_MON=yes]) AC_ARG_WITH(bincue, AS_HELP_STRING([--with-bincue], [Allow cdrom image files in bin/cue mode])) AC_ARG_WITH(libvhd, AS_HELP_STRING([--with-libvhd], [Enable VHD disk images])) dnl Canonical system information. AC_CANONICAL_HOST AC_CANONICAL_TARGET dnl Target OS type (target is host if not cross-compiling). case "$target_os" in linux*) OS_TYPE=linux;; netbsd*) OS_TYPE=netbsd;; freebsd*) OS_TYPE=freebsd;; solaris*) OS_TYPE=solaris;; darwin*) OS_TYPE=darwin;; *) OS_TYPE=`echo $target_os | sed -e 's/-/_/g' | sed -e 's/\./_/g'`;; esac DEFINES="$DEFINES -DOS_$OS_TYPE" dnl Target CPU type. HAVE_I386=no HAVE_M68K=no HAVE_SPARC=no HAVE_POWERPC=no HAVE_X86_64=no case "$target_cpu" in i386* | i486* | i586* | i686* | i786* ) HAVE_I386=yes;; m68k* ) HAVE_M68K=yes;; sparc* ) HAVE_SPARC=yes;; powerpc* ) HAVE_POWERPC=yes;; x86_64* ) HAVE_X86_64=yes;; esac dnl Check if we should really be assuming x86_64 even if we detected HAVE_I386 above. if [[ "x$HAVE_I386" = "xyes" ]]; then AC_TRY_RUN([ int main(void) { #if defined(__x86_64__) return 0; #else return 1; #endif } ], [ HAVE_I386=no HAVE_X86_64=yes ]) fi dnl Checks for programs. AC_PROG_CC AC_PROG_CC_C_O AC_PROG_CPP AC_PROG_CXX AC_PROG_MAKE_SET AC_PROG_INSTALL AC_PROG_EGREP dnl We use mon if possible. MONSRCS= if [[ "x$WANT_MON" = "xyes" ]]; then AC_MSG_CHECKING(for mon) mon_srcdir=../../../mon/src if grep mon_init $mon_srcdir/mon.h >/dev/null 2>/dev/null; then AC_MSG_RESULT(yes) AC_DEFINE(ENABLE_MON, 1, [Define if using "mon".]) MONSRCS="$mon_srcdir/mon.cpp $mon_srcdir/mon_6502.cpp $mon_srcdir/mon_z80.cpp $mon_srcdir/mon_cmd.cpp $mon_srcdir/mon_disass.cpp $mon_srcdir/mon_ppc.cpp $mon_srcdir/mon_lowmem.cpp $mon_srcdir/disass/floatformat.c $mon_srcdir/disass/i386-dis.c $mon_srcdir/disass/m68k-dis.c $mon_srcdir/disass/m68k-opc.c $mon_srcdir/disass/mips-dis.c $mon_srcdir/disass/mips-opc.c $mon_srcdir/disass/mips16-opc.c" CXXFLAGS="$CXXFLAGS -I$mon_srcdir -I$mon_srcdir/disass" AC_CHECK_LIB(ncurses, tgetent, , [AC_CHECK_LIB(termcap, tgetent, , [AC_CHECK_LIB(termlib, tgetent, , [AC_CHECK_LIB(terminfo, tgetent, , [AC_CHECK_LIB(Hcurses, tgetent, , [AC_CHECK_LIB(curses, tgetent)])])])])]) AC_CHECK_LIB(readline, readline) else AC_MSG_RESULT(no) AC_MSG_WARN([Could not find mon, ignoring --with-mon.]) WANT_MON=no fi fi dnl Checks for libraries. AC_CHECK_LIB(posix4, sem_init) AC_CHECK_LIB(rt, timer_create) AC_CHECK_LIB(rt, shm_open) AC_CHECK_LIB(m, cos) dnl AC_CHECK_SDLFRAMEWORK($1=NAME, $2=INCLUDES) dnl AC_TRY_LINK uses main() but SDL needs main to take args, dnl therefore main is undefined with #undef. dnl Framework can be in an custom location. AC_DEFUN([AC_CHECK_SDLFRAMEWORK], [ AS_VAR_PUSHDEF([ac_Framework], [ac_cv_framework_$1]) AC_CACHE_CHECK([whether compiler supports framework $1], ac_Framework, [ saved_LIBS="$LIBS" LIBS="$LIBS -framework $1" if [[ "x$SDL_FRAMEWORK" != "x/Library/Frameworks" ]]; then if [[ "x$SDL_FRAMEWORK" != "x/System/Library/Frameworks" ]]; then LIBS="$saved_LIBS -F$SDL_FRAMEWORK -framework $1" fi fi saved_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I$SDL_FRAMEWORK/SDL.framework/Headers" AC_TRY_LINK( [$2 #undef main], [], [AS_VAR_SET(ac_Framework, yes)], [AS_VAR_SET(ac_Framework, no); LIBS="$saved_LIBS"; CPPFLAGS="$saved_CPPFLAGS"] ) ]) AS_IF([test AS_VAR_GET(ac_Framework) = yes], [AC_DEFINE(AS_TR_CPP(HAVE_FRAMEWORK_$1), 1, [Define if framework $1 is available.])] ) AS_VAR_POPDEF([ac_Framework]) ]) dnl Do we need SDL? WANT_SDL=no if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then WANT_SDL=yes WANT_XF86_DGA=no WANT_XF86_VIDMODE=no WANT_FBDEV_DGA=no SDL_SUPPORT="$SDL_SUPPORT video" fi if [[ "x$WANT_SDL_AUDIO" = "xyes" ]]; then WANT_SDL=yes SDL_SUPPORT="$SDL_SUPPORT audio" fi if [[ "x$WANT_SDL" = "xyes" ]]; then if [[ "x$WANT_SDL_FRAMEWORK" = "xyes" ]]; then AC_CHECK_SDLFRAMEWORK(SDL, [#include ]) else ac_cv_framework_SDL=no fi if [[ "x$ac_cv_framework_SDL" = "xno" ]]; then AC_PATH_PROG(sdl_config, "sdl-config") if [[ -n "$sdl_config" ]]; then case $target_os in # Special treatment for Cygwin so that we can still use the POSIX layer *cygwin*) sdl_cflags="-I`$sdl_config --prefix`/include/SDL" sdl_libs="-L`$sdl_config --exec-prefix`/lib -lSDL" ;; *) sdl_cflags=`$sdl_config --cflags` if [[ "x$WANT_SDL_STATIC" = "xyes" ]]; then sdl_libs=`$sdl_config --static-libs` else sdl_libs=`$sdl_config --libs` fi ;; esac CFLAGS="$CFLAGS $sdl_cflags" CXXFLAGS="$CXXFLAGS $sdl_cflags" LIBS="$LIBS $sdl_libs" else WANT_SDL=no fi fi SDL_SUPPORT=`echo "$SDL_SUPPORT" | sed -e "s/^ //"` else SDL_SUPPORT="none" fi dnl We need X11, if not using SDL. if [[ "x$WANT_SDL" = "xno" ]]; then AC_PATH_XTRA if [[ "x$no_x" = "xyes" ]]; then AC_MSG_ERROR([You need X11 to run Basilisk II.]) fi CFLAGS="$CFLAGS $X_CFLAGS" CXXFLAGS="$CXXFLAGS $X_CFLAGS" LIBS="$LIBS $X_PRE_LIBS $X_LIBS -lX11 -lXext $X_EXTRA_LIBS" fi dnl BINCUE AS_IF([test "x$with_bincue" = "xyes" ], [have_bincue=yes], [have_bincue=no]) AS_IF([test "x$have_bincue" = "xyes" ], [ if [[ "x$WANT_SDL_AUDIO" = "xyes" ]]; then DEFINES="$DEFINES -DBINCUE" else AC_MSG_ERROR([You need SDL Audio to use BINCUE support.]) fi ]) dnl LIBVHD AS_IF([test "x$with_libvhd" = "xyes" ], [have_libvhd=yes], [have_libvhd=no]) AS_IF([test "x$have_libvhd" = "xyes" ], [ CPPFLAGS="$CPPFLAGS -DHAVE_LIBVHD" LIBS="$LIBS -lvhd" case $target_os in linux*) LIBS="$LIBS -luuid" esac AC_CHECK_LIB(vhd, vhd_open) AC_CHECK_LIB(vhd, vhd_io_read) AC_CHECK_LIB(vhd, vhd_io_write) AC_CHECK_LIB(vhd, vhd_close) ]) dnl We want pthreads. Try libpthread first, then libc_r (FreeBSD), then PTL. HAVE_PTHREADS=yes AC_CHECK_LIB(pthread, pthread_create, , [ AC_CHECK_LIB(c_r, pthread_create, , [ AC_CHECK_LIB(PTL, pthread_create, , [ HAVE_PTHREADS=no ]) ]) ]) if [[ "x$HAVE_PTHREADS" = "xyes" ]]; then AC_DEFINE(HAVE_PTHREADS, 1, [Define if pthreads are available.]) fi AC_CHECK_FUNCS(pthread_cond_init) AC_CHECK_FUNCS(pthread_cancel pthread_testcancel) AC_CHECK_FUNCS(pthread_mutexattr_setprotocol) AC_CHECK_FUNCS(pthread_mutexattr_settype) AC_CHECK_FUNCS(pthread_mutexattr_setpshared) dnl If POSIX.4 semaphores are not available, we emulate them with pthread mutexes. SEMSRC= AC_CHECK_FUNCS(sem_init, , [ if test "x$HAVE_PTHREADS" = "xyes"; then SEMSRC=posix_sem.cpp fi ]) dnl We use DGA (XFree86 or fbdev) if possible. if [[ "x$WANT_XF86_DGA" = "xyes" ]]; then AC_CHECK_LIB(Xxf86dga, XF86DGAQueryExtension, [ AC_DEFINE(ENABLE_XF86_DGA, 1, [Define if using XFree86 DGA extension.]) LIBS="$LIBS -lXxf86dga" if [[ "x$WANT_FBDEV_DGA" = "xyes" ]]; then AC_MSG_WARN([Cannot have both --enable-xf86-dga and --enable-fbdev-dga, ignoring --enable-fbdev-dga.]) WANT_FBDEV_DGA=no fi ], [ AC_MSG_WARN([Could not find XFree86 DGA extension, ignoring --enable-xf86-dga.]) WANT_XF86_DGA=no ]) fi if [[ "x$WANT_FBDEV_DGA" = "xyes" ]]; then AC_DEFINE(ENABLE_FBDEV_DGA, 1, [Define if using DGA with framebuffer device.]) fi dnl We use XFree86 VidMode if possible. if [[ "x$WANT_XF86_VIDMODE" = "xyes" ]]; then AC_CHECK_LIB(Xxf86vm, XF86VidModeQueryExtension, [ AC_DEFINE(ENABLE_XF86_VIDMODE, 1, [Define if using XFree86 DGA extension.]) LIBS="$LIBS -lXxf86vm" ], [ AC_MSG_WARN([Could not find XFree86 VidMode extension, ignoring --enable-xf86-vidmode.]) WANT_XF86_VIDMODE=no ]) fi dnl We use GTK+ if possible. UISRCS=../dummy/prefs_editor_dummy.cpp case "x$WANT_GTK" in xgtk2*) AM_PATH_GTK_2_0(1.3.15, [ GUI_CFLAGS="$GTK_CFLAGS" GUI_LIBS="$GTK_LIBS" WANT_GTK=gtk2 ], [ case "x${WANT_GTK}x" in *gtkx) AC_MSG_WARN([Could not find GTK+ 2.0, trying with GTK+ 1.2.]) WANT_GTK=gtk ;; *) AC_MSG_WARN([Could not find GTK+, disabling user interface.]) WANT_GTK=no ;; esac ]) ;; esac if [[ "x$WANT_GTK" = "xgtk" ]]; then AM_PATH_GTK(1.2.0, [ GUI_CFLAGS="$GTK_CFLAGS" GUI_LIBS="$GTK_LIBS" dnl somehow, would redefine gettext() to nothing if dnl ENABLE_NLS is not set, thusly conflicting with C++ which dnl includes AM_GNU_GETTEXT B2_PATH_GNOMEUI([ AC_DEFINE(HAVE_GNOMEUI, 1, [Define if libgnomeui is available.]) GUI_CFLAGS="$GUI_CFLAGS $GNOMEUI_CFLAGS" GUI_LIBS="$GUI_LIBS $GNOMEUI_LIBS" ], []) ], [ AC_MSG_WARN([Could not find GTK+, disabling user interface.]) WANT_GTK=no ]) fi if [[ "x$WANT_GTK" != "xno" -a "x$WANT_STANDALONE_GUI" = "xno" ]]; then AC_DEFINE(ENABLE_GTK, 1, [Define if using GTK.]) UISRCS=prefs_editor_gtk.cpp fi AC_SUBST(GUI_CFLAGS) AC_SUBST(GUI_LIBS) dnl Build external GUI if requested. if [[ "$WANT_STANDALONE_GUI" != "yes" ]]; then WANT_STANDALONE_GUI=no fi if [[ "$WANT_GTK" = "no" ]]; then WANT_STANDALONE_GUI=no fi AC_SUBST(STANDALONE_GUI, [$WANT_STANDALONE_GUI]) dnl We use ESD if possible. if [[ "x$WANT_ESD" = "xyes" ]]; then AM_PATH_ESD(0.2.8, [ AC_DEFINE(ENABLE_ESD, 1, [Define is using ESD.]) CFLAGS="$CFLAGS $ESD_CFLAGS" CXXFLAGS="$CXXFLAGS $ESD_CFLAGS" LIBS="$LIBS $ESD_LIBS" ], [ AC_MSG_WARN([Could not find ESD, disabling ESD support.]) WANT_ESD=no ]) fi dnl We use 64-bit file size support if possible. AC_SYS_LARGEFILE dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(stdlib.h stdint.h) AC_CHECK_HEADERS(unistd.h fcntl.h sys/types.h sys/time.h sys/mman.h mach/mach.h) AC_CHECK_HEADERS(readline.h history.h readline/readline.h readline/history.h) AC_CHECK_HEADERS(sys/socket.h sys/ioctl.h sys/filio.h sys/bitypes.h sys/wait.h) AC_CHECK_HEADERS(sys/poll.h sys/select.h) AC_CHECK_HEADERS(arpa/inet.h) AC_CHECK_HEADERS(linux/if.h linux/if_tun.h net/if.h net/if_tun.h, [], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif ]) AC_CHECK_HEADERS(AvailabilityMacros.h) AC_CHECK_HEADERS(IOKit/storage/IOBlockStorageDevice.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_BIGENDIAN AC_C_CONST AC_C_INLINE AC_CHECK_SIZEOF(short, 2) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(long, 4) AC_CHECK_SIZEOF(long long, 8) AC_CHECK_SIZEOF(float, 4) AC_CHECK_SIZEOF(double, 8) AC_CHECK_SIZEOF(long double, 12) AC_CHECK_SIZEOF(void *, 4) AC_TYPE_OFF_T AC_CHECK_TYPES(loff_t) AC_CHECK_TYPES(caddr_t) AC_TYPE_SIZE_T AC_TYPE_SIGNAL AC_HEADER_TIME AC_STRUCT_TM dnl Check whether sys/socket.h defines type socklen_t. dnl (extracted from ac-archive/Miscellaneous) AC_CACHE_CHECK([for socklen_t], ac_cv_type_socklen_t, [ AC_TRY_COMPILE([ #include #include ], [socklen_t len = 42; return 0;], ac_cv_type_socklen_t=yes, ac_cv_type_socklen_t=no, dnl When cross-compiling, do not assume anything. ac_cv_type_socklen_t="guessing no" ) ]) if [[ "x$ac_cv_type_socklen_t" != "xyes" ]]; then AC_DEFINE(socklen_t, int, [Define to 'int' if doesn't define.]) fi dnl Checks for library functions. AC_CHECK_FUNCS(strdup strerror cfmakeraw) AC_CHECK_FUNCS(clock_gettime timer_create) AC_CHECK_FUNCS(sigaction signal) AC_CHECK_FUNCS(mmap mprotect munmap) AC_CHECK_FUNCS(vm_allocate vm_deallocate vm_protect) AC_CHECK_FUNCS(poll inet_aton) dnl Darwin seems to define mach_task_self() instead of task_self(). AC_CHECK_FUNCS(mach_task_self task_self) dnl Check for headers and functions related to pty support (sshpty.c) dnl From openssh-3.2.2p1 configure.ac AC_CHECK_HEADERS(strings.h login.h sys/bsdtty.h sys/stat.h util.h pty.h) AC_CHECK_FUNCS(_getpty vhangup strlcpy) case "$host" in *-*-hpux10.26) disable_ptmx_check=yes ;; *-*-linux*) no_dev_ptmx=1 ;; mips-sony-bsd|mips-sony-newsos4) AC_DEFINE(HAVE_NEWS4, 1, [Define if you are on NEWS-OS (additions from openssh-3.2.2p1, for sshpty.c).]) ;; *-*-sco3.2v4*) no_dev_ptmx=1 ;; *-*-sco3.2v5*) no_dev_ptmx=1 ;; *-*-cygwin*) no_dev_ptmx=1 ;; *-*-darwin*) no_dev_ptmx=1 ;; esac if test -z "$no_dev_ptmx" ; then if test "x$disable_ptmx_check" != "xyes" ; then AC_CHECK_FILE([/dev/ptmx], [ AC_DEFINE_UNQUOTED(HAVE_DEV_PTMX, 1, [Define if you have /dev/ptmx.]) have_dev_ptmx=1 ] ) fi fi AC_CHECK_FILE([/dev/ptc], [ AC_DEFINE_UNQUOTED(HAVE_DEV_PTS_AND_PTC, 1, [Define if you have /dev/ptc.]) have_dev_ptc=1 ] ) dnl (end of code from openssh-3.2.2p1 configure.ac) dnl Check for systems where POSIX-style non-blocking I/O (O_NONBLOCK) dnl doesn't work or is unimplemented. On these systems (mostly older dnl ones), use the old BSD-style FIONBIO approach instead. [tcl.m4] AC_CACHE_CHECK([FIONBIO vs. O_NONBLOCK for non-blocking I/O], ac_cv_nonblocking_io, [ case "$host" in *-*-osf*) ac_cv_nonblocking_io=FIONBIO ;; *-*-sunos4*) ac_cv_nonblocking_io=FIONBIO ;; *-*-ultrix*) ac_cv_nonblocking_io=FIONBIO ;; *) ac_cv_nonblocking_io=O_NONBLOCK ;; esac ]) if [[ "$ac_cv_nonblocking_io" = "FIONBIO" ]]; then AC_DEFINE(USE_FIONBIO, 1, [Define if BSD-style non-blocking I/O is to be used]) fi dnl Check whether compiler supports byte bit-fields AC_CACHE_CHECK([whether compiler supports byte bit-fields], ac_cv_have_byte_bitfields, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ struct A { unsigned char b1:4; unsigned char b2:4; unsigned char c; unsigned short s; unsigned char a[4]; }; int main(void) { A a; return ! (sizeof(A) == 8 && &a.c == ((unsigned char *)&a + 1)); }], [ac_cv_have_byte_bitfields=yes], [ac_cv_have_byte_bitfields=no], dnl When cross-compiling, assume only GCC supports this [if [[ "$GCC" = "yes" ]]; then ac_cv_have_byte_bitfields="guessing yes" else ac_cv_have_byte_bitfields="guessing no" fi] ) AC_LANG_RESTORE ]) dnl AC_CHECK_FRAMEWORK($1=NAME, $2=INCLUDES) AC_DEFUN([AC_CHECK_FRAMEWORK], [ AS_VAR_PUSHDEF([ac_Framework], [ac_cv_framework_$1])dnl AC_CACHE_CHECK([whether compiler supports framework $1], ac_Framework, [ saved_LIBS="$LIBS" LIBS="$LIBS -framework $1" AC_TRY_LINK( [$2], [], [AS_VAR_SET(ac_Framework, yes)], [AS_VAR_SET(ac_Framework, no); LIBS="$saved_LIBS"] ) ]) AS_IF([test AS_VAR_GET(ac_Framework) = yes], [AC_DEFINE(AS_TR_CPP(HAVE_FRAMEWORK_$1), 1, [Define if framework $1 is available.])] ) AS_VAR_POPDEF([ac_Framework])dnl ]) dnl Check for some MacOS X frameworks AC_CHECK_FRAMEWORK(AppKit, []) AC_CHECK_FRAMEWORK(Carbon, [#include ]) AC_CHECK_FRAMEWORK(IOKit, [#include ]) AC_CHECK_FRAMEWORK(CoreFoundation, [#include ]) dnl Select system-dependant source files. SERIALSRC=serial_unix.cpp ETHERSRC=../dummy/ether_dummy.cpp SCSISRC=../dummy/scsi_dummy.cpp AUDIOSRC=../dummy/audio_dummy.cpp EXTFSSRC=extfs_unix.cpp EXTRASYSSRCS= CAN_NATIVE_M68K=no case "$target_os" in linux*) ETHERSRC=ether_unix.cpp AUDIOSRC=audio_oss_esd.cpp SCSISRC=Linux/scsi_linux.cpp ;; freebsd*) ETHERSRC=ether_unix.cpp AUDIOSRC=audio_oss_esd.cpp DEFINES="$DEFINES -DBSD_COMP" CXXFLAGS="$CXXFLAGS -fpermissive" dnl Check for the CAM library AC_CHECK_LIB(cam, cam_open_btl, HAVE_LIBCAM=yes, HAVE_LIBCAM=no) if [[ "x$HAVE_LIBCAM" = "xno" ]]; then AC_MSG_WARN([Cannot find libcam for SCSI management, disabling SCSI support.]) else dnl Check for the sys kernel includes AC_CHECK_HEADER(camlib.h) if [[ "x$ac_cv_header_camlib_h" = "xno" ]]; then dnl In this case I should fix this thing including a "patch" dnl to access directly to the functions in the kernel :) --Orlando AC_MSG_WARN([Cannot find includes for CAM library, disabling SCSI support.]) else SCSISRC=FreeBSD/scsi_freebsd.cpp LIBS="$LIBS -lcam" DEFINES="$DEFINES -DCAM" fi fi ;; netbsd*) CAN_NATIVE_M68K=yes ETHERSRC=ether_unix.cpp ;; solaris*) AUDIOSRC=Solaris/audio_solaris.cpp DEFINES="$DEFINES -DBSD_COMP -D_POSIX_PTHREAD_SEMANTICS" ;; irix*) AUDIOSRC=Irix/audio_irix.cpp EXTRASYSSRCS=Irix/unaligned.c LIBS="$LIBS -laudio" WANT_ESD=no dnl Check if our compiler supports -IPA (MIPSPro) HAVE_IPA=no ocflags="$CFLAGS" CFLAGS=`echo "$CFLAGS -IPA" | sed -e "s/-g//g"` AC_MSG_CHECKING(if "-IPA" works) dnl Do a test compile of an empty function AC_TRY_COMPILE([#if defined __GNUC__ # error GCC does not support IPA yet #endif],, [AC_MSG_RESULT(yes); HAVE_IPA=yes], AC_MSG_RESULT(no)) CFLAGS="$ocflags" ;; darwin*) ETHERSRC=ether_unix.cpp if [[ "x$ac_cv_framework_IOKit" = "xyes" -a "x$ac_cv_framework_CoreFoundation" = "xyes" ]]; then EXTRASYSSRCS="../MacOSX/sys_darwin.cpp" fi if [[ "x$ac_cv_framework_Carbon" = "xyes" ]]; then EXTFSSRC=../MacOSX/extfs_macosx.cpp fi ;; cygwin*) SERIALSRC="../dummy/serial_dummy.cpp" EXTRASYSSRCS="../Windows/BasiliskII.rc" ;; esac dnl Is the slirp library supported? case "$ac_cv_have_byte_bitfields" in yes|"guessing yes") CAN_SLIRP=yes ETHERSRC=ether_unix.cpp ;; esac if [[ -n "$CAN_SLIRP" ]]; then AC_DEFINE(HAVE_SLIRP, 1, [Define if slirp library is supported]) SLIRP_SRCS="\ ../slirp/bootp.c ../slirp/ip_output.c ../slirp/tcp_input.c \ ../slirp/cksum.c ../slirp/mbuf.c ../slirp/tcp_output.c \ ../slirp/debug.c ../slirp/misc.c ../slirp/tcp_subr.c \ ../slirp/if.c ../slirp/sbuf.c ../slirp/tcp_timer.c \ ../slirp/ip_icmp.c ../slirp/slirp.c ../slirp/tftp.c \ ../slirp/ip_input.c ../slirp/socket.c ../slirp/udp.c" fi AC_SUBST(SLIRP_SRCS) dnl SDL overrides if [[ "x$WANT_SDL" = "xyes" ]]; then AC_DEFINE(USE_SDL, 1, [Define to enble SDL support]) if [[ "x$WANT_SDL_FRAMEWORK" = "xyes" ]]; then EXTRASYSSRCS="$EXTRASYSSRCS ../SDL/SDLMain.m" fi fi if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then AC_DEFINE(USE_SDL_VIDEO, 1, [Define to enable SDL video graphics support]) VIDEOSRCS="../SDL/video_sdl.cpp" KEYCODES="../SDL/keycodes" if [[ "x$ac_cv_framework_Carbon" = "xyes" ]]; then EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp" EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/utils_macosx.mm" CPPFLAGS="$CPPFLAGS -I../MacOSX" else case "$target_os" in cygwin*) EXTRASYSSRCS="$EXTRASYSSRCS ../Windows/clip_windows.cpp" ;; *) EXTRASYSSRCS="$EXTRASYSSRCS ../dummy/clip_dummy.cpp" ;; esac fi else VIDEOSRCS="video_x.cpp" KEYCODES="keycodes" EXTRASYSSRCS="$EXTRASYSSRCS clip_unix.cpp" fi if [[ "x$WANT_SDL_AUDIO" = "xyes" ]]; then AC_DEFINE(USE_SDL_AUDIO, 1, [Define to enable SDL audio support]) AUDIOSRC="../SDL/audio_sdl.cpp" fi dnl BINCUE overrides if [[ "x$have_bincue" = "xyes" ]]; then EXTRASYSSRCS="$EXTRASYSSRCS bincue_unix.cpp" fi dnl libvhd overrides if [[ "x$have_libvhd" = "xyes" ]]; then EXTRASYSSRCS="$EXTRASYSSRCS vhd_unix.cpp" fi dnl Use 68k CPU natively? WANT_NATIVE_M68K=no if [[ "x$HAVE_M68K" = "xyes" -a "x$CAN_NATIVE_M68K" = "xyes" ]]; then AC_DEFINE(ENABLE_NATIVE_M68K, 1, [Define if using native 68k mode.]) WANT_NATIVE_M68K=yes fi if [[ "x$HAVE_PTHREADS" = "xno" ]]; then dnl Serial, ethernet and audio support needs pthreads AC_MSG_WARN([You don't have pthreads, disabling serial, ethernet and audio support.]) SERIALSRC=../dummy/serial_dummy.cpp ETHERSRC=../dummy/ether_dummy.cpp AUDIOSRC=../dummy/audio_dummy.cpp fi SYSSRCS="$VIDEOSRCS $EXTFSSRC $SERIALSRC $ETHERSRC $SCSISRC $AUDIOSRC $SEMSRC $UISRCS $MONSRCS $EXTRASYSSRCS" dnl Define a macro that translates a yesno-variable into a C macro definition dnl to be put into the config.h file dnl $1 -- the macro to define dnl $2 -- the value to translate dnl $3 -- template name AC_DEFUN([AC_TRANSLATE_DEFINE], [ if [[ "x$2" = "xyes" -o "x$2" = "xguessing yes" ]]; then AC_DEFINE($1, 1, $3) fi ]) dnl Check that the host supports TUN/TAP devices AC_CACHE_CHECK([whether TUN/TAP is supported], ac_cv_tun_tap_support, [ AC_TRY_COMPILE([ #if defined(HAVE_LINUX_IF_H) && defined(HAVE_LINUX_IF_TUN_H) #include #include #endif #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_IF_TUN_H) #include #include #endif ], [ struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ], ac_cv_tun_tap_support=yes, ac_cv_tun_tap_support=no ) ]) AC_TRANSLATE_DEFINE(ENABLE_TUNTAP, "$ac_cv_tun_tap_support", [Define if your system supports TUN/TAP devices.]) dnl Various checks if the system supports vm_allocate() and the like functions. have_mach_vm=no if [[ "x$ac_cv_func_vm_allocate" = "xyes" -a "x$ac_cv_func_vm_deallocate" = "xyes" -a \ "x$ac_cv_func_vm_protect" = "xyes" ]]; then have_mach_vm=yes fi AC_TRANSLATE_DEFINE(HAVE_MACH_VM, "$have_mach_vm", [Define if your system has a working vm_allocate()-based memory allocator.]) dnl Check that vm_allocate(), vm_protect() work if [[ "x$have_mach_vm" = "xyes" ]]; then AC_CACHE_CHECK([whether vm_protect works], ac_cv_vm_protect_works, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS ac_cv_vm_protect_works=yes dnl First the tests that should segfault for test_def in NONE_READ NONE_WRITE READ_WRITE; do AC_TRY_RUN([ #define CONFIGURE_TEST_VM_MAP #define TEST_VM_PROT_$test_def #include "vm_alloc.cpp" ], ac_cv_vm_protect_works=no, rm -f core, dnl When cross-compiling, do not assume anything ac_cv_vm_protect_works="guessing no" ) done AC_TRY_RUN([ #define CONFIGURE_TEST_VM_MAP #define TEST_VM_PROT_RDWR_WRITE #include "vm_alloc.cpp" ], , ac_cv_vm_protect_works=no, dnl When cross-compiling, do not assume anything ac_cv_vm_protect_works="guessing no" ) AC_LANG_RESTORE ] ) dnl Remove support for vm_allocate() if vm_protect() does not work if [[ "x$have_mach_vm" = "xyes" ]]; then case $ac_cv_vm_protect_works in *yes) have_mach_vm=yes;; *no) have_mach_vm=no;; esac fi AC_TRANSLATE_DEFINE(HAVE_MACH_VM, "$have_mach_vm", [Define if your system has a working vm_allocate()-based memory allocator.]) fi dnl HAVE_MACH_VM dnl Various checks if the system supports mmap() and the like functions. dnl ... and Mach memory allocators are not supported have_mmap_vm=no if [[ "x$ac_cv_func_mmap" = "xyes" -a "x$ac_cv_func_munmap" = "xyes" -a \ "x$ac_cv_func_mprotect" = "xyes" ]]; then if [[ "x$have_mach_vm" = "xno" ]]; then have_mmap_vm=yes fi fi AC_TRANSLATE_DEFINE(HAVE_MMAP_VM, "$have_mmap_vm", [Define if your system has a working mmap()-based memory allocator.]) dnl Check that mmap() and associated functions work. if [[ "x$have_mmap_vm" = "xyes" ]]; then dnl Check if we have a working anonymous mmap() AC_CACHE_CHECK([whether mmap supports MAP_ANON], ac_cv_mmap_anon, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_MMAP_ANON #define CONFIGURE_TEST_VM_MAP #define TEST_VM_MMAP_ANON #include "vm_alloc.cpp" ], ac_cv_mmap_anon=yes, ac_cv_mmap_anon=no, dnl When cross-compiling, do not assume anything. ac_cv_mmap_anon="guessing no" ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_MMAP_ANON, "$ac_cv_mmap_anon", [Define if defines MAP_ANON and mmap()'ing with MAP_ANON works.]) AC_CACHE_CHECK([whether mmap supports MAP_ANONYMOUS], ac_cv_mmap_anonymous, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_MMAP_ANONYMOUS #define CONFIGURE_TEST_VM_MAP #define TEST_VM_MMAP_ANON #include "vm_alloc.cpp" ], ac_cv_mmap_anonymous=yes, ac_cv_mmap_anonymous=no, dnl When cross-compiling, do not assume anything. ac_cv_mmap_anonymous="guessing no" ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_MMAP_ANONYMOUS, "$ac_cv_mmap_anonymous", [Define if defines MAP_ANONYMOUS and mmap()'ing with MAP_ANONYMOUS works.]) AC_CACHE_CHECK([whether mprotect works], ac_cv_mprotect_works, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS ac_cv_mprotect_works=yes dnl First the tests that should segfault for test_def in NONE_READ NONE_WRITE READ_WRITE; do AC_TRY_RUN([ #define CONFIGURE_TEST_VM_MAP #define TEST_VM_PROT_$test_def #include "vm_alloc.cpp" ], ac_cv_mprotect_works=no, rm -f core, dnl When cross-compiling, do not assume anything ac_cv_mprotect_works="guessing no" ) done AC_TRY_RUN([ #define CONFIGURE_TEST_VM_MAP #define TEST_VM_PROT_RDWR_WRITE #include "vm_alloc.cpp" ], , ac_cv_mprotect_works=no, dnl When cross-compiling, do not assume anything ac_cv_mprotect_works="guessing no" ) AC_LANG_RESTORE ] ) dnl Remove support for mmap() if mprotect() does not work if [[ "x$have_mmap_vm" = "xyes" ]]; then case $ac_cv_mprotect_works in *yes) have_mmap_vm=yes;; *no) have_mmap_vm=no;; esac fi AC_TRANSLATE_DEFINE(HAVE_MMAP_VM, $have_mmap_vm, [Define if your system has a working mmap()-based memory allocator.]) fi dnl HAVE_MMAP_VM dnl Check if we can modify the __PAGEZERO segment for use as Low Memory AC_CACHE_CHECK([whether __PAGEZERO can be Low Memory area 0x0000-0x2000], ac_cv_pagezero_hack, [ ac_cv_pagezero_hack=no if AC_TRY_COMMAND([Darwin/testlmem.sh 0x2000]); then ac_cv_pagezero_hack=yes dnl might as well skip the test for mmap-able low memory ac_cv_can_map_lm=no fi ]) AC_TRANSLATE_DEFINE(PAGEZERO_HACK, "$ac_cv_pagezero_hack", [Define if the __PAGEZERO Mach-O Low Memory Globals hack works on this system.]) dnl Check if we can mmap 0x2000 bytes from 0x0000 AC_CACHE_CHECK([whether we can map Low Memory area 0x0000-0x2000], ac_cv_can_map_lm, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #include "vm_alloc.cpp" int main(void) { /* returns 0 if we could map the lowmem globals */ volatile char * lm = 0; if (vm_init() < 0) exit(1); if (vm_acquire_fixed(0, 0x2000) < 0) exit(1); lm[0] = 'z'; if (vm_release((char *)lm, 0x2000) < 0) exit(1); vm_exit(); exit(0); } ], ac_cv_can_map_lm=yes, ac_cv_can_map_lm=no, dnl When cross-compiling, do not assume anything. ac_cv_can_map_lm="guessing no" ) AC_LANG_RESTORE ] ) dnl Check signal handlers need to be reinstalled AC_CACHE_CHECK([whether signal handlers need to be reinstalled], ac_cv_signal_need_reinstall, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #include #ifdef HAVE_UNISTD_H #include #endif #include static int handled_signal = 0; RETSIGTYPE sigusr1_handler(int) { handled_signal++; } int main(void) { /* returns 0 if signals need not to be reinstalled */ signal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1); exit(handled_signal == 2); } ], ac_cv_signal_need_reinstall=yes, ac_cv_signal_need_reinstall=no, dnl When cross-compiling, do not assume anything. ac_cv_signal_need_reinstall="guessing yes" ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(SIGNAL_NEED_REINSTALL, "$ac_cv_signal_need_reinstall", [Define if your system requires signals to be reinstalled.]) dnl Check if sigaction handlers need to be reinstalled AC_CACHE_CHECK([whether sigaction handlers need to be reinstalled], ac_cv_sigaction_need_reinstall, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #include #ifdef HAVE_UNISTD_H #include #endif #include static int handled_signal = 0; RETSIGTYPE sigusr1_handler(int) { handled_signal++; } typedef RETSIGTYPE (*signal_handler)(int); static signal_handler mysignal(int sig, signal_handler handler) { struct sigaction old_sa; struct sigaction new_sa; new_sa.sa_handler = handler; return ((sigaction(sig,&new_sa,&old_sa) < 0) ? SIG_IGN : old_sa.sa_handler); } int main(void) { /* returns 0 if signals need not to be reinstalled */ mysignal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1); exit(handled_signal == 2); } ], ac_cv_sigaction_need_reinstall=yes, ac_cv_sigaction_need_reinstall=no, dnl When cross-compiling, do not assume anything. ac_cv_sigaction_need_reinstall="guessing yes" ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(SIGACTION_NEED_REINSTALL, "$ac_cv_sigaction_need_reinstall", [Define if your system requires sigactions to be reinstalled.]) dnl Check if Mach exceptions supported. AC_CACHE_CHECK([whether your system supports Mach exceptions], ac_cv_have_mach_exceptions, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_UNISTD_H 1 #define HAVE_MACH_VM 1 #define HAVE_MACH_TASK_SELF 1 #define HAVE_MACH_EXCEPTIONS 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "vm_alloc.cpp" #include "sigsegv.cpp" ], [ sigsegv_recovery=mach ac_cv_have_mach_exceptions=yes ], ac_cv_have_mach_exceptions=no, dnl When cross-compiling, do not assume anything. ac_cv_have_mach_exceptions=no ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_MACH_EXCEPTIONS, "$ac_cv_have_mach_exceptions", [Define if your system supports Mach exceptions.]) dnl Check if Windows exceptions are supported. AC_CACHE_CHECK([whether your system supports Windows exceptions], ac_cv_have_win32_exceptions, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_WIN32_EXCEPTIONS 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "vm_alloc.cpp" #include "sigsegv.cpp" ], [ sigsegv_recovery=win32 ac_cv_have_win32_exceptions=yes ], ac_cv_have_win32_exceptions=no, dnl When cross-compiling, do not assume anything. ac_cv_have_win32_exceptions=no ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_WIN32_EXCEPTIONS, "$ac_cv_have_win32_exceptions", [Define if your system supports Windows exceptions.]) dnl Otherwise, check if extended signals are supported. if [[ -z "$sigsegv_recovery" ]]; then AC_CACHE_CHECK([whether your system supports extended signal handlers], ac_cv_have_extended_signals, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_SIGINFO_T 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "vm_alloc.cpp" #include "sigsegv.cpp" ], [ sigsegv_recovery=siginfo ac_cv_have_extended_signals=yes ], ac_cv_have_extended_signals=no, dnl When cross-compiling, do not assume anything. ac_cv_have_extended_signals=no ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_SIGINFO_T, "$ac_cv_have_extended_signals", [Define if your system support extended signals.]) fi dnl Otherwise, check for subterfuges. if [[ -z "$sigsegv_recovery" ]]; then AC_CACHE_CHECK([whether we then have a subterfuge for your system], ac_cv_have_sigcontext_hack, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_SIGCONTEXT_SUBTERFUGE 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "vm_alloc.cpp" #include "sigsegv.cpp" ], [ sigsegv_recovery=sigcontext ac_cv_have_sigcontext_hack=yes ], ac_cv_have_sigcontext_hack=no, dnl When cross-compiling, do not assume anything. ac_cv_have_sigcontext_hack=no ) AC_LANG_RESTORE ]) AC_TRANSLATE_DEFINE(HAVE_SIGCONTEXT_SUBTERFUGE, "$ac_cv_have_sigcontext_hack", [Define if we know a hack to replace siginfo_t->si_addr member.]) fi dnl Check if we can ignore the fault (instruction skipping in SIGSEGV handler) AC_CACHE_CHECK([whether we can skip instruction in SIGSEGV handler], ac_cv_have_skip_instruction, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_SIGSEGV_SKIP_INSTRUCTION 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "vm_alloc.cpp" #include "sigsegv.cpp" ], ac_cv_have_skip_instruction=yes, ac_cv_have_skip_instruction=no, dnl When cross-compiling, do not assume anything. ac_cv_have_skip_instruction=no ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_SIGSEGV_SKIP_INSTRUCTION, "$ac_cv_have_skip_instruction", [Define if we can ignore the fault (instruction skipping in SIGSEGV handler).]) dnl Can we do Video on SEGV Signals ? CAN_VOSF=no if [[ -n "$sigsegv_recovery" ]]; then CAN_VOSF=yes fi dnl A dummy program that returns always true AC_PATH_PROG([BLESS], "true") dnl Check for linker script support case $target_os:$target_cpu in linux*:i?86) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-i386.ld";; linux*:x86_64) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-x86_64.ld";; linux*:powerpc) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-ppc.ld";; netbsd*:i?86) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-i386.ld";; freebsd*:i?86) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/freebsd-i386.ld";; darwin*:*) LINKER_SCRIPT_FLAGS="-Wl,-seg1addr,0x78048000";; esac if [[ -n "$LINKER_SCRIPT_FLAGS" ]]; then AC_CACHE_CHECK([whether linker script is usable], ac_cv_linker_script_works, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $LINKER_SCRIPT_FLAGS" AC_TRY_RUN( [int main() {if ((char *)&main < (char *)0x70000000) return 1;}], [ac_cv_linker_script_works=yes], [ac_cv_linker_script_works=no], dnl When cross-compiling, assume it works [ac_cv_linker_script_works="guessing yes"] ) AC_LANG_RESTORE if [[ "$ac_cv_linker_script_works" = "no" ]]; then LDFLAGS="$saved_LDFLAGS" LINKER_SCRIPT_FLAGS="" fi ]) fi AC_TRANSLATE_DEFINE(HAVE_LINKER_SCRIPT, "$ac_cv_linker_script_works", [Define if there is a linker script to relocate the executable above 0x70000000.]) dnl Determine the addressing mode to use if [[ "x$WANT_NATIVE_M68K" = "xyes" ]]; then ADDRESSING_MODE="real" else ADDRESSING_MODE="" AC_MSG_CHECKING([for the addressing mode to use]) for am in $ADDRESSING_TEST_ORDER; do case $am in real) dnl Requires ability to mmap() Low Memory globals if [[ "x$ac_cv_can_map_lm$ac_cv_pagezero_hack" = "xnono" ]]; then continue fi dnl Requires VOSF screen updates if [[ "x$CAN_VOSF" = "xno" ]]; then continue fi dnl Real addressing will probably work. ADDRESSING_MODE="real" WANT_VOSF=yes dnl we can use VOSF and we need it actually DEFINES="$DEFINES -DREAL_ADDRESSING" if [[ "x$ac_cv_pagezero_hack" = "xyes" ]]; then BLESS=Darwin/lowmem LDFLAGS="$LDFLAGS -pagezero_size 0x2000" fi break ;; direct) dnl Requires VOSF screen updates if [[ "x$CAN_VOSF" = "xyes" ]]; then ADDRESSING_MODE="direct" WANT_VOSF=yes dnl we can use VOSF and we need it actually DEFINES="$DEFINES -DDIRECT_ADDRESSING" break fi ;; banks) dnl Default addressing mode ADDRESSING_MODE="memory banks" break ;; *) AC_MSG_ERROR([Internal configure.in script error for $am addressing mode]) esac done AC_MSG_RESULT($ADDRESSING_MODE) if [[ "x$ADDRESSING_MODE" = "x" ]]; then AC_MSG_WARN([Sorry, no suitable addressing mode in $ADDRESSING_TEST_ORDER]) ADDRESSING_MODE="memory banks" fi fi dnl Banked Memory Addressing mode is not supported by the JIT compiler if [[ "x$WANT_JIT" = "xyes" -a "x$ADDRESSING_MODE" = "xmemory banks" ]]; then AC_MSG_ERROR([Sorry, the JIT Compiler requires Direct Addressing, at least]) fi dnl Enable VOSF screen updates with this feature is requested and feasible if [[ "x$WANT_VOSF" = "xyes" -a "x$CAN_VOSF" = "xyes" ]]; then AC_DEFINE(ENABLE_VOSF, 1, [Define if using video enabled on SEGV signals.]) else WANT_VOSF=no fi dnl Check for GAS. HAVE_GAS=no AC_MSG_CHECKING(for GAS .p2align feature) cat >conftest.S << EOF .text .p2align 5 EOF if $CC conftest.S -c -o conftest.o >/dev/null 2>&1 ; then HAVE_GAS=yes; fi AC_MSG_RESULT($HAVE_GAS) dnl Check for GCC 2.7 or higher. HAVE_GCC27=no AC_MSG_CHECKING(for GCC 2.7 or higher) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if ! (__GNUC__ - 1 > 1 || __GNUC_MINOR__ - 1 > 5) # error gcc < 2.7 #endif ]])], [AC_MSG_RESULT(yes); HAVE_GCC27=yes], [AC_MSG_RESULT(no)]) dnl Check for GCC 3.0 or higher. HAVE_GCC30=no AC_MSG_CHECKING(for GCC 3.0 or higher) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if ! (__GNUC__ >= 3) # error gcc < 3 #endif ]])], [AC_MSG_RESULT(yes); HAVE_GCC30=yes], [AC_MSG_RESULT(no)]) dnl Check for ICC. AC_MSG_CHECKING(for ICC) HAVE_ICC=no if $CXX -V -v 2>&1 | grep -q "Intel(R) C++ Compiler"; then HAVE_ICC=yes fi AC_MSG_RESULT($HAVE_ICC) dnl Set "-fomit-frame-pointer" on i386 GCC 2.7 or higher. dnl Also set "-fno-exceptions" for C++ because exception handling requires dnl the frame pointer. if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_I386" = "xyes" ]]; then CFLAGS="$CFLAGS -fomit-frame-pointer" CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -fno-exceptions" fi dnl (gb) Do not merge constants since it breaks fpu/fpu_x86.cpp. dnl As of 2001/08/02, this affects the following compilers: dnl Official: probably gcc-3.1 (mainline CVS) dnl Mandrake: gcc-2.96 >= 0.59mdk, gcc-3.0.1 >= 0.1mdk dnl Red Hat : gcc-2.96 >= 89, gcc-3.0 >= 1 if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_ICC" = "xno" ]]; then SAVED_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -fno-merge-constants" AC_CACHE_CHECK([whether GCC supports constants merging], ac_cv_gcc_constants_merging, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_COMPILE([],[],[ac_cv_gcc_constants_merging=yes],[ac_cv_gcc_constants_merging=no]) AC_LANG_RESTORE ]) if [[ "x$ac_cv_gcc_constants_merging" != "xyes" ]]; then CXXFLAGS="$SAVED_CXXFLAGS" fi fi dnl Store motion was introduced in 3.3-hammer branch and any gcc >= 3.4 dnl However, there are some corner cases exposed on x86-64 if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_ICC" = "xno" ]]; then SAVED_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -fno-gcse-sm" AC_CACHE_CHECK([whether GCC supports store motion], ac_cv_gcc_store_motion, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_COMPILE([],[],[ac_cv_gcc_store_motion=yes],[ac_cv_gcc_store_motion=no]) AC_LANG_RESTORE ]) if [[ "x$ac_cv_gcc_store_motion" != "xyes" ]]; then CXXFLAGS="$SAVED_CXXFLAGS" fi fi dnl Add -fno-strict-aliasing for slirp sources if [[ "x$HAVE_GCC30" = "xyes" ]]; then SAVED_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-strict-aliasing" AC_CACHE_CHECK([whether the compiler supports -fno-strict-aliasing], ac_cv_gcc_no_strict_aliasing, [ AC_TRY_COMPILE([],[], [ac_cv_gcc_no_strict_aliasing=yes; AC_SUBST(SLIRP_CFLAGS, "-fno-strict-aliasing")], [ac_cv_gcc_no_strict_aliasing=no]) ]) CFLAGS="$SAVED_CFLAGS" fi dnl Add -mdynamic-no-pic for MacOS X (XXX icc10 will support MacOS X) if [[ "x$HAVE_GCC30" = "xyes" -a "x$HAVE_ICC" = "xno" ]]; then SAVED_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -mdynamic-no-pic" AC_CACHE_CHECK([whether the compiler supports -mdynamic-no-pic], ac_cv_gcc_mdynamic_no_pic, [ AC_TRY_COMPILE([],[],[ac_cv_gcc_mdynamic_no_pic=yes],[ac_cv_gcc_mdynamic_no_pic=no]) ]) if [[ "x$ac_cv_gcc_mdynamic_no_pic" = "xyes" ]]; then CXXFLAGS="$CXXFLAGS -mdynamic-no-pic" else CFLAGS="$SAVED_CFLAGS" fi fi dnl Select appropriate CPU source and REGPARAM define. ASM_OPTIMIZATIONS=none CPUSRCS="cpuemu1.cpp cpuemu2.cpp cpuemu3.cpp cpuemu4.cpp cpuemu5.cpp cpuemu6.cpp cpuemu7.cpp cpuemu8.cpp" dnl (gb) JITSRCS will be emptied later if the JIT is not available dnl Other platforms should define their own set of noflags file variants CAN_JIT=no JITSRCS="compemu1.cpp compemu2.cpp compemu3.cpp compemu4.cpp compemu5.cpp compemu6.cpp compemu7.cpp compemu8.cpp" if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_I386" = "xyes" ]]; then dnl i386 CPU DEFINES="$DEFINES -DUNALIGNED_PROFITABLE -DREGPARAM=\"__attribute__((regparm(3)))\"" if [[ "x$HAVE_GAS" = "xyes" ]]; then ASM_OPTIMIZATIONS=i386 DEFINES="$DEFINES -DX86_ASSEMBLY -DOPTIMIZED_FLAGS -DSAHF_SETO_PROFITABLE" JITSRCS="cpuemu1_nf.cpp cpuemu2_nf.cpp cpuemu3_nf.cpp cpuemu4_nf.cpp cpuemu5_nf.cpp cpuemu6_nf.cpp cpuemu7_nf.cpp cpuemu8_nf.cpp $JITSRCS" CAN_JIT=yes fi elif [[ "x$HAVE_GCC30" = "xyes" -a "x$HAVE_X86_64" = "xyes" ]]; then dnl x86-64 CPU DEFINES="$DEFINES -DUNALIGNED_PROFITABLE" if [[ "x$HAVE_GAS" = "xyes" ]]; then ASM_OPTIMIZATIONS="x86-64" DEFINES="$DEFINES -DX86_64_ASSEMBLY -DOPTIMIZED_FLAGS" JITSRCS="cpuemu1_nf.cpp cpuemu2_nf.cpp cpuemu3_nf.cpp cpuemu4_nf.cpp cpuemu5_nf.cpp cpuemu6_nf.cpp cpuemu7_nf.cpp cpuemu8_nf.cpp $JITSRCS" CAN_JIT=yes fi elif [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_SPARC" = "xyes" -a "x$HAVE_GAS" = "xyes" ]]; then dnl SPARC CPU case "$target_os" in solaris*) AC_MSG_CHECKING(SPARC CPU architecture) SPARC_TYPE=`Solaris/which_sparc` AC_MSG_RESULT($SPARC_TYPE) case "$SPARC_TYPE" in SPARC_V8) ASM_OPTIMIZATIONS="SPARC V8 architecture" DEFINES="$DEFINES -DSPARC_V8_ASSEMBLY" dnl -DOPTIMIZED_FLAGS" CFLAGS="$CFLAGS -Wa,-Av8" CXXFLAGS="$CXXFLAGS -Wa,-Av8" ;; SPARC_V9) ASM_OPTIMIZATIONS="SPARC V9 architecture" DEFINES="$DEFINES -DSPARC_V9_ASSEMBLY" dnl -DOPTIMIZED_FLAGS" CFLAGS="$CFLAGS -Wa,-Av9" CXXFLAGS="$CXXFLAGS -Wa,-Av9" ;; esac ;; esac elif [[ "x$WANT_NATIVE_M68K" = "xyes" ]]; then dnl Native m68k, no emulation CPUINCLUDES="-I../native_cpu" CPUSRCS="asm_support.s" fi dnl Enable JIT compiler, if possible. if [[ "x$WANT_JIT" = "xyes" -a "x$CAN_JIT" ]]; then JITSRCS="$JITSRCS ../uae_cpu/compiler/compemu_support.cpp ../uae_cpu/compiler/compemu_fpp.cpp compstbl.o cpustbl_nf.o" DEFINES="$DEFINES -DUSE_JIT -DUSE_JIT_FPU" if [[ "x$WANT_JIT_DEBUG" = "xyes" ]]; then if [[ "x$WANT_MON" = "xyes" ]]; then DEFINES="$DEFINES -DJIT_DEBUG=1" else AC_MSG_WARN([cxmon not found, ignoring --enable-jit-debug]) WANT_JIT_DEBUG=no fi fi dnl IEEE core is the only FPU emulator to use with the JIT compiler case $FPE_CORE_TEST_ORDER in ieee*) ;; *) AC_MSG_WARN([Forcing use of the IEEE FPU core, as the JIT compiler supports only this one.]) ;; esac FPE_CORE_TEST_ORDER="ieee" else WANT_JIT=no WANT_JIT_DEBUG=no JITSRCS="" fi dnl Utility macro used by next two tests. dnl AC_EXAMINE_OBJECT(C source code, dnl commands examining object file, dnl [commands to run if compile failed]): dnl dnl Compile the source code to an object file; then convert it into a dnl printable representation. All unprintable characters and dnl asterisks (*) are replaced by dots (.). All white space is dnl deleted. Newlines (ASCII 0x10) in the input are preserved in the dnl output, but runs of newlines are compressed to a single newline. dnl Finally, line breaks are forcibly inserted so that no line is dnl longer than 80 columns and the file ends with a newline. The dnl result of all this processing is in the file conftest.dmp, which dnl may be examined by the commands in the second argument. dnl AC_DEFUN([gcc_AC_EXAMINE_OBJECT], [AC_LANG_SAVE AC_LANG_C dnl Next bit cribbed from AC_TRY_COMPILE. cat > conftest.$ac_ext < conftest.dmp $2 ifelse($3, , , else $3 )dnl fi rm -rf conftest* AC_LANG_RESTORE]) dnl Floating point format probe. dnl The basic concept is the same as the above: grep the object dnl file for an interesting string. We have to watch out for dnl rounding changing the values in the object, however; this is dnl handled by ignoring the least significant byte of the float. dnl dnl Does not know about VAX G-float or C4x idiosyncratic format. dnl It does know about PDP-10 idiosyncratic format, but this is dnl not presently supported by GCC. S/390 "binary floating point" dnl is in fact IEEE (but maybe we should have that in EBCDIC as well dnl as ASCII?) dnl AC_DEFUN([gcc_AC_C_FLOAT_FORMAT], [AC_CACHE_CHECK(floating point format, ac_cv_c_float_format, [gcc_AC_EXAMINE_OBJECT( [/* This will not work unless sizeof(double) == 8. */ extern char sizeof_double_must_be_8 [sizeof(double) == 8 ? 1 : -1]; /* This structure must have no internal padding. */ struct possibility { char prefix[8]; double candidate; char postfix[8]; }; #define C(cand) { "\nformat:", cand, ":tamrof\n" } struct possibility table [] = { C( 3.25724264705901305206e+01), /* @@IEEEFP - IEEE 754 */ C( 3.53802595280598432000e+18), /* D__float - VAX */ C( 5.32201830133125317057e-19), /* D.PDP-10 - PDP-10 - the dot is 0x13a */ C( 1.77977764695171661377e+10), /* IBMHEXFP - s/390 format, ascii */ C(-5.22995989424860458374e+10) /* IBMHEXFP - s/390 format, EBCDIC */ };], [if grep 'format:.@IEEEF.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (big-endian)' elif grep 'format:.I@@PFE.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (big-endian)' elif grep 'format:.FEEEI@.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (little-endian)' elif grep 'format:.EFP@@I.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (little-endian)' elif grep 'format:.__floa.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='VAX D-float' elif grep 'format:..PDP-1.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='PDP-10' elif grep 'format:.BMHEXF.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IBM 370 hex' else AC_MSG_ERROR(Unknown floating point format) fi], [AC_MSG_ERROR(compile failed)]) ]) # IEEE is the default format. If the float endianness isn't the same # as the integer endianness, we have to set FLOAT_WORDS_BIG_ENDIAN # (which is a tristate: yes, no, default). This is only an issue with # IEEE; the other formats are only supported by a few machines each, # all with the same endianness. format=IEEE_FLOAT_FORMAT fbigend= case $ac_cv_c_float_format in 'IEEE (big-endian)' ) if test $ac_cv_c_bigendian = no; then fbigend=1 fi ;; 'IEEE (little-endian)' ) if test $ac_cv_c_bigendian = yes; then fbigend=0 fi ;; 'VAX D-float' ) format=VAX_FLOAT_FORMAT ;; 'PDP-10' ) format=PDP10_FLOAT_FORMAT ;; 'IBM 370 hex' ) format=IBM_FLOAT_FORMAT ;; esac AC_DEFINE_UNQUOTED(HOST_FLOAT_FORMAT, $format, [Define to the floating point format of the host machine.]) if test -n "$fbigend"; then AC_DEFINE_UNQUOTED(HOST_FLOAT_WORDS_BIG_ENDIAN, $fbigend, [Define to 1 if the host machine stores floating point numbers in memory with the word containing the sign bit at the lowest address, or to 0 if it does it the other way around. This macro should not be defined if the ordering is the same as for multi-word integers.]) fi ]) dnl Select appropriate FPU source. gcc_AC_C_FLOAT_FORMAT AC_CHECK_HEADERS(ieee754.h ieeefp.h floatingpoint.h nan.h) for fpe in $FPE_CORE_TEST_ORDER; do case $fpe in ieee) case $ac_cv_c_float_format in IEEE*) FPE_CORE="IEEE fpu core" DEFINES="$DEFINES -DFPU_IEEE" FPUSRCS="../uae_cpu/fpu/fpu_ieee.cpp" dnl Math functions not mandated by C99 standard AC_CHECK_FUNCS(isnanl isinfl) dnl Math functions required by C99 standard, but probably not dnl implemented everywhere. In that case, we fall back to the dnl regular variant for doubles. AC_CHECK_FUNCS(logl log10l expl powl fabsl sqrtl) AC_CHECK_FUNCS(sinl cosl tanl sinhl coshl tanhl) AC_CHECK_FUNCS(asinl acosl atanl asinhl acoshl atanhl) AC_CHECK_FUNCS(floorl ceill) break ;; esac ;; x86) if [[ ":$HAVE_GCC27:$HAVE_I386:$HAVE_GAS:" = ":yes:yes:yes:" ]]; then FPE_CORE="i387 fpu core" DEFINES="$DEFINES -DFPU_X86" FPUSRCS="../uae_cpu/fpu/fpu_x86.cpp" break fi ;; uae) FPE_CORE="uae fpu core" DEFINES="$DEFINES -DFPU_UAE" FPUSRCS="../uae_cpu/fpu/fpu_uae.cpp" break ;; *) AC_MSG_ERROR([Internal configure.in script error for $fpe fpu core]) ;; esac done if [[ "x$FPE_CORE" = "x" ]]; then AC_MSG_ERROR([Sorry, no suitable FPU core found in $FPE_CORE_TEST_ORDER]) fi dnl Check for certain math functions AC_CHECK_FUNCS(atanh) AC_CHECK_FUNCS(isnan isinf finite isnormal signbit) dnl UAE CPU sources for all non-m68k-native architectures. if [[ "x$WANT_NATIVE_M68K" = "xno" ]]; then CPUINCLUDES="-I../uae_cpu" CPUSRCS="../uae_cpu/basilisk_glue.cpp ../uae_cpu/memory.cpp ../uae_cpu/newcpu.cpp ../uae_cpu/readcpu.cpp $FPUSRCS cpustbl.cpp cpudefs.cpp $CPUSRCS $JITSRCS" fi dnl Remove the "-g" option if set for GCC. if [[ "x$HAVE_GCC27" = "xyes" ]]; then CFLAGS=`echo $CFLAGS | sed -e 's/-g\b//g'` CXXFLAGS=`echo $CXXFLAGS | sed -e 's/-g\b//g'` fi dnl Or if we have -IPA (MIPSPro compilers) if [[ "x$HAVE_IPA" = "xyes" ]]; then CFLAGS="`echo $CFLAGS | sed -e 's/-g//g'` -O3 -OPT:Olimit=0 -IPA" CXXFLAGS="`echo $CXXFLAGS | sed -e 's/-g//g'` -O3 -OPT:Olimit=0 -IPA" CXXFLAGS="-LANG:std $CXXFLAGS" LDFLAGS="$LDFLAGS -O3 -OPT:Olimit=0 -IPA" fi dnl Generate Makefile. AC_SUBST(DEFINES) AC_SUBST(SYSSRCS) AC_SUBST(CPUINCLUDES) AC_SUBST(CPUSRCS) AC_SUBST(BLESS) AC_SUBST(KEYCODES) AC_CONFIG_FILES([Makefile]) AC_OUTPUT dnl Print summary. echo echo Basilisk II configuration summary: echo echo SDL support ............................ : $SDL_SUPPORT echo BINCUE support ......................... : $have_bincue echo LIBVHD support ......................... : $have_libvhd echo XFree86 DGA support .................... : $WANT_XF86_DGA echo XFree86 VidMode support ................ : $WANT_XF86_VIDMODE echo fbdev DGA support ...................... : $WANT_FBDEV_DGA echo Enable video on SEGV signals ........... : $WANT_VOSF echo ESD sound support ...................... : $WANT_ESD echo GTK user interface ..................... : $WANT_GTK echo mon debugger support ................... : $WANT_MON echo Running m68k code natively ............. : $WANT_NATIVE_M68K echo Use JIT compiler ....................... : $WANT_JIT echo JIT debug mode ......................... : $WANT_JIT_DEBUG echo Floating-Point emulation core .......... : $FPE_CORE echo Assembly optimizations ................. : $ASM_OPTIMIZATIONS echo Addressing mode ........................ : $ADDRESSING_MODE echo Bad memory access recovery type ........ : $sigsegv_recovery echo echo "Configuration done. Now type \"make\" (or \"gmake\")." BasiliskII/src/Unix/timer_unix.cpp0000644000175000017500000002207211243555756017362 0ustar centriscentris/* * timer_unix.cpp - Time Manager emulation, Unix specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "macos_util.h" #include "timer.h" #include #define DEBUG 0 #include "debug.h" // For NetBSD with broken pthreads headers #ifndef CLOCK_REALTIME #define CLOCK_REALTIME 0 #endif #if defined(__MACH__) #include #include static clock_serv_t host_clock; static bool host_clock_inited = false; static inline void mach_current_time(tm_time_t &t) { if(!host_clock_inited) { host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &host_clock); host_clock_inited = true; } clock_get_time(host_clock, &t); } #endif /* * Return microseconds since boot (64 bit) */ void Microseconds(uint32 &hi, uint32 &lo) { D(bug("Microseconds\n")); #if defined(HAVE_CLOCK_GETTIME) struct timespec t; clock_gettime(CLOCK_REALTIME, &t); uint64 tl = (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; #elif defined(__MACH__) tm_time_t t; mach_current_time(t); uint64 tl = (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; #else struct timeval t; gettimeofday(&t, NULL); uint64 tl = (uint64)t.tv_sec * 1000000 + t.tv_usec; #endif hi = tl >> 32; lo = tl; } /* * Return local date/time in Mac format (seconds since 1.1.1904) */ uint32 TimerDateTime(void) { return TimeToMacTime(time(NULL)); } /* * Get current time */ void timer_current_time(tm_time_t &t) { #ifdef HAVE_CLOCK_GETTIME clock_gettime(CLOCK_REALTIME, &t); #elif defined(__MACH__) mach_current_time(t); #else gettimeofday(&t, NULL); #endif } /* * Add times */ void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b) { #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) res.tv_sec = a.tv_sec + b.tv_sec; res.tv_nsec = a.tv_nsec + b.tv_nsec; if (res.tv_nsec >= 1000000000) { res.tv_sec++; res.tv_nsec -= 1000000000; } #else res.tv_sec = a.tv_sec + b.tv_sec; res.tv_usec = a.tv_usec + b.tv_usec; if (res.tv_usec >= 1000000) { res.tv_sec++; res.tv_usec -= 1000000; } #endif } /* * Subtract times */ void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b) { #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) res.tv_sec = a.tv_sec - b.tv_sec; res.tv_nsec = a.tv_nsec - b.tv_nsec; if (res.tv_nsec < 0) { res.tv_sec--; res.tv_nsec += 1000000000; } #else res.tv_sec = a.tv_sec - b.tv_sec; res.tv_usec = a.tv_usec - b.tv_usec; if (res.tv_usec < 0) { res.tv_sec--; res.tv_usec += 1000000; } #endif } /* * Compare times (<0: a < b, =0: a = b, >0: a > b) */ int timer_cmp_time(tm_time_t a, tm_time_t b) { #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) if (a.tv_sec == b.tv_sec) return a.tv_nsec - b.tv_nsec; else return a.tv_sec - b.tv_sec; #else if (a.tv_sec == b.tv_sec) return a.tv_usec - b.tv_usec; else return a.tv_sec - b.tv_sec; #endif } /* * Convert Mac time value (>0: microseconds, <0: microseconds) to tm_time_t */ void timer_mac2host_time(tm_time_t &res, int32 mactime) { #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) if (mactime > 0) { // Time in milliseconds res.tv_sec = mactime / 1000; res.tv_nsec = (mactime % 1000) * 1000000; } else { // Time in negative microseconds res.tv_sec = -mactime / 1000000; res.tv_nsec = (-mactime % 1000000) * 1000; } #else if (mactime > 0) { // Time in milliseconds res.tv_sec = mactime / 1000; res.tv_usec = (mactime % 1000) * 1000; } else { // Time in negative microseconds res.tv_sec = -mactime / 1000000; res.tv_usec = -mactime % 1000000; } #endif } /* * Convert positive tm_time_t to Mac time value (>0: microseconds, <0: microseconds) * A negative input value for hosttime results in a zero return value * As long as the microseconds value fits in 32 bit, it must not be converted to milliseconds! */ int32 timer_host2mac_time(tm_time_t hosttime) { if (hosttime.tv_sec < 0) return 0; else { #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) uint64 t = (uint64)hosttime.tv_sec * 1000000 + hosttime.tv_nsec / 1000; #else uint64 t = (uint64)hosttime.tv_sec * 1000000 + hosttime.tv_usec; #endif if (t > 0x7fffffff) return t / 1000; // Time in milliseconds else return -t; // Time in negative microseconds } } /* * Get current value of microsecond timer */ uint64 GetTicks_usec(void) { #ifdef HAVE_CLOCK_GETTIME struct timespec t; clock_gettime(CLOCK_REALTIME, &t); return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; #elif defined(__MACH__) tm_time_t t; mach_current_time(t); return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; #else struct timeval t; gettimeofday(&t, NULL); return (uint64)t.tv_sec * 1000000 + t.tv_usec; #endif } /* * Delay by specified number of microseconds (<1 second) * (adapted from SDL_Delay() source; this function is designed to provide * the highest accuracy possible) */ #if defined(linux) // Linux select() changes its timeout parameter upon return to contain // the remaining time. Most other unixen leave it unchanged or undefined. #define SELECT_SETS_REMAINING #elif defined(__FreeBSD__) || defined(__sun__) || (defined(__MACH__) && defined(__APPLE__)) #define USE_NANOSLEEP #elif defined(HAVE_PTHREADS) && defined(sgi) // SGI pthreads has a bug when using pthreads+signals+nanosleep, // so instead of using nanosleep, wait on a CV which is never signalled. #include #define USE_COND_TIMEDWAIT #endif void Delay_usec(uint32 usec) { int was_error; #if defined(USE_NANOSLEEP) struct timespec elapsed, tv; #elif defined(USE_COND_TIMEDWAIT) // Use a local mutex and cv, so threads remain independent pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER; struct timespec elapsed; uint64 future; #else struct timeval tv; #ifndef SELECT_SETS_REMAINING uint64 then, now, elapsed; #endif #endif // Set the timeout interval - Linux only needs to do this once #if defined(SELECT_SETS_REMAINING) tv.tv_sec = 0; tv.tv_usec = usec; #elif defined(USE_NANOSLEEP) elapsed.tv_sec = 0; elapsed.tv_nsec = usec * 1000; #elif defined(USE_COND_TIMEDWAIT) future = GetTicks_usec() + usec; elapsed.tv_sec = future / 1000000; elapsed.tv_nsec = (future % 1000000) * 1000; #else then = GetTicks_usec(); #endif do { errno = 0; #if defined(USE_NANOSLEEP) tv.tv_sec = elapsed.tv_sec; tv.tv_nsec = elapsed.tv_nsec; was_error = nanosleep(&tv, &elapsed); #elif defined(USE_COND_TIMEDWAIT) was_error = pthread_mutex_lock(&delay_mutex); was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed); was_error = pthread_mutex_unlock(&delay_mutex); #else #ifndef SELECT_SETS_REMAINING // Calculate the time interval left (in case of interrupt) now = GetTicks_usec(); elapsed = now - then; then = now; if (elapsed >= usec) break; usec -= elapsed; tv.tv_sec = 0; tv.tv_usec = usec; #endif was_error = select(0, NULL, NULL, NULL, &tv); #endif } while (was_error && (errno == EINTR)); } /* * Suspend emulator thread, virtual CPU in idle mode */ #ifdef HAVE_PTHREADS #if defined(HAVE_PTHREAD_COND_INIT) #define IDLE_USES_COND_WAIT 1 static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t idle_cond = PTHREAD_COND_INITIALIZER; #elif defined(HAVE_SEM_INIT) #define IDLE_USES_SEMAPHORE 1 #include #ifdef HAVE_SPINLOCKS static spinlock_t idle_lock = SPIN_LOCK_UNLOCKED; #define LOCK_IDLE spin_lock(&idle_lock) #define UNLOCK_IDLE spin_unlock(&idle_lock) #else static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER; #define LOCK_IDLE pthread_mutex_lock(&idle_lock) #define UNLOCK_IDLE pthread_mutex_unlock(&idle_lock) #endif static sem_t idle_sem; static int idle_sem_ok = -1; #endif #endif void idle_wait(void) { #ifdef IDLE_USES_COND_WAIT pthread_mutex_lock(&idle_lock); pthread_cond_wait(&idle_cond, &idle_lock); pthread_mutex_unlock(&idle_lock); #else #ifdef IDLE_USES_SEMAPHORE LOCK_IDLE; if (idle_sem_ok < 0) idle_sem_ok = (sem_init(&idle_sem, 0, 0) == 0); if (idle_sem_ok > 0) { idle_sem_ok++; UNLOCK_IDLE; sem_wait(&idle_sem); return; } UNLOCK_IDLE; #endif // Fallback: sleep 10 ms Delay_usec(10000); #endif } /* * Resume execution of emulator thread, events just arrived */ void idle_resume(void) { #ifdef IDLE_USES_COND_WAIT pthread_cond_signal(&idle_cond); #else #ifdef IDLE_USES_SEMAPHORE LOCK_IDLE; if (idle_sem_ok > 1) { idle_sem_ok--; UNLOCK_IDLE; sem_post(&idle_sem); return; } UNLOCK_IDLE; #endif #endif } BasiliskII/src/Unix/bincue_unix.h0000644000175000017500000000267011452741437017151 0ustar centriscentris/* * bincue_unix.h -- support for cdrom image files in bin/cue format * * (C) 2010 Geoffrey Brown * * 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 */ #ifndef BINCUE_H #define BINCUE_H extern void *open_bincue(const char *name); extern bool readtoc_bincue(void *, uint8 *); extern size_t read_bincue(void *, void *, loff_t, size_t); extern loff_t size_bincue(void *); extern void close_bincue(void *); extern bool GetPosition_bincue(void *, uint8 *); extern bool CDPlay_bincue(void *, uint8, uint8, uint8, uint8, uint8, uint8); extern bool CDPause_bincue(void *); extern bool CDResume_bincue(void *); extern bool CDStop_bincue(void *); #ifdef USE_SDL_AUDIO extern void OpenAudio_bincue(int, int, int, uint8); extern void MixAudio_bincue(uint8 *, int); #endif #endif BasiliskII/src/Unix/vm_alloc.h0000644000175000017500000001010411677420412016420 0ustar centriscentris/* * vm_alloc.h - Wrapper to various virtual memory allocation schemes * (supports mmap, vm_allocate or fallbacks to malloc) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef VM_ALLOC_H #define VM_ALLOC_H #ifdef HAVE_UNISTD_H #include #include #endif #ifdef HAVE_SYS_MMAN_H #include #endif #ifdef HAVE_MACH_VM extern "C" { #include #include } #endif /* Return value of `vm_acquire' in case of an error. */ #ifdef HAVE_MACH_VM #define VM_MAP_FAILED ((void *)-1) #else #ifdef HAVE_MMAP_VM #define VM_MAP_FAILED ((void *)-1) #else #define VM_MAP_FAILED 0 #endif #endif /* Option to vm_get_write_watch() to reset the write-tracking state once it was retrieved. Otherwise, you have to manually call vm_reset_write_watch() and potentially lose some info. */ #define VM_WRITE_WATCH_RESET 0x01 /* Mapping options. */ #define VM_MAP_SHARED 0x01 #define VM_MAP_PRIVATE 0x02 #define VM_MAP_FIXED 0x04 #define VM_MAP_32BIT 0x08 #define VM_MAP_WRITE_WATCH 0x10 /* Default mapping options. */ #define VM_MAP_DEFAULT (VM_MAP_PRIVATE) /* Protection bits. */ #ifdef HAVE_MACH_VM #define VM_PAGE_NOACCESS VM_PROT_NONE #define VM_PAGE_READ VM_PROT_READ #define VM_PAGE_WRITE VM_PROT_WRITE #define VM_PAGE_EXECUTE VM_PROT_EXECUTE #else #ifdef HAVE_MMAP_VM #define VM_PAGE_NOACCESS PROT_NONE #define VM_PAGE_READ PROT_READ #define VM_PAGE_WRITE PROT_WRITE #define VM_PAGE_EXECUTE PROT_EXEC #else #define VM_PAGE_NOACCESS 0x0 #define VM_PAGE_READ 0x1 #define VM_PAGE_WRITE 0x2 #define VM_PAGE_EXECUTE 0x4 #endif #endif /* Default protection bits. */ #define VM_PAGE_DEFAULT (VM_PAGE_READ | VM_PAGE_WRITE) /* Initialize the VM system. Returns 0 if successful, -1 for errors. */ extern int vm_init(void); /* Deallocate all internal data used to wrap virtual memory allocators. */ extern void vm_exit(void); /* Allocate zero-filled memory of SIZE bytes. The mapping is private and default protection bits are read / write. The return value is the actual mapping address chosen or VM_MAP_FAILED for errors. */ extern void * vm_acquire(size_t size, int options = VM_MAP_DEFAULT); /* Allocate zero-filled memory at exactly ADDR (which must be page-aligned). Returns 0 if successful, -1 on errors. */ extern int vm_acquire_fixed(void * addr, size_t size, int options = VM_MAP_DEFAULT); /* Deallocate any mapping for the region starting at ADDR and extending LEN bytes. Returns 0 if successful, -1 on errors. */ extern int vm_release(void * addr, size_t size); /* Change the memory protection of the region starting at ADDR and extending SIZE bytes to PROT. Returns 0 if successful, -1 for errors. */ extern int vm_protect(void * addr, size_t size, int prot); /* Return the addresses of the pages that got modified since the last reset of the write-tracking state for the specified range [ ADDR, ADDR + SIZE [. Returns 0 if successful, -1 for errors. */ extern int vm_get_write_watch(void * addr, size_t size, void ** pages, unsigned int * n_pages, int options = 0); /* Reset the write-tracking state for the specified range [ ADDR, ADDR + SIZE [. Returns 0 if successful, -1 for errors. */ extern int vm_reset_write_watch(void * addr, size_t size); /* Returns the size of a page. */ extern int vm_get_page_size(void); #endif /* VM_ALLOC_H */ BasiliskII/src/Unix/config.guess0000755000175000017500000012025607677046664017027 0ustar centriscentris#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-01-10' # This file 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. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:MicroBSD:*:*) echo ${UNAME_MACHINE}-unknown-microbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. eval $set_cc_for_build cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF $CC_FOR_BUILD -o $dummy $dummy.s 2>/dev/null if test "$?" = 0 ; then case `$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; 2-1307) UNAME_MACHINE="alphaev68" ;; 3-1307) UNAME_MACHINE="alphaev7" ;; esac fi echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:3*) echo i586-pc-interix3 exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) case `uname -p` in *86) UNAME_PROCESSOR=i686 ;; powerpc) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: BasiliskII/src/Unix/rpc_unix.cpp0000644000175000017500000010261210736405221017010 0ustar centriscentris/* * rpc_unix.cpp - Remote Procedure Calls, Unix specific backend * * Basilisk II (C) 1997-2008 Christian Bauer * Contributed by Gwenole Beauchesne * * 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 */ /* * NOTES: * - this is subject to rewrite but the API is to be kept intact * - this RPC system is very minimal and only suited for 1:1 communication * * TODO: * - better failure conditions * - windows rpc */ #include "sysdeps.h" #include #include #include #include #include #include #include #include #include #include "rpc.h" #define DEBUG 0 #include "debug.h" #define NON_BLOCKING_IO 0 #if defined __linux__ #define USE_ABSTRACT_NAMESPACES 1 #endif /* ====================================================================== */ /* === PThreads Glue === */ /* ====================================================================== */ //#define USE_THREADS #ifndef USE_THREADS #define pthread_t void * #define pthread_cancel(th) #define pthread_join(th, ret) #define pthread_testcancel() #define pthread_create(th, attr, start, arg) dummy_thread_create() static inline int dummy_thread_create(void) { errno = ENOSYS; return -1; } #undef pthread_mutex_t #define pthread_mutex_t volatile int #undef pthread_mutex_lock #define pthread_mutex_lock(m) -1 #undef pthread_mutex_unlock #define pthread_mutex_unlock(m) -1 #undef PTHREAD_MUTEX_INITIALIZER #define PTHREAD_MUTEX_INITIALIZER 0 #endif /* ====================================================================== */ /* === RPC Connection Handling === */ /* ====================================================================== */ // Connection type enum { RPC_CONNECTION_SERVER, RPC_CONNECTION_CLIENT, }; // Connection status enum { RPC_STATUS_IDLE, RPC_STATUS_BUSY, }; // Client / Server connection struct rpc_connection_t { int type; int status; int socket; char *socket_path; int server_socket; int server_thread_active; pthread_t server_thread; rpc_method_descriptor_t *callbacks; int n_callbacks; int send_offset; char send_buffer[BUFSIZ]; }; #define return_error(ERROR) do { error = (ERROR); goto do_return; } while (0) // Set connection status (XXX protect connection with a lock?) static inline void rpc_connection_set_status(rpc_connection_t *connection, int status) { connection->status = status; } // Returns TRUE if the connection is busy (e.g. waiting for a reply) int rpc_connection_busy(rpc_connection_t *connection) { return connection && connection->status == RPC_STATUS_BUSY; } // Prepare socket path for addr.sun_path[] static int _rpc_socket_path(char **pathp, const char *ident) { int i, len; len = strlen(ident); if (pathp == NULL) return 0; char *path; #if USE_ABSTRACT_NAMESPACES const int len_bias = 1; if ((path = (char *)malloc(len + len_bias + 1)) == NULL) return 0; path[0] = 0; strcpy(&path[len_bias], ident); #else const int len_bias = 5; if ((path = (char *)malloc(len + len_bias + 1)) == NULL) return 0; strcpy(path, "/tmp/"); for (i = 0; i < len; i++) { char ch = ident[i]; if (ch == '/') ch = '_'; path[len_bias + i] = ch; } #endif len += len_bias; path[len] = '\0'; if (*pathp) free(*pathp); *pathp = path; return len; } // Initialize server-side RPC system rpc_connection_t *rpc_init_server(const char *ident) { D(bug("rpc_init_server ident='%s'\n", ident)); rpc_connection_t *connection; struct sockaddr_un addr; socklen_t addr_len; if (ident == NULL) return NULL; connection = (rpc_connection_t *)malloc(sizeof(*connection)); if (connection == NULL) return NULL; connection->type = RPC_CONNECTION_SERVER; connection->status = RPC_STATUS_IDLE; connection->socket = -1; connection->server_thread_active = 0; connection->callbacks = NULL; connection->n_callbacks = 0; if ((connection->server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("server socket"); free(connection); return NULL; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; connection->socket_path = NULL; addr_len = _rpc_socket_path(&connection->socket_path, ident); memcpy(&addr.sun_path[0], connection->socket_path, addr_len); addr_len += sizeof(struct sockaddr_un) - sizeof(addr.sun_path); if (bind(connection->server_socket, (struct sockaddr *)&addr, addr_len) < 0) { perror("server bind"); free(connection); return NULL; } if (listen(connection->server_socket, 1) < 0) { perror("server listen"); free(connection); return NULL; } return connection; } // Initialize client-side RPC system rpc_connection_t *rpc_init_client(const char *ident) { D(bug("rpc_init_client ident='%s'\n", ident)); rpc_connection_t *connection; struct sockaddr_un addr; socklen_t addr_len; if (ident == NULL) return NULL; connection = (rpc_connection_t *)malloc(sizeof(*connection)); if (connection == NULL) return NULL; connection->type = RPC_CONNECTION_CLIENT; connection->status = RPC_STATUS_IDLE; connection->server_socket = -1; connection->callbacks = NULL; connection->n_callbacks = 0; if ((connection->socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("client socket"); free(connection); return NULL; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; connection->socket_path = NULL; addr_len = _rpc_socket_path(&connection->socket_path, ident); memcpy(&addr.sun_path[0], connection->socket_path, addr_len); addr_len += sizeof(struct sockaddr_un) - sizeof(addr.sun_path); // Wait at most 5 seconds for server to initialize const int N_CONNECT_WAIT_DELAY = 10; int n_connect_attempts = 5000 / N_CONNECT_WAIT_DELAY; if (n_connect_attempts == 0) n_connect_attempts = 1; while (n_connect_attempts > 0) { if (connect(connection->socket, (struct sockaddr *)&addr, addr_len) == 0) break; if (n_connect_attempts > 1 && errno != ECONNREFUSED && errno != ENOENT) { perror("client_connect"); free(connection); return NULL; } n_connect_attempts--; usleep(N_CONNECT_WAIT_DELAY); } if (n_connect_attempts == 0) { free(connection); return NULL; } return connection; } // Close RPC connection int rpc_exit(rpc_connection_t *connection) { D(bug("rpc_exit\n")); if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->socket_path) { if (connection->socket_path[0]) unlink(connection->socket_path); free(connection->socket_path); } if (connection->type == RPC_CONNECTION_SERVER) { if (connection->server_thread_active) { pthread_cancel(connection->server_thread); pthread_join(connection->server_thread, NULL); } if (connection->socket != -1) close(connection->socket); if (connection->server_socket != -1) close(connection->server_socket); } else { if (connection->socket != -1) close(connection->socket); } if (connection->callbacks) free(connection->callbacks); free(connection); return RPC_ERROR_NO_ERROR; } // Wait for a message to arrive on the connection port static inline int _rpc_wait_dispatch(rpc_connection_t *connection, int timeout) { struct timeval tv; tv.tv_sec = timeout / 1000000; tv.tv_usec = timeout % 1000000; fd_set rfds; FD_ZERO(&rfds); FD_SET(connection->socket, &rfds); return select(connection->socket + 1, &rfds, NULL, NULL, &tv); } int rpc_wait_dispatch(rpc_connection_t *connection, int timeout) { if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->type != RPC_CONNECTION_SERVER) return RPC_ERROR_CONNECTION_TYPE_MISMATCH; return _rpc_wait_dispatch(connection, timeout); } // Process incoming messages in the background static void *rpc_server_func(void *arg) { rpc_connection_t *connection = (rpc_connection_t *)arg; int ret = rpc_listen_socket(connection); if (ret < 0) return NULL; connection->server_thread_active = 1; for (;;) { // XXX broken MacOS X doesn't implement cancellation points correctly pthread_testcancel(); // wait for data to arrive int ret = _rpc_wait_dispatch(connection, 50000); if (ret == 0) continue; if (ret < 0) break; rpc_dispatch(connection); } connection->server_thread_active = 0; return NULL; } // Return listen socket of RPC connection int rpc_listen_socket(rpc_connection_t *connection) { D(bug("rpc_listen_socket\n")); if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->type != RPC_CONNECTION_SERVER) return RPC_ERROR_CONNECTION_TYPE_MISMATCH; struct sockaddr_un addr; socklen_t addr_len = sizeof(addr); if ((connection->socket = accept(connection->server_socket, (struct sockaddr *)&addr, &addr_len)) < 0) { perror("server accept"); return RPC_ERROR_ERRNO_SET; } #if NON_BLOCKING_IO int val = fcntl(connection->socket, F_GETFL, 0); if (val < 0) { perror("server fcntl F_GETFL"); return RPC_ERROR_ERRNO_SET; } if (fcntl(connection->socket, F_SETFL, val | O_NONBLOCK) < 0) { perror("server fcntl F_SETFL"); return RPC_ERROR_ERRNO_SET; } #endif return connection->socket; } // Listen for incoming messages on RPC connection #ifdef USE_THREADS int rpc_listen(rpc_connection_t *connection) { D(bug("rpc_listen\n")); if (pthread_create(&connection->server_thread, NULL, rpc_server_func, connection) != 0) { perror("server thread"); return RPC_ERROR_ERRNO_SET; } return RPC_ERROR_NO_ERROR; } #endif /* ====================================================================== */ /* === Message Passing === */ /* ====================================================================== */ // Message markers enum { RPC_MESSAGE_START = -3000, RPC_MESSAGE_END = -3001, RPC_MESSAGE_ACK = -3002, RPC_MESSAGE_REPLY = -3003, RPC_MESSAGE_FAILURE = -3004, }; // Message type struct rpc_message_t { int socket; int offset; unsigned char buffer[BUFSIZ]; }; // User-defined marshalers static struct { rpc_message_descriptor_t *descs; int last; int count; } g_message_descriptors = { NULL, 0, 0 }; static pthread_mutex_t g_message_descriptors_lock = PTHREAD_MUTEX_INITIALIZER; // Add a user-defined marshaler static int rpc_message_add_callback(const rpc_message_descriptor_t *desc) { D(bug("rpc_message_add_callback\n")); const int N_ENTRIES_ALLOC = 8; int error = RPC_ERROR_NO_ERROR; pthread_mutex_lock(&g_message_descriptors_lock); if (g_message_descriptors.descs == NULL) { g_message_descriptors.count = N_ENTRIES_ALLOC; if ((g_message_descriptors.descs = (rpc_message_descriptor_t *)malloc(g_message_descriptors.count * sizeof(g_message_descriptors.descs[0]))) == NULL) { pthread_mutex_unlock(&g_message_descriptors_lock); return RPC_ERROR_NO_MEMORY; } g_message_descriptors.last = 0; } else if (g_message_descriptors.last >= g_message_descriptors.count) { g_message_descriptors.count += N_ENTRIES_ALLOC; if ((g_message_descriptors.descs = (rpc_message_descriptor_t *)realloc(g_message_descriptors.descs, g_message_descriptors.count * sizeof(g_message_descriptors.descs[0]))) == NULL) { pthread_mutex_unlock(&g_message_descriptors_lock); return RPC_ERROR_NO_MEMORY; } } // XXX only one callback per ID int i; for (i = 0; i < g_message_descriptors.last; i++) { if (g_message_descriptors.descs[i].id == desc->id) { pthread_mutex_unlock(&g_message_descriptors_lock); return RPC_ERROR_NO_ERROR; } } g_message_descriptors.descs[g_message_descriptors.last++] = *desc; pthread_mutex_unlock(&g_message_descriptors_lock); return error; } // Add user-defined marshalers int rpc_message_add_callbacks(const rpc_message_descriptor_t *descs, int n_descs) { D(bug("rpc_message_add_callbacks\n")); int i, error; for (i = 0; i < n_descs; i++) { if ((error = rpc_message_add_callback(&descs[i])) < 0) return error; } return RPC_ERROR_NO_ERROR; } // Find user-defined marshaler static rpc_message_descriptor_t *rpc_message_find_descriptor(int id) { D(bug("rpc_message_find_descriptor\n")); if (g_message_descriptors.descs) { int i; for (i = 0; i < g_message_descriptors.count; i++) { if (g_message_descriptors.descs[i].id == id) return &g_message_descriptors.descs[i]; } } return NULL; } // Initialize message static inline void rpc_message_init(rpc_message_t *message, rpc_connection_t *connection) { message->socket = connection->socket; message->offset = 0; } // Send BYTES static inline int _rpc_message_send_bytes(rpc_message_t *message, unsigned char *bytes, int count) { if (send(message->socket, bytes, count, 0) != count) return RPC_ERROR_ERRNO_SET; return RPC_ERROR_NO_ERROR; } // Send message on wire static inline int rpc_message_flush(rpc_message_t *message) { int error = _rpc_message_send_bytes(message, message->buffer, message->offset); message->offset = 0; return error; } // Send BYTES (public interface, may need to flush internal buffer) int rpc_message_send_bytes(rpc_message_t *message, unsigned char *bytes, int count) { if (message->offset > 0) { int error = rpc_message_flush(message); if (error != RPC_ERROR_NO_ERROR) return error; } return _rpc_message_send_bytes(message, bytes, count); } // Send BYTES (buffered) static inline void _rpc_message_send_bytes_buffered(rpc_message_t *message, unsigned char *bytes, int count) { memcpy(&message->buffer[message->offset], bytes, count); message->offset += count; } // Send CHAR int rpc_message_send_char(rpc_message_t *message, char c) { D(bug(" send CHAR '%c'\n", c)); unsigned char e_value = c; if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { int error = rpc_message_flush(message); if (error != RPC_ERROR_NO_ERROR) return error; } _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); return RPC_ERROR_NO_ERROR; } // Send INT32 int rpc_message_send_int32(rpc_message_t *message, int32_t value) { D(bug(" send INT32 %d\n", value)); int32_t e_value = htonl(value); if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { int error = rpc_message_flush(message); if (error != RPC_ERROR_NO_ERROR) return error; } _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); return RPC_ERROR_NO_ERROR; } // Send UINT32 int rpc_message_send_uint32(rpc_message_t *message, uint32_t value) { D(bug(" send UINT32 %u\n", value)); uint32_t e_value = htonl(value); if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { int error = rpc_message_flush(message); if (error != RPC_ERROR_NO_ERROR) return error; } _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); return RPC_ERROR_NO_ERROR; } // Send STRING int rpc_message_send_string(rpc_message_t *message, const char *str) { D(bug(" send STRING \"%s\"\n", str)); int error, length = str ? strlen(str) : 0; uint32_t e_value = htonl(length); if (message->offset + sizeof(e_value) >= sizeof(message->buffer)) { error = rpc_message_flush(message); if (error != RPC_ERROR_NO_ERROR) return error; } _rpc_message_send_bytes_buffered(message, (unsigned char *)&e_value, sizeof(e_value)); error = rpc_message_flush(message); if (error != RPC_ERROR_NO_ERROR) return error; D(bug("str=%p\n", str)); return _rpc_message_send_bytes(message, (unsigned char *)str, length); } // Send message arguments static int rpc_message_send_args(rpc_message_t *message, va_list args) { int type; rpc_message_descriptor_t *desc; while ((type = va_arg(args, int)) != RPC_TYPE_INVALID) { int error = rpc_message_send_int32(message, type); if (error != RPC_ERROR_NO_ERROR) return error; switch (type) { case RPC_TYPE_CHAR: error = rpc_message_send_char(message, (char )va_arg(args, int)); break; case RPC_TYPE_BOOLEAN: case RPC_TYPE_INT32: error = rpc_message_send_int32(message, va_arg(args, int)); break; case RPC_TYPE_UINT32: error = rpc_message_send_uint32(message, va_arg(args, unsigned int)); break; case RPC_TYPE_STRING: error = rpc_message_send_string(message, va_arg(args, char *)); break; case RPC_TYPE_ARRAY: { int i; int array_type = va_arg(args, int32_t); int array_size = va_arg(args, uint32_t); if ((error = rpc_message_send_int32(message, array_type)) < 0) return error; if ((error = rpc_message_send_uint32(message, array_size)) < 0) return error; switch (array_type) { case RPC_TYPE_CHAR: { unsigned char *array = va_arg(args, unsigned char *); error = rpc_message_flush(message); if (error != RPC_ERROR_NO_ERROR) return error; error = _rpc_message_send_bytes(message, array, array_size); break; } case RPC_TYPE_BOOLEAN: case RPC_TYPE_INT32: { int32_t *array = va_arg(args, int32_t *); for (i = 0; i < array_size; i++) { if ((error = rpc_message_send_int32(message, array[i])) < 0) break; } break; } case RPC_TYPE_UINT32: { uint32_t *array = va_arg(args, uint32_t *); for (i = 0; i < array_size; i++) { if ((error = rpc_message_send_uint32(message, array[i])) < 0) break; } break; } case RPC_TYPE_STRING: { char **array = va_arg(args, char **); for (i = 0; i < array_size; i++) { if ((error = rpc_message_send_string(message, array[i])) < 0) break; } break; } default: if ((desc = rpc_message_find_descriptor(array_type)) != NULL) { uint8_t *array = va_arg(args, uint8_t *); for (i = 0; i < array_size; i++) { if ((error = desc->send_callback(message, &array[i * desc->size])) < 0) break; } } else { fprintf(stderr, "unknown array arg type %d to send\n", type); error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; } break; } break; } default: if ((desc = rpc_message_find_descriptor(type)) != NULL) error = desc->send_callback(message, va_arg(args, uint8_t *)); else { fprintf(stderr, "unknown arg type %d to send\n", type); error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; } break; } if (error != RPC_ERROR_NO_ERROR) return error; } return RPC_ERROR_NO_ERROR; } // Receive raw BYTES static inline int _rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count) { do { int n = recv(message->socket, bytes, count, 0); if (n > 0) { count -= n; bytes += n; } else if (n == -1 && errno == EINTR) continue; else { #if NON_BLOCKING_IO if (errno == EAGAIN || errno == EWOULDBLOCK) { // wait for data to arrive fd_set rfds; FD_ZERO(&rfds); FD_SET(message->socket, &rfds); int ret = select(message->socket + 1, &rfds, NULL, NULL, NULL); if (ret > 0) continue; } #endif return RPC_ERROR_ERRNO_SET; } } while (count > 0); return RPC_ERROR_NO_ERROR; } int rpc_message_recv_bytes(rpc_message_t *message, unsigned char *bytes, int count) { return _rpc_message_recv_bytes(message, bytes, count); } // Receive CHAR int rpc_message_recv_char(rpc_message_t *message, char *ret) { char r_value; int error; if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) return error; *ret = r_value; D(bug(" recv CHAR '%c'\n", *ret)); return RPC_ERROR_NO_ERROR; } // Receive INT32 int rpc_message_recv_int32(rpc_message_t *message, int32_t *ret) { int32_t r_value; int error; if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) return error; *ret = ntohl(r_value); D(bug(" recv INT32 %d\n", *ret)); return RPC_ERROR_NO_ERROR; } // Receive UINT32 int rpc_message_recv_uint32(rpc_message_t *message, uint32_t *ret) { uint32_t r_value; int error; if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) return error; *ret = ntohl(r_value); D(bug(" recv UINT32 %u\n", *ret)); return RPC_ERROR_NO_ERROR; } // Receive STRING int rpc_message_recv_string(rpc_message_t *message, char **ret) { char *str; int length; uint32_t r_value; int error; if ((error = _rpc_message_recv_bytes(message, (unsigned char *)&r_value, sizeof(r_value))) < 0) return error; length = ntohl(r_value); if (length == 0) str = NULL; else { if ((str = (char *)malloc(length + 1)) == NULL) return RPC_ERROR_NO_MEMORY; if ((error = _rpc_message_recv_bytes(message, (unsigned char *)str, length)) < 0) return error; str[length] = '\0'; } *ret = str; D(bug(" recv STRING \"%s\"\n", *ret)); return RPC_ERROR_NO_ERROR; } // Receive message arguments static int rpc_message_recv_args(rpc_message_t *message, va_list args) { int expected_type, error; rpc_message_descriptor_t *desc; while ((expected_type = va_arg(args, int)) != RPC_TYPE_INVALID) { void *p_value = va_arg(args, void *); int32_t type; if ((error = rpc_message_recv_int32(message, &type)) < 0) return error; if (type != expected_type) return RPC_ERROR_MESSAGE_ARGUMENT_MISMATCH; switch (type) { case RPC_TYPE_CHAR: error = rpc_message_recv_char(message, (char *)p_value); break; case RPC_TYPE_BOOLEAN: case RPC_TYPE_INT32: error = rpc_message_recv_int32(message, (int32_t *)p_value); break; case RPC_TYPE_UINT32: error = rpc_message_recv_uint32(message, (uint32_t *)p_value); break; case RPC_TYPE_STRING: error = rpc_message_recv_string(message, (char **)p_value); break; case RPC_TYPE_ARRAY: { int i; int32_t array_type; uint32_t array_size; if ((error = rpc_message_recv_int32(message, &array_type)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &array_size)) < 0) return error; p_value = va_arg(args, void *); *((uint32_t *)p_value) = array_size; p_value = va_arg(args, void *); switch (array_type) { case RPC_TYPE_CHAR: { unsigned char *array; if ((array = (unsigned char *)malloc(array_size * sizeof(*array))) == NULL) return RPC_ERROR_NO_MEMORY; error = _rpc_message_recv_bytes(message, array, array_size); if (error != RPC_ERROR_NO_ERROR) return error; *((void **)p_value) = (void *)array; break; } case RPC_TYPE_BOOLEAN: case RPC_TYPE_INT32: { int *array; if ((array = (int *)malloc(array_size * sizeof(*array))) == NULL) return RPC_ERROR_NO_MEMORY; for (i = 0; i < array_size; i++) { int32_t value; if ((error = rpc_message_recv_int32(message, &value)) < 0) return error; array[i] = value; } *((void **)p_value) = (void *)array; break; } case RPC_TYPE_UINT32: { unsigned int *array; if ((array = (unsigned int *)malloc(array_size * sizeof(*array))) == NULL) return RPC_ERROR_NO_MEMORY; for (i = 0; i < array_size; i++) { uint32_t value; if ((error = rpc_message_recv_uint32(message, &value)) < 0) return error; array[i] = value; } *((void **)p_value) = (void *)array; break; } case RPC_TYPE_STRING: { char **array; if ((array = (char **)malloc(array_size * sizeof(*array))) == NULL) return RPC_ERROR_NO_MEMORY; for (i = 0; i < array_size; i++) { char *str; if ((error = rpc_message_recv_string(message, &str)) < 0) return error; array[i] = str; } *((void **)p_value) = (void *)array; break; } default: if ((desc = rpc_message_find_descriptor(array_type)) != NULL) { char *array; if ((array = (char *)malloc(array_size * desc->size)) == NULL) return RPC_ERROR_NO_MEMORY; for (i = 0; i < array_size; i++) { if ((error = desc->recv_callback(message, &array[i * desc->size])) < 0) return error; } *((void **)p_value) = array; } else { fprintf(stderr, "unknown array arg type %d to receive\n", type); error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; } break; } break; } default: if ((desc = rpc_message_find_descriptor(type)) != NULL) error = desc->recv_callback(message, p_value); else { fprintf(stderr, "unknown arg type %d to send\n", type); error = RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN; } break; } if (error != RPC_ERROR_NO_ERROR) return error; } return RPC_ERROR_NO_ERROR; } // Skip message argument static int rpc_message_skip_arg(rpc_message_t *message, int type) { unsigned char dummy[BUFSIZ]; int error = RPC_ERROR_GENERIC; switch (type) { case RPC_TYPE_CHAR: error = _rpc_message_recv_bytes(message, dummy, 1); break; case RPC_TYPE_BOOLEAN: case RPC_TYPE_INT32: case RPC_TYPE_UINT32: error = _rpc_message_recv_bytes(message, dummy, 4); break; case RPC_TYPE_STRING: { int32_t length; if ((error = rpc_message_recv_int32(message, &length)) < 0) return error; while (length >= sizeof(dummy)) { if ((error = _rpc_message_recv_bytes(message, dummy, sizeof(dummy))) < 0) return error; length -= sizeof(dummy); } if (length > 0) { if ((error = _rpc_message_recv_bytes(message, dummy, length)) < 0) return error; } break; } default: fprintf(stderr, "unknown arg type %d to receive\n", type); break; } return error; } // Dispatch message received in the server loop int rpc_dispatch(rpc_connection_t *connection) { rpc_message_t message; rpc_message_init(&message, connection); int32_t method, value, ret = RPC_MESSAGE_FAILURE; if (rpc_message_recv_int32(&message, &value) != RPC_ERROR_NO_ERROR && value != RPC_MESSAGE_START) return ret; D(bug("receiving message\n")); if (rpc_message_recv_int32(&message, &method) == RPC_ERROR_NO_ERROR && connection->callbacks != NULL) { int i; for (i = 0; i < connection->n_callbacks; i++) { if (connection->callbacks[i].id == method) { if (connection->callbacks[i].callback && connection->callbacks[i].callback(connection) == RPC_ERROR_NO_ERROR) { if (rpc_message_recv_int32(&message, &value) == RPC_ERROR_NO_ERROR && value == RPC_MESSAGE_END) ret = RPC_MESSAGE_ACK; else { fprintf(stderr, "corrupted message handler %d\n", method); for (;;) { if (rpc_message_skip_arg(&message, value) != RPC_ERROR_NO_ERROR) break; if (rpc_message_recv_int32(&message, &value) != RPC_ERROR_NO_ERROR) break; if (value == RPC_MESSAGE_END) break; } } break; } } } } rpc_message_send_int32(&message, ret); rpc_message_flush(&message); D(bug(" -- message received\n")); return ret == RPC_MESSAGE_ACK ? method : ret; } /* ====================================================================== */ /* === Method Callbacks Handling === */ /* ====================================================================== */ // Add a user-defined method callback (server side) static int rpc_method_add_callback(rpc_connection_t *connection, const rpc_method_descriptor_t *desc) { const int N_ENTRIES_ALLOC = 8; int i; // pre-allocate up to N_ENTRIES_ALLOC entries if (connection->callbacks == NULL) { if ((connection->callbacks = (rpc_method_descriptor_t *)calloc(N_ENTRIES_ALLOC, sizeof(connection->callbacks[0]))) == NULL) return RPC_ERROR_NO_MEMORY; connection->n_callbacks = N_ENTRIES_ALLOC; } // look for a free slot for (i = connection->n_callbacks - 1; i >= 0; i--) { if (connection->callbacks[i].callback == NULL) break; } // none found, reallocate if (i < 0) { if ((connection->callbacks = (rpc_method_descriptor_t *)realloc(connection->callbacks, (connection->n_callbacks + N_ENTRIES_ALLOC) * sizeof(connection->callbacks[0]))) == NULL) return RPC_ERROR_NO_MEMORY; i = connection->n_callbacks; memset(&connection->callbacks[i], 0, N_ENTRIES_ALLOC * sizeof(connection->callbacks[0])); connection->n_callbacks += N_ENTRIES_ALLOC; } D(bug("rpc_method_add_callback for method %d in slot %d\n", desc->id, i)); connection->callbacks[i] = *desc; return RPC_ERROR_NO_ERROR; } // Add user-defined method callbacks (server side) int rpc_method_add_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs) { D(bug("rpc_method_add_callbacks\n")); if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->type != RPC_CONNECTION_SERVER) return RPC_ERROR_CONNECTION_TYPE_MISMATCH; while (--n_descs >= 0) { int error = rpc_method_add_callback(connection, &descs[n_descs]); if (error != RPC_ERROR_NO_ERROR) return error; } return RPC_ERROR_NO_ERROR; } // Remove a user-defined method callback (common code) int rpc_method_remove_callback_id(rpc_connection_t *connection, int id) { D(bug("rpc_method_remove_callback_id\n")); if (connection->callbacks) { int i; for (i = 0; i < connection->n_callbacks; i++) { if (connection->callbacks[i].id == id) { connection->callbacks[i].callback = NULL; return RPC_ERROR_NO_ERROR; } } } return RPC_ERROR_GENERIC; } // Remove user-defined method callbacks (server side) int rpc_method_remove_callbacks(rpc_connection_t *connection, const rpc_method_descriptor_t *callbacks, int n_callbacks) { D(bug("rpc_method_remove_callbacks\n")); if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->type != RPC_CONNECTION_SERVER) return RPC_ERROR_CONNECTION_TYPE_MISMATCH; while (--n_callbacks >= 0) { int error = rpc_method_remove_callback_id(connection, callbacks[n_callbacks].id); if (error != RPC_ERROR_NO_ERROR) return error; } return RPC_ERROR_NO_ERROR; } /* ====================================================================== */ /* === Remote Procedure Call (method invocation) === */ /* ====================================================================== */ // Invoke remote procedure (client side) int rpc_method_invoke(rpc_connection_t *connection, int method, ...) { D(bug("rpc_method_invoke method=%d\n", method)); rpc_message_t message; int error; va_list args; if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->type != RPC_CONNECTION_CLIENT) return RPC_ERROR_CONNECTION_TYPE_MISMATCH; rpc_message_init(&message, connection); error = rpc_message_send_int32(&message, RPC_MESSAGE_START); if (error != RPC_ERROR_NO_ERROR) return error; error = rpc_message_send_int32(&message, method); if (error != RPC_ERROR_NO_ERROR) return error; va_start(args, method); error = rpc_message_send_args(&message, args); va_end(args); if (error != RPC_ERROR_NO_ERROR) return error; error = rpc_message_send_int32(&message, RPC_MESSAGE_END); if (error != RPC_ERROR_NO_ERROR) return error; error = rpc_message_flush(&message); if (error != RPC_ERROR_NO_ERROR) return error; return RPC_ERROR_NO_ERROR; } // Retrieve procedure arguments (server side) int rpc_method_get_args(rpc_connection_t *connection, ...) { D(bug("rpc_method_get_args\n")); int error; va_list args; rpc_message_t message; if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->type != RPC_CONNECTION_SERVER) return RPC_ERROR_CONNECTION_TYPE_MISMATCH; rpc_message_init(&message, connection); va_start(args, connection); error = rpc_message_recv_args(&message, args); va_end(args); return error; } // Wait for a reply from the remote procedure (client side) int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) { D(bug("rpc_method_wait_for_reply\n")); int error, type; int32_t ret; va_list args; rpc_message_t message; if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (connection->type != RPC_CONNECTION_CLIENT) return RPC_ERROR_CONNECTION_TYPE_MISMATCH; rpc_connection_set_status(connection, RPC_STATUS_BUSY); rpc_message_init(&message, connection); va_start(args, connection); type = va_arg(args, int); va_end(args); if (type != RPC_TYPE_INVALID) { error = rpc_message_recv_int32(&message, &ret); if (error != RPC_ERROR_NO_ERROR) return_error(error); if (ret != RPC_MESSAGE_REPLY) { D(bug("TRUNCATED 1 [%d]\n", ret)); return_error(RPC_ERROR_MESSAGE_TRUNCATED); } va_start(args, connection); error = rpc_message_recv_args(&message, args); va_end(args); if (error != RPC_ERROR_NO_ERROR) return_error(error); error = rpc_message_recv_int32(&message, &ret); if (error != RPC_ERROR_NO_ERROR) return_error(error); if (ret != RPC_MESSAGE_END) { D(bug("TRUNCATED 2 [%d]\n", ret)); return_error(RPC_ERROR_MESSAGE_TRUNCATED); } } error = rpc_message_recv_int32(&message, &ret); if (error != RPC_ERROR_NO_ERROR) return_error(error); if (ret != RPC_MESSAGE_ACK) { D(bug("TRUNCATED 3 [%d]\n", ret)); return_error(RPC_ERROR_MESSAGE_TRUNCATED); } return_error(RPC_ERROR_NO_ERROR); do_return: rpc_connection_set_status(connection, RPC_STATUS_IDLE); return error; } // Send a reply to the client (server side) int rpc_method_send_reply(rpc_connection_t *connection, ...) { D(bug("rpc_method_send_reply\n")); rpc_message_t message; int error; va_list args; if (connection == NULL) return RPC_ERROR_GENERIC; if (connection->type != RPC_CONNECTION_SERVER) return RPC_ERROR_GENERIC; rpc_message_init(&message, connection); error = rpc_message_send_int32(&message, RPC_MESSAGE_REPLY); if (error != RPC_ERROR_NO_ERROR) return error; va_start(args, connection); error = rpc_message_send_args(&message, args); va_end(args); if (error != RPC_ERROR_NO_ERROR) return error; error = rpc_message_send_int32(&message, RPC_MESSAGE_END); if (error != RPC_ERROR_NO_ERROR) return error; error = rpc_message_flush(&message); if (error != RPC_ERROR_NO_ERROR) return error; return RPC_ERROR_NO_ERROR; } BasiliskII/src/Unix/install-sh0000755000175000017500000001270107677046664016506 0ustar centriscentris#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else : fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f "$src" ] || [ -d "$src" ] then : else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else : fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else : fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else : fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else : fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 BasiliskII/src/Unix/autogen.sh0000755000175000017500000000310410633770314016456 0ustar centriscentris#! /bin/sh # Run this to generate all the initial makefiles, etc. # This was lifted from the Gimp, and adapted slightly by # Christian Bauer. DIE=0 PROG="Basilisk II" # Check how echo works in this /bin/sh case `echo -n` in -n) _echo_n= _echo_c='\c';; *) _echo_n=-n _echo_c=;; esac (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have autoconf installed to compile $PROG." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" DIE=1 } (aclocal --version) < /dev/null > /dev/null 2>&1 || { echo echo "**Error**: Missing aclocal. The version of automake" echo "installed doesn't appear recent enough." echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz" echo "(or a newer version if it is available)" DIE=1 } if test "$DIE" -eq 1; then exit 1 fi if test -z "$ACLOCAL_FLAGS"; then ACLOCAL_FLAGS="-I `aclocal --print-ac-dir` -I `dirname $0`/m4" fi aclocalinclude="$ACLOCAL_FLAGS"; \ (echo $_echo_n " + Running aclocal: $_echo_c"; \ aclocal $aclocalinclude; \ echo "done.") && \ (echo $_echo_n " + Running autoheader: $_echo_c"; \ autoheader; \ echo "done.") && \ (echo $_echo_n " + Running autoconf: $_echo_c"; \ autoconf; \ echo "done.") rm -f config.cache if [ x"$NO_CONFIGURE" = "x" ]; then echo " + Running 'configure $@':" if [ -z "$*" ]; then echo " ** If you wish to pass arguments to ./configure, please" echo " ** specify them on the command line." fi ./configure "$@" fi BasiliskII/src/Unix/config.sub0000755000175000017500000007201407677046664016470 0ustar centriscentris#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-01-03' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | s390 | s390x \ | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | s390-* | s390x-* \ | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic4x | c4x*) basic_machine=tic4x-unknown os=-coff ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -microbsd*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: BasiliskII/src/Unix/BasiliskII.10000644000175000017500000000350010000536525016512 0ustar centriscentris.TH BasiliskII 1 "January, 2002" .SH NAME Basilisk II \- a free, portable Mac II emulator .SH SYNOPSIS .B BasiliskII [\-\-display .IR display-name ] [\-\-break .IR offset ] [\-\-rominfo] .SH DESCRIPTION .B Basilisk II is a free, portable 68k Mac emulator. For more information, see the included "README" file. .SH OPTIONS .TP .BI "\-\-display " display-name specifies the display to use; see .BR X (1) .TP .BI "\-\-break " offset specifies a ROM offset where a breakpoint will be placed (for debugging) .TP .B \-\-rominfo causes Basilisk II to print some information about the ROM being used on startup (for debugging) .TP .B \-\-help shows a complete list of options .SH FILES .TP .I /usr/share/BasiliskII/keycodes X server keycodes definitions. .TP .I /usr/share/BasiliskII/fbdevices Framebuffer device specifications. .TP .I ~/.basilisk_ii_prefs User-specific configuration file. .TP .I ~/.basilisk_ii_xpram Contents of Mac non-volatile RAM. .SH BUGS Several. See the included "TODO" file. .SH SEE ALSO http://www.uni-mainz.de/~bauec002/B2Main.html (Basilisk II homepage) .SH AUTHOR Christian Bauer .SH COPYRIGHT Copyright \(co 1997-2004 Christian Bauer et al. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. BasiliskII/src/Unix/vhd_unix.h0000644000175000017500000000212211457207320016446 0ustar centriscentris/* * vhd_unix.h -- support for disk images in vhd format * * (C) 2010 Geoffrey Brown * * 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 */ #ifndef VHD_H #define VHD_H void *vhd_unix_open(const char *name, int *size, bool read_only); int vhd_unix_read(void *arg, void *buffer, loff_t offset, size_t length); int vhd_unix_write(void *arg, void *buffer, loff_t offset, size_t length); void vhd_unix_close(void *arg); #endif BasiliskII/src/Unix/cpr.sh0000755000175000017500000000326311147200623015576 0ustar centriscentris#!/bin/sh # A script to copy recursively ignoring detritus. # I based this off of a script I had that copied over ssh. # source can be a file or directory. # Mike Sliczniak 2009 # Don't copy resource forks or extended attributes on Mac OS X 10.4. COPY_EXTENDED_ATTRIBUTES_DISABLE=true; export COPY_EXTENDED_ATTRIBUTES_DISABLE # Don't copy resource forks or extended attributes on Mac OS X 10.5. COPYFILE_DISABLE=true; export COPYFILE_DISABLE case $# in 2) ;; *) echo "Usage: cpr source destdir" >&2 exit 2 ;; esac # dir and base names of the source d=`dirname "$1"` || exit b=`basename "$1"` || exit # handle relative and absolute destination dirs case "$2" in /*) p=$2 ;; *) p="$PWD"/"$2" ;; esac # cd into the source dir cd "$d" || exit # This is only for Mac OS X, but some systems do not have gtar, find # sometimes lacks -f, and other systems use test -a. # List all interesting files for tar to copy: # The first clause skips directories used for revision control. # The second clause ignores detritus files from revision control and OSs. # The third clause ignores ._ style files created by Mac OS X on file systems # that do not have native resource forks or extended attributes. It checks to # see that the file it is associated with exists. find -f "$b" \( \! \( -type d \( \ -name CVS -o -name RCS -o -name SCCS -o -name .git -o -name .svn \ \) -prune \) \) \ \ \( \! \( -type f \( \ -name .DS_Store -o -name Thumbs.db -o -name .cvsignore -o -name .gitignore \ \) \) \) \ \ \( \! \( \ -type f -name '._*' -execdir /bin/sh -c \ 'f=`echo "$1" | sed "s:^\._:./:"`; [ -e "$f" ]' /bin/sh '{}' \; \ \) \) -print0 | tar -c -f - --null -T - --no-recursion | tar -x -C "$p" -f - BasiliskII/src/Unix/mkinstalldirs0000755000175000017500000000341107677046664017306 0ustar centriscentris#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain errstatus=0 dirmode="" usage="\ Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." # process command line arguments while test $# -gt 0 ; do case "${1}" in -h | --help | --h* ) # -h for help echo "${usage}" 1>&2; exit 0 ;; -m ) # -m PERM arg shift test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; } dirmode="${1}" shift ;; -- ) shift; break ;; # stop option processing -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option * ) break ;; # first non-opt arg esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac case $dirmode in '') if mkdir -p -- . 2>/dev/null; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" fi ;; *) if mkdir -m "$dirmode" -p -- . 2>/dev/null; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" fi ;; esac for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr="" chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp="$pathcomp/" done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 3 # End: # mkinstalldirs ends here BasiliskII/src/Unix/ldscripts/0000755000175000017500000000000011735674761016503 5ustar centriscentrisBasiliskII/src/Unix/ldscripts/linux-ppc.ld0000644000175000017500000001740710411166202020724 0ustar centriscentris/* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") OUTPUT_ARCH(powerpc:common) ENTRY(_start) SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SECTIONS { /* Read-only sections, merged into text segment: */ . = 0x78048000 + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } .rel.dyn : { *(.rel.init) *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) *(.rel.fini) *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) *(.rel.data.rel.ro*) *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) *(.rel.ctors) *(.rel.dtors) *(.rel.got) *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } .rela.dyn : { *(.rela.init) *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) *(.rela.fini) *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) *(.rela.ctors) *(.rela.dtors) *(.rela.got) *(.rela.got1) *(.rela.got2) *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } .init : { KEEP (*(.init)) } =0 .text : { *(.text .stub .text.* .gnu.linkonce.t.*) KEEP (*(.text.*personality*)) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } =0 .fini : { KEEP (*(.fini)) } =0 PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } .eh_frame_hdr : { *(.eh_frame_hdr) } .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); /* Exception handling */ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } /* Thread Local Storage sections */ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but the linker would then create the section even if it turns out to be empty, which isn't pretty. */ . = ALIGN(32 / 8); PROVIDE (__preinit_array_start = .); .preinit_array : { KEEP (*(.preinit_array)) } PROVIDE (__preinit_array_end = .); PROVIDE (__init_array_start = .); .init_array : { KEEP (*(.init_array)) } PROVIDE (__init_array_end = .); PROVIDE (__fini_array_start = .); .fini_array : { KEEP (*(.fini_array)) } PROVIDE (__fini_array_end = .); .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin*.o(.ctors)) /* We don't want to include the .ctor section from from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin*.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } .jcr : { KEEP (*(.jcr)) } .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } .fixup : { *(.fixup) } .got1 : { *(.got1) } .got2 : { *(.got2) } .dynamic : { *(.dynamic) } . = DATA_SEGMENT_RELRO_END (0, .); .data : { *(.data .data.* .gnu.linkonce.d.*) KEEP (*(.gnu.linkonce.d.*personality*)) SORT(CONSTRUCTORS) } .data1 : { *(.data1) } .got1 : { *(.got1) } .got2 : { *(.got2) } .got : { *(.got.plt) *(.got) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ .sdata : { *(.sdata .sdata.* .gnu.linkonce.s.*) } _edata = .; PROVIDE (edata = .); __bss_start = .; .sbss : { PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .); *(.dynsbss) *(.sbss .sbss.* .gnu.linkonce.sb.*) *(.scommon) PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .); } .plt : { *(.plt) } .bss : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ . = ALIGN(32 / 8); } . = ALIGN(32 / 8); _end = .; PROVIDE (end = .); . = DATA_SEGMENT_END (.); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } /DISCARD/ : { *(.fixup) } } BasiliskII/src/Unix/ldscripts/linux-x86_64.ld0000644000175000017500000001472210400523337021101 0ustar centriscentris/* Default linker script, for normal executables */ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(_start) SEARCH_DIR("/lib64"); SEARCH_DIR("/usr/lib64"); SEARCH_DIR("/usr/local/lib64"); SECTIONS { /* Read-only sections, merged into text segment: */ . = 0x78048000 + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } .rel.init : { *(.rel.init) } .rela.init : { *(.rela.init) } .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } .rel.fini : { *(.rel.fini) } .rela.fini : { *(.rela.fini) } .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } .rel.ctors : { *(.rel.ctors) } .rela.ctors : { *(.rela.ctors) } .rel.dtors : { *(.rel.dtors) } .rela.dtors : { *(.rela.dtors) } .rel.got : { *(.rel.got) } .rela.got : { *(.rela.got) } .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } .init : { KEEP (*(.init)) } =0x90909090 .plt : { *(.plt) } .text : { *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } =0x90909090 .fini : { KEEP (*(.fini)) } =0x90909090 PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) } .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN (0x100000) - ((0x100000 - .) & (0x100000 - 1)); . = DATA_SEGMENT_ALIGN (0x100000, 0x1000); /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but the linker would then create the section even if it turns out to be empty, which isn't pretty. */ . = ALIGN(64 / 8); PROVIDE (__preinit_array_start = .); .preinit_array : { *(.preinit_array) } PROVIDE (__preinit_array_end = .); PROVIDE (__init_array_start = .); .init_array : { *(.init_array) } PROVIDE (__init_array_end = .); PROVIDE (__fini_array_start = .); .fini_array : { *(.fini_array) } PROVIDE (__fini_array_end = .); .data : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } .data1 : { *(.data1) } .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) } .dynamic : { *(.dynamic) } .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) /* We don't want to include the .ctor section from from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } .jcr : { KEEP (*(.jcr)) } .got : { *(.got.plt) *(.got) } _edata = .; PROVIDE (edata = .); __bss_start = .; .bss : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ . = ALIGN(64 / 8); } . = ALIGN(64 / 8); _end = .; PROVIDE (end = .); . = DATA_SEGMENT_END (.); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } BasiliskII/src/Unix/ldscripts/freebsd-i386.ld0000644000175000017500000001376710405735052021123 0ustar centriscentris/* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf32-i386-freebsd", "elf32-i386-freebsd", "elf32-i386-freebsd") OUTPUT_ARCH(i386) ENTRY(_start) SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); SECTIONS { /* Read-only sections, merged into text segment: */ . = 0x78048000 + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } .rel.dyn : { *(.rel.init) *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) *(.rel.fini) *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) *(.rel.ctors) *(.rel.dtors) *(.rel.got) *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } .rela.dyn : { *(.rela.init) *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) *(.rela.fini) *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) *(.rela.ctors) *(.rela.dtors) *(.rela.got) *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } .init : { KEEP (*(.init)) } =0x90909090 .plt : { *(.plt) } .text : { *(.text .stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) } =0x90909090 .fini : { KEEP (*(.fini)) } =0x90909090 PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .rodata1 : { *(.rodata1) } .eh_frame_hdr : { *(.eh_frame_hdr) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1)); . = DATA_SEGMENT_ALIGN (0x1000, 0x1000); /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but the linker would then create the section even if it turns out to be empty, which isn't pretty. */ . = ALIGN(32 / 8); PROVIDE (__preinit_array_start = .); .preinit_array : { *(.preinit_array) } PROVIDE (__preinit_array_end = .); PROVIDE (__init_array_start = .); .init_array : { *(.init_array) } PROVIDE (__init_array_end = .); PROVIDE (__fini_array_start = .); .fini_array : { *(.fini_array) } PROVIDE (__fini_array_end = .); .data : { *(.data .data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) } .data1 : { *(.data1) } .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } .eh_frame : { KEEP (*(.eh_frame)) } .gcc_except_table : { *(.gcc_except_table) } .dynamic : { *(.dynamic) } .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin*.o(.ctors)) /* We don't want to include the .ctor section from from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin*.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } .jcr : { KEEP (*(.jcr)) } .got : { *(.got.plt) *(.got) } _edata = .; PROVIDE (edata = .); __bss_start = .; .bss : { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ . = ALIGN(32 / 8); } . = ALIGN(32 / 8); _end = .; PROVIDE (end = .); . = DATA_SEGMENT_END (.); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } BasiliskII/src/Unix/ldscripts/linux-i386.ld0000644000175000017500000001046010400523337020627 0ustar centriscentrisOUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); ENTRY(_start) SECTIONS { /* Read-only sections, merged into text segment: */ . = 0x78048000 + SIZEOF_HEADERS; .interp : { *(.interp) } .hash : { *(.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } .gnu.version_d : { *(.gnu.version_d) } .gnu.version_r : { *(.gnu.version_r) } .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) } .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) } .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) } .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) } .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } .rel.got : { *(.rel.got) } .rela.got : { *(.rela.got) } .rel.ctors : { *(.rel.ctors) } .rela.ctors : { *(.rela.ctors) } .rel.dtors : { *(.rel.dtors) } .rela.dtors : { *(.rela.dtors) } .rel.init : { *(.rel.init) } .rela.init : { *(.rela.init) } .rel.fini : { *(.rel.fini) } .rela.fini : { *(.rela.fini) } .rel.bss : { *(.rel.bss) } .rela.bss : { *(.rela.bss) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } .init : { *(.init) } =0x47ff041f .text : { *(.text) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) *(.gnu.linkonce.t*) } =0x47ff041f _etext = .; PROVIDE (etext = .); .fini : { *(.fini) } =0x47ff041f . = ALIGN(32 / 8); PROVIDE (__preinit_array_start = .); .preinit_array : { *(.preinit_array) } PROVIDE (__preinit_array_end = .); PROVIDE (__init_array_start = .); .init_array : { *(.init_array) } PROVIDE (__init_array_end = .); PROVIDE (__fini_array_start = .); .fini_array : { *(.fini_array) } PROVIDE (__fini_array_end = .); .rodata : { *(.rodata) *(.gnu.linkonce.r*) } .rodata1 : { *(.rodata1) } .reginfo : { *(.reginfo) } /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ . = ALIGN(0x100000) + (. & (0x100000 - 1)); .data : { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } .data1 : { *(.data1) } .ctors : { *(.ctors) } .dtors : { *(.dtors) } .plt : { *(.plt) } .got : { *(.got.plt) *(.got) } .dynamic : { *(.dynamic) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ .sdata : { *(.sdata) } _edata = .; PROVIDE (edata = .); __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : { *(.dynbss) *(.bss) *(COMMON) } _end = . ; PROVIDE (end = .); /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } /* These must appear regardless of . */ } BasiliskII/src/Unix/ether_unix.cpp0000644000175000017500000005220011723575276017347 0ustar centriscentris/* * ether_unix.cpp - Ethernet device driver, Unix specific stuff (Linux and FreeBSD) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" /* * NOTES concerning MacOS X issues: * - poll() does not exist in 10.2.8, but is available in 10.4.4 * - select(), and very likely poll(), are not cancellation points. So * the ethernet thread doesn't stop on exit. An explicit check is * performed to workaround this problem. */ #if (defined __APPLE__ && defined __MACH__) || ! defined HAVE_POLL #define USE_POLL 0 #else #define USE_POLL 1 #endif // Define to let the slirp library determine the right timeout for select() #define USE_SLIRP_TIMEOUT 1 #ifdef HAVE_SYS_POLL_H #include #endif #include #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) || defined(sgi) || (defined(__APPLE__) && defined(__MACH__)) #include #endif #if defined(HAVE_LINUX_IF_H) && defined(HAVE_LINUX_IF_TUN_H) #include #include #endif #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_IF_TUN_H) #include #include #endif #ifdef HAVE_SLIRP #include "libslirp.h" #endif #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "ether.h" #include "ether_defs.h" #ifndef NO_STD_NAMESPACE using std::map; #endif #define DEBUG 0 #include "debug.h" #define STATISTICS 0 #define MONITOR 0 // Ethernet device types enum { NET_IF_SHEEPNET, NET_IF_ETHERTAP, NET_IF_TUNTAP, NET_IF_SLIRP }; // Constants static const char ETHERCONFIG_FILE_NAME[] = DATADIR "/tunconfig"; // Global variables static int fd = -1; // fd of sheep_net device static pthread_t ether_thread; // Packet reception thread static pthread_attr_t ether_thread_attr; // Packet reception thread attributes static bool thread_active = false; // Flag: Packet reception thread installed static sem_t int_ack; // Interrupt acknowledge semaphore static bool udp_tunnel; // Flag: UDP tunnelling active, fd is the socket descriptor static int net_if_type = -1; // Ethernet device type static char *net_if_name = NULL; // TUN/TAP device name static const char *net_if_script = NULL; // Network config script static pthread_t slirp_thread; // Slirp reception thread static bool slirp_thread_active = false; // Flag: Slirp reception threadinstalled static int slirp_output_fd = -1; // fd of slirp output pipe static int slirp_input_fds[2] = { -1, -1 }; // fds of slirp input pipe #ifdef SHEEPSHAVER static bool net_open = false; // Flag: initialization succeeded, network device open static uint8 ether_addr[6]; // Our Ethernet address #else const bool ether_driver_opened = true; // Flag: is the MacOS driver opened? #endif // Attached network protocols, maps protocol type to MacOS handler address static map net_protocols; // Prototypes static void *receive_func(void *arg); static void *slirp_receive_func(void *arg); static int16 ether_do_add_multicast(uint8 *addr); static int16 ether_do_del_multicast(uint8 *addr); static int16 ether_do_write(uint32 arg); static void ether_do_interrupt(void); /* * Start packet reception thread */ static bool start_thread(void) { if (sem_init(&int_ack, 0, 0) < 0) { printf("WARNING: Cannot init semaphore"); return false; } Set_pthread_attr(ðer_thread_attr, 1); thread_active = (pthread_create(ðer_thread, ðer_thread_attr, receive_func, NULL) == 0); if (!thread_active) { printf("WARNING: Cannot start Ethernet thread"); return false; } #ifdef HAVE_SLIRP if (net_if_type == NET_IF_SLIRP) { slirp_thread_active = (pthread_create(&slirp_thread, NULL, slirp_receive_func, NULL) == 0); if (!slirp_thread_active) { printf("WARNING: Cannot start slirp reception thread\n"); return false; } } #endif return true; } /* * Stop packet reception thread */ static void stop_thread(void) { #ifdef HAVE_SLIRP if (slirp_thread_active) { #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(slirp_thread); #endif pthread_join(slirp_thread, NULL); slirp_thread_active = false; } #endif if (thread_active) { #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(ether_thread); #endif pthread_join(ether_thread, NULL); sem_destroy(&int_ack); thread_active = false; } } /* * Execute network script up|down */ static bool execute_network_script(const char *action) { if (net_if_script == NULL || net_if_name == NULL) return false; int pid = fork(); if (pid >= 0) { if (pid == 0) { char *args[4]; args[0] = (char *)net_if_script; args[1] = net_if_name; args[2] = (char *)action; args[3] = NULL; execv(net_if_script, args); exit(1); } int status; while (waitpid(pid, &status, 0) != pid); return WIFEXITED(status) && WEXITSTATUS(status) == 0; } return false; } /* * Initialization */ bool ether_init(void) { int val; char str[256]; // Do nothing if no Ethernet device specified const char *name = PrefsFindString("ether"); if (name == NULL) return false; // Determine Ethernet device type net_if_type = -1; if (strncmp(name, "tap", 3) == 0) net_if_type = NET_IF_ETHERTAP; #if ENABLE_TUNTAP else if (strcmp(name, "tun") == 0) net_if_type = NET_IF_TUNTAP; #endif #ifdef HAVE_SLIRP else if (strcmp(name, "slirp") == 0) net_if_type = NET_IF_SLIRP; #endif else net_if_type = NET_IF_SHEEPNET; // Don't raise SIGPIPE, let errno be set to EPIPE struct sigaction sigpipe_sa; if (sigaction(SIGPIPE, NULL, &sigpipe_sa) == 0) { assert(sigpipe_sa.sa_handler == SIG_DFL || sigpipe_sa.sa_handler == SIG_IGN); sigfillset(&sigpipe_sa.sa_mask); sigpipe_sa.sa_flags = 0; sigpipe_sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sigpipe_sa, NULL); } #ifdef HAVE_SLIRP // Initialize slirp library if (net_if_type == NET_IF_SLIRP) { if (slirp_init() < 0) { sprintf(str, GetString(STR_SLIRP_NO_DNS_FOUND_WARN)); WarningAlert(str); return false; } // Open slirp output pipe int fds[2]; if (pipe(fds) < 0) return false; fd = fds[0]; slirp_output_fd = fds[1]; // Open slirp input pipe if (pipe(slirp_input_fds) < 0) return false; } #endif // Open sheep_net or ethertap or TUN/TAP device char dev_name[16]; switch (net_if_type) { case NET_IF_ETHERTAP: sprintf(dev_name, "/dev/%s", name); break; case NET_IF_TUNTAP: strcpy(dev_name, "/dev/net/tun"); break; case NET_IF_SHEEPNET: strcpy(dev_name, "/dev/sheep_net"); break; } if (net_if_type != NET_IF_SLIRP) { fd = open(dev_name, O_RDWR); if (fd < 0) { sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno)); WarningAlert(str); goto open_error; } } #if ENABLE_TUNTAP // Open TUN/TAP interface if (net_if_type == NET_IF_TUNTAP) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strcpy(ifr.ifr_name, "tun%d"); if (ioctl(fd, TUNSETIFF, (void *) &ifr) != 0) { sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno)); WarningAlert(str); goto open_error; } // Get network config script file path net_if_script = PrefsFindString("etherconfig"); if (net_if_script == NULL) net_if_script = ETHERCONFIG_FILE_NAME; // Start network script up if (net_if_script == NULL) { sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script not found"); WarningAlert(str); goto open_error; } net_if_name = strdup(ifr.ifr_name); if (!execute_network_script("up")) { sprintf(str, GetString(STR_TUN_TAP_CONFIG_WARN), "script execute error"); WarningAlert(str); goto open_error; } D(bug("Connected to host network interface: %s\n", net_if_name)); } #endif #if defined(__linux__) // Attach sheep_net to selected Ethernet card if (net_if_type == NET_IF_SHEEPNET && ioctl(fd, SIOCSIFLINK, name) < 0) { sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno)); WarningAlert(str); goto open_error; } #endif // Set nonblocking I/O #ifdef USE_FIONBIO int nonblock = 1; if (ioctl(fd, FIONBIO, &nonblock) < 0) { sprintf(str, GetString(STR_BLOCKING_NET_SOCKET_WARN), strerror(errno)); WarningAlert(str); goto open_error; } #else val = fcntl(fd, F_GETFL, 0); if (val < 0 || fcntl(fd, F_SETFL, val | O_NONBLOCK) < 0) { sprintf(str, GetString(STR_BLOCKING_NET_SOCKET_WARN), strerror(errno)); WarningAlert(str); goto open_error; } #endif // Get Ethernet address if (net_if_type == NET_IF_ETHERTAP) { pid_t p = getpid(); // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID ether_addr[0] = 0xfe; ether_addr[1] = 0xfd; ether_addr[2] = p >> 24; ether_addr[3] = p >> 16; ether_addr[4] = p >> 8; ether_addr[5] = p; #ifdef HAVE_SLIRP } else if (net_if_type == NET_IF_SLIRP) { ether_addr[0] = 0x52; ether_addr[1] = 0x54; ether_addr[2] = 0x00; ether_addr[3] = 0x12; ether_addr[4] = 0x34; ether_addr[5] = 0x56; #endif } else ioctl(fd, SIOCGIFADDR, ether_addr); D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); // Start packet reception thread if (!start_thread()) goto open_error; // Everything OK return true; open_error: stop_thread(); if (fd > 0) { close(fd); fd = -1; } if (slirp_input_fds[0] >= 0) { close(slirp_input_fds[0]); slirp_input_fds[0] = -1; } if (slirp_input_fds[1] >= 0) { close(slirp_input_fds[1]); slirp_input_fds[1] = -1; } if (slirp_output_fd >= 0) { close(slirp_output_fd); slirp_output_fd = -1; } return false; } /* * Deinitialization */ void ether_exit(void) { // Stop reception threads stop_thread(); // Shut down TUN/TAP interface if (net_if_type == NET_IF_TUNTAP) execute_network_script("down"); // Free TUN/TAP device name if (net_if_name) free(net_if_name); // Close sheep_net device if (fd > 0) close(fd); // Close slirp input buffer if (slirp_input_fds[0] >= 0) close(slirp_input_fds[0]); if (slirp_input_fds[1] >= 0) close(slirp_input_fds[1]); // Close slirp output buffer if (slirp_output_fd > 0) close(slirp_output_fd); #if STATISTICS // Show statistics printf("%ld messages put on write queue\n", num_wput); printf("%ld error acks\n", num_error_acks); printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets); printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full); printf("%ld packets received\n", num_rx_packets); printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind); printf("EtherIRQ called %ld times\n", num_ether_irq); printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem); printf("%ld rx packets dropped because no stream found\n", num_rx_dropped); printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready); printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem); #endif } /* * Glue around low-level implementation */ #ifdef SHEEPSHAVER // Error codes enum { eMultiErr = -91, eLenErr = -92, lapProtErr = -94, excessCollsns = -95 }; // Initialize ethernet void EtherInit(void) { net_open = false; // Do nothing if the user disabled the network if (PrefsFindBool("nonet")) return; net_open = ether_init(); } // Exit ethernet void EtherExit(void) { ether_exit(); net_open = false; } // Get ethernet hardware address void AO_get_ethernet_address(uint32 arg) { uint8 *addr = Mac2HostAddr(arg); if (net_open) OTCopy48BitAddress(ether_addr, addr); else { addr[0] = 0x12; addr[1] = 0x34; addr[2] = 0x56; addr[3] = 0x78; addr[4] = 0x9a; addr[5] = 0xbc; } D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5])); } // Add multicast address void AO_enable_multicast(uint32 addr) { if (net_open) ether_do_add_multicast(Mac2HostAddr(addr)); } // Disable multicast address void AO_disable_multicast(uint32 addr) { if (net_open) ether_do_del_multicast(Mac2HostAddr(addr)); } // Transmit one packet void AO_transmit_packet(uint32 mp) { if (net_open) { switch (ether_do_write(mp)) { case noErr: num_tx_packets++; break; case excessCollsns: num_tx_buffer_full++; break; } } } // Copy packet data from message block to linear buffer static inline int ether_arg_to_buffer(uint32 mp, uint8 *p) { return ether_msgb_to_buffer(mp, p); } // Ethernet interrupt void EtherIRQ(void) { D(bug("EtherIRQ\n")); num_ether_irq++; OTEnterInterrupt(); ether_do_interrupt(); OTLeaveInterrupt(); // Acknowledge interrupt to reception thread D(bug(" EtherIRQ done\n")); sem_post(&int_ack); } #else // Add multicast address int16 ether_add_multicast(uint32 pb) { return ether_do_add_multicast(Mac2HostAddr(pb + eMultiAddr)); } // Disable multicast address int16 ether_del_multicast(uint32 pb) { return ether_do_del_multicast(Mac2HostAddr(pb + eMultiAddr)); } // Transmit one packet int16 ether_write(uint32 wds) { return ether_do_write(wds); } // Copy packet data from WDS to linear buffer static inline int ether_arg_to_buffer(uint32 wds, uint8 *p) { return ether_wds_to_buffer(wds, p); } // Dispatch packet to protocol handler static void ether_dispatch_packet(uint32 p, uint32 length) { // Get packet type uint16 type = ReadMacInt16(p + 12); // Look for protocol uint16 search_type = (type <= 1500 ? 0 : type); if (net_protocols.find(search_type) == net_protocols.end()) return; uint32 handler = net_protocols[search_type]; // No default handler if (handler == 0) return; // Copy header to RHA Mac2Mac_memcpy(ether_data + ed_RHA, p, 14); D(bug(" header %08x%04x %08x%04x %04x\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12))); // Call protocol handler M68kRegisters r; r.d[0] = type; // Packet type r.d[1] = length - 14; // Remaining packet length (without header, for ReadPacket) r.a[0] = p + 14; // Pointer to packet (Mac address, for ReadPacket) r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines D(bug(" calling protocol handler %08x, type %08x, length %08x, data %08x, rha %08x, read_packet %08x\n", handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4])); Execute68k(handler, &r); } // Ethernet interrupt void EtherInterrupt(void) { D(bug("EtherIRQ\n")); ether_do_interrupt(); // Acknowledge interrupt to reception thread D(bug(" EtherIRQ done\n")); sem_post(&int_ack); } #endif /* * Reset */ void ether_reset(void) { net_protocols.clear(); } /* * Add multicast address */ static int16 ether_do_add_multicast(uint8 *addr) { switch (net_if_type) { case NET_IF_ETHERTAP: case NET_IF_SHEEPNET: if (ioctl(fd, SIOCADDMULTI, addr) < 0) { D(bug("WARNING: Couldn't enable multicast address\n")); if (net_if_type == NET_IF_ETHERTAP) return noErr; else return eMultiErr; } default: return noErr; } } /* * Delete multicast address */ static int16 ether_do_del_multicast(uint8 *addr) { switch (net_if_type) { case NET_IF_ETHERTAP: case NET_IF_SHEEPNET: if (ioctl(fd, SIOCDELMULTI, addr) < 0) { D(bug("WARNING: Couldn't disable multicast address\n")); return eMultiErr; } default: return noErr; } } /* * Attach protocol handler */ int16 ether_attach_ph(uint16 type, uint32 handler) { if (net_protocols.find(type) != net_protocols.end()) return lapProtErr; net_protocols[type] = handler; return noErr; } /* * Detach protocol handler */ int16 ether_detach_ph(uint16 type) { if (net_protocols.erase(type) == 0) return lapProtErr; return noErr; } /* * Transmit raw ethernet packet */ static int16 ether_do_write(uint32 arg) { // Copy packet to buffer uint8 packet[1516], *p = packet; int len = 0; #if defined(__linux__) if (net_if_type == NET_IF_ETHERTAP) { *p++ = 0; // Linux ethertap discards the first 2 bytes *p++ = 0; len += 2; } #endif len += ether_arg_to_buffer(arg, p); #if MONITOR bug("Sending Ethernet packet:\n"); for (int i=0; i 0) { int len; read(slirp_input_fd, &len, sizeof(len)); uint8 packet[1516]; assert(len <= sizeof(packet)); read(slirp_input_fd, packet, len); slirp_input(packet, len); } // ... in the output queue nfds = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); int timeout = slirp_select_fill(&nfds, &rfds, &wfds, &xfds); #if ! USE_SLIRP_TIMEOUT timeout = 10000; #endif tv.tv_sec = 0; tv.tv_usec = timeout; if (select(nfds + 1, &rfds, &wfds, &xfds, &tv) >= 0) slirp_select_poll(&rfds, &wfds, &xfds); #ifdef HAVE_PTHREAD_TESTCANCEL // Explicit cancellation point if select() was not covered // This seems to be the case on MacOS X 10.2 pthread_testcancel(); #endif } return NULL; } #else int slirp_can_output(void) { return 0; } void slirp_output(const uint8 *packet, int len) { } #endif /* * Packet reception thread */ static void *receive_func(void *arg) { for (;;) { // Wait for packets to arrive #if USE_POLL struct pollfd pf = {fd, POLLIN, 0}; int res = poll(&pf, 1, -1); #else fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds); // A NULL timeout could cause select() to block indefinitely, // even if it is supposed to be a cancellation point [MacOS X] struct timeval tv = { 0, 20000 }; int res = select(fd + 1, &rfds, NULL, NULL, &tv); #ifdef HAVE_PTHREAD_TESTCANCEL pthread_testcancel(); #endif if (res == 0 || (res == -1 && errno == EINTR)) continue; #endif if (res <= 0) break; if (ether_driver_opened) { // Trigger Ethernet interrupt D(bug(" packet received, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); // Wait for interrupt acknowledge by EtherInterrupt() sem_wait(&int_ack); } else Delay_usec(20000); } return NULL; } /* * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers */ void ether_do_interrupt(void) { // Call protocol handler for received packets EthernetPacket ether_packet; uint32 packet = ether_packet.addr(); ssize_t length; for (;;) { #ifndef SHEEPSHAVER if (udp_tunnel) { // Read packet from socket struct sockaddr_in from; socklen_t from_len = sizeof(from); length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len); if (length < 14) break; ether_udp_read(packet, length, &from); } else #endif { // Read packet from sheep_net device #if defined(__linux__) length = read(fd, Mac2HostAddr(packet), net_if_type == NET_IF_ETHERTAP ? 1516 : 1514); #else length = read(fd, Mac2HostAddr(packet), 1514); #endif if (length < 14) break; #if MONITOR bug("Receiving Ethernet packet:\n"); for (int i=0; i /dev/null 2>&1 define SRCS_LIST_TO_OBJS $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(SRCS), \ $(basename $(notdir $(file)))))) endef OBJS = $(SRCS_LIST_TO_OBJS) define GUI_SRCS_LIST_TO_OBJS $(addprefix $(OBJ_DIR)/, $(addsuffix .go, $(foreach file, $(GUI_SRCS), \ $(basename $(notdir $(file)))))) endef GUI_OBJS = $(GUI_SRCS_LIST_TO_OBJS) SRC_PATHS += $(sort $(foreach file, $(SRCS), $(dir $(file)))) VPATH := VPATH += $(addprefix :, $(subst ,:, $(filter-out $($(subst, :, ,$(VPATH))), $(SRC_PATHS)))) $(APP)$(EXEEXT): $(OBJ_DIR) $(OBJS) $(CXX) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) $(BLESS) $(APP)$(EXEEXT) $(GUI_APP)$(EXEEXT): $(OBJ_DIR) $(GUI_OBJS) $(CXX) -o $@ $(LDFLAGS) $(GUI_OBJS) $(GUI_LIBS) $(APP)_app: $(APP) ../MacOSX/Info.plist ../MacOSX/$(APP).icns rm -rf $(APP_APP)/Contents mkdir -p $(APP_APP)/Contents ./cpr.sh ../MacOSX/Info.plist $(APP_APP)/Contents/ echo -n 'APPL????' > $(APP_APP)/Contents/PkgInfo mkdir -p $(APP_APP)/Contents/MacOS ./cpr.sh $(APP) $(APP_APP)/Contents/MacOS/ strip -x $(APP_APP)/Contents/MacOS/$(APP) mkdir -p $(APP_APP)/Contents/Resources ./cpr.sh ../MacOSX/$(APP).icns $(APP_APP)/Contents/Resources/ $(GUI_APP)_app: $(GUI_APP) ../MacOSX/Info.plist ../MacOSX/$(APP).icns rm -rf $(GUI_APP_APP)/Contents mkdir -p $(GUI_APP_APP)/Contents sed -e "s/$(APP)/$(GUI_APP)/" < ../MacOSX/Info.plist > $(GUI_APP_APP)/Contents/Info.plist echo -n 'APPL????' > $(GUI_APP_APP)/Contents/PkgInfo mkdir -p $(GUI_APP_APP)/Contents/MacOS ./cpr.sh $(GUI_APP) $(GUI_APP_APP)/Contents/MacOS/ strip -x $(GUI_APP_APP)/Contents/MacOS/$(GUI_APP) mkdir -p $(GUI_APP_APP)/Contents/Resources ./cpr.sh ../MacOSX/$(APP).icns $(GUI_APP_APP)/Contents/Resources/$(GUI_APP).icns modules: cd Linux/NetDriver; make install: $(PROGS) installdirs $(INSTALL_PROGRAM) $(APP)$(EXEEXT) $(DESTDIR)$(bindir)/$(APP)$(EXEEXT) if test -f "$(GUI_APP)$(EXEEXT)"; then \ $(INSTALL_PROGRAM) $(GUI_APP)$(EXEEXT) $(DESTDIR)$(bindir)/$(GUI_APP)$(EXEEXT); \ fi -$(INSTALL_DATA) $(APP).1 $(DESTDIR)$(man1dir)/$(APP).1 $(INSTALL_DATA) $(KEYCODES) $(DESTDIR)$(datadir)/$(APP)/keycodes $(INSTALL_DATA) fbdevices $(DESTDIR)$(datadir)/$(APP)/fbdevices $(INSTALL_DATA) tunconfig $(DESTDIR)$(datadir)/$(APP)/tunconfig installdirs: $(SHELL) mkinstalldirs $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir) $(DESTDIR)$(datadir)/$(APP) uninstall: rm -f $(DESTDIR)$(bindir)/$(APP)$(EXEEXT) rm -f $(DESTDIR)$(bindir)/$(GUI_APP)$(EXEEXT) rm -f $(DESTDIR)$(man1dir)/$(APP).1 rm -f $(DESTDIR)$(datadir)/$(APP)/keycodes rm -f $(DESTDIR)$(datadir)/$(APP)/fbdevices rm -f $(DESTDIR)$(datadir)/$(APP)/tunconfig rmdir $(DESTDIR)$(datadir)/$(APP) mostlyclean: rm -f $(PROGS) $(OBJ_DIR)/* core* *.core *~ *.bak clean: mostlyclean rm -f cpuemu.cpp cpudefs.cpp cputmp*.s cpufast*.s cpustbl.cpp cputbl.h compemu.cpp compstbl.cpp comptbl.h distclean: clean rm -rf $(OBJ_DIR) rm -rf autom4te.cache rm -f Makefile rm -f config.cache config.log config.status config.h rm -f Darwin/lowmem Darwin/pagezero depend dep: makedepend $(CPPFLAGS) -Y. $(SRCS) 2>/dev/null $(OBJ_DIR)/SDLMain.o : SDLMain.m $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : ../slirp/%.c $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) $(SLIRP_CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.c $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.mm $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.s $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.go : %.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) $(GUI_CFLAGS) -DSTANDALONE_GUI -c $< -o $@ # Windows resources $(OBJ_DIR)/%.o: %.rc windres --include-dir ../Windows -i $< -o $@ $(OBJ_DIR)/build68k$(EXEEXT): $(OBJ_DIR)/build68k.o $(CC) $(LDFLAGS) -o $(OBJ_DIR)/build68k$(EXEEXT) $(OBJ_DIR)/build68k.o $(OBJ_DIR)/gencpu$(EXEEXT): $(OBJ_DIR)/gencpu.o $(OBJ_DIR)/readcpu.o $(OBJ_DIR)/cpudefs.o $(CXX) $(LDFLAGS) -o $(OBJ_DIR)/gencpu$(EXEEXT) $(OBJ_DIR)/gencpu.o $(OBJ_DIR)/readcpu.o $(OBJ_DIR)/cpudefs.o $(OBJ_DIR)/gencomp$(EXEEXT): $(OBJ_DIR)/gencomp.o $(OBJ_DIR)/readcpu.o $(OBJ_DIR)/cpudefs.o $(CXX) $(LDFLAGS) -o $(OBJ_DIR)/gencomp$(EXEEXT) $(OBJ_DIR)/gencomp.o $(OBJ_DIR)/readcpu.o $(OBJ_DIR)/cpudefs.o cpudefs.cpp: $(OBJ_DIR)/build68k$(EXEEXT) ../uae_cpu/table68k $(OBJ_DIR)/build68k$(EXEEXT) <../uae_cpu/table68k >cpudefs.cpp cpustbl.cpp: cpuemu.cpp cpustbl_nf.cpp: cpustbl.cpp compstbl.cpp: compemu.cpp cputbl.h: cpuemu.cpp comptbl.h: compemu.cpp cpuemu.cpp: $(OBJ_DIR)/gencpu$(EXEEXT) $(OBJ_DIR)/gencpu$(EXEEXT) compemu.cpp: $(OBJ_DIR)/gencomp$(EXEEXT) $(OBJ_DIR)/gencomp$(EXEEXT) $(OBJ_DIR)/cpustbl_nf.o: cpustbl.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -DNOFLAGS -c $< -o $@ $(OBJ_DIR)/compemu_support.o: compemu_support.cpp comptbl.h $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu1.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu2.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu3.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu4.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu5.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu6.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu7.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu8.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu1_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu2_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu3_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu4_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu5_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu6_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu7_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu8_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu1.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu2.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu3.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu4.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu5.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu6.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu7.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu8.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 $(CXXFLAGS) -c $< -o $@ #------------------------------------------------------------------------- # DO NOT DELETE THIS LINE -- make depend depends on it. BasiliskII/src/Unix/video_x.cpp0000644000175000017500000021636311340220152016615 0ustar centriscentris/* * video_x.cpp - Video/graphics emulation, X11 specific stuff * * Basilisk II (C) Christian Bauer * * 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 */ /* * NOTES: * The Ctrl key works like a qualifier for special actions: * Ctrl-Tab = suspend DGA mode * Ctrl-Esc = emergency quit * Ctrl-F1 = mount floppy * Ctrl-F5 = grab mouse (in windowed mode) */ #include "sysdeps.h" #include #include #include #include #include #include #include #include #ifdef HAVE_PTHREADS # include #endif #ifdef ENABLE_XF86_DGA # include #endif #ifdef ENABLE_XF86_VIDMODE # include #endif #ifdef ENABLE_FBDEV_DGA # include #endif #include "cpu_emulation.h" #include "main.h" #include "adb.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "video.h" #include "video_blit.h" #define DEBUG 0 #include "debug.h" // Supported video modes static vector VideoModes; // Display types enum { DISPLAY_WINDOW, // X11 window, using MIT SHM extensions if possible DISPLAY_DGA // DGA fullscreen display }; // Constants const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes"; static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask | StructureNotifyMask; static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask; // Global variables static int32 frame_skip; // Prefs items static int16 mouse_wheel_mode; static int16 mouse_wheel_lines; static int display_type = DISPLAY_WINDOW; // See enum above static bool local_X11; // Flag: X server running on local machine? static uint8 *the_buffer = NULL; // Mac frame buffer (where MacOS draws into) static uint8 *the_buffer_copy = NULL; // Copy of Mac frame buffer (for refreshed modes) static uint32 the_buffer_size; // Size of allocated the_buffer static bool redraw_thread_active = false; // Flag: Redraw thread installed #ifdef HAVE_PTHREADS static pthread_attr_t redraw_thread_attr; // Redraw thread attributes static volatile bool redraw_thread_cancel; // Flag: Cancel Redraw thread static volatile bool redraw_thread_cancel_ack; // Flag: Acknowledge for redraw thread cancellation static pthread_t redraw_thread; // Redraw thread #endif static bool has_dga = false; // Flag: Video DGA capable static bool has_vidmode = false; // Flag: VidMode extension available #ifdef ENABLE_VOSF static bool use_vosf = true; // Flag: VOSF enabled #else static const bool use_vosf = false; // VOSF not possible #endif static bool ctrl_down = false; // Flag: Ctrl key pressed static bool caps_on = false; // Flag: Caps Lock on static bool quit_full_screen = false; // Flag: DGA close requested from redraw thread static bool emerg_quit = false; // Flag: Ctrl-Esc pressed, emergency quit requested from MacOS thread static bool emul_suspended = false; // Flag: Emulator suspended static bool classic_mode = false; // Flag: Classic Mac video mode static bool use_keycodes = false; // Flag: Use keycodes rather than keysyms static int keycode_table[256]; // X keycode -> Mac keycode translation table // X11 variables char *x_display_name = NULL; // X11 display name Display *x_display = NULL; // X11 display handle static int screen; // Screen number static Window rootwin; // Root window and our window static int num_depths = 0; // Number of available X depths static int *avail_depths = NULL; // List of available X depths static XColor black, white; static unsigned long black_pixel, white_pixel; static int eventmask; static int xdepth; // Depth of X screen static VisualFormat visualFormat; static XVisualInfo visualInfo; static Visual *vis; static int color_class; static bool x_native_byte_order; // XImage has native byte order? static int rshift, rloss, gshift, gloss, bshift, bloss; // Pixel format of DirectColor/TrueColor modes static Colormap cmap[2] = {0, 0}; // Colormaps for indexed modes (DGA needs two of them) static XColor x_palette[256]; // Color palette to be used as CLUT and gamma table static bool x_palette_changed = false; // Flag: Palette changed, redraw thread must set new colors #ifdef ENABLE_FBDEV_DGA static int fbdev_fd = -1; #endif #ifdef ENABLE_XF86_VIDMODE static XF86VidModeModeInfo **x_video_modes = NULL; // Array of all available modes static int num_x_video_modes; #endif // Mutex to protect palette #ifdef HAVE_PTHREADS static pthread_mutex_t x_palette_lock = PTHREAD_MUTEX_INITIALIZER; #define LOCK_PALETTE pthread_mutex_lock(&x_palette_lock) #define UNLOCK_PALETTE pthread_mutex_unlock(&x_palette_lock) #else #define LOCK_PALETTE #define UNLOCK_PALETTE #endif // Mutex to protect frame buffer #ifdef HAVE_PTHREADS static pthread_mutex_t frame_buffer_lock = PTHREAD_MUTEX_INITIALIZER; #define LOCK_FRAME_BUFFER pthread_mutex_lock(&frame_buffer_lock); #define UNLOCK_FRAME_BUFFER pthread_mutex_unlock(&frame_buffer_lock); #else #define LOCK_FRAME_BUFFER #define UNLOCK_FRAME_BUFFER #endif // Variables for non-VOSF incremental refresh static const int sm_uptd[] = {4,1,6,3,0,5,2,7}; static int sm_no_boxes[] = {1,8,32,64,128,300}; static bool updt_box[17][17]; static int nr_boxes; // Video refresh function static void VideoRefreshInit(void); static void (*video_refresh)(void); // Prototypes static void *redraw_func(void *arg); // From main_unix.cpp extern char *x_display_name; extern Display *x_display; // From sys_unix.cpp extern void SysMountFirstFloppy(void); // From clip_unix.cpp extern void ClipboardSelectionClear(XSelectionClearEvent *); extern void ClipboardSelectionRequest(XSelectionRequestEvent *); /* * monitor_desc subclass for X11 display */ class X11_monitor_desc : public monitor_desc { public: X11_monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id) : monitor_desc(available_modes, default_depth, default_id) {} ~X11_monitor_desc() {} virtual void switch_to_current_mode(void); virtual void set_palette(uint8 *pal, int num); bool video_open(void); void video_close(void); }; /* * Utility functions */ // Map video_mode depth ID to numerical depth value static inline int depth_of_video_mode(video_mode const & mode) { int depth = -1; switch (mode.depth) { case VDEPTH_1BIT: depth = 1; break; case VDEPTH_2BIT: depth = 2; break; case VDEPTH_4BIT: depth = 4; break; case VDEPTH_8BIT: depth = 8; break; case VDEPTH_16BIT: depth = 16; break; case VDEPTH_32BIT: depth = 32; break; default: abort(); } return depth; } // Map RGB color to pixel value (this only works in TrueColor/DirectColor visuals) static inline uint32 map_rgb(uint8 red, uint8 green, uint8 blue, bool fix_byte_order = false) { uint32 val = ((red >> rloss) << rshift) | ((green >> gloss) << gshift) | ((blue >> bloss) << bshift); if (fix_byte_order && !x_native_byte_order) { // We have to fix byte order in the ExpandMap[] // NOTE: this is only an optimization since Screen_blitter_init() // could be arranged to choose an NBO or OBO (with // byteswapping) Blit_Expand_X_To_Y() function switch (visualFormat.depth) { case 15: case 16: val = do_byteswap_16(val); break; case 24: case 32: val = do_byteswap_32(val); break; } } return val; } // Do we have a visual for handling the specified Mac depth? If so, set the // global variables "xdepth", "visualInfo", "vis" and "color_class". static bool find_visual_for_depth(video_depth depth) { D(bug("have_visual_for_depth(%d)\n", 1 << depth)); // 1-bit works always and uses default visual if (depth == VDEPTH_1BIT) { vis = DefaultVisual(x_display, screen); visualInfo.visualid = XVisualIDFromVisual(vis); int num = 0; XVisualInfo *vi = XGetVisualInfo(x_display, VisualIDMask, &visualInfo, &num); visualInfo = vi[0]; XFree(vi); xdepth = visualInfo.depth; color_class = visualInfo.c_class; D(bug(" found visual ID 0x%02x, depth %d\n", visualInfo.visualid, xdepth)); return true; } // Calculate minimum and maximum supported X depth int min_depth = 1, max_depth = 32; switch (depth) { #ifdef ENABLE_VOSF case VDEPTH_2BIT: case VDEPTH_4BIT: // VOSF blitters can convert 2/4/8-bit -> 8/16/32-bit case VDEPTH_8BIT: min_depth = 8; max_depth = 32; break; #else case VDEPTH_2BIT: case VDEPTH_4BIT: // 2/4-bit requires VOSF blitters return false; case VDEPTH_8BIT: // 8-bit without VOSF requires an 8-bit visual min_depth = 8; max_depth = 8; break; #endif case VDEPTH_16BIT: // 16-bit requires a 15/16-bit visual min_depth = 15; max_depth = 16; break; case VDEPTH_32BIT: // 32-bit requires a 24/32-bit visual min_depth = 24; max_depth = 32; break; } D(bug(" minimum required X depth is %d, maximum supported X depth is %d\n", min_depth, max_depth)); // Try to find a visual for one of the color depths bool visual_found = false; for (int i=0; i max_depth) continue; // Determine best color class for this depth switch (xdepth) { case 1: // Try StaticGray or StaticColor if (XMatchVisualInfo(x_display, screen, xdepth, StaticGray, &visualInfo) || XMatchVisualInfo(x_display, screen, xdepth, StaticColor, &visualInfo)) visual_found = true; break; case 8: // Need PseudoColor if (XMatchVisualInfo(x_display, screen, xdepth, PseudoColor, &visualInfo)) visual_found = true; break; case 15: case 16: case 24: case 32: // Try DirectColor first, as this will allow gamma correction if (XMatchVisualInfo(x_display, screen, xdepth, DirectColor, &visualInfo) || XMatchVisualInfo(x_display, screen, xdepth, TrueColor, &visualInfo)) visual_found = true; break; default: D(bug(" not a supported depth\n")); break; } } if (!visual_found) return false; // Visual was found vis = visualInfo.visual; color_class = visualInfo.c_class; D(bug(" found visual ID 0x%02x, depth %d, class ", visualInfo.visualid, xdepth)); #if DEBUG switch (color_class) { case StaticGray: D(bug("StaticGray\n")); break; case GrayScale: D(bug("GrayScale\n")); break; case StaticColor: D(bug("StaticColor\n")); break; case PseudoColor: D(bug("PseudoColor\n")); break; case TrueColor: D(bug("TrueColor\n")); break; case DirectColor: D(bug("DirectColor\n")); break; } #endif return true; } // Add mode to list of supported modes static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth) { video_mode mode; mode.x = width; mode.y = height; mode.resolution_id = resolution_id; mode.bytes_per_row = bytes_per_row; mode.depth = depth; VideoModes.push_back(mode); } // Add standard list of windowed modes for given color depth static void add_window_modes(video_depth depth) { add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth); add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth); add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth); add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth), depth); add_mode(1152, 870, 0x84, TrivialBytesPerRow(1152, depth), depth); add_mode(1280, 1024, 0x85, TrivialBytesPerRow(1280, depth), depth); add_mode(1600, 1200, 0x86, TrivialBytesPerRow(1600, depth), depth); } // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac) static void set_mac_frame_buffer(X11_monitor_desc &monitor, video_depth depth, bool native_byte_order) { #if !REAL_ADDRESSING && !DIRECT_ADDRESSING int layout = FLAYOUT_DIRECT; if (depth == VDEPTH_16BIT) layout = (xdepth == 15) ? FLAYOUT_HOST_555 : FLAYOUT_HOST_565; else if (depth == VDEPTH_32BIT) layout = (xdepth == 24) ? FLAYOUT_HOST_888 : FLAYOUT_DIRECT; if (native_byte_order) MacFrameLayout = layout; else MacFrameLayout = FLAYOUT_DIRECT; monitor.set_mac_frame_base(MacFrameBaseMac); // Set variables used by UAE memory banking const video_mode &mode = monitor.get_current_mode(); MacFrameBaseHost = the_buffer; MacFrameSize = mode.bytes_per_row * mode.y; InitFrameBufferMapping(); #else monitor.set_mac_frame_base(Host2MacAddr(the_buffer)); #endif D(bug("monitor.mac_frame_base = %08x\n", monitor.get_mac_frame_base())); } // Set window name and class static void set_window_name(Window w, int name) { const char *str = GetString(name); XStoreName(x_display, w, str); XSetIconName(x_display, w, str); XClassHint *hints; hints = XAllocClassHint(); if (hints) { hints->res_name = "BasiliskII"; hints->res_class = "BasiliskII"; XSetClassHint(x_display, w, hints); XFree(hints); } } // Set window input focus flag static void set_window_focus(Window w) { XWMHints *hints = XAllocWMHints(); if (hints) { hints->input = True; hints->initial_state = NormalState; hints->flags = InputHint | StateHint; XSetWMHints(x_display, w, hints); XFree(hints); } } // Set WM_DELETE_WINDOW protocol on window (preventing it from being destroyed by the WM when clicking on the "close" widget) static Atom WM_DELETE_WINDOW = (Atom)0; static void set_window_delete_protocol(Window w) { WM_DELETE_WINDOW = XInternAtom(x_display, "WM_DELETE_WINDOW", false); XSetWMProtocols(x_display, w, &WM_DELETE_WINDOW, 1); } // Wait until window is mapped/unmapped void wait_mapped(Window w) { XEvent e; do { XMaskEvent(x_display, StructureNotifyMask, &e); } while ((e.type != MapNotify) || (e.xmap.event != w)); } void wait_unmapped(Window w) { XEvent e; do { XMaskEvent(x_display, StructureNotifyMask, &e); } while ((e.type != UnmapNotify) || (e.xmap.event != w)); } // Trap SHM errors static bool shm_error = false; static int (*old_error_handler)(Display *, XErrorEvent *); static int error_handler(Display *d, XErrorEvent *e) { if (e->error_code == BadAccess) { shm_error = true; return 0; } else return old_error_handler(d, e); } /* * Framebuffer allocation routines */ #ifdef ENABLE_VOSF #include "vm_alloc.h" static void *vm_acquire_framebuffer(uint32 size) { // always try to allocate framebuffer at the same address static void *fb = VM_MAP_FAILED; if (fb != VM_MAP_FAILED) { if (vm_acquire_fixed(fb, size) < 0) fb = VM_MAP_FAILED; } if (fb == VM_MAP_FAILED) fb = vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT); return fb; } static inline void vm_release_framebuffer(void *fb, uint32 size) { vm_release(fb, size); } #endif /* * Display "driver" classes */ class driver_base { public: driver_base(X11_monitor_desc &m); virtual ~driver_base(); virtual void update_palette(void); virtual void suspend(void) {} virtual void resume(void) {} virtual void toggle_mouse_grab(void) {} virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); } void disable_mouse_accel(void); void restore_mouse_accel(void); virtual void grab_mouse(void) {} virtual void ungrab_mouse(void) {} public: X11_monitor_desc &monitor; // Associated video monitor const video_mode &mode; // Video mode handled by the driver bool init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer) Window w; // The window we draw into int orig_accel_numer, orig_accel_denom, orig_threshold; // Original mouse acceleration }; class driver_window; static void update_display_window_vosf(driver_window *drv); static void update_display_dynamic(int ticker, driver_window *drv); static void update_display_static(driver_window *drv); class driver_window : public driver_base { friend void update_display_window_vosf(driver_window *drv); friend void update_display_dynamic(int ticker, driver_window *drv); friend void update_display_static(driver_window *drv); public: driver_window(X11_monitor_desc &monitor); ~driver_window(); void toggle_mouse_grab(void); void mouse_moved(int x, int y); void grab_mouse(void); void ungrab_mouse(void); private: GC gc; XImage *img; bool have_shm; // Flag: SHM extensions available XShmSegmentInfo shminfo; Cursor mac_cursor; bool mouse_grabbed; // Flag: mouse pointer grabbed, using relative mouse mode int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode) }; class driver_dga; static void update_display_dga_vosf(driver_dga *drv); class driver_dga : public driver_base { friend void update_display_dga_vosf(driver_dga *drv); public: driver_dga(X11_monitor_desc &monitor); ~driver_dga(); void suspend(void); void resume(void); protected: struct FakeXImage { int width, height; // size of image int depth; // depth of image int bytes_per_line; // accelerator to next line FakeXImage(int w, int h, int d) : width(w), height(h), depth(d) { bytes_per_line = TrivialBytesPerRow(width, DepthModeForPixelDepth(depth)); } }; FakeXImage *img; private: Window suspend_win; // "Suspend" information window void *fb_save; // Saved frame buffer for suspend/resume }; static driver_base *drv = NULL; // Pointer to currently used driver object #ifdef ENABLE_VOSF # include "video_vosf.h" #endif driver_base::driver_base(X11_monitor_desc &m) : monitor(m), mode(m.get_current_mode()), init_ok(false), w(0) { the_buffer = NULL; the_buffer_copy = NULL; XGetPointerControl(x_display, &orig_accel_numer, &orig_accel_denom, &orig_threshold); } driver_base::~driver_base() { ungrab_mouse(); restore_mouse_accel(); if (w) { XUnmapWindow(x_display, w); wait_unmapped(w); XDestroyWindow(x_display, w); } XFlush(x_display); XSync(x_display, false); // Free frame buffer(s) if (!use_vosf) { if (the_buffer) { free(the_buffer); the_buffer = NULL; } if (the_buffer_copy) { free(the_buffer_copy); the_buffer_copy = NULL; } } #ifdef ENABLE_VOSF else { // the_buffer shall always be mapped through vm_acquire() so that we can vm_protect() it at will if (the_buffer != VM_MAP_FAILED) { D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size)); vm_release_framebuffer(the_buffer, the_buffer_size); the_buffer = NULL; } if (the_host_buffer) { D(bug(" freeing the_host_buffer at %p\n", the_host_buffer)); free(the_host_buffer); the_host_buffer = NULL; } if (the_buffer_copy) { D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy)); free(the_buffer_copy); the_buffer_copy = NULL; } } #endif } // Palette has changed void driver_base::update_palette(void) { if (color_class == PseudoColor || color_class == DirectColor) { int num = vis->map_entries; if (!IsDirectMode(monitor.get_current_mode()) && color_class == DirectColor) return; // Indexed mode on true color screen, don't set CLUT XStoreColors(x_display, cmap[0], x_palette, num); XStoreColors(x_display, cmap[1], x_palette, num); } XSync(x_display, false); } // Disable mouse acceleration void driver_base::disable_mouse_accel(void) { XChangePointerControl(x_display, True, False, 1, 1, 0); } // Restore mouse acceleration to original value void driver_base::restore_mouse_accel(void) { XChangePointerControl(x_display, True, True, orig_accel_numer, orig_accel_denom, orig_threshold); } /* * Windowed display driver */ // Open display driver_window::driver_window(X11_monitor_desc &m) : driver_base(m), gc(0), img(NULL), have_shm(false), mac_cursor(0), mouse_grabbed(false) { int width = mode.x, height = mode.y; int aligned_width = (width + 15) & ~15; int aligned_height = (height + 15) & ~15; // Set absolute mouse mode ADBSetRelMouseMode(mouse_grabbed); // Create window (setting background_pixel, border_pixel and colormap is // mandatory when using a non-default visual; in 1-bit mode we use the // default visual, so we can also use the default colormap) XSetWindowAttributes wattr; wattr.event_mask = eventmask = win_eventmask; wattr.background_pixel = (vis == DefaultVisual(x_display, screen) ? black_pixel : 0); wattr.border_pixel = 0; wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]); w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, InputOutput, vis, CWEventMask | CWBackPixel | CWBorderPixel | CWColormap, &wattr); D(bug(" window created\n")); // Set window name/class set_window_name(w, STR_WINDOW_TITLE); // Indicate that we want keyboard input set_window_focus(w); // Set delete protocol property set_window_delete_protocol(w); // Make window unresizable { XSizeHints *hints = XAllocSizeHints(); if (hints) { hints->min_width = width; hints->max_width = width; hints->min_height = height; hints->max_height = height; hints->flags = PMinSize | PMaxSize; XSetWMNormalHints(x_display, w, hints); XFree(hints); } } D(bug(" window attributes set\n")); // Show window XMapWindow(x_display, w); wait_mapped(w); D(bug(" window mapped\n")); // 1-bit mode is big-endian; if the X server is little-endian, we can't // use SHM because that doesn't allow changing the image byte order bool need_msb_image = (mode.depth == VDEPTH_1BIT && XImageByteOrder(x_display) == LSBFirst); // Try to create and attach SHM image if (local_X11 && !need_msb_image && XShmQueryExtension(x_display)) { // Create SHM image ("height + 2" for safety) img = XShmCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, &shminfo, width, height); D(bug(" shm image created\n")); shminfo.shmid = shmget(IPC_PRIVATE, (aligned_height + 2) * img->bytes_per_line, IPC_CREAT | 0777); the_buffer_copy = (uint8 *)shmat(shminfo.shmid, 0, 0); shminfo.shmaddr = img->data = (char *)the_buffer_copy; shminfo.readOnly = False; // Try to attach SHM image, catching errors shm_error = false; old_error_handler = XSetErrorHandler(error_handler); XShmAttach(x_display, &shminfo); XSync(x_display, false); XSetErrorHandler(old_error_handler); if (shm_error) { shmdt(shminfo.shmaddr); XDestroyImage(img); img = NULL; shminfo.shmid = -1; } else { have_shm = true; shmctl(shminfo.shmid, IPC_RMID, 0); } D(bug(" shm image attached\n")); } // Create normal X image if SHM doesn't work ("height + 2" for safety) if (!have_shm) { int bytes_per_row = (mode.depth == VDEPTH_1BIT ? aligned_width/8 : TrivialBytesPerRow(aligned_width, DepthModeForPixelDepth(xdepth))); the_buffer_copy = (uint8 *)malloc((aligned_height + 2) * bytes_per_row); img = XCreateImage(x_display, vis, mode.depth == VDEPTH_1BIT ? 1 : xdepth, mode.depth == VDEPTH_1BIT ? XYBitmap : ZPixmap, 0, (char *)the_buffer_copy, aligned_width, aligned_height, 32, bytes_per_row); D(bug(" X image created\n")); } if (need_msb_image) { img->byte_order = MSBFirst; img->bitmap_bit_order = MSBFirst; } #ifdef ENABLE_VOSF use_vosf = true; // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer_copy; the_buffer_size = page_extend((aligned_height + 2) * img->bytes_per_line); the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size); the_buffer_copy = (uint8 *)malloc(the_buffer_size); D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer)); #else // Allocate memory for frame buffer the_buffer = (uint8 *)malloc((aligned_height + 2) * img->bytes_per_line); D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy)); #endif // Create GC gc = XCreateGC(x_display, w, 0, 0); XSetState(x_display, gc, black_pixel, white_pixel, GXcopy, AllPlanes); // Create no_cursor mac_cursor = XCreatePixmapCursor(x_display, XCreatePixmap(x_display, w, 1, 1, 1), XCreatePixmap(x_display, w, 1, 1, 1), &black, &white, 0, 0); XDefineCursor(x_display, w, mac_cursor); // Init blitting routines #ifdef ENABLE_VOSF Screen_blitter_init(visualFormat, x_native_byte_order, depth_of_video_mode(mode)); #endif // Set frame buffer base set_mac_frame_buffer(monitor, mode.depth, x_native_byte_order); // Everything went well init_ok = true; } // Close display driver_window::~driver_window() { if (have_shm) { XShmDetach(x_display, &shminfo); #ifdef ENABLE_VOSF the_host_buffer = NULL; // don't free() in driver_base dtor #else the_buffer_copy = NULL; // don't free() in driver_base dtor #endif } if (img) { if (!have_shm) img->data = NULL; XDestroyImage(img); } if (have_shm) { shmdt(shminfo.shmaddr); shmctl(shminfo.shmid, IPC_RMID, 0); } if (gc) XFreeGC(x_display, gc); } // Toggle mouse grab void driver_window::toggle_mouse_grab(void) { if (mouse_grabbed) ungrab_mouse(); else grab_mouse(); } // Grab mouse, switch to relative mouse mode void driver_window::grab_mouse(void) { int result; for (int i=0; i<10; i++) { result = XGrabPointer(x_display, w, True, 0, GrabModeAsync, GrabModeAsync, w, None, CurrentTime); if (result != AlreadyGrabbed) break; Delay_usec(100000); } if (result == GrabSuccess) { XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED)); ADBSetRelMouseMode(mouse_grabbed = true); disable_mouse_accel(); } } // Ungrab mouse, switch to absolute mouse mode void driver_window::ungrab_mouse(void) { if (mouse_grabbed) { XUngrabPointer(x_display, CurrentTime); XStoreName(x_display, w, GetString(STR_WINDOW_TITLE)); ADBSetRelMouseMode(mouse_grabbed = false); restore_mouse_accel(); } } // Mouse moved void driver_window::mouse_moved(int x, int y) { if (!mouse_grabbed) { mouse_last_x = x; mouse_last_y = y; ADBMouseMoved(x, y); return; } // Warped mouse motion (this code is taken from SDL) // Post first mouse event int width = monitor.get_current_mode().x, height = monitor.get_current_mode().y; int delta_x = x - mouse_last_x, delta_y = y - mouse_last_y; mouse_last_x = x; mouse_last_y = y; ADBMouseMoved(delta_x, delta_y); // Only warp the pointer when it has reached the edge const int MOUSE_FUDGE_FACTOR = 8; if (x < MOUSE_FUDGE_FACTOR || x > (width - MOUSE_FUDGE_FACTOR) || y < MOUSE_FUDGE_FACTOR || y > (height - MOUSE_FUDGE_FACTOR)) { XEvent event; while (XCheckTypedEvent(x_display, MotionNotify, &event)) { delta_x = x - mouse_last_x; delta_y = y - mouse_last_y; mouse_last_x = x; mouse_last_y = y; ADBMouseMoved(delta_x, delta_y); } mouse_last_x = width/2; mouse_last_y = height/2; XWarpPointer(x_display, None, w, 0, 0, 0, 0, mouse_last_x, mouse_last_y); for (int i=0; i<10; i++) { XMaskEvent(x_display, PointerMotionMask, &event); if (event.xmotion.x > (mouse_last_x - MOUSE_FUDGE_FACTOR) && event.xmotion.x < (mouse_last_x + MOUSE_FUDGE_FACTOR) && event.xmotion.y > (mouse_last_y - MOUSE_FUDGE_FACTOR) && event.xmotion.y < (mouse_last_y + MOUSE_FUDGE_FACTOR)) break; } } } #if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA) /* * DGA display driver base class */ driver_dga::driver_dga(X11_monitor_desc &m) : driver_base(m), suspend_win(0), fb_save(NULL), img(NULL) { } driver_dga::~driver_dga() { XUngrabPointer(x_display, CurrentTime); XUngrabKeyboard(x_display, CurrentTime); if (img) delete img; } // Suspend emulation void driver_dga::suspend(void) { // Release ctrl key ADBKeyUp(0x36); ctrl_down = false; // Lock frame buffer (this will stop the MacOS thread) LOCK_FRAME_BUFFER; // Save frame buffer fb_save = malloc(mode.y * mode.bytes_per_row); if (fb_save) memcpy(fb_save, the_buffer, mode.y * mode.bytes_per_row); // Close full screen display #ifdef ENABLE_XF86_DGA XF86DGADirectVideo(x_display, screen, 0); #endif XUngrabPointer(x_display, CurrentTime); XUngrabKeyboard(x_display, CurrentTime); restore_mouse_accel(); XUnmapWindow(x_display, w); wait_unmapped(w); // Open "suspend" window XSetWindowAttributes wattr; wattr.event_mask = KeyPressMask; wattr.background_pixel = black_pixel; suspend_win = XCreateWindow(x_display, rootwin, 0, 0, 512, 1, 0, xdepth, InputOutput, vis, CWEventMask | CWBackPixel, &wattr); set_window_name(suspend_win, STR_SUSPEND_WINDOW_TITLE); set_window_focus(suspend_win); XMapWindow(x_display, suspend_win); emul_suspended = true; } // Resume emulation void driver_dga::resume(void) { // Close "suspend" window XDestroyWindow(x_display, suspend_win); XSync(x_display, false); // Reopen full screen display XMapRaised(x_display, w); wait_mapped(w); XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0); XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); disable_mouse_accel(); #ifdef ENABLE_XF86_DGA XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse); XF86DGASetViewPort(x_display, screen, 0, 0); #endif XSync(x_display, false); // the_buffer already contains the data to restore. i.e. since a temporary // frame buffer is used when VOSF is actually used, fb_save is therefore // not necessary. #ifdef ENABLE_VOSF if (use_vosf) { LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } #endif // Restore frame buffer if (fb_save) { #ifdef ENABLE_VOSF // Don't copy fb_save to the temporary frame buffer in VOSF mode if (!use_vosf) #endif memcpy(the_buffer, fb_save, mode.y * mode.bytes_per_row); free(fb_save); fb_save = NULL; } // Unlock frame buffer (and continue MacOS thread) UNLOCK_FRAME_BUFFER; emul_suspended = false; } #endif #ifdef ENABLE_FBDEV_DGA /* * fbdev DGA display driver */ const char FBDEVICES_FILE_NAME[] = DATADIR "/fbdevices"; const char FBDEVICE_FILE_NAME[] = "/dev/fb"; class driver_fbdev : public driver_dga { public: driver_fbdev(X11_monitor_desc &monitor); ~driver_fbdev(); }; // Open display driver_fbdev::driver_fbdev(X11_monitor_desc &m) : driver_dga(m) { int width = mode.x, height = mode.y; // Set absolute mouse mode ADBSetRelMouseMode(false); // Find the maximum depth available int ndepths, max_depth(0); int *depths = XListDepths(x_display, screen, &ndepths); if (depths == NULL) { printf("FATAL: Could not determine the maximal depth available\n"); return; } else { while (ndepths-- > 0) { if (depths[ndepths] > max_depth) max_depth = depths[ndepths]; } } // Get fbdevices file path from preferences const char *fbd_path = PrefsFindString("fbdevicefile"); // Open fbdevices file FILE *fp = fopen(fbd_path ? fbd_path : FBDEVICES_FILE_NAME, "r"); if (fp == NULL) { char str[256]; sprintf(str, GetString(STR_NO_FBDEVICE_FILE_ERR), fbd_path ? fbd_path : FBDEVICES_FILE_NAME, strerror(errno)); ErrorAlert(str); return; } int fb_depth; // supported depth uint32 fb_offset; // offset used for mmap(2) char fb_name[20]; char line[256]; bool device_found = false; while (fgets(line, 255, fp)) { // Read line int len = strlen(line); if (len == 0) continue; line[len - 1] = '\0'; // Comments begin with "#" or ";" if ((line[0] == '#') || (line[0] == ';') || (line[0] == '\0')) continue; if ((sscanf(line, "%19s %d %x", fb_name, &fb_depth, &fb_offset) == 3) && (strcmp(fb_name, fb_name) == 0) && (fb_depth == max_depth)) { device_found = true; break; } } // fbdevices file completely read fclose(fp); // Frame buffer name not found ? Then, display warning if (!device_found) { char str[256]; sprintf(str, GetString(STR_FBDEV_NAME_ERR), fb_name, max_depth); ErrorAlert(str); return; } // Create window XSetWindowAttributes wattr; wattr.event_mask = eventmask = dga_eventmask; wattr.background_pixel = white_pixel; wattr.override_redirect = True; wattr.colormap = cmap[0]; w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, InputOutput, vis, CWEventMask | CWBackPixel | CWOverrideRedirect | (fb_depth <= 8 ? CWColormap : 0), &wattr); // Set window name/class set_window_name(w, STR_WINDOW_TITLE); // Indicate that we want keyboard input set_window_focus(w); // Show window XMapRaised(x_display, w); wait_mapped(w); // Grab mouse and keyboard XGrabKeyboard(x_display, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(x_display, w, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, w, None, CurrentTime); disable_mouse_accel(); // Calculate bytes per row int bytes_per_row = TrivialBytesPerRow(mode.x, mode.depth); // Map frame buffer the_buffer_size = height * bytes_per_row; if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fbdev_fd, fb_offset)) == MAP_FAILED) { if ((the_buffer = (uint8 *) mmap(NULL, the_buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev_fd, fb_offset)) == MAP_FAILED) { char str[256]; sprintf(str, GetString(STR_FBDEV_MMAP_ERR), strerror(errno)); ErrorAlert(str); return; } } #if ENABLE_VOSF #if REAL_ADDRESSING || DIRECT_ADDRESSING // Screen_blitter_init() returns TRUE if VOSF is mandatory // i.e. the framebuffer update function is not Blit_Copy_Raw use_vosf = Screen_blitter_init(visualFormat, true, mode.depth); if (use_vosf) { // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer; the_buffer_size = page_extend((height + 2) * bytes_per_row); the_buffer_copy = (uint8 *)malloc(the_buffer_size); the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size); // Fake image for DGA/VOSF mode to know about display bounds img = new FakeXImage(width, height, depth_of_video_mode(mode)); } #else use_vosf = false; #endif #endif // Set frame buffer base const_cast(&mode)->bytes_per_row = bytes_per_row; const_cast(&mode)->depth = DepthModeForPixelDepth(fb_depth); set_mac_frame_buffer(monitor, mode.depth, true); // Everything went well init_ok = true; } // Close display driver_fbdev::~driver_fbdev() { if (!use_vosf) { if (the_buffer != MAP_FAILED) { // don't free() the screen buffer in driver_base dtor munmap(the_buffer, the_buffer_size); the_buffer = NULL; } } #ifdef ENABLE_VOSF else { if (the_host_buffer != MAP_FAILED) { // don't free() the screen buffer in driver_base dtor munmap(the_host_buffer, the_buffer_size); the_host_buffer = NULL; } } #endif } #endif #ifdef ENABLE_XF86_DGA /* * XFree86 DGA display driver */ class driver_xf86dga : public driver_dga { public: driver_xf86dga(X11_monitor_desc &monitor); ~driver_xf86dga(); void update_palette(void); void resume(void); private: int current_dga_cmap; // Number (0 or 1) of currently installed DGA colormap }; // Open display driver_xf86dga::driver_xf86dga(X11_monitor_desc &m) : driver_dga(m), current_dga_cmap(0) { int width = mode.x, height = mode.y; // Set relative mouse mode ADBSetRelMouseMode(true); #ifdef ENABLE_XF86_VIDMODE // Switch to best mode if (has_vidmode) { int best = 0; for (int i=1; ihdisplay >= width && x_video_modes[i]->vdisplay >= height && x_video_modes[i]->hdisplay <= x_video_modes[best]->hdisplay && x_video_modes[i]->vdisplay <= x_video_modes[best]->vdisplay) { best = i; } } XF86VidModeSwitchToMode(x_display, screen, x_video_modes[best]); XF86VidModeSetViewPort(x_display, screen, 0, 0); XSync(x_display, false); } #endif // Create window XSetWindowAttributes wattr; wattr.event_mask = eventmask = dga_eventmask; wattr.override_redirect = True; wattr.colormap = (mode.depth == VDEPTH_1BIT ? DefaultColormap(x_display, screen) : cmap[0]); w = XCreateWindow(x_display, rootwin, 0, 0, width, height, 0, xdepth, InputOutput, vis, CWEventMask | CWOverrideRedirect | (color_class == DirectColor ? CWColormap : 0), &wattr); // Set window name/class set_window_name(w, STR_WINDOW_TITLE); // Indicate that we want keyboard input set_window_focus(w); // Show window XMapRaised(x_display, w); wait_mapped(w); // Establish direct screen connection XMoveResizeWindow(x_display, w, 0, 0, width, height); XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0); XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); disable_mouse_accel(); int v_width, v_bank, v_size; XF86DGAGetVideo(x_display, screen, (char **)&the_buffer, &v_width, &v_bank, &v_size); XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse); XF86DGASetViewPort(x_display, screen, 0, 0); XF86DGASetVidPage(x_display, screen, 0); // Set colormap if (!IsDirectMode(mode)) { XSetWindowColormap(x_display, w, cmap[current_dga_cmap = 0]); XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); } XSync(x_display, false); // Init blitting routines int bytes_per_row = TrivialBytesPerRow((v_width + 7) & ~7, mode.depth); #if ENABLE_VOSF #if REAL_ADDRESSING || DIRECT_ADDRESSING // Screen_blitter_init() returns TRUE if VOSF is mandatory // i.e. the framebuffer update function is not Blit_Copy_Raw use_vosf = Screen_blitter_init(visualFormat, x_native_byte_order, depth_of_video_mode(mode)); if (use_vosf) { // Allocate memory for frame buffer (SIZE is extended to page-boundary) the_host_buffer = the_buffer; the_buffer_size = page_extend((height + 2) * bytes_per_row); the_buffer_copy = (uint8 *)malloc(the_buffer_size); the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size); // Fake image for DGA/VOSF mode to know about display bounds img = new FakeXImage((v_width + 7) & ~7, height, depth_of_video_mode(mode)); } #else use_vosf = false; #endif #endif // Set frame buffer base const_cast(&mode)->bytes_per_row = bytes_per_row; set_mac_frame_buffer(monitor, mode.depth, true); // Everything went well init_ok = true; } // Close display driver_xf86dga::~driver_xf86dga() { XF86DGADirectVideo(x_display, screen, 0); if (!use_vosf) { // don't free() the screen buffer in driver_base dtor the_buffer = NULL; } #ifdef ENABLE_VOSF else { // don't free() the screen buffer in driver_base dtor the_host_buffer = NULL; } #endif #ifdef ENABLE_XF86_VIDMODE if (has_vidmode) XF86VidModeSwitchToMode(x_display, screen, x_video_modes[0]); #endif } // Palette has changed void driver_xf86dga::update_palette(void) { driver_dga::update_palette(); current_dga_cmap ^= 1; if (!IsDirectMode(monitor.get_current_mode()) && cmap[current_dga_cmap]) XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); } // Resume emulation void driver_xf86dga::resume(void) { driver_dga::resume(); if (!IsDirectMode(monitor.get_current_mode())) XF86DGAInstallColormap(x_display, screen, cmap[current_dga_cmap]); } #endif /* * Initialization */ // Init keycode translation table static void keycode_init(void) { bool use_kc = PrefsFindBool("keycodes"); if (use_kc) { // Get keycode file path from preferences const char *kc_path = PrefsFindString("keycodefile"); // Open keycode table FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r"); if (f == NULL) { char str[256]; sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno)); WarningAlert(str); return; } // Default translation table for (int i=0; i<256; i++) keycode_table[i] = -1; // Search for server vendor string, then read keycodes const char *vendor = ServerVendor(x_display); // Force use of MacX mappings on MacOS X with Apple's X server int dummy; if (XQueryExtension(x_display, "Apple-DRI", &dummy, &dummy, &dummy)) vendor = "MacX"; bool vendor_found = false; char line[256]; while (fgets(line, 255, f)) { // Read line int len = strlen(line); if (len == 0) continue; line[len-1] = 0; // Comments begin with "#" or ";" if (line[0] == '#' || line[0] == ';' || line[0] == 0) continue; if (vendor_found) { // Read keycode int x_code, mac_code; if (sscanf(line, "%d %d", &x_code, &mac_code) == 2) keycode_table[x_code & 0xff] = mac_code; else break; } else { // Search for vendor string if (strstr(vendor, line) == vendor) vendor_found = true; } } // Keycode file completely read fclose(f); use_keycodes = vendor_found; // Vendor not found? Then display warning if (!vendor_found) { char str[256]; sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), vendor, kc_path ? kc_path : KEYCODE_FILE_NAME); WarningAlert(str); return; } } } // Open display for current mode bool X11_monitor_desc::video_open(void) { D(bug("video_open()\n")); const video_mode &mode = get_current_mode(); // Find best available X visual if (!find_visual_for_depth(mode.depth)) { ErrorAlert(STR_NO_XVISUAL_ERR); return false; } // Determine the byte order of an XImage content #ifdef WORDS_BIGENDIAN x_native_byte_order = (XImageByteOrder(x_display) == MSBFirst); #else x_native_byte_order = (XImageByteOrder(x_display) == LSBFirst); #endif // Build up visualFormat structure visualFormat.fullscreen = (display_type == DISPLAY_DGA); visualFormat.depth = visualInfo.depth; visualFormat.Rmask = visualInfo.red_mask; visualFormat.Gmask = visualInfo.green_mask; visualFormat.Bmask = visualInfo.blue_mask; // Create color maps if (color_class == PseudoColor || color_class == DirectColor) { cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocAll); cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocAll); } else { cmap[0] = XCreateColormap(x_display, rootwin, vis, AllocNone); cmap[1] = XCreateColormap(x_display, rootwin, vis, AllocNone); } // Find pixel format of direct modes if (color_class == DirectColor || color_class == TrueColor) { rshift = gshift = bshift = 0; rloss = gloss = bloss = 8; uint32 mask; for (mask=vis->red_mask; !(mask&1); mask>>=1) ++rshift; for (; mask&1; mask>>=1) --rloss; for (mask=vis->green_mask; !(mask&1); mask>>=1) ++gshift; for (; mask&1; mask>>=1) --gloss; for (mask=vis->blue_mask; !(mask&1); mask>>=1) ++bshift; for (; mask&1; mask>>=1) --bloss; } // Preset palette pixel values for CLUT or gamma table if (color_class == DirectColor) { int num = vis->map_entries; for (int i=0; imap_entries : 256); for (int i=0; i16/32 expand map if (!IsDirectMode(mode) && xdepth > 8) for (int i=0; i<256; i++) ExpandMap[i] = map_rgb(i, i, i, true); #endif // Create display driver object of requested type switch (display_type) { case DISPLAY_WINDOW: drv = new driver_window(*this); break; #ifdef ENABLE_FBDEV_DGA case DISPLAY_DGA: drv = new driver_fbdev(*this); break; #endif #ifdef ENABLE_XF86_DGA case DISPLAY_DGA: drv = new driver_xf86dga(*this); break; #endif } if (drv == NULL) return false; if (!drv->init_ok) { delete drv; drv = NULL; return false; } #ifdef ENABLE_VOSF if (use_vosf) { // Initialize the VOSF system if (!video_vosf_init(*this)) { ErrorAlert(STR_VOSF_INIT_ERR); return false; } } #endif // Initialize VideoRefresh function VideoRefreshInit(); // Lock down frame buffer XSync(x_display, false); LOCK_FRAME_BUFFER; // Start redraw/input thread #ifdef USE_PTHREADS_SERVICES redraw_thread_cancel = false; Set_pthread_attr(&redraw_thread_attr, 0); redraw_thread_active = (pthread_create(&redraw_thread, &redraw_thread_attr, redraw_func, NULL) == 0); if (!redraw_thread_active) { printf("FATAL: cannot create redraw thread\n"); return false; } #else redraw_thread_active = true; #endif return true; } bool VideoInit(bool classic) { classic_mode = classic; #ifdef ENABLE_VOSF // Zero the mainBuffer structure mainBuffer.dirtyPages = NULL; mainBuffer.pageInfo = NULL; #endif // Check if X server runs on local machine local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0) || (strncmp(XDisplayName(x_display_name), "/", 1) == 0) || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0); // Init keycode translation keycode_init(); // Read prefs frame_skip = PrefsFindInt32("frameskip"); mouse_wheel_mode = PrefsFindInt32("mousewheelmode"); mouse_wheel_lines = PrefsFindInt32("mousewheellines"); // Find screen and root window screen = XDefaultScreen(x_display); rootwin = XRootWindow(x_display, screen); // Get sorted list of available depths avail_depths = XListDepths(x_display, screen, &num_depths); if (avail_depths == NULL) { ErrorAlert(STR_UNSUPP_DEPTH_ERR); return false; } std::sort(avail_depths, avail_depths + num_depths); #ifdef ENABLE_FBDEV_DGA // Frame buffer name char fb_name[20]; // Could do fbdev DGA? if ((fbdev_fd = open(FBDEVICE_FILE_NAME, O_RDWR)) != -1) has_dga = true; else has_dga = false; #endif #ifdef ENABLE_XF86_DGA // DGA available? int dga_event_base, dga_error_base; if (local_X11 && XF86DGAQueryExtension(x_display, &dga_event_base, &dga_error_base)) { int dga_flags = 0; XF86DGAQueryDirectVideo(x_display, screen, &dga_flags); has_dga = dga_flags & XF86DGADirectPresent; } else has_dga = false; #endif #ifdef ENABLE_XF86_VIDMODE // VidMode available? int vm_event_base, vm_error_base; has_vidmode = XF86VidModeQueryExtension(x_display, &vm_event_base, &vm_error_base); if (has_vidmode) XF86VidModeGetAllModeLines(x_display, screen, &num_x_video_modes, &x_video_modes); #endif // Find black and white colors XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:00/00/00", &black); XAllocColor(x_display, DefaultColormap(x_display, screen), &black); XParseColor(x_display, DefaultColormap(x_display, screen), "rgb:ff/ff/ff", &white); XAllocColor(x_display, DefaultColormap(x_display, screen), &white); black_pixel = BlackPixel(x_display, screen); white_pixel = WhitePixel(x_display, screen); // Get screen mode from preferences const char *mode_str; if (classic_mode) mode_str = "win/512/342"; else mode_str = PrefsFindString("screen"); // Determine display type and default dimensions int default_width = 512, default_height = 384; display_type = DISPLAY_WINDOW; if (mode_str) { if (sscanf(mode_str, "win/%d/%d", &default_width, &default_height) == 2) { display_type = DISPLAY_WINDOW; #ifdef ENABLE_FBDEV_DGA } else if (has_dga && sscanf(mode_str, "dga/%19s", fb_name) == 1) { display_type = DISPLAY_DGA; default_width = -1; default_height = -1; // use entire screen #endif #ifdef ENABLE_XF86_DGA } else if (has_dga && sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2) { display_type = DISPLAY_DGA; #endif } } if (default_width <= 0) default_width = DisplayWidth(x_display, screen); else if (default_width > DisplayWidth(x_display, screen)) default_width = DisplayWidth(x_display, screen); if (default_height <= 0) default_height = DisplayHeight(x_display, screen); else if (default_height > DisplayHeight(x_display, screen)) default_height = DisplayHeight(x_display, screen); // Mac screen depth follows X depth video_depth default_depth = VDEPTH_1BIT; switch (DefaultDepth(x_display, screen)) { case 8: default_depth = VDEPTH_8BIT; break; case 15: case 16: default_depth = VDEPTH_16BIT; break; case 24: case 32: default_depth = VDEPTH_32BIT; break; } // Construct list of supported modes if (display_type == DISPLAY_WINDOW) { if (classic) add_mode(512, 342, 0x80, 64, VDEPTH_1BIT); else { for (unsigned d=VDEPTH_1BIT; d<=VDEPTH_32BIT; d++) { if (find_visual_for_depth(video_depth(d))) add_window_modes(video_depth(d)); } } } else add_mode(default_width, default_height, 0x80, TrivialBytesPerRow(default_width, default_depth), default_depth); if (VideoModes.empty()) { ErrorAlert(STR_NO_XVISUAL_ERR); return false; } // Find requested default mode with specified dimensions uint32 default_id; std::vector::const_iterator i, end = VideoModes.end(); for (i = VideoModes.begin(); i != end; ++i) { if (i->x == default_width && i->y == default_height && i->depth == default_depth) { default_id = i->resolution_id; break; } } if (i == end) { // not found, use first available mode default_depth = VideoModes[0].depth; default_id = VideoModes[0].resolution_id; } #if DEBUG D(bug("Available video modes:\n")); for (i = VideoModes.begin(); i != end; ++i) { int bits = 1 << i->depth; if (bits == 16) bits = 15; else if (bits == 32) bits = 24; D(bug(" %dx%d (ID %02x), %d colors\n", i->x, i->y, i->resolution_id, 1 << bits)); } #endif // Create X11_monitor_desc for this (the only) display X11_monitor_desc *monitor = new X11_monitor_desc(VideoModes, default_depth, default_id); VideoMonitors.push_back(monitor); // Open display return monitor->video_open(); } /* * Deinitialization */ // Close display void X11_monitor_desc::video_close(void) { D(bug("video_close()\n")); // Stop redraw thread #ifdef USE_PTHREADS_SERVICES if (redraw_thread_active) { redraw_thread_cancel = true; redraw_thread_cancel_ack = false; pthread_join(redraw_thread, NULL); while (!redraw_thread_cancel_ack) ; } #endif redraw_thread_active = false; // Unlock frame buffer UNLOCK_FRAME_BUFFER; XSync(x_display, false); D(bug(" frame buffer unlocked\n")); #ifdef ENABLE_VOSF if (use_vosf) { // Deinitialize VOSF video_vosf_exit(); } #endif // Close display delete drv; drv = NULL; // Free colormaps if (cmap[0]) { XFreeColormap(x_display, cmap[0]); cmap[0] = 0; } if (cmap[1]) { XFreeColormap(x_display, cmap[1]); cmap[1] = 0; } } void VideoExit(void) { // Close displays vector::iterator i, end = VideoMonitors.end(); for (i = VideoMonitors.begin(); i != end; ++i) dynamic_cast(*i)->video_close(); #ifdef ENABLE_XF86_VIDMODE // Free video mode list if (x_video_modes) { XFree(x_video_modes); x_video_modes = NULL; } #endif #ifdef ENABLE_FBDEV_DGA // Close framebuffer device if (fbdev_fd >= 0) { close(fbdev_fd); fbdev_fd = -1; } #endif // Free depth list if (avail_depths) { XFree(avail_depths); avail_depths = NULL; } } /* * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode) */ void VideoQuitFullScreen(void) { D(bug("VideoQuitFullScreen()\n")); quit_full_screen = true; } /* * Mac VBL interrupt */ void VideoInterrupt(void) { // Emergency quit requested? Then quit if (emerg_quit) QuitEmulator(); // Temporarily give up frame buffer lock (this is the point where // we are suspended when the user presses Ctrl-Tab) UNLOCK_FRAME_BUFFER; LOCK_FRAME_BUFFER; } /* * Set palette */ void X11_monitor_desc::set_palette(uint8 *pal, int num_in) { const video_mode &mode = get_current_mode(); LOCK_PALETTE; // Convert colors to XColor array int num_out = 256; bool stretch = false; if (IsDirectMode(mode)) { // If X is in 565 mode we have to stretch the gamma table from 32 to 64 entries num_out = vis->map_entries; stretch = true; } XColor *p = x_palette; for (int i=0; ired = pal[c*3 + 0] * 0x0101; p->green = pal[c*3 + 1] * 0x0101; p->blue = pal[c*3 + 2] * 0x0101; p++; } #ifdef ENABLE_VOSF // Recalculate pixel color expansion map if (!IsDirectMode(mode) && xdepth > 8) { for (int i=0; i<256; i++) { int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier) ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2], true); } // We have to redraw everything because the interpretation of pixel values changed LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } #endif // Tell redraw thread to change palette x_palette_changed = true; UNLOCK_PALETTE; } /* * Switch video mode */ void X11_monitor_desc::switch_to_current_mode(void) { // Close and reopen display video_close(); video_open(); if (drv == NULL) { ErrorAlert(STR_OPEN_WINDOW_ERR); QuitEmulator(); } } /* * Translate key event to Mac keycode, returns -1 if no keycode was found * and -2 if the key was recognized as a hotkey */ static int kc_decode(KeySym ks, bool key_down) { switch (ks) { case XK_A: case XK_a: return 0x00; case XK_B: case XK_b: return 0x0b; case XK_C: case XK_c: return 0x08; case XK_D: case XK_d: return 0x02; case XK_E: case XK_e: return 0x0e; case XK_F: case XK_f: return 0x03; case XK_G: case XK_g: return 0x05; case XK_H: case XK_h: return 0x04; case XK_I: case XK_i: return 0x22; case XK_J: case XK_j: return 0x26; case XK_K: case XK_k: return 0x28; case XK_L: case XK_l: return 0x25; case XK_M: case XK_m: return 0x2e; case XK_N: case XK_n: return 0x2d; case XK_O: case XK_o: return 0x1f; case XK_P: case XK_p: return 0x23; case XK_Q: case XK_q: return 0x0c; case XK_R: case XK_r: return 0x0f; case XK_S: case XK_s: return 0x01; case XK_T: case XK_t: return 0x11; case XK_U: case XK_u: return 0x20; case XK_V: case XK_v: return 0x09; case XK_W: case XK_w: return 0x0d; case XK_X: case XK_x: return 0x07; case XK_Y: case XK_y: return 0x10; case XK_Z: case XK_z: return 0x06; case XK_1: case XK_exclam: return 0x12; case XK_2: case XK_at: return 0x13; case XK_3: case XK_numbersign: return 0x14; case XK_4: case XK_dollar: return 0x15; case XK_5: case XK_percent: return 0x17; case XK_6: return 0x16; case XK_7: return 0x1a; case XK_8: return 0x1c; case XK_9: return 0x19; case XK_0: return 0x1d; case XK_grave: case XK_asciitilde: return 0x0a; case XK_minus: case XK_underscore: return 0x1b; case XK_equal: case XK_plus: return 0x18; case XK_bracketleft: case XK_braceleft: return 0x21; case XK_bracketright: case XK_braceright: return 0x1e; case XK_backslash: case XK_bar: return 0x2a; case XK_semicolon: case XK_colon: return 0x29; case XK_apostrophe: case XK_quotedbl: return 0x27; case XK_comma: case XK_less: return 0x2b; case XK_period: case XK_greater: return 0x2f; case XK_slash: case XK_question: return 0x2c; case XK_Tab: if (ctrl_down) {if (key_down) drv->suspend(); return -2;} else return 0x30; case XK_Return: return 0x24; case XK_space: return 0x31; case XK_BackSpace: return 0x33; case XK_Delete: return 0x75; case XK_Insert: return 0x72; case XK_Home: case XK_Help: return 0x73; case XK_End: return 0x77; #ifdef __hpux case XK_Prior: return 0x74; case XK_Next: return 0x79; #else case XK_Page_Up: return 0x74; case XK_Page_Down: return 0x79; #endif case XK_Control_L: return 0x36; case XK_Control_R: return 0x36; case XK_Shift_L: return 0x38; case XK_Shift_R: return 0x38; case XK_Alt_L: return 0x37; case XK_Alt_R: return 0x37; case XK_Meta_L: return 0x3a; case XK_Meta_R: return 0x3a; case XK_Menu: return 0x32; case XK_Caps_Lock: return 0x39; case XK_Num_Lock: return 0x47; case XK_Up: return 0x3e; case XK_Down: return 0x3d; case XK_Left: return 0x3b; case XK_Right: return 0x3c; case XK_Escape: if (ctrl_down) {if (key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35; case XK_F1: if (ctrl_down) {if (key_down) SysMountFirstFloppy(); return -2;} else return 0x7a; case XK_F2: return 0x78; case XK_F3: return 0x63; case XK_F4: return 0x76; case XK_F5: if (ctrl_down) {if (key_down) drv->toggle_mouse_grab(); return -2;} else return 0x60; case XK_F6: return 0x61; case XK_F7: return 0x62; case XK_F8: return 0x64; case XK_F9: return 0x65; case XK_F10: return 0x6d; case XK_F11: return 0x67; case XK_F12: return 0x6f; case XK_Print: return 0x69; case XK_Scroll_Lock: return 0x6b; case XK_Pause: return 0x71; #if defined(XK_KP_Prior) && defined(XK_KP_Left) && defined(XK_KP_Insert) && defined (XK_KP_End) case XK_KP_0: case XK_KP_Insert: return 0x52; case XK_KP_1: case XK_KP_End: return 0x53; case XK_KP_2: case XK_KP_Down: return 0x54; case XK_KP_3: case XK_KP_Next: return 0x55; case XK_KP_4: case XK_KP_Left: return 0x56; case XK_KP_5: case XK_KP_Begin: return 0x57; case XK_KP_6: case XK_KP_Right: return 0x58; case XK_KP_7: case XK_KP_Home: return 0x59; case XK_KP_8: case XK_KP_Up: return 0x5b; case XK_KP_9: case XK_KP_Prior: return 0x5c; case XK_KP_Decimal: case XK_KP_Delete: return 0x41; #else case XK_KP_0: return 0x52; case XK_KP_1: return 0x53; case XK_KP_2: return 0x54; case XK_KP_3: return 0x55; case XK_KP_4: return 0x56; case XK_KP_5: return 0x57; case XK_KP_6: return 0x58; case XK_KP_7: return 0x59; case XK_KP_8: return 0x5b; case XK_KP_9: return 0x5c; case XK_KP_Decimal: return 0x41; #endif case XK_KP_Add: return 0x45; case XK_KP_Subtract: return 0x4e; case XK_KP_Multiply: return 0x43; case XK_KP_Divide: return 0x4b; case XK_KP_Enter: return 0x4c; case XK_KP_Equal: return 0x51; } return -1; } static int event2keycode(XKeyEvent &ev, bool key_down) { KeySym ks; int i = 0; do { ks = XLookupKeysym(&ev, i++); int as = kc_decode(ks, key_down); if (as >= 0) return as; if (as == -2) return as; } while (ks != NoSymbol); return -1; } /* * X event handling */ static void handle_events(void) { for (;;) { XEvent event; XDisplayLock(); if (!XCheckMaskEvent(x_display, eventmask, &event)) { // Handle clipboard events if (XCheckTypedEvent(x_display, SelectionRequest, &event)) ClipboardSelectionRequest(&event.xselectionrequest); else if (XCheckTypedEvent(x_display, SelectionClear, &event)) ClipboardSelectionClear(&event.xselectionclear); // Window "close" widget clicked else if (XCheckTypedEvent(x_display, ClientMessage, &event)) { if (event.xclient.format == 32 && event.xclient.data.l[0] == WM_DELETE_WINDOW) { ADBKeyDown(0x7f); // Power key ADBKeyUp(0x7f); } } XDisplayUnlock(); break; } switch (event.type) { // Mouse button case ButtonPress: { unsigned int button = event.xbutton.button; if (button < 4) ADBMouseDown(button - 1); else if (button < 6) { // Wheel mouse if (mouse_wheel_mode == 0) { int key = (button == 5) ? 0x79 : 0x74; // Page up/down ADBKeyDown(key); ADBKeyUp(key); } else { int key = (button == 5) ? 0x3d : 0x3e; // Cursor up/down for(int i=0; imouse_moved(event.xmotion.x, event.xmotion.y); break; // Mouse entered window case EnterNotify: if (event.xcrossing.mode != NotifyGrab && event.xcrossing.mode != NotifyUngrab) drv->mouse_moved(event.xmotion.x, event.xmotion.y); break; // Keyboard case KeyPress: { int code = -1; if (use_keycodes) { if (event2keycode(event.xkey, true) != -2) // This is called to process the hotkeys code = keycode_table[event.xkey.keycode & 0xff]; } else code = event2keycode(event.xkey, true); if (code >= 0) { if (!emul_suspended) { if (code == 0x39) { // Caps Lock pressed if (caps_on) { ADBKeyUp(code); caps_on = false; } else { ADBKeyDown(code); caps_on = true; } } else ADBKeyDown(code); if (code == 0x36) ctrl_down = true; } else { if (code == 0x31) drv->resume(); // Space wakes us up } } break; } case KeyRelease: { int code = -1; if (use_keycodes) { if (event2keycode(event.xkey, false) != -2) // This is called to process the hotkeys code = keycode_table[event.xkey.keycode & 0xff]; } else code = event2keycode(event.xkey, false); if (code >= 0 && code != 0x39) { // Don't propagate Caps Lock releases ADBKeyUp(code); if (code == 0x36) ctrl_down = false; } break; } // Hidden parts exposed, force complete refresh of window case Expose: if (display_type == DISPLAY_WINDOW) { const video_mode &mode = VideoMonitors[0]->get_current_mode(); #ifdef ENABLE_VOSF if (use_vosf) { // VOSF refresh LOCK_VOSF; PFLAG_SET_ALL; UNLOCK_VOSF; memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } else #endif if (frame_skip == 0) { // Dynamic refresh int x1, y1; for (y1=0; y1<16; y1++) for (x1=0; x1<16; x1++) updt_box[x1][y1] = true; nr_boxes = 16 * 16; } else // Static refresh memset(the_buffer_copy, 0, mode.bytes_per_row * mode.y); } break; } XDisplayUnlock(); } } /* * Window display update */ // Dynamic display update (variable frame rate for each box) static void update_display_dynamic(int ticker, driver_window *drv) { int y1, y2, y2s, y2a, i, x1, xm, xmo, ymo, yo, yi, yil, xi; int xil = 0; int rxm = 0, rxmo = 0; const video_mode &mode = drv->monitor.get_current_mode(); int bytes_per_row = mode.bytes_per_row; int bytes_per_pixel = mode.bytes_per_row / mode.x; int rx = mode.bytes_per_row / 16; int ry = mode.y / 16; int max_box; y2s = sm_uptd[ticker % 8]; y2a = 8; for (i = 0; i < 6; i++) if (ticker % (2 << i)) break; max_box = sm_no_boxes[i]; if (y2a) { for (y1=0; y1<16; y1++) { for (y2=y2s; y2 < ry; y2 += y2a) { i = ((y1 * ry) + y2) * bytes_per_row; for (x1=0; x1<16; x1++, i += rx) { if (updt_box[x1][y1] == false) { if (memcmp(&the_buffer_copy[i], &the_buffer[i], rx)) { updt_box[x1][y1] = true; nr_boxes++; } } } } } } XDisplayLock(); if ((nr_boxes <= max_box) && (nr_boxes)) { for (y1=0; y1<16; y1++) { for (x1=0; x1<16; x1++) { if (updt_box[x1][y1] == true) { if (rxm == 0) xm = x1; rxm += rx; updt_box[x1][y1] = false; } if (((updt_box[x1+1][y1] == false) || (x1 == 15)) && (rxm)) { if ((rxmo != rxm) || (xmo != xm) || (yo != y1 - 1)) { if (rxmo) { xi = xmo * rx; yi = ymo * ry; xil = rxmo; yil = (yo - ymo +1) * ry; } rxmo = rxm; xmo = xm; ymo = y1; } rxm = 0; yo = y1; } if (xil) { i = (yi * bytes_per_row) + xi; for (y2=0; y2 < yil; y2++, i += bytes_per_row) memcpy(&the_buffer_copy[i], &the_buffer[i], xil); if (mode.depth == VDEPTH_1BIT) { if (drv->have_shm) XShmPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil, 0); else XPutImage(x_display, drv->w, drv->gc, drv->img, xi * 8, yi, xi * 8, yi, xil * 8, yil); } else { if (drv->have_shm) XShmPutImage(x_display, drv->w, drv->gc, drv->img, xi / bytes_per_pixel, yi, xi / bytes_per_pixel, yi, xil / bytes_per_pixel, yil, 0); else XPutImage(x_display, drv->w, drv->gc, drv->img, xi / bytes_per_pixel, yi, xi / bytes_per_pixel, yi, xil / bytes_per_pixel, yil); } xil = 0; } if ((x1 == 15) && (y1 == 15) && (rxmo)) { x1--; xi = xmo * rx; yi = ymo * ry; xil = rxmo; yil = (yo - ymo +1) * ry; rxmo = 0; } } } nr_boxes = 0; } XDisplayUnlock(); } // Static display update (fixed frame rate, but incremental) static void update_display_static(driver_window *drv) { // Incremental update code unsigned wide = 0, high = 0, x1, x2, y1, y2, i, j; const video_mode &mode = drv->monitor.get_current_mode(); int bytes_per_row = mode.bytes_per_row; int bytes_per_pixel = mode.bytes_per_row / mode.x; uint8 *p, *p2; // Check for first line from top and first line from bottom that have changed y1 = 0; for (j=0; j=y1; j--) { if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) { y2 = j; break; } } high = y2 - y1 + 1; // Check for first column from left and first column from right that have changed if (high) { if (mode.depth == VDEPTH_1BIT) { x1 = mode.x - 1; for (j=y1; j<=y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; for (i=0; i<(x1>>3); i++) { if (*p != *p2) { x1 = i << 3; break; } p++; p2++; } } x2 = x1; for (j=y1; j<=y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; p += bytes_per_row; p2 += bytes_per_row; for (i=(mode.x>>3); i>(x2>>3); i--) { p--; p2--; if (*p != *p2) { x2 = (i << 3) + 7; break; } } } wide = x2 - x1 + 1; // Update copy of the_buffer if (high && wide) { for (j=y1; j<=y2; j++) { i = j * bytes_per_row + (x1 >> 3); memcpy(the_buffer_copy + i, the_buffer + i, wide >> 3); } } } else { x1 = mode.x; for (j=y1; j<=y2; j++) { p = &the_buffer[j * bytes_per_row]; p2 = &the_buffer_copy[j * bytes_per_row]; for (i=0; ix2*bytes_per_pixel; i--) { p--; p2--; if (*p != *p2) { x2 = i / bytes_per_pixel; break; } } } wide = x2 - x1; // Update copy of the_buffer if (high && wide) { for (j=y1; j<=y2; j++) { i = j * bytes_per_row + x1 * bytes_per_pixel; memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * wide); } } } } // Refresh display XDisplayLock(); if (high && wide) { if (drv->have_shm) XShmPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high, 0); else XPutImage(x_display, drv->w, drv->gc, drv->img, x1, y1, x1, y1, wide, high); } XDisplayUnlock(); } /* * Screen refresh functions */ // We suggest the compiler to inline the next two functions so that it // may specialise the code according to the current screen depth and // display type. A clever compiler would do that job by itself though... // NOTE: update_display_vosf is inlined too static inline void possibly_quit_dga_mode() { // Quit DGA mode if requested (something terrible has happened and we // want to give control back to the user) if (quit_full_screen) { quit_full_screen = false; delete drv; drv = NULL; } } static inline void possibly_ungrab_mouse() { // Ungrab mouse if requested (something terrible has happened and we // want to give control back to the user) if (quit_full_screen) { quit_full_screen = false; if (drv) drv->ungrab_mouse(); } } static inline void handle_palette_changes(void) { LOCK_PALETTE; if (x_palette_changed) { x_palette_changed = false; XDisplayLock(); drv->update_palette(); XDisplayUnlock(); } UNLOCK_PALETTE; } static void video_refresh_dga(void) { // Quit DGA mode if requested possibly_quit_dga_mode(); } #ifdef ENABLE_VOSF #if REAL_ADDRESSING || DIRECT_ADDRESSING static void video_refresh_dga_vosf(void) { // Quit DGA mode if requested possibly_quit_dga_mode(); // Update display (VOSF variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { tick_counter = 0; if (mainBuffer.dirty) { LOCK_VOSF; update_display_dga_vosf(static_cast(drv)); UNLOCK_VOSF; } } } #endif static void video_refresh_window_vosf(void) { // Ungrab mouse if requested possibly_ungrab_mouse(); // Update display (VOSF variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { tick_counter = 0; if (mainBuffer.dirty) { XDisplayLock(); LOCK_VOSF; update_display_window_vosf(static_cast(drv)); UNLOCK_VOSF; XSync(x_display, false); // Let the server catch up XDisplayUnlock(); } } } #endif // def ENABLE_VOSF static void video_refresh_window_static(void) { // Ungrab mouse if requested possibly_ungrab_mouse(); // Update display (static variant) static int tick_counter = 0; if (++tick_counter >= frame_skip) { tick_counter = 0; update_display_static(static_cast(drv)); } } static void video_refresh_window_dynamic(void) { // Ungrab mouse if requested possibly_ungrab_mouse(); // Update display (dynamic variant) static int tick_counter = 0; tick_counter++; update_display_dynamic(tick_counter, static_cast(drv)); } /* * Thread for screen refresh, input handling etc. */ static void VideoRefreshInit(void) { // TODO: set up specialised 8bpp VideoRefresh handlers ? if (display_type == DISPLAY_DGA) { #if ENABLE_VOSF && (REAL_ADDRESSING || DIRECT_ADDRESSING) if (use_vosf) video_refresh = video_refresh_dga_vosf; else #endif video_refresh = video_refresh_dga; } else { #ifdef ENABLE_VOSF if (use_vosf) video_refresh = video_refresh_window_vosf; else #endif if (frame_skip == 0) video_refresh = video_refresh_window_dynamic; else video_refresh = video_refresh_window_static; } } // This function is called on non-threaded platforms from a timer interrupt void VideoRefresh(void) { // We need to check redraw_thread_active to inhibit refreshed during // mode changes on non-threaded platforms if (!redraw_thread_active) return; // Handle X events handle_events(); // Handle palette changes handle_palette_changes(); // Update display video_refresh(); } const int VIDEO_REFRESH_HZ = 60; const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ; #ifdef USE_PTHREADS_SERVICES static void *redraw_func(void *arg) { int fd = ConnectionNumber(x_display); uint64 start = GetTicks_usec(); int64 ticks = 0; uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY; while (!redraw_thread_cancel) { int64 delay = next - GetTicks_usec(); if (delay < -VIDEO_REFRESH_DELAY) { // We are lagging far behind, so we reset the delay mechanism next = GetTicks_usec(); } else if (delay <= 0) { // Delay expired, refresh display handle_events(); handle_palette_changes(); video_refresh(); next += VIDEO_REFRESH_DELAY; ticks++; } else { // No display refresh pending, check for X events fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds); struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = delay; if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0) handle_events(); } } uint64 end = GetTicks_usec(); D(bug("%lld refreshes in %lld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); redraw_thread_cancel_ack = true; return NULL; } #endif BasiliskII/src/Unix/clip_unix.cpp0000644000175000017500000004534611340201450017153 0ustar centriscentris/* * clip_unix.cpp - Clipboard handling, Unix implementation * * SheepShaver (C) Christian Bauer and Marc Hellwig * * 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 */ /* * NOTES: * * We must have (fast) X11 display locking routines. Otherwise, we * can corrupt the X11 event queue from the emulator thread whereas * the redraw thread is expected to handle them. * * Two functions are exported to video_x.cpp: * - ClipboardSelectionClear() * called when we lose the selection ownership * - ClipboardSelectionRequest() * called when another client wants our clipboard data * The display is locked by the redraw thread during their execution. * * On PutScrap (Mac application wrote to clipboard), we always cache * the Mac clipboard to a local structure (clip_data). Then, the * selection ownership is grabbed until ClipboardSelectionClear() * occurs. In that case, contents in cache becomes invalid. * * On GetScrap (Mac application reads clipboard), we always fetch * data from the X11 clipboard and immediately put it back to Mac * side. Local cache does not need to be updated. If the selection * owner supports the TIMESTAMP target, we can avoid useless copies. * * For safety purposes, we lock the X11 display in the emulator * thread during the whole GetScrap/PutScrap execution. Of course, we * temporarily release the lock when waiting for SelectioNotify. * * TODO: * - handle 'PICT' to image/png, image/ppm, PIXMAP (prefs order) * - handle 'styl' to text/richtext (OOo Writer) * - patch ZeroScrap so that we know when cached 'styl' is stale? */ #include "sysdeps.h" #include #include #include #include #include "macos_util.h" #include "clip.h" #include "prefs.h" #include "cpu_emulation.h" #include "main.h" #include "emul_op.h" #define DEBUG 0 #include "debug.h" #ifndef NO_STD_NAMESPACE using std::vector; #endif // Do we want GetScrap() to check for TIMESTAMP and optimize out clipboard syncs? #define GETSCRAP_REQUESTS_TIMESTAMP 0 // Do we want GetScrap() to first check for TARGETS available from the clipboard? #define GETSCRAP_REQUESTS_TARGETS 0 // From main_linux.cpp extern Display *x_display; // Conversion tables static const uint8 mac2iso[0x80] = { 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, 0x2b, 0xb0, 0xa2, 0xa3, 0xa7, 0xb7, 0xb6, 0xdf, 0xae, 0xa9, 0x20, 0xb4, 0xa8, 0x23, 0xc6, 0xd8, 0x20, 0xb1, 0x3c, 0x3e, 0xa5, 0xb5, 0xf0, 0x53, 0x50, 0x70, 0x2f, 0xaa, 0xba, 0x4f, 0xe6, 0xf8, 0xbf, 0xa1, 0xac, 0x2f, 0x66, 0x7e, 0x44, 0xab, 0xbb, 0x2e, 0x20, 0xc0, 0xc3, 0xd5, 0x4f, 0x6f, 0x2d, 0x2d, 0x22, 0x22, 0x60, 0x27, 0xf7, 0x20, 0xff, 0x59, 0x2f, 0xa4, 0x3c, 0x3e, 0x66, 0x66, 0x23, 0xb7, 0x2c, 0x22, 0x25, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, 0x20, 0xd2, 0xda, 0xdb, 0xd9, 0x69, 0x5e, 0x7e, 0xaf, 0x20, 0xb7, 0xb0, 0xb8, 0x22, 0xb8, 0x20 }; static const uint8 iso2mac[0x80] = { 0xad, 0xb0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0, 0xf6, 0xe4, 0xde, 0xdc, 0xce, 0xb2, 0xb3, 0xb6, 0xb7, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1, 0xf7, 0xaa, 0xdf, 0xdd, 0xcf, 0xba, 0xfd, 0xd9, 0xca, 0xc1, 0xa2, 0xa3, 0xdb, 0xb4, 0xbd, 0xa4, 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xf0, 0xa8, 0xf8, 0xa1, 0xb1, 0xc3, 0xc5, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0xc6, 0xbc, 0xc8, 0xf9, 0xda, 0xd7, 0xc0, 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, 0xf5, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xfb, 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xfa, 0xb8, 0xa7, 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, 0xfe, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xff, 0xb9, 0xd8 }; // Flag: Don't convert clipboard text static bool no_clip_conversion; // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Unix side static bool we_put_this_data = false; // X11 variables static int screen; // Screen number static Window rootwin, clip_win; // Root window and the clipboard window static Atom xa_clipboard; static Atom xa_targets; static Atom xa_multiple; static Atom xa_timestamp; static Atom xa_atom_pair; // Define a byte array (rewrite if it's a bottleneck) struct ByteArray : public vector { void resize(int size) { reserve(size); vector::resize(size); } uint8 *data() { return &(*this)[0]; } }; // Clipboard data for requestors struct ClipboardData { Time time; Atom type; ByteArray data; }; static ClipboardData clip_data; // Prototypes static void do_putscrap(uint32 type, void *scrap, int32 length); static void do_getscrap(void **handle, uint32 type, int32 offset); /* * Read an X11 property (hack from QT 3.1.2) */ static inline int max_selection_incr(Display *dpy) { int max_request_size = 4 * XMaxRequestSize(dpy); if (max_request_size > 4 * 65536) max_request_size = 4 * 65536; else if ((max_request_size -= 100) < 0) max_request_size = 100; return max_request_size; } static bool read_property(Display *dpy, Window win, Atom property, bool deleteProperty, ByteArray & buffer, int *size, Atom *type, int *format, bool nullterm) { int maxsize = max_selection_incr(dpy); unsigned long bytes_left; unsigned long length; unsigned char *data; Atom dummy_type; int dummy_format; if (!type) type = &dummy_type; if (!format) format = &dummy_format; // Don't read anything but get the size of the property data if (XGetWindowProperty(dpy, win, property, 0, 0, False, AnyPropertyType, type, format, &length, &bytes_left, &data) != Success) { buffer.clear(); return false; } XFree(data); int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left; switch (*format) { case 16: format_inc = sizeof(short) / 2; proplen *= format_inc; break; case 32: format_inc = sizeof(long) / 4; proplen *= format_inc; break; } buffer.resize(proplen + (nullterm ? 1 : 0)); while (bytes_left) { if (XGetWindowProperty(dpy, win, property, offset, maxsize / 4, False, AnyPropertyType, type, format, &length, &bytes_left, &data) != Success) break; offset += length / (32 / *format); length *= format_inc * (*format / 8); memcpy(buffer.data() + buffer_offset, data, length); buffer_offset += length; XFree(data); } if (nullterm) buffer[buffer_offset] = '\0'; if (size) *size = buffer_offset; if (deleteProperty) XDeleteProperty(dpy, win, property); XFlush(dpy); return true; } /* * Timed wait for a SelectionNotify event */ static const uint64 SELECTION_MAX_WAIT = 500000; // 500 ms static bool wait_for_selection_notify_event(Display *dpy, Window win, XEvent *event, int timeout) { uint64 start = GetTicks_usec(); do { // Wait XDisplayUnlock(); Delay_usec(5000); XDisplayLock(); // Check for SelectionNotify event if (XCheckTypedWindowEvent(dpy, win, SelectionNotify, event)) return true; } while ((GetTicks_usec() - start) < timeout); return false; } /* * Initialization */ void ClipInit(void) { no_clip_conversion = PrefsFindBool("noclipconversion"); // Find screen and root window screen = XDefaultScreen(x_display); rootwin = XRootWindow(x_display, screen); // Create fake window to receive selection events clip_win = XCreateSimpleWindow(x_display, rootwin, 0, 0, 1, 1, 0, 0, 0); // Initialize X11 atoms xa_clipboard = XInternAtom(x_display, "CLIPBOARD", False); xa_targets = XInternAtom(x_display, "TARGETS", False); xa_multiple = XInternAtom(x_display, "MULTIPLE", False); xa_timestamp = XInternAtom(x_display, "TIMESTAMP", False); xa_atom_pair = XInternAtom(x_display, "ATOM_PAIR", False); } /* * Deinitialization */ void ClipExit(void) { // Close window if (clip_win) XDestroyWindow(x_display, clip_win); } /* * Mac application wrote to clipboard */ void PutScrap(uint32 type, void *scrap, int32 length) { D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length)); if (we_put_this_data) { we_put_this_data = false; return; } if (length <= 0) return; XDisplayLock(); do_putscrap(type, scrap, length); XDisplayUnlock(); } static void do_putscrap(uint32 type, void *scrap, int32 length) { clip_data.type = None; switch (type) { case FOURCC('T','E','X','T'): { D(bug(" clipping TEXT\n")); clip_data.type = XA_STRING; clip_data.data.clear(); clip_data.data.reserve(length); // Convert text from Mac charset to ISO-Latin1 uint8 *p = (uint8 *)scrap; for (int i=0; i LF c = 10; } else if (!no_clip_conversion) c = mac2iso[c & 0x7f]; clip_data.data.push_back(c); } break; } case FOURCC('s','t','y','l'): { D(bug(" clipping styl\n")); uint16 *p = (uint16 *)scrap; uint16 n = ntohs(*p++); D(bug(" %d styles (%d bytes)\n", n, length)); for (int i = 0; i < n; i++) { uint32 offset = ntohl(*(uint32 *)p); p += 2; uint16 line_height = ntohs(*p++); uint16 font_ascent = ntohs(*p++); uint16 font_family = ntohs(*p++); uint16 style_code = ntohs(*p++); uint16 char_size = ntohs(*p++); uint16 r = ntohs(*p++); uint16 g = ntohs(*p++); uint16 b = ntohs(*p++); D(bug(" offset=%d, height=%d, font ascent=%d, id=%d, style=%x, size=%d, RGB=%x/%x/%x\n", offset, line_height, font_ascent, font_family, style_code, char_size, r, g, b)); } break; } } // Acquire selection ownership if (clip_data.type != None) { clip_data.time = CurrentTime; while (XGetSelectionOwner(x_display, xa_clipboard) != clip_win) XSetSelectionOwner(x_display, xa_clipboard, clip_win, clip_data.time); } } /* * Mac application reads clipboard */ void GetScrap(void **handle, uint32 type, int32 offset) { D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); XDisplayLock(); do_getscrap(handle, type, offset); XDisplayUnlock(); } static void do_getscrap(void **handle, uint32 type, int32 offset) { ByteArray data; XEvent event; // If we own the selection, the data is already available on MacOS side if (XGetSelectionOwner(x_display, xa_clipboard) == clip_win) return; // Check TIMESTAMP #if GETSCRAP_REQUESTS_TIMESTAMP static Time last_timestamp = 0; XConvertSelection(x_display, xa_clipboard, xa_timestamp, xa_clipboard, clip_win, CurrentTime); if (wait_for_selection_notify_event(x_display, clip_win, &event, SELECTION_MAX_WAIT) && event.xselection.property != None && read_property(x_display, event.xselection.requestor, event.xselection.property, true, data, 0, 0, 0, false)) { Time timestamp = ((long *)data.data())[0]; if (timestamp <= last_timestamp) return; } last_timestamp = CurrentTime; #endif // Get TARGETS available #if GETSCRAP_REQUESTS_TARGETS XConvertSelection(x_display, xa_clipboard, xa_targets, xa_clipboard, clip_win, CurrentTime); if (!wait_for_selection_notify_event(x_display, clip_win, &event, SELECTION_MAX_WAIT) || event.xselection.property == None || !read_property(x_display, event.xselection.requestor, event.xselection.property, true, data, 0, 0, 0, false)) return; #endif // Get appropriate format for requested data Atom format = None; #if GETSCRAP_REQUESTS_TARGETS int n_atoms = data.size() / sizeof(long); long *atoms = (long *)data.data(); for (int i = 0; i < n_atoms; i++) { Atom target = atoms[i]; D(bug(" target %08x (%s)\n", target, XGetAtomName(x_display, target))); switch (type) { case FOURCC('T','E','X','T'): D(bug(" clipping TEXT\n")); if (target == XA_STRING) format = target; break; case FOURCC('P','I','C','T'): break; } } #else switch (type) { case FOURCC('T','E','X','T'): D(bug(" clipping TEXT\n")); format = XA_STRING; break; case FOURCC('P','I','C','T'): break; } #endif if (format == None) return; // Get the native clipboard data XConvertSelection(x_display, xa_clipboard, format, xa_clipboard, clip_win, CurrentTime); if (!wait_for_selection_notify_event(x_display, clip_win, &event, SELECTION_MAX_WAIT) || event.xselection.property == None || !read_property(x_display, event.xselection.requestor, event.xselection.property, false, data, 0, 0, 0, format == XA_STRING)) return; // Allocate space for new scrap in MacOS side M68kRegisters r; r.d[0] = data.size(); Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 scrap_area = r.a[0]; if (scrap_area) { switch (type) { case FOURCC('T','E','X','T'): // Convert text from ISO-Latin1 to Mac charset uint8 *p = Mac2HostAddr(scrap_area); for (int i = 0; i < data.size(); i++) { uint8 c = data[i]; if (c < 0x80) { if (c == 10) // LF -> CR c = 13; } else if (!no_clip_conversion) c = iso2mac[c & 0x7f]; *p++ = c; } break; } // Add new data to clipboard static uint8 proc[] = { 0x59, 0x8f, // subq.l #4,sp 0xa9, 0xfc, // ZeroScrap() 0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp) 0xa9, 0xfe, // PutScrap() 0x58, 0x8f, // addq.l #4,sp M68K_RTS >> 8, M68K_RTS & 0xff }; r.d[0] = sizeof(proc); Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 proc_area = r.a[0]; // The procedure is run-time generated because it must lays in // Mac address space. This is mandatory for "33-bit" address // space optimization on 64-bit platforms because the static // proc[] array is not remapped Host2Mac_memcpy(proc_area, proc, sizeof(proc)); WriteMacInt32(proc_area + 6, data.size()); WriteMacInt32(proc_area + 12, type); WriteMacInt32(proc_area + 18, scrap_area); we_put_this_data = true; Execute68k(proc_area, &r); // We are done with scratch memory r.a[0] = proc_area; Execute68kTrap(0xa01f, &r); // DisposePtr r.a[0] = scrap_area; Execute68kTrap(0xa01f, &r); // DisposePtr } } /* * Handle X11 selection events */ void ClipboardSelectionClear(XSelectionClearEvent *xev) { if (xev->selection != xa_clipboard) return; D(bug("Selection cleared, lost clipboard ownership\n")); clip_data.type = None; clip_data.data.clear(); } // Top level selection handler static bool handle_selection(XSelectionRequestEvent *req, bool is_multiple); static bool handle_selection_TIMESTAMP(XSelectionRequestEvent *req) { // 32-bit integer values are always passed as a long whatever is its size long timestamp = clip_data.time; // Change requestor property XChangeProperty(x_display, req->requestor, req->property, XA_INTEGER, 32, PropModeReplace, (uint8 *)×tamp, 1); return true; } static bool handle_selection_TARGETS(XSelectionRequestEvent *req) { // Default supported targets vector targets; targets.push_back(xa_targets); targets.push_back(xa_multiple); targets.push_back(xa_timestamp); // Extra targets matchin current clipboard data if (clip_data.type != None) targets.push_back(clip_data.type); // Change requestor property XChangeProperty(x_display, req->requestor, req->property, xa_targets, 32, PropModeReplace, (uint8 *)&targets[0], targets.size()); return true; } static bool handle_selection_STRING(XSelectionRequestEvent *req) { // Make sure we have valid data to send though ICCCM compliant // clients should have first requested TARGETS to identify // this possibility. if (clip_data.type != XA_STRING) return false; // Send the string, it's already encoded as ISO-8859-1 XChangeProperty(x_display, req->requestor, req->property, XA_STRING, 8, PropModeReplace, (uint8 *)clip_data.data.data(), clip_data.data.size()); return true; } static bool handle_selection_MULTIPLE(XSelectionRequestEvent *req) { Atom rtype; int rformat; ByteArray data; if (!read_property(x_display, req->requestor, req->property, false, data, 0, &rtype, &rformat, 0)) return false; // rtype should be ATOM_PAIR but some clients don't honour that if (rformat != 32) return false; struct AtomPair { long target; long property; }; AtomPair *atom_pairs = (AtomPair *)data.data(); int n_atom_pairs = data.size() / sizeof(AtomPair); bool handled = true; if (n_atom_pairs) { // Setup a new XSelectionRequestEvent when servicing individual requests XSelectionRequestEvent event; memcpy(&event, req, sizeof(event)); for (int i = 0; i < n_atom_pairs; i++) { Atom target = atom_pairs[i].target; Atom property = atom_pairs[i].property; // None is not a valid property if (property == None) continue; // Service this request event.target = target; event.property = property; if (!handle_selection(&event, true)) { /* FIXME: ICCCM 2.6.2: If the owner fails to convert the target named by an atom in the MULTIPLE property, it should replace that atom in the property with None. */ handled = false; } } } return handled; } static bool handle_selection(XSelectionRequestEvent *req, bool is_multiple) { bool handled =false; if (req->target == xa_timestamp) handled = handle_selection_TIMESTAMP(req); else if (req->target == xa_targets) handled = handle_selection_TARGETS(req); else if (req->target == XA_STRING) handled = handle_selection_STRING(req); else if (req->target == xa_multiple) handled = handle_selection_MULTIPLE(req); // Notify requestor only when we are done with his request if (handled && !is_multiple) { XEvent out_event; out_event.xselection.type = SelectionNotify; out_event.xselection.requestor = req->requestor; out_event.xselection.selection = req->selection; out_event.xselection.target = req->target; out_event.xselection.property = handled ? req->property : None; out_event.xselection.time = req->time; XSendEvent(x_display, req->requestor, False, 0, &out_event); } return handled; } void ClipboardSelectionRequest(XSelectionRequestEvent *req) { if (req->requestor == clip_win || req->selection != xa_clipboard) return; D(bug("Selection requested from 0x%lx to 0x%lx (%s) 0x%lx (%s)\n", req->requestor, req->selection, XGetAtomName(req->display, req->selection), req->target, XGetAtomName(req->display, req->target))); handle_selection(req, false); } BasiliskII/src/Unix/user_strings_unix.cpp0000644000175000017500000001163010736405221020752 0ustar centriscentris/* * user_strings_unix.cpp - Unix-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "user_strings.h" // Platform-specific string definitions user_string_def platform_strings[] = { // Common strings that have a platform-specific variant {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under Unix. Basilisk II will try to unmount it."}, {STR_EXTFS_CTRL, "Unix Root"}, {STR_EXTFS_NAME, "Unix Directory Tree"}, {STR_EXTFS_VOLUME_NAME, "Unix"}, // Purely platform-specific strings {STR_NO_XSERVER_ERR, "Cannot connect to X server '%s'."}, {STR_NO_XVISUAL_ERR, "Cannot obtain appropriate X visual."}, {STR_UNSUPP_DEPTH_ERR, "Unsupported color depth of screen."}, {STR_NO_FBDEVICE_FILE_ERR, "Cannot open frame buffer device specification file %s (%s)."}, {STR_FBDEV_NAME_ERR, "The %s frame buffer is not supported in %d bit mode."}, {STR_FBDEV_MMAP_ERR, "Cannot mmap() the frame buffer memory (%s)."}, {STR_VOSF_INIT_ERR, "Cannot initialize Video on SEGV signals."}, {STR_NO_DEV_ZERO_ERR, "Cannot open /dev/zero (%s)."}, {STR_LOW_MEM_MMAP_ERR, "Cannot map Low Memory Globals (%s)."}, {STR_SIGALTSTACK_ERR, "Cannot install alternate signal stack (%s)."}, {STR_SIG_INSTALL_ERR, "Cannot install %s handler (%s)."}, {STR_TIMER_CREATE_ERR, "Cannot create timer (%s)."}, {STR_TIMER_SETTIME_ERR, "Cannot start timer (%s)."}, {STR_TICK_THREAD_ERR, "Cannot create 60Hz thread (%s)."}, {STR_BLOCKING_NET_SOCKET_WARN, "Cannot set non-blocking I/O to net socket (%s). Ethernet will not be available."}, {STR_NO_SHEEP_NET_DRIVER_WARN, "Cannot open %s (%s). Ethernet will not be available."}, {STR_SHEEP_NET_ATTACH_WARN, "Cannot attach to Ethernet card (%s). Ethernet will not be available."}, {STR_TUN_TAP_CONFIG_WARN, "Cannot configure TUN/TAP device (%s). Ethernet will not be available."}, {STR_SLIRP_NO_DNS_FOUND_WARN, "Cannot get DNS address. Ethernet will not be available."}, {STR_SCSI_DEVICE_OPEN_WARN, "Cannot open %s (%s). SCSI Manager access to this device will be disabled."}, {STR_SCSI_DEVICE_NOT_SCSI_WARN, "%s doesn't seem to comply to the Generic SCSI API. SCSI Manager access to this device will be disabled."}, {STR_NO_AUDIO_DEV_WARN, "Cannot open %s (%s). Audio output will be disabled."}, {STR_NO_AUDIO_WARN, "No audio device found, audio output will be disabled."}, {STR_AUDIO_FORMAT_WARN, "Audio hardware doesn't seem to support necessary format. Audio output will be disabled."}, {STR_KEYCODE_FILE_WARN, "Cannot open keycode translation file %s (%s)."}, {STR_KEYCODE_VENDOR_WARN, "Cannot find vendor '%s' in keycode translation file %s."}, {STR_PREFS_MENU_FILE_GTK, "/_File"}, {STR_PREFS_ITEM_START_GTK, "/File/_Start Basilisk II"}, {STR_PREFS_ITEM_ZAP_PRAM_GTK, "/File/_Zap PRAM File"}, {STR_PREFS_ITEM_SEPL_GTK, "/File/sepl"}, {STR_PREFS_ITEM_QUIT_GTK, "/File/_Quit Basilisk II"}, {STR_HELP_MENU_GTK, "/_Help"}, {STR_HELP_ITEM_ABOUT_GTK, "/Help/_About Basilisk II"}, {STR_FBDEV_NAME_CTRL, "Frame Buffer Name"}, {STR_FBDEVICE_FILE_CTRL, "Frame Buffer Spec File"}, {STR_DSPDEVICE_FILE_CTRL, "Audio Output Device"}, {STR_MIXERDEVICE_FILE_CTRL, "Audio Mixer Device"}, {STR_BROWSE_TITLE, "Browse file"}, {STR_BROWSE_CTRL, "Browse..."}, {STR_INPUT_PANE_TITLE, "Keyboard/Mouse"}, {STR_KEYCODES_CTRL, "Use Raw Keycodes"}, {STR_KEYCODE_FILE_CTRL, "Keycode Translation File"}, {STR_MOUSEWHEELMODE_CTRL, "Mouse Wheel Function"}, {STR_MOUSEWHEELMODE_PAGE_LAB, "Page Up/Down"}, {STR_MOUSEWHEELMODE_CURSOR_LAB, "Cursor Up/Down"}, {STR_MOUSEWHEELLINES_CTRL, "Lines To Scroll"}, {STR_IGNORESEGV_CTRL, "Ignore Illegal Memory Accesses"}, {STR_WINDOW_TITLE_GRABBED, "Basilisk II (mouse grabbed, press Ctrl-F5 to release)"}, {STR_NO_B2_EXE_FOUND, "Could not start %s (%s)."}, {-1, NULL} // End marker }; /* * Fetch pointer to string, given the string number */ const char *GetString(int num) { // First search for platform-specific string int i = 0; while (platform_strings[i].num >= 0) { if (platform_strings[i].num == num) return platform_strings[i].str; i++; } // Not found, search for common string i = 0; while (common_strings[i].num >= 0) { if (common_strings[i].num == num) return common_strings[i].str; i++; } return NULL; } BasiliskII/src/Unix/prefs_unix.cpp0000644000175000017500000000735611232133662017353 0ustar centriscentris/* * prefs_unix.cpp - Preferences handling, Unix specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include using std::string; #include "prefs.h" // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {"keycodes", TYPE_BOOLEAN, false, "use keycodes rather than keysyms to decode keyboard"}, {"keycodefile", TYPE_STRING, false, "path of keycode translation file"}, {"fbdevicefile", TYPE_STRING, false, "path of frame buffer device specification file"}, {"mousewheelmode", TYPE_INT32, false, "mouse wheel support mode (0=page up/down, 1=cursor up/down)"}, {"mousewheellines", TYPE_INT32, false, "number of lines to scroll in mouse wheel mode 1"}, {"dsp", TYPE_STRING, false, "audio output (dsp) device name"}, {"mixer", TYPE_STRING, false, "audio mixer device name"}, #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION {"ignoresegv", TYPE_BOOLEAN, false, "ignore illegal memory accesses"}, #endif {"idlewait", TYPE_BOOLEAN, false, "sleep when idle"}, {NULL, TYPE_END, false, NULL} // End of list }; // Prefs file name and path const char PREFS_FILE_NAME[] = ".basilisk_ii_prefs"; string UserPrefsPath; static string prefs_path; /* * Load preferences from settings file */ void LoadPrefs(const char *vmdir) { if (vmdir) { prefs_path = string(vmdir) + '/' + string("prefs"); FILE *prefs = fopen(prefs_path.c_str(), "r"); if (!prefs) { printf("No file at %s found.\n", prefs_path.c_str()); exit(1); } LoadPrefsFromStream(prefs); fclose(prefs); return; } // Construct prefs path if (UserPrefsPath.empty()) { char *home = getenv("HOME"); if (home) prefs_path = string(home) + '/'; prefs_path += PREFS_FILE_NAME; } else prefs_path = UserPrefsPath; // Read preferences from settings file FILE *f = fopen(prefs_path.c_str(), "r"); if (f != NULL) { // Prefs file found, load settings LoadPrefsFromStream(f); fclose(f); } else { // No prefs file, save defaults SavePrefs(); } } /* * Save preferences to settings file */ void SavePrefs(void) { FILE *f; if ((f = fopen(prefs_path.c_str(), "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit() */ void AddPlatformPrefsDefaults(void) { PrefsAddBool("keycodes", false); PrefsReplaceString("extfs", "/"); PrefsReplaceInt32("mousewheelmode", 1); PrefsReplaceInt32("mousewheellines", 3); #ifdef __linux__ if (access("/dev/sound/dsp", F_OK) == 0) { PrefsReplaceString("dsp", "/dev/sound/dsp"); } else { PrefsReplaceString("dsp", "/dev/dsp"); } if (access("/dev/sound/mixer", F_OK) == 0) { PrefsReplaceString("mixer", "/dev/sound/mixer"); } else { PrefsReplaceString("mixer", "/dev/mixer"); } #else PrefsReplaceString("dsp", "/dev/dsp"); PrefsReplaceString("mixer", "/dev/mixer"); #endif #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION PrefsAddBool("ignoresegv", false); #endif PrefsAddBool("idlewait", true); } BasiliskII/src/Unix/video_blit.h0000644000175000017500000001225110736405221016745 0ustar centriscentris/* * video_blit.h - Video/graphics emulation, blitters * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef DEFINE_VIDEO_BLITTERS #ifndef VIDEO_BLIT_H #define VIDEO_BLIT_H // Format of the target visual struct VisualFormat { bool fullscreen; // Full screen mode? int depth; // Screen depth uint32 Rmask, Gmask, Bmask; // RGB mask values uint32 Rshift, Gshift, Bshift; // RGB shift values }; // Prototypes extern void (*Screen_blit)(uint8 * dest, const uint8 * source, uint32 length); extern bool Screen_blitter_init(VisualFormat const & visual_format, bool native_byte_order, int mac_depth); extern uint32 ExpandMap[256]; // Glue for SheepShaver and BasiliskII #ifdef SHEEPSHAVER enum { VIDEO_DEPTH_1BIT = APPLE_1_BIT, VIDEO_DEPTH_2BIT = APPLE_2_BIT, VIDEO_DEPTH_4BIT = APPLE_4_BIT, VIDEO_DEPTH_8BIT = APPLE_8_BIT, VIDEO_DEPTH_16BIT = APPLE_16_BIT, VIDEO_DEPTH_32BIT = APPLE_32_BIT }; #define VIDEO_MODE VideoInfo #define VIDEO_MODE_INIT VideoInfo const & mode = VModes[cur_mode] #define VIDEO_MODE_INIT_MONITOR VIDEO_MODE_INIT #define VIDEO_MODE_ROW_BYTES mode.viRowBytes #define VIDEO_MODE_X mode.viXsize #define VIDEO_MODE_Y mode.viYsize #define VIDEO_MODE_RESOLUTION mode.viAppleID #define VIDEO_MODE_DEPTH mode.viAppleMode #else enum { VIDEO_DEPTH_1BIT = VDEPTH_1BIT, VIDEO_DEPTH_2BIT = VDEPTH_2BIT, VIDEO_DEPTH_4BIT = VDEPTH_4BIT, VIDEO_DEPTH_8BIT = VDEPTH_8BIT, VIDEO_DEPTH_16BIT = VDEPTH_16BIT, VIDEO_DEPTH_32BIT = VDEPTH_32BIT }; #define VIDEO_MODE video_mode #define VIDEO_MODE_INIT video_mode const & mode = drv->mode #define VIDEO_MODE_INIT_MONITOR video_mode const & mode = monitor.get_current_mode() #define VIDEO_MODE_ROW_BYTES mode.bytes_per_row #define VIDEO_MODE_X mode.x #define VIDEO_MODE_Y mode.y #define VIDEO_MODE_RESOLUTION mode.resolution_id #define VIDEO_MODE_DEPTH mode.depth #endif #endif /* VIDEO_BLIT_H */ #else #ifndef FB_DEPTH # error "Undefined screen depth" #endif #if !defined(FB_BLIT_1) && (FB_DEPTH <= 16) # error "Undefined 16-bit word blit function" #endif #if !defined(FB_BLIT_2) # error "Undefined 32-bit word blit function" #endif #if !defined(FB_BLIT_4) # error "Undefined 64-bit word blit function" #endif static void FB_FUNC_NAME(uint8 * dest, const uint8 * source, uint32 length) { #define DEREF_WORD_PTR(ptr, ofs) (((uint16 *)(ptr))[(ofs)]) #define DEREF_LONG_PTR(ptr, ofs) (((uint32 *)(ptr))[(ofs)]) #define DEREF_QUAD_PTR(ptr, ofs) (((uint64 *)(ptr))[(ofs)]) #ifndef UNALIGNED_PROFITABLE #if FB_DEPTH <= 8 // Align source and dest to 16-bit word boundaries if (((unsigned long) source) & 1) { *dest++ = *source++; length -= 1; } #endif #if FB_DEPTH <= 16 // Align source and dest to 32-bit word boundaries if (((unsigned long) source) & 2) { FB_BLIT_1(DEREF_WORD_PTR(dest, 0), DEREF_WORD_PTR(source, 0)); dest += 2; source += 2; length -= 2; } #endif #endif // Blit 8-byte words if (length >= 8) { const int remainder = (length / 8) % 8; source += remainder * 8; dest += remainder * 8; int n = ((length / 8) + 7) / 8; switch (remainder) { case 0: do { dest += 64; source += 64; FB_BLIT_4(DEREF_QUAD_PTR(dest, -8), DEREF_QUAD_PTR(source, -8)); case 7: FB_BLIT_4(DEREF_QUAD_PTR(dest, -7), DEREF_QUAD_PTR(source, -7)); case 6: FB_BLIT_4(DEREF_QUAD_PTR(dest, -6), DEREF_QUAD_PTR(source, -6)); case 5: FB_BLIT_4(DEREF_QUAD_PTR(dest, -5), DEREF_QUAD_PTR(source, -5)); case 4: FB_BLIT_4(DEREF_QUAD_PTR(dest, -4), DEREF_QUAD_PTR(source, -4)); case 3: FB_BLIT_4(DEREF_QUAD_PTR(dest, -3), DEREF_QUAD_PTR(source, -3)); case 2: FB_BLIT_4(DEREF_QUAD_PTR(dest, -2), DEREF_QUAD_PTR(source, -2)); case 1: FB_BLIT_4(DEREF_QUAD_PTR(dest, -1), DEREF_QUAD_PTR(source, -1)); } while (--n > 0); } } // There could be one long left to blit if (length & 4) { FB_BLIT_2(DEREF_LONG_PTR(dest, 0), DEREF_LONG_PTR(source, 0)); #if FB_DEPTH <= 16 dest += 4; source += 4; #endif } #if FB_DEPTH <= 16 // There could be one word left to blit if (length & 2) { FB_BLIT_1(DEREF_WORD_PTR(dest, 0), DEREF_WORD_PTR(source, 0)); #if FB_DEPTH <= 8 dest += 2; source += 2; #endif } #endif #if FB_DEPTH <= 8 // There could be one byte left to blit if (length & 1) *dest = *source; #endif #undef DEREF_QUAD_PTR #undef DEREF_LONG_PTR #undef DEREF_WORD_PTR } #undef FB_FUNC_NAME #ifdef FB_BLIT_1 #undef FB_BLIT_1 #endif #ifdef FB_BLIT_2 #undef FB_BLIT_2 #endif #ifdef FB_BLIT_4 #undef FB_BLIT_4 #endif #ifdef FB_DEPTH #undef FB_DEPTH #endif #endif /* DEFINE_VIDEO_BLITTERS */ BasiliskII/src/Unix/user_strings_unix.h0000644000175000017500000000413510736405221020421 0ustar centriscentris/* * user_strings_unix.h - Unix-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef USER_STRINGS_UNIX_H #define USER_STRINGS_UNIX_H enum { STR_NO_XSERVER_ERR = 10000, STR_NO_XVISUAL_ERR, STR_UNSUPP_DEPTH_ERR, STR_NO_FBDEVICE_FILE_ERR, STR_FBDEV_NAME_ERR, STR_FBDEV_MMAP_ERR, STR_VOSF_INIT_ERR, STR_NO_DEV_ZERO_ERR, STR_LOW_MEM_MMAP_ERR, STR_SIGALTSTACK_ERR, STR_SIG_INSTALL_ERR, STR_TIMER_CREATE_ERR, STR_TIMER_SETTIME_ERR, STR_TICK_THREAD_ERR, STR_BLOCKING_NET_SOCKET_WARN, STR_NO_SHEEP_NET_DRIVER_WARN, STR_SHEEP_NET_ATTACH_WARN, STR_TUN_TAP_CONFIG_WARN, STR_SLIRP_NO_DNS_FOUND_WARN, STR_SCSI_DEVICE_OPEN_WARN, STR_SCSI_DEVICE_NOT_SCSI_WARN, STR_NO_AUDIO_DEV_WARN, STR_NO_AUDIO_WARN, STR_AUDIO_FORMAT_WARN, STR_KEYCODE_FILE_WARN, STR_KEYCODE_VENDOR_WARN, STR_PREFS_MENU_FILE_GTK, STR_PREFS_ITEM_START_GTK, STR_PREFS_ITEM_ZAP_PRAM_GTK, STR_PREFS_ITEM_SEPL_GTK, STR_PREFS_ITEM_QUIT_GTK, STR_HELP_MENU_GTK, STR_HELP_ITEM_ABOUT_GTK, STR_FBDEV_NAME_CTRL, STR_FBDEVICE_FILE_CTRL, STR_DSPDEVICE_FILE_CTRL, STR_MIXERDEVICE_FILE_CTRL, STR_BROWSE_CTRL, STR_BROWSE_TITLE, STR_INPUT_PANE_TITLE, STR_KEYCODES_CTRL, STR_KEYCODE_FILE_CTRL, STR_MOUSEWHEELMODE_CTRL, STR_MOUSEWHEELMODE_PAGE_LAB, STR_MOUSEWHEELMODE_CURSOR_LAB, STR_MOUSEWHEELLINES_CTRL, STR_IGNORESEGV_CTRL, STR_WINDOW_TITLE_GRABBED, STR_NO_B2_EXE_FOUND }; #endif BasiliskII/src/Unix/tunconfig0000755000175000017500000000503610241421161016371 0ustar centriscentris#!/bin/bash ########################################################################### # Configuration of the tunN devices for usage with Basilisk II. # (derived MOL tunconfig script) # # This script should be named /usr/share/BasiliskII/tunconfig (unless # the default name has been changed with the 'etherconfig' keyword). # # Usage: tunconfig iface up|down # # If the linux box is configured as a firewall, the rules below might # need some adjustments. # # The IP Tunnel driver requires IP forwarding to be enabled. Run as root: # # echo 1 >/proc/sys/net/ipv4/ip_forward # ########################################################################### SUDO=/usr/bin/sudo IFCONFIG=/sbin/ifconfig IPTABLES=/sbin/iptables ######################################################### [[ "x$1" = "x-n" ]] && { DONT_EXECUTE=yes shift 1 } TUN_DEV=$1 ACTION=$2 TUN_NUM=`echo $TUN_DEV | sed s/[^0-9]//g` NET_NUM=`expr 40 + $TUN_NUM` TUN_NET=172.20.$NET_NUM.0/24 TUN_HOST=172.20.$NET_NUM.1 ######################################################### # Misc Checks ######################################################### [[ $# = 2 ]] || { echo "Usage: tunconfig [-n] iface up|down" exit 2 } [[ "`id -u`" = "0" ]] && { echo "---> $SUDO not necessary." 1>&2 SUDO="" } [[ -x $IPTABLES ]] || { echo "---> $IPTABLES not found." 1>&2 exit 1 } if [ -n "$SUDO" ]; then $SUDO -l | grep -q "NOPASSWD: $IFCONFIG" || { echo "---> Missing sudo NOPASSWD: $IFCONFIG." 1>&2 exit 1 } $SUDO -l | grep -q "NOPASSWD: $IPTABLES" || { echo "---> Missing sudo NOPASSWD: $IPTABLES." 1>&2 exit 1 } IFCONFIG="$SUDO $IFCONFIG" IPTABLES="$SUDO $IPTABLES" fi [[ "x$DONT_EXECUTE" = "xyes" ]] && exit 0 $IPTABLES -L -n -t nat > /dev/null || exit 1 ######################################################### # Remove old (possibly stale) ruleset ######################################################### { $IPTABLES -t nat -D POSTROUTING -s $TUN_NET -d ! $TUN_NET -j MASQUERADE } >& /dev/null ######################################################### # Bring down interface ######################################################### [[ "$ACTION" = down ]] && { $IFCONFIG $TUN_DEV down } ######################################################### # Configure interface ######################################################### [[ "$ACTION" = up ]] && { $IFCONFIG $TUN_DEV $TUN_HOST # masquerade the tun network $IPTABLES -t nat -A POSTROUTING -s $TUN_NET -d ! $TUN_NET -j MASQUERADE } exit 0 BasiliskII/src/Unix/sshpty.c0000644000175000017500000002720711536450256016170 0ustar centriscentris/* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * Allocating a pseudo-terminal, and making it the controlling tty. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #if 0 /* not in BasiliskII */ #include "includes.h" RCSID("$OpenBSD: sshpty.c,v 1.4 2001/12/19 07:18:56 deraadt Exp $"); #else /* not in BasiliskII */ /* Selections from openssh's "includes.h" */ #include "config.h" #include #include #include #include /* For O_NONBLOCK */ #include #include #include #include /* For STDIN_FILENO, etc */ #include /* Struct winsize */ /* *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively */ #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_LOGIN_H # include #endif #include #ifdef HAVE_SYS_BSDTTY_H # include #endif #ifdef HAVE_SYS_STAT_H # include /* For S_* constants and macros */ #endif #ifndef _PATH_TTY # define _PATH_TTY "/dev/tty" #endif #include "strlcpy.h" #define debug(x) ; #endif /* not in BasiliskII */ #ifdef HAVE_UTIL_H # include #endif /* HAVE_UTIL_H */ #include "sshpty.h" #if 0 /* not in BasiliskII */ #include "log.h" #include "misc.h" #else /* stubs for BasiliskII */ #define log printf #define error printf #define fatal(x) do { printf("Fatal error: %s", x); return 0; } while(0) #endif /* not in BasiliskII */ /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */ #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY) #undef HAVE_DEV_PTMX #endif #ifdef HAVE_PTY_H # include #endif #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H) # include #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif /* * Allocates and opens a pty. Returns 0 if no pty could be allocated, or * nonzero if a pty was successfully allocated. On success, open file * descriptors for the pty and tty sides and the name of the tty side are * returned (the buffer must be able to hold at least 64 characters). */ int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen) { #if defined(HAVE_OPENPTY) || defined(BSD4_4) /* openpty(3) exists in OSF/1 and some other os'es */ char *name; int i; i = openpty(ptyfd, ttyfd, NULL, NULL, NULL); if (i < 0) { error("openpty: %.100s", strerror(errno)); return 0; } name = ttyname(*ttyfd); if (!name) fatal("openpty returns device for which ttyname fails."); strlcpy(namebuf, name, namebuflen); /* possible truncation */ return 1; #else /* HAVE_OPENPTY */ #ifdef HAVE__GETPTY /* * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more * pty's automagically when needed */ char *slave; slave = _getpty(ptyfd, O_RDWR, 0622, 0); if (slave == NULL) { error("_getpty: %.100s", strerror(errno)); return 0; } strlcpy(namebuf, slave, namebuflen); /* Open the slave side. */ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); if (*ttyfd < 0) { error("%.200s: %.100s", namebuf, strerror(errno)); close(*ptyfd); return 0; } return 1; #else /* HAVE__GETPTY */ #if defined(HAVE_DEV_PTMX) /* * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 * also has bsd-style ptys, but they simply do not work.) */ int ptm; char *pts; mysig_t old_signal; ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (ptm < 0) { error("/dev/ptmx: %.100s", strerror(errno)); return 0; } old_signal = mysignal(SIGCHLD, SIG_DFL); if (grantpt(ptm) < 0) { error("grantpt: %.100s", strerror(errno)); return 0; } mysignal(SIGCHLD, old_signal); if (unlockpt(ptm) < 0) { error("unlockpt: %.100s", strerror(errno)); return 0; } pts = ptsname(ptm); if (pts == NULL) error("Slave pty side name could not be obtained."); strlcpy(namebuf, pts, namebuflen); *ptyfd = ptm; /* Open the slave side. */ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); if (*ttyfd < 0) { error("%.100s: %.100s", namebuf, strerror(errno)); close(*ptyfd); return 0; } #ifndef HAVE_CYGWIN /* * Push the appropriate streams modules, as described in Solaris pts(7). * HP-UX pts(7) doesn't have ttcompat module. */ if (ioctl(*ttyfd, I_PUSH, "ptem") < 0) error("ioctl I_PUSH ptem: %.100s", strerror(errno)); if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0) error("ioctl I_PUSH ldterm: %.100s", strerror(errno)); #ifndef __hpux if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0) error("ioctl I_PUSH ttcompat: %.100s", strerror(errno)); #endif #endif return 1; #else /* HAVE_DEV_PTMX */ #ifdef HAVE_DEV_PTS_AND_PTC /* AIX-style pty code. */ const char *name; *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY); if (*ptyfd < 0) { error("Could not open /dev/ptc: %.100s", strerror(errno)); return 0; } name = ttyname(*ptyfd); if (!name) fatal("Open of /dev/ptc returns device for which ttyname fails."); strlcpy(namebuf, name, namebuflen); *ttyfd = open(name, O_RDWR | O_NOCTTY); if (*ttyfd < 0) { error("Could not open pty slave side %.100s: %.100s", name, strerror(errno)); close(*ptyfd); return 0; } return 1; #else /* HAVE_DEV_PTS_AND_PTC */ #ifdef _CRAY char buf[64]; int i; int highpty; #ifdef _SC_CRAY_NPTY highpty = sysconf(_SC_CRAY_NPTY); if (highpty == -1) highpty = 128; #else highpty = 128; #endif for (i = 0; i < highpty; i++) { snprintf(buf, sizeof(buf), "/dev/pty/%03d", i); *ptyfd = open(buf, O_RDWR|O_NOCTTY); if (*ptyfd < 0) continue; snprintf(namebuf, namebuflen, "/dev/ttyp%03d", i); /* Open the slave side. */ *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); if (*ttyfd < 0) { error("%.100s: %.100s", namebuf, strerror(errno)); close(*ptyfd); return 0; } return 1; } return 0; #else /* BSD-style pty code. */ char buf[64]; int i; const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *ptyminors = "0123456789abcdef"; int num_minors = strlen(ptyminors); int num_ptys = strlen(ptymajors) * num_minors; struct termios tio; for (i = 0; i < num_ptys; i++) { snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors], ptyminors[i % num_minors]); snprintf(namebuf, namebuflen, "/dev/tty%c%c", ptymajors[i / num_minors], ptyminors[i % num_minors]); *ptyfd = open(buf, O_RDWR | O_NOCTTY); if (*ptyfd < 0) { /* Try SCO style naming */ snprintf(buf, sizeof buf, "/dev/ptyp%d", i); snprintf(namebuf, namebuflen, "/dev/ttyp%d", i); *ptyfd = open(buf, O_RDWR | O_NOCTTY); if (*ptyfd < 0) continue; } /* Open the slave side. */ *ttyfd = open(namebuf, O_RDWR | O_NOCTTY); if (*ttyfd < 0) { error("%.100s: %.100s", namebuf, strerror(errno)); close(*ptyfd); return 0; } /* set tty modes to a sane state for broken clients */ if (tcgetattr(*ptyfd, &tio) < 0) log("Getting tty modes for pty failed: %.100s", strerror(errno)); else { tio.c_lflag |= (ECHO | ISIG | ICANON); tio.c_oflag |= (OPOST | ONLCR); tio.c_iflag |= ICRNL; /* Set the new modes for the terminal. */ if (tcsetattr(*ptyfd, TCSANOW, &tio) < 0) log("Setting tty modes for pty failed: %.100s", strerror(errno)); } return 1; } return 0; #endif /* CRAY */ #endif /* HAVE_DEV_PTS_AND_PTC */ #endif /* HAVE_DEV_PTMX */ #endif /* HAVE__GETPTY */ #endif /* HAVE_OPENPTY */ } /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */ void pty_release(const char *ttyname) { if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0) error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno)); if (chmod(ttyname, (mode_t) 0666) < 0) error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno)); } /* Makes the tty the processes controlling tty and sets it to sane modes. */ void pty_make_controlling_tty(int *ttyfd, const char *ttyname) { int fd; #ifdef USE_VHANGUP void *old; #endif /* USE_VHANGUP */ #ifdef _CRAY if (setsid() < 0) error("setsid: %.100s", strerror(errno)); fd = open(ttyname, O_RDWR|O_NOCTTY); if (fd != -1) { mysignal(SIGHUP, SIG_IGN); ioctl(fd, TCVHUP, (char *)NULL); mysignal(SIGHUP, SIG_DFL); setpgid(0, 0); close(fd); } else { error("Failed to disconnect from controlling tty."); } debug("Setting controlling tty using TCSETCTTY."); ioctl(*ttyfd, TCSETCTTY, NULL); fd = open("/dev/tty", O_RDWR); if (fd < 0) error("%.100s: %.100s", ttyname, strerror(errno)); close(*ttyfd); *ttyfd = fd; #else /* _CRAY */ /* First disconnect from the old controlling tty. */ #ifdef TIOCNOTTY fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); if (fd >= 0) { (void) ioctl(fd, TIOCNOTTY, NULL); close(fd); } #endif /* TIOCNOTTY */ if (setsid() < 0) error("setsid: %.100s", strerror(errno)); /* * Verify that we are successfully disconnected from the controlling * tty. */ fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); if (fd >= 0) { error("Failed to disconnect from controlling tty."); close(fd); } /* Make it our controlling tty. */ #ifdef TIOCSCTTY debug("Setting controlling tty using TIOCSCTTY."); if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) error("ioctl(TIOCSCTTY): %.100s", strerror(errno)); #endif /* TIOCSCTTY */ #ifdef HAVE_NEWS4 if (setpgrp(0,0) < 0) error("SETPGRP %s",strerror(errno)); #endif /* HAVE_NEWS4 */ #ifdef USE_VHANGUP old = mysignal(SIGHUP, SIG_IGN); vhangup(); mysignal(SIGHUP, old); #endif /* USE_VHANGUP */ fd = open(ttyname, O_RDWR); if (fd < 0) { error("%.100s: %.100s", ttyname, strerror(errno)); } else { #ifdef USE_VHANGUP close(*ttyfd); *ttyfd = fd; #else /* USE_VHANGUP */ close(fd); #endif /* USE_VHANGUP */ } /* Verify that we now have a controlling tty. */ fd = open(_PATH_TTY, O_WRONLY); if (fd < 0) error("open /dev/tty failed - could not set controlling tty: %.100s", strerror(errno)); else { close(fd); } #endif /* _CRAY */ } #if 0 /* not in BasiliskII */ /* Changes the window size associated with the pty. */ void pty_change_window_size(int ptyfd, int row, int col, int xpixel, int ypixel) { struct winsize w; w.ws_row = row; w.ws_col = col; w.ws_xpixel = xpixel; w.ws_ypixel = ypixel; (void) ioctl(ptyfd, TIOCSWINSZ, &w); } void pty_setowner(struct passwd *pw, const char *ttyname) { struct group *grp; gid_t gid; mode_t mode; struct stat st; /* Determine the group to make the owner of the tty. */ grp = getgrnam("tty"); if (grp) { gid = grp->gr_gid; mode = S_IRUSR | S_IWUSR | S_IWGRP; } else { gid = pw->pw_gid; mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH; } /* * Change owner and mode of the tty as required. * Warn but continue if filesystem is read-only and the uids match/ * tty is owned by root. */ if (stat(ttyname, &st)) fatal("stat(%.100s) failed: %.100s", ttyname, strerror(errno)); if (st.st_uid != pw->pw_uid || st.st_gid != gid) { if (chown(ttyname, pw->pw_uid, gid) < 0) { if (errno == EROFS && (st.st_uid == pw->pw_uid || st.st_uid == 0)) error("chown(%.100s, %d, %d) failed: %.100s", ttyname, pw->pw_uid, gid, strerror(errno)); else fatal("chown(%.100s, %d, %d) failed: %.100s", ttyname, pw->pw_uid, gid, strerror(errno)); } } if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) { if (chmod(ttyname, mode) < 0) { if (errno == EROFS && (st.st_mode & (S_IRGRP | S_IROTH)) == 0) error("chmod(%.100s, 0%o) failed: %.100s", ttyname, mode, strerror(errno)); else fatal("chmod(%.100s, 0%o) failed: %.100s", ttyname, mode, strerror(errno)); } } } #endif /* not in BasiliskII */ BasiliskII/src/Unix/sshpty.h0000644000175000017500000000166407522012126016162 0ustar centriscentris/* $OpenBSD: sshpty.h,v 1.4 2002/03/04 17:27:39 stevesk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * Functions for allocating a pseudo-terminal and making it the controlling * tty. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ #ifndef SSHPTY_H #define SSHPTY_H int pty_allocate(int *, int *, char *, int); void pty_release(const char *); void pty_make_controlling_tty(int *, const char *); void pty_change_window_size(int, int, int, int, int); void pty_setowner(struct passwd *, const char *); #endif /* SSHPTY_H */ BasiliskII/src/Unix/acinclude.m40000644000175000017500000000142110261061506016637 0ustar centriscentrisdnl Additional macros for Basilisk II dnl Check for libgnomeui dnl B2_PATH_GNOMEUI([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) dnl Test to see if libgnomeui is installed, and define GNOMEUI_CFLAGS, LIBS AC_DEFUN([B2_PATH_GNOMEUI], [dnl dnl Get the cflags and libraries from the gnome-config script dnl AC_ARG_WITH(gnome-config, [ --with-gnome-config=GNOME_CONFIG Location of gnome-config], GNOME_CONFIG="$withval") AC_PATH_PROG(GNOME_CONFIG, gnome-config, no) AC_MSG_CHECKING(for libgnomeui) if test "$GNOME_CONFIG" = "no"; then AC_MSG_RESULT(no) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(yes) GNOMEUI_CFLAGS=`$GNOME_CONFIG --cflags gnomeui` GNOMEUI_LIBS=`$GNOME_CONFIG --libs gnomeui` ifelse([$1], , :, [$1]) fi AC_SUBST(GNOMEUI_CFLAGS) AC_SUBST(GNOMEUI_LIBS) ]) BasiliskII/src/Unix/xpram_unix.cpp0000644000175000017500000000426611232133662017360 0ustar centriscentris/* * xpram_unix.cpp - XPRAM handling, Unix specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include "xpram.h" // XPRAM file name and path #if POWERPC_ROM const char XPRAM_FILE_NAME[] = ".sheepshaver_nvram"; #else const char XPRAM_FILE_NAME[] = ".basilisk_ii_xpram"; #endif static char xpram_path[1024]; /* * Load XPRAM from settings file */ void LoadXPRAM(const char *vmdir) { if (vmdir) { #if POWERPC_ROM snprintf(xpram_path, sizeof(xpram_path), "%s/nvram", vmdir); #else snprintf(xpram_path, sizeof(xpram_path), "%s/xpram", vmdir); #endif } else { // Construct XPRAM path xpram_path[0] = 0; char *home = getenv("HOME"); if (home != NULL && strlen(home) < 1000) { strncpy(xpram_path, home, 1000); strcat(xpram_path, "/"); } strcat(xpram_path, XPRAM_FILE_NAME); } // Load XPRAM from settings file int fd; if ((fd = open(xpram_path, O_RDONLY)) >= 0) { read(fd, XPRAM, XPRAM_SIZE); close(fd); } } /* * Save XPRAM to settings file */ void SaveXPRAM(void) { int fd; if ((fd = open(xpram_path, O_WRONLY | O_CREAT, 0666)) >= 0) { write(fd, XPRAM, XPRAM_SIZE); close(fd); } } /* * Delete PRAM file */ void ZapPRAM(void) { // Construct PRAM path xpram_path[0] = 0; char *home = getenv("HOME"); if (home != NULL && strlen(home) < 1000) { strncpy(xpram_path, home, 1000); strcat(xpram_path, "/"); } strcat(xpram_path, XPRAM_FILE_NAME); // Delete file unlink(xpram_path); } BasiliskII/src/Unix/audio_oss_esd.cpp0000644000175000017500000003413310736405221020003 0ustar centriscentris/* * audio_oss_esd.cpp - Audio support, implementation for OSS and ESD (Linux and FreeBSD) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #ifdef __linux__ #include #endif #ifdef __FreeBSD__ #include #endif #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "audio.h" #include "audio_defs.h" #ifdef ENABLE_ESD #include #endif #define DEBUG 0 #include "debug.h" // The currently selected audio parameters (indices in audio_sample_rates[] etc. vectors) static int audio_sample_rate_index = 0; static int audio_sample_size_index = 0; static int audio_channel_count_index = 0; // Global variables static bool is_dsp_audio = false; // Flag: is DSP audio static int audio_fd = -1; // fd of dsp or ESD static int mixer_fd = -1; // fd of mixer static sem_t audio_irq_done_sem; // Signal from interrupt to streaming thread: data block read static bool sem_inited = false; // Flag: audio_irq_done_sem initialized static int sound_buffer_size; // Size of sound buffer in bytes static bool little_endian = false; // Flag: DSP accepts only little-endian 16-bit sound data static uint8 silence_byte; // Byte value to use to fill sound buffers with silence static pthread_t stream_thread; // Audio streaming thread static pthread_attr_t stream_thread_attr; // Streaming thread attributes static bool stream_thread_active = false; // Flag: streaming thread installed static volatile bool stream_thread_cancel = false; // Flag: cancel streaming thread // Prototypes static void *stream_func(void *arg); /* * Initialization */ // Set AudioStatus to reflect current audio stream format static void set_audio_status_format(void) { AudioStatus.sample_rate = audio_sample_rates[audio_sample_rate_index]; AudioStatus.sample_size = audio_sample_sizes[audio_sample_size_index]; AudioStatus.channels = audio_channel_counts[audio_channel_count_index]; } // Init using the dsp device, returns false on error static bool open_dsp(void) { // Open the device const char *dsp = PrefsFindString("dsp"); audio_fd = open(dsp, O_WRONLY); if (audio_fd < 0) { fprintf(stderr, "WARNING: Cannot open %s (%s)\n", dsp, strerror(errno)); return false; } printf("Using %s audio output\n", dsp); is_dsp_audio = true; // Get supported sample formats if (audio_sample_sizes.empty()) { unsigned long format; ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format); if (format & AFMT_U8) audio_sample_sizes.push_back(8); if (format & (AFMT_S16_BE | AFMT_S16_LE)) audio_sample_sizes.push_back(16); int stereo = 0; if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == 0 && stereo == 0) audio_channel_counts.push_back(1); stereo = 1; if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == 0 && stereo == 1) audio_channel_counts.push_back(2); if (audio_sample_sizes.empty() || audio_channel_counts.empty()) { WarningAlert(GetString(STR_AUDIO_FORMAT_WARN)); close(audio_fd); audio_fd = -1; return false; } audio_sample_rates.push_back(11025 << 16); audio_sample_rates.push_back(22050 << 16); int rate = 44100; ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate); if (rate > 22050) audio_sample_rates.push_back(rate << 16); // Default to highest supported values audio_sample_rate_index = audio_sample_rates.size() - 1; audio_sample_size_index = audio_sample_sizes.size() - 1; audio_channel_count_index = audio_channel_counts.size() - 1; } // Set DSP parameters unsigned long format; if (audio_sample_sizes[audio_sample_size_index] == 8) { format = AFMT_U8; little_endian = false; silence_byte = 0x80; } else { unsigned long sup_format; ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &sup_format); if (sup_format & AFMT_S16_BE) { little_endian = false; format = AFMT_S16_BE; } else { little_endian = true; format = AFMT_S16_LE; } silence_byte = 0; } ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format); int frag = 0x0004000c; // Block size: 4096 frames ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag); int stereo = (audio_channel_counts[audio_channel_count_index] == 2); ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo); int rate = audio_sample_rates[audio_sample_rate_index] >> 16; ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate); // Get sound buffer size ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &audio_frames_per_block); D(bug("DSP_GETBLKSIZE %d\n", audio_frames_per_block)); return true; } // Init using ESD, returns false on error static bool open_esd(void) { #ifdef ENABLE_ESD int rate; esd_format_t format = ESD_STREAM | ESD_PLAY; if (audio_sample_sizes.empty()) { // Default values rate = 44100; format |= (ESD_BITS16 | ESD_STEREO); } else { rate = audio_sample_rates[audio_sample_rate_index] >> 16; if (audio_sample_sizes[audio_sample_size_index] == 8) format |= ESD_BITS8; else format |= ESD_BITS16; if (audio_channel_counts[audio_channel_count_index] == 1) format |= ESD_MONO; else format |= ESD_STEREO; } #if WORDS_BIGENDIAN little_endian = false; #else little_endian = true; #endif silence_byte = 0; // Is this correct for 8-bit mode? // Open connection to ESD server audio_fd = esd_play_stream(format, rate, NULL, NULL); if (audio_fd < 0) { fprintf(stderr, "WARNING: Cannot open ESD connection\n"); return false; } printf("Using ESD audio output\n"); // ESD supports a variety of twisted little audio formats, all different if (audio_sample_sizes.empty()) { // The reason we do this here is that we don't want to add sample // rates etc. unless the ESD server connection could be opened // (if ESD fails, dsp might be tried next) audio_sample_rates.push_back(11025 << 16); audio_sample_rates.push_back(22050 << 16); audio_sample_rates.push_back(44100 << 16); audio_sample_sizes.push_back(8); audio_sample_sizes.push_back(16); audio_channel_counts.push_back(1); audio_channel_counts.push_back(2); // Default to highest supported values audio_sample_rate_index = audio_sample_rates.size() - 1; audio_sample_size_index = audio_sample_sizes.size() - 1; audio_channel_count_index = audio_channel_counts.size() - 1; } // Sound buffer size = 4096 frames audio_frames_per_block = 4096; return true; #else // ESD is not enabled, shut up the compiler return false; #endif } static bool open_audio(void) { #ifdef ENABLE_ESD // If ESPEAKER is set, the user probably wants to use ESD, so try that first if (getenv("ESPEAKER")) if (open_esd()) goto dev_opened; #endif // Try to open dsp if (open_dsp()) goto dev_opened; #ifdef ENABLE_ESD // Hm, dsp failed so we try ESD again if ESPEAKER wasn't set if (!getenv("ESPEAKER")) if (open_esd()) goto dev_opened; #endif // No audio device succeeded WarningAlert(GetString(STR_NO_AUDIO_WARN)); return false; // Device opened, set AudioStatus dev_opened: sound_buffer_size = (audio_sample_sizes[audio_sample_size_index] >> 3) * audio_channel_counts[audio_channel_count_index] * audio_frames_per_block; set_audio_status_format(); // Start streaming thread Set_pthread_attr(&stream_thread_attr, 0); stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0); // Everything went fine audio_open = true; return true; } void AudioInit(void) { // Init audio status (reasonable defaults) and feature flags AudioStatus.sample_rate = 44100 << 16; AudioStatus.sample_size = 16; AudioStatus.channels = 2; AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; // Init semaphore if (sem_init(&audio_irq_done_sem, 0, 0) < 0) return; sem_inited = true; // Try to open the mixer device const char *mixer = PrefsFindString("mixer"); mixer_fd = open(mixer, O_RDWR); if (mixer_fd < 0) printf("WARNING: Cannot open %s (%s)\n", mixer, strerror(errno)); // Open and initialize audio device open_audio(); } /* * Deinitialization */ static void close_audio(void) { // Stop stream and delete semaphore if (stream_thread_active) { stream_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(stream_thread); #endif pthread_join(stream_thread, NULL); stream_thread_active = false; } // Close dsp or ESD socket if (audio_fd >= 0) { close(audio_fd); audio_fd = -1; } audio_open = false; } void AudioExit(void) { // Stop the device immediately. Otherwise, close() sends // SNDCTL_DSP_SYNC, which may hang if (is_dsp_audio) ioctl(audio_fd, SNDCTL_DSP_RESET, 0); // Close audio device close_audio(); // Delete semaphore if (sem_inited) { sem_destroy(&audio_irq_done_sem); sem_inited = false; } // Close mixer device if (mixer_fd >= 0) { close(mixer_fd); mixer_fd = -1; } } /* * First source added, start audio stream */ void audio_enter_stream() { // Streaming thread is always running to avoid clicking noises } /* * Last source removed, stop audio stream */ void audio_exit_stream() { // Streaming thread is always running to avoid clicking noises } /* * Streaming function */ static void *stream_func(void *arg) { int16 *silent_buffer = new int16[sound_buffer_size / 2]; int16 *last_buffer = new int16[sound_buffer_size / 2]; memset(silent_buffer, silence_byte, sound_buffer_size); while (!stream_thread_cancel) { if (AudioStatus.num_sources) { // Trigger audio interrupt to get new buffer D(bug("stream: triggering irq\n")); SetInterruptFlag(INTFLAG_AUDIO); TriggerInterrupt(); D(bug("stream: waiting for ack\n")); sem_wait(&audio_irq_done_sem); D(bug("stream: ack received\n")); // Get size of audio data uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); if (apple_stream_info) { int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels; D(bug("stream: work_size %d\n", work_size)); if (work_size > sound_buffer_size) work_size = sound_buffer_size; if (work_size == 0) goto silence; // Send data to DSP if (work_size == sound_buffer_size && !little_endian) write(audio_fd, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), sound_buffer_size); else { // Last buffer or little-endian DSP if (little_endian) { int16 *p = (int16 *)Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)); for (int i=0; i= 0) { int vol; if (ioctl(mixer_fd, SOUND_MIXER_READ_PCM, &vol) == 0) { int left = vol >> 8; int right = vol & 0xff; return ((left * 256 / 100) << 16) | (right * 256 / 100); } } return 0x01000100; } bool audio_get_speaker_mute(void) { return false; } uint32 audio_get_speaker_volume(void) { if (mixer_fd >= 0) { int vol; if (ioctl(mixer_fd, SOUND_MIXER_READ_VOLUME, &vol) == 0) { int left = vol >> 8; int right = vol & 0xff; return ((left * 256 / 100) << 16) | (right * 256 / 100); } } return 0x01000100; } void audio_set_main_mute(bool mute) { } void audio_set_main_volume(uint32 vol) { if (mixer_fd >= 0) { int left = vol >> 16; int right = vol & 0xffff; int p = ((left * 100 / 256) << 8) | (right * 100 / 256); ioctl(mixer_fd, SOUND_MIXER_WRITE_PCM, &p); } } void audio_set_speaker_mute(bool mute) { } void audio_set_speaker_volume(uint32 vol) { if (mixer_fd >= 0) { int left = vol >> 16; int right = vol & 0xffff; int p = ((left * 100 / 256) << 8) | (right * 100 / 256); ioctl(mixer_fd, SOUND_MIXER_WRITE_VOLUME, &p); } } BasiliskII/src/Unix/Solaris/0000755000175000017500000000000011735674761016110 5ustar centriscentrisBasiliskII/src/Unix/Solaris/audio_solaris.cpp0000644000175000017500000001675010736405221021441 0ustar centriscentris/* * audio_solaris.cpp - Audio support, Solaris implementation * * Adapted from Frodo's Solaris sound routines by Marc Chabanas * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "audio.h" #include "audio_defs.h" #define DEBUG 0 #include "debug.h" // Global variables static int fd = -1; // fd of /dev/audio static sem_t audio_irq_done_sem; // Signal from interrupt to streaming thread: data block read static pthread_t stream_thread; // Audio streaming thread static pthread_attr_t stream_thread_attr; // Streaming thread attributes static bool stream_thread_active = false; static int sound_buffer_size; // Size of sound buffer in bytes // Prototypes static void *stream_func(void *arg); /* * Initialization */ // Set AudioStatus to reflect current audio stream format static void set_audio_status_format(void) { AudioStatus.sample_rate = audio_sample_rates[0]; AudioStatus.sample_size = audio_sample_sizes[0]; AudioStatus.channels = audio_channel_counts[0]; } void AudioInit(void) { char str[256]; // Init audio status and feature flags audio_sample_rates.push_back(44100 << 16); audio_sample_sizes.push_back(16); audio_channel_counts.push_back(2); set_audio_status_format(); AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; // Init semaphore if (sem_init(&audio_irq_done_sem, 0, 0) < 0) return; // Open /dev/audio fd = open("/dev/audio", O_WRONLY | O_NDELAY); if (fd < 0) { sprintf(str, GetString(STR_NO_AUDIO_DEV_WARN), "/dev/audio", strerror(errno)); WarningAlert(str); sem_destroy(&audio_irq_done_sem); return; } // Set audio parameters struct audio_info info; AUDIO_INITINFO(&info); info.play.sample_rate = AudioStatus.sample_rate >> 16; info.play.channels = AudioStatus.channels; info.play.precision = AudioStatus.sample_size; info.play.encoding = AUDIO_ENCODING_LINEAR; info.play.port = AUDIO_SPEAKER; if (ioctl(fd, AUDIO_SETINFO, &info)) { WarningAlert(GetString(STR_AUDIO_FORMAT_WARN)); close(fd); fd = -1; sem_destroy(&audio_irq_done_sem); return; } // 2048 frames per buffer audio_frames_per_block = 2048; sound_buffer_size = (AudioStatus.sample_size>>3) * AudioStatus.channels * audio_frames_per_block; // Start audio thread Set_pthread_attr(&stream_thread_attr, 0); stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0); // Everything OK audio_open = true; } /* * Deinitialization */ void AudioExit(void) { // Stop audio thread if (stream_thread_active) { pthread_cancel(stream_thread); pthread_join(stream_thread, NULL); sem_destroy(&audio_irq_done_sem); stream_thread_active = false; } // Close /dev/audio if (fd > 0) { ioctl(fd, AUDIO_DRAIN); close(fd); } } /* * First source added, start audio stream */ void audio_enter_stream() { } /* * Last source removed, stop audio stream */ void audio_exit_stream() { } /* * Streaming function */ static uint32 apple_stream_info; // Mac address of SoundComponentData struct describing next buffer static void *stream_func(void *arg) { int16 *silent_buffer = new int16[sound_buffer_size / 2]; int16 *last_buffer = new int16[sound_buffer_size / 2]; memset(silent_buffer, 0, sound_buffer_size); uint_t sent = 0, delta; struct audio_info status; for (;;) { if (AudioStatus.num_sources) { // Trigger audio interrupt to get new buffer D(bug("stream: triggering irq\n")); SetInterruptFlag(INTFLAG_AUDIO); TriggerInterrupt(); D(bug("stream: waiting for ack\n")); sem_wait(&audio_irq_done_sem); D(bug("stream: ack received\n")); // Get size of audio data uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); if (apple_stream_info) { int work_size = ReadMacInt32(apple_stream_info + scd_sampleCount) * (AudioStatus.sample_size >> 3) * AudioStatus.channels; D(bug("stream: work_size %d\n", work_size)); if (work_size > sound_buffer_size) work_size = sound_buffer_size; if (work_size == 0) goto silence; // Send data to audio port if (work_size == sound_buffer_size) write(fd, Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)), sound_buffer_size); else { // Last buffer Mac2Host_memcpy(last_buffer, ReadMacInt32(apple_stream_info + scd_buffer), work_size); memset((uint8 *)last_buffer + work_size, 0, sound_buffer_size - work_size); write(fd, last_buffer, sound_buffer_size); } D(bug("stream: data written\n")); } else goto silence; } else { // Audio not active, play silence silence: write(fd, silent_buffer, sound_buffer_size); } // We allow a maximum of three buffers to be sent sent += audio_frames_per_block; ioctl(fd, AUDIO_GETINFO, &status); while ((delta = sent - status.play.samples) > (audio_frames_per_block * 3)) { unsigned int sl = 1000000 * (delta - audio_frames_per_block * 3) / (AudioStatus.sample_rate >> 16); usleep(sl); ioctl(fd, AUDIO_GETINFO, &status); } } return NULL; } /* * MacOS audio interrupt, read next data block */ void AudioInterrupt(void) { D(bug("AudioInterrupt\n")); // Get data from apple mixer if (AudioStatus.mixer) { M68kRegisters r; r.a[0] = audio_data + adatStreamInfo; r.a[1] = AudioStatus.mixer; Execute68k(audio_data + adatGetSourceData, &r); D(bug(" GetSourceData() returns %08lx\n", r.d[0])); } else WriteMacInt32(audio_data + adatStreamInfo, 0); // Signal stream function sem_post(&audio_irq_done_sem); D(bug("AudioInterrupt done\n")); } /* * Set sampling parameters * "index" is an index into the audio_sample_rates[] etc. arrays * It is guaranteed that AudioStatus.num_sources == 0 */ bool audio_set_sample_rate(int index) { return true; } bool audio_set_sample_size(int index) { return true; } bool audio_set_channels(int index) { return true; } /* * Get/set volume controls (volume values received/returned have the left channel * volume in the upper 16 bits and the right channel volume in the lower 16 bits; * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume")) */ bool audio_get_main_mute(void) { return false; } uint32 audio_get_main_volume(void) { return 0x01000100; } bool audio_get_speaker_mute(void) { return false; } uint32 audio_get_speaker_volume(void) { return 0x01000100; } void audio_set_main_mute(bool mute) { } void audio_set_main_volume(uint32 vol) { } void audio_set_speaker_mute(bool mute) { } void audio_set_speaker_volume(uint32 vol) { } BasiliskII/src/Unix/Solaris/which_sparc0000755000175000017500000000434407003630313020307 0ustar centriscentris#!/bin/sh # which_sparc # # This script generates a program that tests for a SPARC processor class # Program returns: # 0 unknown SPARC processor # 8 SPARC V8 `compliant' processor (umul instruction is legal) # 9 SPARC V9 `compliant' processor (popc instruction is legal) # # The script prints: # "unknown SPARC architecture" # SPARC_V8 # SPARC_V9 # # I hope this works for other machines and OS. Tested machines are: # Sun Ultra 10 (Solaris 7), SPARC Station 5 (Solaris 2.5.1) # # Gwenole Beauchesne # gb@dial.oleane.com CC=gcc PROG=./conftest SOURCE=./conftest.c if [ ! -x $PROG ]; then cat > $SOURCE << EOF #include #include typedef unsigned int uint32; typedef uint32 (*sparc_code_func)(void); #define SPARC_UNKNOWN 0 #define SPARC_V8 8 #define SPARC_V9 9 #define MAX_CODE_SIZE 16 struct sparc_code_struct { int version; uint32 code[MAX_CODE_SIZE]; struct sparc_code_struct * next; }; typedef struct sparc_code_struct sparc_code_struct; static sparc_code_struct *current_test_code; static sparc_code_struct unknown_sparc_code = { SPARC_UNKNOWN, { 0x81C3E008, /* retl */ 0x01000000 /* nop */ } }; static sparc_code_struct sparc_v9_code = { SPARC_V9, { 0x81C3E008, /* retl */ 0x81702007 /* popc 7, %g0 */ } }; static sparc_code_struct sparc_v8_code = { SPARC_V8, { 0x90102002, /* mov 2, %o0 */ 0x81C3E008, /* retl */ 0x90520008 /* umul %o0, %o0, %o0 */ } }; static void test_sparc_code(int unused_int) { sparc_code_struct *tested_code = current_test_code; if (current_test_code == NULL) exit(SPARC_UNKNOWN); signal(SIGILL, test_sparc_code); current_test_code = current_test_code->next; (void) ((sparc_code_func)(tested_code->code))(); exit(tested_code->version); } int main(void) { sparc_v9_code.next = &sparc_v8_code; sparc_v8_code.next = &unknown_sparc_code; unknown_sparc_code.next = NULL; signal(SIGILL, test_sparc_code); current_test_code = &sparc_v9_code; raise(SIGILL); return 0; } EOF $CC -o $PROG $SOURCE if [ $? -ne 0 ]; then echo "Error: could not compile the test program" exit 1 fi fi $PROG case $? in 0) echo "unknown SPARC architecture";; 8) echo "SPARC_V8";; 9) echo "SPARC_V9";; esac rm -f $PROG rm -f $SOURCE exit 0 BasiliskII/src/Unix/fbdevices0000644000175000017500000000062407003611332016325 0ustar centriscentris# ------------------------------------------------------------------------------ # device depth offset for mmap(2) # ------------------------------------------------------------------------------ # Frame buffers known to work cgsix 8 0x70016000 tcx 8 0x00000000 # Untested frame buffers cgthree 8 0x04000000 cgtwo 8 0x00000000 cgfour 8 0x00000000 cgeight 24 0x00000000 tcx 24 0x01000000 BasiliskII/src/Unix/asm_support.s0000644000175000017500000001071310177252266017225 0ustar centriscentris/* * asm_support.s - Utility functions in assembly language (for native 68k support) * * Basilisk II (C) 1997-2005 Christian Bauer * * 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 */ .file "asm_support.s" .text .globl _m68k_sync_icache .globl _Start680x0__Fv .globl _SetInterruptFlag__FUi .globl _ClearInterruptFlag__FUi .globl _Execute68k .globl _Execute68kTrap .globl _EmulOpTrampoline .globl _RAMBaseHost .globl _ROMBaseHost .globl _EmulOp__FUsP13M68kRegisters .globl _EmulatedSR .globl _InterruptFlags .globl _TriggerInterrupt__Fv /* * Call m68k_sync_icache() (NetBSD, the version in libm68k is broken) */ .type _m68k_sync_icache,@function _m68k_sync_icache: movl sp@(8),d1 movl sp@(4),a1 movl #0x80000004,d0 trap #12 rts /* * Jump to Mac ROM, start emulation */ .type _Start680x0__Fv,@function _Start680x0__Fv: movl _RAMBaseHost,a0 addl #0x8000,a0 movl a0,sp movl _ROMBaseHost,a0 lea a0@(0x2a),a0 jmp a0@ /* * Set/clear interrupt flag (atomically) */ .type _SetInterruptFlag__FUi,@function _SetInterruptFlag__FUi: movl sp@(4),d0 orl d0,_InterruptFlags rts .type _ClearInterruptFlag__FUi,@function _ClearInterruptFlag__FUi: movl sp@(4),d0 notl d0 andl d0,_InterruptFlags rts /* * Execute 68k subroutine (must be ended with rts) * r->a[7] and r->sr are unused! */ /* void Execute68k(uint32 addr, M68kRegisters *r); */ .type _Execute68k,@function _Execute68k: movl sp@(4),d0 |Get arguments movl sp@(8),a0 movml d2-d7/a2-a6,sp@- |Save registers movl a0,sp@- |Push pointer to M68kRegisters on stack pea exec68kret |Push return address on stack movl d0,sp@- |Push pointer to 68k routine on stack movml a0@,d0-d7/a0-a6 |Load registers from M68kRegisters rts |Jump into 68k routine exec68kret: movl a6,sp@- |Save a6 movl sp@(4),a6 |Get pointer to M68kRegisters movml d0-d7/a0-a5,a6@ |Save d0-d7/a0-a5 to M68kRegisters movl sp@+,a6@(56) |Save a6 to M68kRegisters addql #4,sp |Remove pointer from stack movml sp@+,d2-d7/a2-a6 |Restore registers rts /* * Execute MacOS 68k trap * r->a[7] and r->sr are unused! */ /* void Execute68kTrap(uint16 trap, M68kRegisters *r); */ .type _Execute68kTrap,@function _Execute68kTrap: movl sp@(4),d0 |Get arguments movl sp@(8),a0 movml d2-d7/a2-a6,sp@- |Save registers movl a0,sp@- |Push pointer to M68kRegisters on stack movw d0,sp@- |Push trap word on stack subql #8,sp |Create fake A-Line exception frame movml a0@,d0-d7/a0-a6 |Load registers from M68kRegisters movl a2,sp@- |Save a2 and d2 movl d2,sp@- lea exectrapret,a2 |a2 points to return address movw sp@(16),d2 |Load trap word into d2 jmp zpc@(0x28:w)@(10) |Jump into MacOS A-Line handler exectrapret: movl a6,sp@- |Save a6 movl sp@(6),a6 |Get pointer to M68kRegisters movml d0-d7/a0-a5,a6@ |Save d0-d7/a0-a5 to M68kRegisters movl sp@+,a6@(56) |Save a6 to M68kRegisters addql #6,sp |Remove pointer and trap word from stack movml sp@+,d2-d7/a2-a6 |Restore registers rts /* * Call EmulOp() after return from SIGILL handler, registers are pushed on stack */ .type _EmulOpTrampoline,@function _EmulOpTrampoline: movl sp,a0 |Get pointer to registers movw _EmulatedSR,d0 |Save EmulatedSR, disable interrupts movw d0,sp@- oriw #0x0700,d0 movw d0,_EmulatedSR movl a0,sp@- |Push pointer to registers movl a0@(66),a1 |Get saved PC addql #2,a0@(66) |Skip EMUL_OP opcode movw a1@,sp@- |Push opcode word clrw sp@- jbsr _EmulOp__FUsP13M68kRegisters addql #8,sp movw sp@+,d0 |Restore interrupts, trigger pending interrupt movw d0,_EmulatedSR andiw #0x0700,d0 bne eot1 tstl _InterruptFlags beq eot1 jbsr _TriggerInterrupt__Fv eot1: moveml sp@+,d0-d7/a0-a6 |Restore registers addql #4,sp |Skip saved SP rtr BasiliskII/src/Unix/FreeBSD/0000755000175000017500000000000011735674761015706 5ustar centriscentrisBasiliskII/src/Unix/FreeBSD/scsi_freebsd.cpp0000644000175000017500000004263110736405221021032 0ustar centriscentris/* * scsi_freebsd.cpp - SCSI Manager, FreeBSD SCSI Driver implementation * Copyright (C) 1999 Orlando Bassotto * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 * * History: * 29-Jun-1999 Started * 05-Jul-1999 Changed from array to queue removing the limit of 8 * devices. * Implemented old SCSI management for FreeBSD 2.x. * (Note: This implementation hasn't been tested; * I don't own anymore a machine with FreeBSD 2.x, * so if something goes wrong, please mail me to * future@mediabit.net). */ #include #include #include #include #include #include #include #include #include #include #ifdef CAM #include #include #include #include #include #include #include #include #else /* !CAM */ #include #include #endif /* !CAM */ #include "sysdeps.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "scsi.h" #define DEBUG 0 #include "debug.h" #undef u_int8_t #define u_int8_t unsigned char typedef struct _SCSIDevice { int controller; // SCSI Controller int controller_bus; // SCSI Controller Bus char controller_name[33]; // SCSI Controller name int mac_unit; // Macintosh SCSI ID (remapped) int faked_controller; // "Faked" SCSI Controller (Always 0) int faked_unit; // "Faked" SCSI ID int unit; // Real SCSI ID int lun; // Real SCSI LUN u_int8_t vendor[16]; // SCSI Vendor u_int8_t product[48]; // SCSI Product u_int8_t revision[16]; // SCSI Revision char device[33]; // SCSI Device #ifdef CAM char pass_device[33]; // SCSI Pass Device #else /* !CAM */ int dev_fd; // Device File Descriptor #endif /* !CAM */ void* dev_ptr; // Pointer to CAM/SCSI structure bool enabled; // Device enabled ? struct _SCSIDevice* next; // Pointer to the next device } SCSIDevice; static int nDevices = 0; static SCSIDevice* Devices = NULL; static uint32 buffer_size; static uint8* buffer = NULL; static uint8 the_cmd[12]; static int the_cmd_len; static SCSIDevice* CurrentDevice = NULL; inline static SCSIDevice* _GetSCSIDeviceByID(int id) { SCSIDevice* aux = Devices; while(aux) { if(aux->faked_unit==id) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _GetSCSIDeviceByIDLUN(int id, int lun) { SCSIDevice* aux = Devices; while(aux) { if(aux->faked_unit==id&&aux->lun==lun) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _GetSCSIDeviceByMacID(int id) { SCSIDevice* aux = Devices; while(aux) { if(aux->mac_unit==id) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _GetSCSIDeviceByMacIDLUN(int id, int lun) { SCSIDevice* aux = Devices; while(aux) { if(aux->mac_unit==id&&aux->lun==lun) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _AllocNewDevice() { SCSIDevice* aux; aux = new SCSIDevice; if(aux==NULL) return NULL; memset(aux, 0, sizeof(SCSIDevice)); aux->next = Devices; Devices = aux; return aux; } #ifdef CAM inline static struct cam_device* _GetCurrentSCSIDevice() { if(CurrentDevice==NULL) return NULL; return (struct cam_device*)CurrentDevice->dev_ptr; } #else /* !CAM */ inline static struct scsireq* _GetCurrentSCSIDevice() { if(CurrentDevice==NULL) return NULL; return (struct scsireq*)CurrentDevice->dev_ptr; } #endif /* !CAM */ /* * _Build_SCSI_Controller() * * This function builds a virtual SCSI Controller (Controller=0) * where keeps all the devices found, this is due the fact * I have two SCSI controllers in my PC. :-) * Use scsidump in contrib/ to see how is remapped your * SCSI device (only if you have more than one controller, * that's for sure :-). * If you have only one controller, remapping does not take act. */ #define GET_FREE_ID(id) \ { \ for(int x=0;x<32;x++) { \ if(!(busyIDs&(1<<(x+1)))) { \ id = x; \ break; \ } \ } \ } static void _Build_SCSI_Controller() { unsigned int id = 0; unsigned long long busyIDs = 0x0ll; SCSIDevice* aux, * dev; // What IDs are busy? dev = Devices; while(dev) { dev->enabled = false; dev->faked_controller = 0; dev->faked_unit = dev->unit; busyIDs |= (1 << (dev->unit+1)); dev = dev->next; } // Find out the duplicate IDs and remap them dev = Devices, aux = NULL; while(dev) { aux = dev; while(aux) { SCSIDevice* dev1, * dev2; dev1 = dev, dev2 = aux; if(dev1->controller!=dev2->controller&& dev1->unit==dev2->unit) { int free_id; GET_FREE_ID(free_id); busyIDs |= (1<<(free_id+1)); dev1->faked_unit = free_id; } aux = aux->next; } dev = dev->next; } // Now reorder the queue #if 0 dev = Devices; while(dev) { aux = dev; while(aux) { SCSIDevice* dev1, * dev2; dev1 = dev, dev2 = aux; if(dev1->faked_unit>dev2->faked_unit) { SCSIDevice tmp; memcpy(&tmp, dev1, sizeof(SCSIDevice)); memcpy(dev1, dev2, sizeof(SCSIDevice)); memcpy(dev2, &tmp, sizeof(SCSIDevice)); } aux = aux->next; } dev = dev->next; } #endif // Now open the selected SCSI devices :-) for(int n=0;n<8;n++) { char tmp[25]; snprintf(tmp, sizeof(tmp), "scsi%d", n); const char* scsi = PrefsFindString(tmp); if(scsi) { int id, lun; // The format is: RemappedID (or FakedID)/LUN sscanf(scsi, "%d/%d", &id, &lun); SCSIDevice* dev = _GetSCSIDeviceByIDLUN(id, lun); if(dev==NULL) continue; dev->enabled = true; dev->mac_unit = n; #ifdef CAM struct cam_device* cam; cam = cam_open_btl(dev->controller, dev->unit, dev->lun, O_RDWR, NULL); if(cam==NULL) { fprintf(stderr, "Failed to open %d:%d:%d = %s!!!\n", dev->controller, dev->unit, dev->lun, cam_errbuf); } dev->dev_ptr = (void*)cam; #else /* !CAM */ dev->dev_fd = scsi_open(dev->device, O_RDWR); if(dev->dev_fd<0) { perror("Failed to open %d:%d:%d"); } else { dev->dev_ptr = (void*)scsireq_new(); } #endif /* !CAM */ } } } /* * Initialization */ void SCSIInit(void) { // Finds the SCSI hosts in the system filling the SCSIDevices queue. // "Stolen" from camcontrol.c // Copyright (C) 1997-99 Kenneth D. Merry // Old SCSI detection "stolen" from scsi.c // Copyright (C) 1993 Julian Elischer // int bufsize, fd; int need_close = 0; int error = 0; int skip_device = 0; SCSIDevice* Dev, * dev, * PrevDev = NULL; nDevices = 0; if(PrefsFindBool("noscsi")) goto no_scsi; #ifdef CAM union ccb ccb; if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { fprintf(stderr, "WARNING: Cannot open CAM device %s (%s)\n", XPT_DEVICE, strerror(errno)); goto no_scsi; } memset(&(&ccb.ccb_h)[1], 0, sizeof(struct ccb_dev_match)-sizeof(struct ccb_hdr)); ccb.ccb_h.func_code = XPT_DEV_MATCH; bufsize = sizeof(struct dev_match_result) * 100; ccb.cdm.match_buf_len = bufsize; ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); ccb.cdm.num_matches = 0; ccb.cdm.num_patterns = 0; ccb.cdm.pattern_buf_len = 0; do { Dev = _AllocNewDevice(); if(ioctl(fd, CAMIOCOMMAND, &ccb)==-1) { fprintf(stderr, "Error sending CAMIOCOMMAND ioctl\n"); return; } if((ccb.ccb_h.status != CAM_REQ_CMP) || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { fprintf(stderr, "Got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status); return; } char current_controller_name[33]; int current_controller = -1; for(int i=0;ipath_id==-1) break; Dev->controller = bus_result->path_id; snprintf(Dev->controller_name, sizeof(Dev->controller_name), "%s%d", bus_result->dev_name, bus_result->unit_number); strncpy(current_controller_name, Dev->controller_name, sizeof(current_controller_name)); current_controller = Dev->controller; Dev->controller_bus = bus_result->bus_id; break; } case DEV_MATCH_DEVICE: { struct device_match_result* dev_result; char tmpstr[256]; dev_result = &ccb.cdm.matches[i].result.device_result; if(current_controller==-1||dev_result->target_id==-1) { skip_device = 1; break; } else skip_device = 0; cam_strvis(Dev->vendor, (u_int8_t*)dev_result->inq_data.vendor, sizeof(dev_result->inq_data.vendor), sizeof(Dev->vendor)); cam_strvis(Dev->product, (u_int8_t*)dev_result->inq_data.product, sizeof(dev_result->inq_data.product), sizeof(Dev->product)); cam_strvis(Dev->revision, (u_int8_t*)dev_result->inq_data.revision, sizeof(dev_result->inq_data.revision), sizeof(Dev->revision)); strncpy(Dev->controller_name, current_controller_name, sizeof(Dev->controller_name)); Dev->controller = current_controller; Dev->unit = dev_result->target_id; Dev->lun = dev_result->target_lun; break; } case DEV_MATCH_PERIPH: { struct periph_match_result* periph_result; periph_result = &ccb.cdm.matches[i].result.periph_result; if(skip_device != 0) break; if(need_close==1) { snprintf(Dev->device, sizeof(Dev->device), "%s%d*", periph_result->periph_name, periph_result->unit_number); need_close = 0; } else if(need_close==0) { snprintf(Dev->pass_device, sizeof(Dev->pass_device), "%s%d", periph_result->periph_name, periph_result->unit_number); need_close++; break; } else { need_close = 0; } PrevDev = Dev; Dev = _AllocNewDevice(); break; } } } } while (ccb.ccb_h.status == CAM_REQ_CMP && ccb.cdm.status == CAM_DEV_MATCH_MORE); /* Remove last one (ugly coding) */ Devices = PrevDev; delete Dev; end_loop: close(fd); #else /* !CAM */ /* * FreeBSD 2.x SCSI management is quiet different and * unfortunatly not flexible as CAM library in FreeBSD 3.x... * I probe only the first bus, LUN 0, and the * first 8 devices only. */ u_char* inq_buf; scsireq_t* scsireq; struct scsi_addr scsi; int ssc_fd; if((ssc_fd=open("/dev/ssc", O_RDWR))==-1) { fprintf(stderr, "Cannot open SCSI manager: /dev/ssc\n"); SCSIReset(); return; } inq_buf = (u_char*)malloc(96); if(inq_buf==NULL) { perror("malloc failed"); SCSIReset(); return; } scsireq = scsireq_build((scsireq_t*)dev->dev_ptr, 96, inq_buf, SCCMD_READ, "12 0 0 0 v 0", 96); addr.scbus = 0; addr.lun = 0; for(int n=0;n<8;n++) { addr.target = n; if(ioctl(ssc_fd, SCIOCADDR, &addr) != -1) { Dev = _AllocNewDevice(); Dev->controller = addr.scbus; Dev->lun = addr.lun; Dev->unit = addr.target; struct scsi_devinfo devInfo; devInfo.addr = addr; if(ioctl(ssc_fd, SCIOCGETDEVINFO, &devInfo) != -1) { strncpy(Dev->device, devInfo.devname, sizeof(Dev->device)); } strncpy(Dev->controller_name, "FreeBSD 2.x SCSI Manager", sizeof(Dev->controller_name)); if(scsireq_enter(ssc_fd, scsireq)!=-1) { Dev->vendor[sizeof(Dev->vendor)-1] = 0; Dev->product[sizeof(Dev->product)-1] = 0; Dev->revision[sizeof(Dev->revision)-1] = 0; scsireq_decode(scsireq, "s8 c8 c16 c4", Dev->vendor, Dev->product, Dev->revision); } } } free(inq_buf); close(ssc_fd); #endif /* !CAM */ _Build_SCSI_Controller(); // Print out the periph with ID:LUNs fprintf(stderr, "Device RealID FkdID MacID Enabled\n"); fprintf(stderr, "-------------------------------------------------------------\n"); // 012345678901234567890123456789012 0:0:0 0/0 0:0 Yes dev = Devices; while(dev) { char tmp[40]; snprintf(tmp, sizeof(tmp), "%s %s %s", dev->vendor, dev->product, dev->revision); fprintf(stderr, "%-33s %d:%d:%d %d/%d %d:%d %s\n", tmp, dev->controller, dev->unit, dev->lun, dev->faked_unit, dev->lun, dev->mac_unit, dev->lun, dev->enabled?"Yes":"No"); dev = dev->next; } no_scsi: // Reset SCSI bus SCSIReset(); } /* * Deinitialization */ void SCSIExit(void) { SCSIDevice* aux; while(Devices) { aux = Devices->next; if(Devices->dev_ptr!=NULL) { #ifdef CAM cam_close_device((struct cam_device*)Devices->dev_ptr); #else /* !CAM */ free(Devices->dev_ptr); // Is this right? close(Devices->dev_fd); // And this one? #endif /* !CAM */ } delete Devices; Devices = aux; } nDevices = 0; } /* * Set SCSI command to be sent by scsi_send_cmd() */ void scsi_set_cmd(int cmd_length, uint8 *cmd) { the_cmd_len = cmd_length; memset(the_cmd, 0, sizeof(the_cmd)); memcpy(the_cmd, cmd, the_cmd_len); } /* * Check for presence of SCSI target */ bool scsi_is_target_present(int id) { return (_GetSCSIDeviceByMacID(id)!=NULL&&_GetSCSIDeviceByMacID(id)->enabled); } /* * Set SCSI target (returns false on error) */ bool scsi_set_target(int id, int lun) { SCSIDevice* dev; dev = _GetSCSIDeviceByMacIDLUN(id, lun); if(dev==NULL) return false; CurrentDevice = dev; return true; } /* * Send SCSI command to active target (scsi_set_command() must have been called), * read/write data according to S/G table (returns false on error) */ static bool try_buffer(int size) { if(size <= buffer_size) { return true; } D(bug("Allocating buffer of %d bytes.\n", size)); uint8* new_buffer = (uint8*)valloc(size); if(new_buffer==NULL) { return false; } if(buffer!=NULL) free(buffer); buffer = new_buffer; buffer_size = size; return true; } bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout) { int value = 0; #ifdef CAM #ifdef VERBOSE_CAM_DEBUG D(bug("Sending command %x (len=%d) to SCSI Device %d:%d:%d\n", the_cmd[0], the_cmd_len, CurrentDevice->controller, CurrentDevice->unit, CurrentDevice->lun)); D(bug("DataLength: %d\n", data_length)); D(bug("Reading: %d\n", reading)); D(bug("SG Size: %d\n", sg_size)); D(bug("Timeout: %d\n", timeout)); #endif /* VERBOSE_CAM_DEBUG */ #endif /* CAM */ if(!try_buffer(data_length)) { char str[256]; sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length); ErrorAlert(str); return false; } if(!reading) { uint8* buffer_ptr = buffer; for(int i=0;i0) { dir_flags = reading?CAM_DIR_IN:CAM_DIR_OUT; } ccb.ccb_h.path_id = CurrentDevice->controller; ccb.ccb_h.target_id = CurrentDevice->unit; ccb.ccb_h.target_lun = CurrentDevice->lun; cam_fill_csio(&ccb.csio, 0, NULL, dir_flags, MSG_SIMPLE_Q_TAG, (u_int8_t*)buffer, data_length, SSD_FULL_SIZE, the_cmd_len, (timeout?timeout:50)*1000); ccb.ccb_h.flags |= CAM_DEV_QFRZDIS; memcpy(ccb.csio.cdb_io.cdb_bytes, the_cmd, the_cmd_len); if(cam_send_ccb(device, &ccb)<0) { fprintf(stderr, "%d:%d:%d ", CurrentDevice->controller, CurrentDevice->unit, CurrentDevice->lun); perror("cam_send_ccb"); return false; } value = ccb.ccb_h.status; *stat = ccb.csio.scsi_status; if((value & CAM_STATUS_MASK) != CAM_REQ_CMP) { char tmp[4096]; if((value & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) { scsi_sense_string(device, &ccb.csio, tmp, sizeof(tmp)); fprintf(stderr, "SCSI Status Error:\n%s\n", tmp); return false; } } #else /* !CAM */ struct scsireq* scsireq = _GetCurrentSCSIDevice(); if(device==NULL) return false; int dir_flags = 0x00; if(data_length>0) dir_flags = reading?SCCMD_READ:SCCMD_WRITE; scsireq_reset(scsireq); scsireq->timeout = (timeout?timeout:50)*1000; scsireq_build(scsireq, data_length, (caddr_t)buffer, dir_flags, "0"); memcpy(scsireq->cmd, the_cmd, scsireq->cmdlen = the_cmd_len); int result = scsi_enter(dev->dev_fd, scsireq); if(SCSIREQ_ERROR(result)) { scsi_debug(stderr, result, scsireq); } *stat = scsireq->status; #endif /* !CAM */ if(reading) { uint8* buffer_ptr = buffer; for(int i=0;i #include #include #include #include #include #include #include #include #ifdef CAM #include #include #include #include #include #include #include #include #else /* !CAM */ #include #include #endif /* !CAM */ #undef u_int8_t #define u_int8_t unsigned char typedef struct _SCSIDevice { int controller; // SCSI Controller int controller_bus; // SCSI Controller Bus char controller_name[33]; // SCSI Controller name int mac_unit; // Macintosh SCSI ID (remapped) int faked_controller; // "Faked" SCSI Controller (Always 0) int faked_unit; // "Faked" SCSI ID int unit; // Real SCSI ID int lun; // Real SCSI LUN u_int8_t vendor[16]; // SCSI Vendor u_int8_t product[48]; // SCSI Product u_int8_t revision[16]; // SCSI Revision char device[33]; // SCSI Device #ifdef CAM char pass_device[33]; // SCSI Pass Device #else /* !CAM */ int dev_fd; // Device File Descriptor #endif /* !CAM */ void* dev_ptr; // Pointer to CAM/SCSI structure bool enabled; // Device enabled ? struct _SCSIDevice* next; // Pointer to the next device } SCSIDevice; static int nDevices = 0; static SCSIDevice* Devices = NULL; inline static SCSIDevice* _GetSCSIDeviceByID(int id) { SCSIDevice* aux = Devices; while(aux) { if(aux->faked_unit==id) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _GetSCSIDeviceByIDLUN(int id, int lun) { SCSIDevice* aux = Devices; while(aux) { if(aux->faked_unit==id&&aux->lun==lun) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _GetSCSIDeviceByMacID(int id) { SCSIDevice* aux = Devices; while(aux) { if(aux->mac_unit==id) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _GetSCSIDeviceByMacIDLUN(int id, int lun) { SCSIDevice* aux = Devices; while(aux) { if(aux->mac_unit==id&&aux->lun==lun) { return aux; } aux = aux->next; } return NULL; } inline static SCSIDevice* _AllocNewDevice() { SCSIDevice* aux; aux = new SCSIDevice; if(aux==NULL) return NULL; memset(aux, 0, sizeof(SCSIDevice)); aux->next = Devices; Devices = aux; return aux; } /* * _Build_SCSI_Controller() * * This function builds a virtual SCSI Controller (Controller=0) * where keeps all the devices found, this is due the fact * I have two SCSI controllers in my PC. :-) * Use FreeBSD-SCSIDump in contrib/ to see how is remapped your * SCSI device (only if you have more than one controller, * that's for sure :-). */ #define GET_FREE_ID(id) \ { \ for(int x=0;x<32;x++) { \ if(!(busyIDs&(1<<(x+1)))) { \ id = x; \ break; \ } \ } \ } static void _Build_SCSI_Controller() { unsigned int id = 0; unsigned long long busyIDs = 0x0ll; SCSIDevice* aux, * dev; // What IDs are busy? dev = Devices; while(dev) { dev->enabled = false; dev->faked_controller = 0; dev->faked_unit = dev->unit; busyIDs |= (1 << (dev->unit+1)); dev = dev->next; } // Find out the duplicate IDs and change them dev = Devices, aux = NULL; while(dev) { aux = dev; while(aux) { SCSIDevice* dev1, * dev2; dev1 = dev, dev2 = aux; if(dev1->controller!=dev2->controller&& dev1->unit==dev2->unit) { int free_id; GET_FREE_ID(free_id); busyIDs |= (1<<(free_id+1)); dev1->faked_unit = free_id; } aux = aux->next; } dev = dev->next; } // Now reorder the queue dev = Devices; while(dev) { aux = dev; while(aux) { SCSIDevice* dev1, * dev2; dev1 = dev, dev2 = aux; /* if(dev1->faked_unit>dev2->faked_unit) { SCSIDevice tmp; memcpy(&tmp, dev1, sizeof(SCSIDevice)); memcpy(dev1, dev2, sizeof(SCSIDevice)); memcpy(dev2, &tmp, sizeof(SCSIDevice)); } */ aux = aux->next; } dev = dev->next; } } #define SCSIReset() /* * Initialization */ void SCSIInit(void) { // Find the SCSI hosts in the system // Filling out the SCSIDevices queue. // Stolen from camcontrol.c int bufsize, fd; int need_close = 0; int error = 0; int skip_device = 0; SCSIDevice* Dev, * dev, * PrevDev = NULL; nDevices = 0; #ifdef CAM union ccb ccb; if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { fprintf(stderr, "Cannot open CAM device: %s\n", XPT_DEVICE); goto no_scsi; } memset(&(&ccb.ccb_h)[1], 0, sizeof(struct ccb_dev_match)-sizeof(struct ccb_hdr)); ccb.ccb_h.func_code = XPT_DEV_MATCH; bufsize = sizeof(struct dev_match_result) * 100; ccb.cdm.match_buf_len = bufsize; ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); ccb.cdm.num_matches = 0; ccb.cdm.num_patterns = 0; ccb.cdm.pattern_buf_len = 0; do { Dev = _AllocNewDevice(); if(ioctl(fd, CAMIOCOMMAND, &ccb)==-1) { fprintf(stderr, "Error sending CAMIOCOMMAND ioctl\n"); return; } if((ccb.ccb_h.status != CAM_REQ_CMP) || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { fprintf(stderr, "Got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status); return; } char current_controller_name[33]; int current_controller = -1; for(int i=0;ipath_id==-1) break; Dev->controller = bus_result->path_id; snprintf(Dev->controller_name, sizeof(Dev->controller_name), "%s%d", bus_result->dev_name, bus_result->unit_number); strncpy(current_controller_name, Dev->controller_name, sizeof(current_controller_name)); current_controller = Dev->controller; Dev->controller_bus = bus_result->bus_id; break; } case DEV_MATCH_DEVICE: { struct device_match_result* dev_result; char tmpstr[256]; dev_result = &ccb.cdm.matches[i].result.device_result; if(current_controller==-1||dev_result->target_id==-1) { skip_device = 1; break; } else skip_device = 0; cam_strvis(Dev->vendor, (u_int8_t*)dev_result->inq_data.vendor, sizeof(dev_result->inq_data.vendor), sizeof(Dev->vendor)); cam_strvis(Dev->product, (u_int8_t*)dev_result->inq_data.product, sizeof(dev_result->inq_data.product), sizeof(Dev->product)); cam_strvis(Dev->revision, (u_int8_t*)dev_result->inq_data.revision, sizeof(dev_result->inq_data.revision), sizeof(Dev->revision)); strncpy(Dev->controller_name, current_controller_name, sizeof(Dev->controller_name)); Dev->controller = current_controller; Dev->unit = dev_result->target_id; Dev->lun = dev_result->target_lun; break; } case DEV_MATCH_PERIPH: { struct periph_match_result* periph_result; periph_result = &ccb.cdm.matches[i].result.periph_result; if(skip_device != 0) break; if(need_close==1) { snprintf(Dev->device, sizeof(Dev->device), "%s%d*", periph_result->periph_name, periph_result->unit_number); need_close = 0; } else if(need_close==0) { snprintf(Dev->pass_device, sizeof(Dev->pass_device), "%s%d", periph_result->periph_name, periph_result->unit_number); need_close++; break; } else { need_close = 0; } PrevDev = Dev; Dev = _AllocNewDevice(); break; } } } } while (ccb.ccb_h.status == CAM_REQ_CMP && ccb.cdm.status == CAM_DEV_MATCH_MORE); /* Remove last one (ugly coding) */ Devices = PrevDev; delete Dev; end_loop: close(fd); #else /* !CAM */ /* * FreeBSD 2.x SCSI management is quiet different and * unfortunatly not flexible as CAM library in FreeBSD 3.x... * I only scan for the first bus, LUN 0, and the * first 8 devices only. */ u_char* inq_buf; scsireq_t* scsireq; struct scsi_addr scsi; int ssc_fd; if((ssc_fd=open("/dev/ssc", O_RDWR))==-1) { fprintf(stderr, "Cannot open SCSI manager: /dev/ssc\n"); SCSIReset(); return; } inq_buf = (u_char*)malloc(96); if(inq_buf==NULL) { perror("malloc failed"); SCSIReset(); return; } scsireq = scsireq_build((scsireq_t*)dev->dev_ptr, 96, inq_buf, SCCMD_READ, "12 0 0 0 v 0", 96); addr.scbus = 0; addr.lun = 0; for(int n=0;n<8;n++) { addr.target = n; if(ioctl(ssc_fd, SCIOCADDR, &addr) != -1) { Dev = _AllocNewDevice(); Dev->controller = addr.scbus; Dev->lun = addr.lun; Dev->unit = addr.target; struct scsi_devinfo devInfo; devInfo.addr = addr; if(ioctl(ssc_fd, SCIOCGETDEVINFO, &devInfo) != -1) { strncpy(Dev->device, devInfo.devname, sizeof(Dev->device)); } strncpy(Dev->controller_name, "FreeBSD 2.x SCSI Manager", sizeof(Dev->controller_name)); if(scsireq_enter(ssc_fd, scsireq)!=-1) { Dev->vendor[sizeof(Dev->vendor)-1] = 0; Dev->product[sizeof(Dev->product)-1] = 0; Dev->revision[sizeof(Dev->revision)-1] = 0; scsireq_decode(scsireq, "s8 c8 c16 c4", Dev->vendor, Dev->product, Dev->revision); } } } free(inq_buf); close(ssc_fd); #endif /* !CAM */ _Build_SCSI_Controller(); // Print out the periph with ID:LUNs fprintf(stderr, "Device RealID FkdID\n"); fprintf(stderr, "----------------------------------------------\n"); // 012345678901234567890123456789012 0:0:0 0/0 dev = Devices; while(dev) { char tmp[40]; snprintf(tmp, sizeof(tmp), "%s %s %s", dev->vendor, dev->product, dev->revision); fprintf(stderr, "%-33s %d:%d:%d %d/%d\n", tmp, dev->controller, dev->unit, dev->lun, dev->faked_unit, dev->lun); dev = dev->next; } no_scsi: // Reset SCSI bus SCSIReset(); } /* * Deinitialization */ void SCSIExit(void) { SCSIDevice* aux; while(Devices) { aux = Devices->next; if(Devices->dev_ptr!=NULL) { #ifdef CAM cam_close_device((struct cam_device*)Devices->dev_ptr); #else /* !CAM */ free(Devices->dev_ptr); // Is this right? close(Devices->dev_fd); // And this one? #endif /* !CAM */ } delete Devices; Devices = aux; } nDevices = 0; } int main() { SCSIInit(); SCSIExit(); return 0; } BasiliskII/src/Unix/video_vosf.h0000644000175000017500000005212710744632755017013 0ustar centriscentris/* * video_vosf.h - Video/graphics emulation, video on SEGV signals support * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef VIDEO_VOSF_H #define VIDEO_VOSF_H // Note: this file must be #include'd only in video_x.cpp #ifdef ENABLE_VOSF #include "sigsegv.h" #include "vm_alloc.h" #ifdef _WIN32 #include "util_windows.h" #endif // Glue for SDL and X11 support #ifdef TEST_VOSF_PERFORMANCE #define MONITOR_INIT /* nothing */ #else #ifdef USE_SDL_VIDEO #define MONITOR_INIT SDL_monitor_desc &monitor #define VIDEO_DRV_WIN_INIT driver_window *drv #define VIDEO_DRV_DGA_INIT driver_fullscreen *drv #define VIDEO_DRV_LOCK_PIXELS SDL_VIDEO_LOCK_SURFACE(drv->s) #define VIDEO_DRV_UNLOCK_PIXELS SDL_VIDEO_UNLOCK_SURFACE(drv->s) #define VIDEO_DRV_DEPTH drv->s->format->BitsPerPixel #define VIDEO_DRV_WIDTH drv->s->w #define VIDEO_DRV_HEIGHT drv->s->h #define VIDEO_DRV_ROW_BYTES drv->s->pitch #else #ifdef SHEEPSHAVER #define MONITOR_INIT /* nothing */ #define VIDEO_DRV_WIN_INIT /* nothing */ #define VIDEO_DRV_DGA_INIT /* nothing */ #define VIDEO_DRV_WINDOW the_win #define VIDEO_DRV_GC the_gc #define VIDEO_DRV_IMAGE img #define VIDEO_DRV_HAVE_SHM have_shm #else #define MONITOR_INIT X11_monitor_desc &monitor #define VIDEO_DRV_WIN_INIT driver_window *drv #define VIDEO_DRV_DGA_INIT driver_dga *drv #define VIDEO_DRV_WINDOW drv->w #define VIDEO_DRV_GC drv->gc #define VIDEO_DRV_IMAGE drv->img #define VIDEO_DRV_HAVE_SHM drv->have_shm #endif #define VIDEO_DRV_LOCK_PIXELS /* nothing */ #define VIDEO_DRV_UNLOCK_PIXELS /* nothing */ #define VIDEO_DRV_DEPTH VIDEO_DRV_IMAGE->depth #define VIDEO_DRV_WIDTH VIDEO_DRV_IMAGE->width #define VIDEO_DRV_HEIGHT VIDEO_DRV_IMAGE->height #define VIDEO_DRV_ROW_BYTES VIDEO_DRV_IMAGE->bytes_per_line #endif #endif // Prototypes static void vosf_do_set_dirty_area(uintptr first, uintptr last); static void vosf_set_dirty_area(int x, int y, int w, int h, int screen_width, int screen_height, int bytes_per_row); // Variables for Video on SEGV support static uint8 *the_host_buffer; // Host frame buffer in VOSF mode struct ScreenPageInfo { int top, bottom; // Mapping between this virtual page and Mac scanlines }; struct ScreenInfo { uintptr memStart; // Start address aligned to page boundary uint32 memLength; // Length of the memory addressed by the screen pages uintptr pageSize; // Size of a page int pageBits; // Shift count to get the page number uint32 pageCount; // Number of pages allocated to the screen bool dirty; // Flag: set if the frame buffer was touched bool very_dirty; // Flag: set if the frame buffer was completely modified (e.g. colormap changes) char * dirtyPages; // Table of flags set if page was altered ScreenPageInfo * pageInfo; // Table of mappings page -> Mac scanlines }; static ScreenInfo mainBuffer; #define PFLAG_SET_VALUE 0x00 #define PFLAG_CLEAR_VALUE 0x01 #define PFLAG_SET_VALUE_4 0x00000000 #define PFLAG_CLEAR_VALUE_4 0x01010101 #define PFLAG_SET(page) mainBuffer.dirtyPages[page] = PFLAG_SET_VALUE #define PFLAG_CLEAR(page) mainBuffer.dirtyPages[page] = PFLAG_CLEAR_VALUE #define PFLAG_ISSET(page) (mainBuffer.dirtyPages[page] == PFLAG_SET_VALUE) #define PFLAG_ISCLEAR(page) (mainBuffer.dirtyPages[page] != PFLAG_SET_VALUE) #ifdef UNALIGNED_PROFITABLE # define PFLAG_ISSET_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_SET_VALUE_4) # define PFLAG_ISCLEAR_4(page) (*((uint32 *)(mainBuffer.dirtyPages + (page))) == PFLAG_CLEAR_VALUE_4) #else # define PFLAG_ISSET_4(page) \ PFLAG_ISSET(page ) && PFLAG_ISSET(page+1) \ && PFLAG_ISSET(page+2) && PFLAG_ISSET(page+3) # define PFLAG_ISCLEAR_4(page) \ PFLAG_ISCLEAR(page ) && PFLAG_ISCLEAR(page+1) \ && PFLAG_ISCLEAR(page+2) && PFLAG_ISCLEAR(page+3) #endif // Set the selected page range [ first_page, last_page [ into the SET state #define PFLAG_SET_RANGE(first_page, last_page) \ memset(mainBuffer.dirtyPages + (first_page), PFLAG_SET_VALUE, \ (last_page) - (first_page)) // Set the selected page range [ first_page, last_page [ into the CLEAR state #define PFLAG_CLEAR_RANGE(first_page, last_page) \ memset(mainBuffer.dirtyPages + (first_page), PFLAG_CLEAR_VALUE, \ (last_page) - (first_page)) #define PFLAG_SET_ALL do { \ PFLAG_SET_RANGE(0, mainBuffer.pageCount); \ mainBuffer.dirty = true; \ } while (0) #define PFLAG_CLEAR_ALL do { \ PFLAG_CLEAR_RANGE(0, mainBuffer.pageCount); \ mainBuffer.dirty = false; \ mainBuffer.very_dirty = false; \ } while (0) #define PFLAG_SET_VERY_DIRTY do { \ mainBuffer.very_dirty = true; \ } while (0) // Set the following macro definition to 1 if your system // provides a really fast strchr() implementation //#define HAVE_FAST_STRCHR 0 static inline int find_next_page_set(int page) { #if HAVE_FAST_STRCHR char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_SET_VALUE); return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; #else while (PFLAG_ISCLEAR_4(page)) page += 4; while (PFLAG_ISCLEAR(page)) page++; return page; #endif } static inline int find_next_page_clear(int page) { #if HAVE_FAST_STRCHR char *match = strchr(mainBuffer.dirtyPages + page, PFLAG_CLEAR_VALUE); return match ? match - mainBuffer.dirtyPages : mainBuffer.pageCount; #else while (PFLAG_ISSET_4(page)) page += 4; while (PFLAG_ISSET(page)) page++; return page; #endif } #if defined(HAVE_PTHREADS) static pthread_mutex_t vosf_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect frame buffer (dirtyPages in fact) #define LOCK_VOSF pthread_mutex_lock(&vosf_lock); #define UNLOCK_VOSF pthread_mutex_unlock(&vosf_lock); #elif defined(_WIN32) static mutex_t vosf_lock; // Mutex to protect frame buffer (dirtyPages in fact) #define LOCK_VOSF vosf_lock.lock(); #define UNLOCK_VOSF vosf_lock.unlock(); #elif defined(HAVE_SPINLOCKS) static spinlock_t vosf_lock = SPIN_LOCK_UNLOCKED; // Mutex to protect frame buffer (dirtyPages in fact) #define LOCK_VOSF spin_lock(&vosf_lock) #define UNLOCK_VOSF spin_unlock(&vosf_lock) #else #define LOCK_VOSF #define UNLOCK_VOSF #endif static int log_base_2(uint32 x) { uint32 mask = 0x80000000; int l = 31; while (l >= 0 && (x & mask) == 0) { mask >>= 1; l--; } return l; } // Extend size to page boundary static uint32 page_extend(uint32 size) { const uint32 page_size = vm_get_page_size(); const uint32 page_mask = page_size - 1; return (size + page_mask) & ~page_mask; } /* * Check if VOSF acceleration is profitable on this platform */ #ifndef VOSF_PROFITABLE_TRIES #define VOSF_PROFITABLE_TRIES VOSF_PROFITABLE_TRIES_DFL #endif const int VOSF_PROFITABLE_TRIES_DFL = 3; // Make 3 attempts for full screen update const int VOSF_PROFITABLE_THRESHOLD = 16667/2; // 60 Hz (half of the quantum) static bool video_vosf_profitable(uint32 *duration_p = NULL, uint32 *n_page_faults_p = NULL) { uint32 duration = 0; uint32 n_tries = VOSF_PROFITABLE_TRIES; const uint32 n_page_faults = mainBuffer.pageCount * n_tries; #ifdef SHEEPSHAVER const bool accel = PrefsFindBool("gfxaccel"); #else const bool accel = false; #endif for (int i = 0; i < n_tries; i++) { uint64 start = GetTicks_usec(); for (int p = 0; p < mainBuffer.pageCount; p++) { uint8 *addr = (uint8 *)(mainBuffer.memStart + (p * mainBuffer.pageSize)); if (accel) vosf_do_set_dirty_area((uintptr)addr, (uintptr)addr + mainBuffer.pageSize - 1); else addr[0] = 0; // Trigger Screen_fault_handler() } uint64 elapsed = GetTicks_usec() - start; duration += elapsed; PFLAG_CLEAR_ALL; mainBuffer.dirty = false; if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0) return false; } if (duration_p) *duration_p = duration; if (n_page_faults_p) *n_page_faults_p = n_page_faults; D(bug("Triggered %d page faults in %ld usec (%.1f usec per fault)\n", n_page_faults, duration, double(duration) / double(n_page_faults))); return ((duration / n_tries) < (VOSF_PROFITABLE_THRESHOLD * (frame_skip ? frame_skip : 1))); } /* * Initialize the VOSF system (mainBuffer structure, SIGSEGV handler) */ static bool video_vosf_init(MONITOR_INIT) { VIDEO_MODE_INIT_MONITOR; const uintptr page_size = vm_get_page_size(); const uintptr page_mask = page_size - 1; // Round up frame buffer base to page boundary mainBuffer.memStart = (((uintptr) the_buffer) + page_mask) & ~page_mask; // The frame buffer size shall already be aligned to page boundary (use page_extend) mainBuffer.memLength = the_buffer_size; mainBuffer.pageSize = page_size; mainBuffer.pageBits = log_base_2(mainBuffer.pageSize); mainBuffer.pageCount = (mainBuffer.memLength + page_mask)/mainBuffer.pageSize; // The "2" more bytes requested are a safety net to insure the // loops in the update routines will terminate. // See "How can we deal with array overrun conditions ?" hereunder for further details. mainBuffer.dirtyPages = (char *) malloc(mainBuffer.pageCount + 2); if (mainBuffer.dirtyPages == NULL) return false; PFLAG_CLEAR_ALL; PFLAG_CLEAR(mainBuffer.pageCount); PFLAG_SET(mainBuffer.pageCount+1); // Allocate and fill in pageInfo with start and end (inclusive) row in number of bytes mainBuffer.pageInfo = (ScreenPageInfo *) malloc(mainBuffer.pageCount * sizeof(ScreenPageInfo)); if (mainBuffer.pageInfo == NULL) return false; uint32 a = 0; for (unsigned i = 0; i < mainBuffer.pageCount; i++) { unsigned y1 = a / VIDEO_MODE_ROW_BYTES; if (y1 >= VIDEO_MODE_Y) y1 = VIDEO_MODE_Y - 1; unsigned y2 = (a + mainBuffer.pageSize) / VIDEO_MODE_ROW_BYTES; if (y2 >= VIDEO_MODE_Y) y2 = VIDEO_MODE_Y - 1; mainBuffer.pageInfo[i].top = y1; mainBuffer.pageInfo[i].bottom = y2; a += mainBuffer.pageSize; if (a > mainBuffer.memLength) a = mainBuffer.memLength; } // We can now write-protect the frame buffer if (vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ) != 0) return false; // The frame buffer is sane, i.e. there is no write to it yet mainBuffer.dirty = false; return true; } /* * Deinitialize VOSF system */ static void video_vosf_exit(void) { if (mainBuffer.pageInfo) { free(mainBuffer.pageInfo); mainBuffer.pageInfo = NULL; } if (mainBuffer.dirtyPages) { free(mainBuffer.dirtyPages); mainBuffer.dirtyPages = NULL; } } /* * Update VOSF state with specified dirty area */ static void vosf_do_set_dirty_area(uintptr first, uintptr last) { const int first_page = (first - mainBuffer.memStart) >> mainBuffer.pageBits; const int last_page = (last - mainBuffer.memStart) >> mainBuffer.pageBits; uint8 *addr = (uint8 *)(first & -mainBuffer.pageSize); for (int i = first_page; i <= last_page; i++) { if (PFLAG_ISCLEAR(i)) { PFLAG_SET(i); vm_protect(addr, mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); } addr += mainBuffer.pageSize; } } static void vosf_set_dirty_area(int x, int y, int w, int h, int screen_width, int screen_height, int bytes_per_row) { if (x < 0) { w -= -x; x = 0; } if (y < 0) { h -= -y; y = 0; } if (w <= 0 || h <= 0) return; if (x + w > screen_width) w -= (x + w) - screen_width; if (y + h > screen_height) h -= (y + h) - screen_height; LOCK_VOSF; if (bytes_per_row >= screen_width) { const int bytes_per_pixel = bytes_per_row / screen_width; if (bytes_per_row <= mainBuffer.pageSize) { const uintptr a0 = mainBuffer.memStart + y * bytes_per_row + x * bytes_per_pixel; const uintptr a1 = mainBuffer.memStart + (y + h - 1) * bytes_per_row + (x + w - 1) * bytes_per_pixel; vosf_do_set_dirty_area(a0, a1); } else { for (int j = y; j < y + h; j++) { const uintptr a0 = mainBuffer.memStart + j * bytes_per_row + x * bytes_per_pixel; const uintptr a1 = a0 + (w - 1) * bytes_per_pixel; vosf_do_set_dirty_area(a0, a1); } } } else { const int pixels_per_byte = screen_width / bytes_per_row; if (bytes_per_row <= mainBuffer.pageSize) { const uintptr a0 = mainBuffer.memStart + y * bytes_per_row + x / pixels_per_byte; const uintptr a1 = mainBuffer.memStart + (y + h - 1) * bytes_per_row + (x + w - 1) / pixels_per_byte; vosf_do_set_dirty_area(a0, a1); } else { for (int j = y; j < y + h; j++) { const uintptr a0 = mainBuffer.memStart + j * bytes_per_row + x / pixels_per_byte; const uintptr a1 = mainBuffer.memStart + j * bytes_per_row + (x + w - 1) / pixels_per_byte; vosf_do_set_dirty_area(a0, a1); } } } mainBuffer.dirty = true; UNLOCK_VOSF; } /* * Screen fault handler */ bool Screen_fault_handler(sigsegv_info_t *sip) { const uintptr addr = (uintptr)sigsegv_get_fault_address(sip); /* Someone attempted to write to the frame buffer. Make it writeable * now so that the data could actually be written to. It will be made * read-only back in one of the screen update_*() functions. */ if (((uintptr)addr - mainBuffer.memStart) < mainBuffer.memLength) { const int page = ((uintptr)addr - mainBuffer.memStart) >> mainBuffer.pageBits; LOCK_VOSF; if (PFLAG_ISCLEAR(page)) { PFLAG_SET(page); vm_protect((char *)(addr & -mainBuffer.pageSize), mainBuffer.pageSize, VM_PAGE_READ | VM_PAGE_WRITE); } mainBuffer.dirty = true; UNLOCK_VOSF; return true; } /* Otherwise, we don't know how to handle the fault, let it crash */ return false; } /* * Update display for Windowed mode and VOSF */ /* How can we deal with array overrun conditions ? The state of the framebuffer pages that have been touched are maintained in the dirtyPages[] table. That table is (pageCount + 2) bytes long. Terminology "Last Page" denotes the pageCount-nth page, i.e. dirtyPages[pageCount - 1]. "CLEAR Page Guard" refers to the page following the Last Page but is always in the CLEAR state. "SET Page Guard" refers to the page following the CLEAR Page Guard but is always in the SET state. Rough process The update routines must determine which pages have to be blitted to the screen. This job consists in finding the first_page that was touched. i.e. find the next page that is SET. Then, finding how many pages were touched starting from first_page. i.e. find the next page that is CLEAR. There are two cases to check: - Last Page is CLEAR: find_next_page_set() will reach the SET Page Guard but it is beyond the valid pageCount value. Therefore, we exit from the update routine. - Last Page is SET: first_page equals (pageCount - 1) and find_next_page_clear() will reach the CLEAR Page Guard. We blit the last page to the screen. On the next iteration, page equals pageCount and find_next_page_set() will reach the SET Page Guard. We still safely exit from the update routine because the SET Page Guard position is greater than pageCount. */ #ifndef TEST_VOSF_PERFORMANCE static void update_display_window_vosf(VIDEO_DRV_WIN_INIT) { VIDEO_MODE_INIT; int page = 0; for (;;) { const unsigned first_page = find_next_page_set(page); if (first_page >= mainBuffer.pageCount) break; page = find_next_page_clear(first_page); PFLAG_CLEAR_RANGE(first_page, page); // Make the dirty pages read-only again const int32 offset = first_page << mainBuffer.pageBits; const uint32 length = (page - first_page) << mainBuffer.pageBits; vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ); // There is at least one line to update const int y1 = mainBuffer.pageInfo[first_page].top; const int y2 = mainBuffer.pageInfo[page - 1].bottom; const int height = y2 - y1 + 1; // Update the_host_buffer VIDEO_DRV_LOCK_PIXELS; const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES; const int dst_bytes_per_row = VIDEO_DRV_ROW_BYTES; int i1 = y1 * src_bytes_per_row, i2 = y1 * dst_bytes_per_row, j; for (j = y1; j <= y2; j++) { Screen_blit(the_host_buffer + i2, the_buffer + i1, src_bytes_per_row); i1 += src_bytes_per_row; i2 += dst_bytes_per_row; } VIDEO_DRV_UNLOCK_PIXELS; #ifdef USE_SDL_VIDEO SDL_UpdateRect(drv->s, 0, y1, VIDEO_MODE_X, height); #else if (VIDEO_DRV_HAVE_SHM) XShmPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height, 0); else XPutImage(x_display, VIDEO_DRV_WINDOW, VIDEO_DRV_GC, VIDEO_DRV_IMAGE, 0, y1, 0, y1, VIDEO_MODE_X, height); #endif } mainBuffer.dirty = false; } #endif /* * Update display for DGA mode and VOSF * (only in Real or Direct Addressing mode) */ #ifndef TEST_VOSF_PERFORMANCE #if REAL_ADDRESSING || DIRECT_ADDRESSING static void update_display_dga_vosf(VIDEO_DRV_DGA_INIT) { VIDEO_MODE_INIT; // Compute number of bytes per row, take care to virtual screens const int src_bytes_per_row = VIDEO_MODE_ROW_BYTES; const int dst_bytes_per_row = TrivialBytesPerRow(VIDEO_MODE_X, DepthModeForPixelDepth(VIDEO_DRV_DEPTH)); const int scr_bytes_per_row = VIDEO_DRV_ROW_BYTES; assert(dst_bytes_per_row <= scr_bytes_per_row); const int scr_bytes_left = scr_bytes_per_row - dst_bytes_per_row; // Full screen update requested? if (mainBuffer.very_dirty) { PFLAG_CLEAR_ALL; vm_protect((char *)mainBuffer.memStart, mainBuffer.memLength, VM_PAGE_READ); memcpy(the_buffer_copy, the_buffer, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y); VIDEO_DRV_LOCK_PIXELS; int i1 = 0, i2 = 0; for (int j = 0; j < VIDEO_MODE_Y; j++) { Screen_blit(the_host_buffer + i2, the_buffer + i1, src_bytes_per_row); i1 += src_bytes_per_row; i2 += scr_bytes_per_row; } #ifdef USE_SDL_VIDEO SDL_UpdateRect(drv->s, 0, 0, VIDEO_MODE_X, VIDEO_MODE_Y); #endif VIDEO_DRV_UNLOCK_PIXELS; return; } // Setup partial blitter (use 64-pixel wide chunks) const int n_pixels = 64; const int n_chunks = VIDEO_MODE_X / n_pixels; const int n_pixels_left = VIDEO_MODE_X - (n_chunks * n_pixels); const int src_chunk_size = src_bytes_per_row / n_chunks; const int dst_chunk_size = dst_bytes_per_row / n_chunks; const int src_chunk_size_left = src_bytes_per_row - (n_chunks * src_chunk_size); const int dst_chunk_size_left = dst_bytes_per_row - (n_chunks * dst_chunk_size); int page = 0, last_scanline = -1; for (;;) { const unsigned first_page = find_next_page_set(page); if (first_page >= mainBuffer.pageCount) break; page = find_next_page_clear(first_page); PFLAG_CLEAR_RANGE(first_page, page); // Make the dirty pages read-only again const int32 offset = first_page << mainBuffer.pageBits; const uint32 length = (page - first_page) << mainBuffer.pageBits; vm_protect((char *)mainBuffer.memStart + offset, length, VM_PAGE_READ); // Optimized for scanlines, don't process overlapping lines again int y1 = mainBuffer.pageInfo[first_page].top; int y2 = mainBuffer.pageInfo[page - 1].bottom; if (y1 <= last_scanline && ++y1 >= VIDEO_MODE_Y) continue; if (y2 <= last_scanline && ++y2 >= VIDEO_MODE_Y) continue; last_scanline = y2; // Update the_host_buffer and copy of the_buffer, one line at a time int i1 = y1 * src_bytes_per_row; int i2 = y1 * scr_bytes_per_row; #ifdef USE_SDL_VIDEO int bbi = 0; SDL_Rect bb[3] = { { VIDEO_MODE_X, y1, 0, 0 }, { VIDEO_MODE_X, -1, 0, 0 }, { VIDEO_MODE_X, -1, 0, 0 } }; #endif VIDEO_DRV_LOCK_PIXELS; for (int j = y1; j <= y2; j++) { for (int i = 0; i < n_chunks; i++) { if (memcmp(the_buffer_copy + i1, the_buffer + i1, src_chunk_size) != 0) { memcpy(the_buffer_copy + i1, the_buffer + i1, src_chunk_size); Screen_blit(the_host_buffer + i2, the_buffer + i1, src_chunk_size); #ifdef USE_SDL_VIDEO const int x = i * n_pixels; if (x < bb[bbi].x) { if (bb[bbi].w) bb[bbi].w += bb[bbi].x - x; else bb[bbi].w = n_pixels; bb[bbi].x = x; } else if (x >= bb[bbi].x + bb[bbi].w) bb[bbi].w = x + n_pixels - bb[bbi].x; #endif } i1 += src_chunk_size; i2 += dst_chunk_size; } if (src_chunk_size_left && dst_chunk_size_left) { if (memcmp(the_buffer_copy + i1, the_buffer + i1, src_chunk_size_left) != 0) { memcpy(the_buffer_copy + i1, the_buffer + i1, src_chunk_size_left); Screen_blit(the_host_buffer + i2, the_buffer + i1, src_chunk_size_left); } i1 += src_chunk_size_left; i2 += dst_chunk_size_left; #ifdef USE_SDL_VIDEO const int x = n_chunks * n_pixels; if (x < bb[bbi].x) { if (bb[bbi].w) bb[bbi].w += bb[bbi].x - x; else bb[bbi].w = n_pixels_left; bb[bbi].x = x; } else if (x >= bb[bbi].x + bb[bbi].w) bb[bbi].w = x + n_pixels_left - bb[bbi].x; #endif } i2 += scr_bytes_left; #ifdef USE_SDL_VIDEO bb[bbi].h++; if (bb[bbi].w && (j == y1 || j == y2 - 1 || j == y2)) { bbi++; assert(bbi <= 3); if (j != y2) bb[bbi].y = j + 1; } #endif } #ifdef USE_SDL_VIDEO SDL_UpdateRects(drv->s, bbi, bb); #endif VIDEO_DRV_UNLOCK_PIXELS; } mainBuffer.dirty = false; } #endif #endif #endif /* ENABLE_VOSF */ #endif /* VIDEO_VOSF_H */ BasiliskII/src/Unix/keycodes0000644000175000017500000001443310177252266016221 0ustar centriscentris# /usr/share/BasiliskII/keycodes # # Basilisk II (C) 1997-2005 Christian Bauer # # This file is used to translate the (server-specific) X11 keycodes to Mac # keycodes depending on the X11 server being used. # # The format of this file is as follows: # # # # # # ... # # # # ... # # The "vendor string" must match the first part of the X11 server vendor # description as reported by ServerVendor(). If a match is found, the keycode # translation table is constructed from the following lines. Each line # contains an X11 keycode followed by its associated Mac keycode. Both # keycodes have to be given in decimal. Lines beginning with "#" or ";" are # treated as comments and ignored. # # # XFree86 # The XFree86 Project, Inc 9 53 # Esc 67 122 # F1 68 120 # F2 69 99 # F3 70 118 # F4 71 96 # F5 72 97 # F6 73 98 # F7 74 100 # F8 75 101 # F9 76 109 # F10 95 103 # F11 96 111 # F12 111 105 # PrintScrn 78 107 # Scroll Lock 110 113 # Pause 49 10 # ` 10 18 # 1 11 19 # 2 12 20 # 3 13 21 # 4 14 23 # 5 15 22 # 6 16 26 # 7 17 28 # 8 18 25 # 9 19 29 # 0 20 27 # - 21 24 # = 22 51 # Backspace 106 114 # Insert 97 115 # Home 99 116 # Page Up 77 71 # Num Lock 112 75 # KP / 63 67 # KP * 82 78 # KP - 23 48 # Tab 24 12 # Q 25 13 # W 26 14 # E 27 15 # R 28 17 # T 29 16 # Y 30 32 # U 31 34 # I 32 31 # O 33 35 # P 34 33 # [ 35 30 # ] 36 36 # Return 107 117 # Delete 103 119 # End 105 121 # Page Down 79 89 # KP 7 80 91 # KP 8 81 92 # KP 9 86 69 # KP + 66 57 # Caps Lock 38 0 # A 39 1 # S 40 2 # D 41 3 # F 42 5 # G 43 4 # H 44 38 # J 45 40 # K 46 37 # L 47 41 # ; 48 39 # ' 83 86 # KP 4 84 87 # KP 5 85 88 # KP 6 50 56 # Shift Left 94 50 # International 52 6 # Z 53 7 # X 54 8 # C 55 9 # V 56 11 # B 57 45 # N 58 46 # M 59 43 # , 60 47 # . 61 44 # / 62 56 # Shift Right 51 42 # \ 98 62 # Cursor Up 87 83 # KP 1 88 84 # KP 2 89 85 # KP 3 108 76 # KP Enter 37 54 # Ctrl Left 115 58 # Logo Left (-> Option) 64 55 # Alt Left (-> Command) 65 49 # Space 113 55 # Alt Right (-> Command) 116 58 # Logo Right (-> Option) 117 50 # Menu (-> International) 109 54 # Ctrl Right 100 59 # Cursor Left 104 61 # Cursor Down 102 60 # Cursor Right 90 82 # KP 0 91 65 # KP . # # MacX (keycodes depend on Mac keymap, so this doesn't make much sense...) # MacX 61 53 # Esc 130 122 # F1 128 120 # F2 107 99 # F3 126 118 # F4 104 96 # F5 105 97 # F6 106 98 # F7 108 100 # F8 109 101 # F9 117 109 # F10 111 103 # F11 119 111 # F12 113 105 # F13/PrintScrn 115 107 # F14/Scroll Lock 121 113 # F15/Pause 18 10 # ` 26 18 # 1 27 19 # 2 28 20 # 3 29 21 # 4 31 23 # 5 30 22 # 6 34 26 # 7 36 28 # 8 33 25 # 9 37 29 # 0 35 27 # - 32 24 # = 59 51 # Backspace 122 114 # Help/Insert 123 115 # Home 124 116 # Page Up 79 71 # Num Lock 89 81 # KP = 83 75 # KP / 75 67 # KP * 56 48 # Tab 20 12 # Q 21 13 # W 22 14 # E 23 15 # R 25 17 # T 24 16 # Y 40 32 # U 42 34 # I 39 31 # O 43 35 # P 41 33 # [ 38 30 # ] 44 36 # Return 125 117 # Delete 127 119 # End 129 121 # Page Down 97 89 # KP 7 99 91 # KP 8 100 92 # KP 9 86 78 # KP - 65 57 # Caps Lock 8 0 # A 9 1 # S 10 2 # D 11 3 # F 13 5 # G 12 4 # H 46 38 # J 48 40 # K 45 37 # L 49 41 # ; 47 39 # ' 50 42 # \ 94 86 # KP 4 95 87 # KP 5 96 88 # KP 6 77 69 # KP + 64 56 # Shift 58 50 # International 14 6 # Z 15 7 # X 16 8 # C 17 9 # V 19 11 # B 53 45 # N 54 46 # M 51 43 # , 55 47 # . 52 44 # / 134 62 # Cursor Up 91 83 # KP 1 92 84 # KP 2 93 85 # KP 3 84 76 # KP Enter 62 54 # Ctrl 66 58 # Option 63 55 # Command 67 54 # Ctrl Left 57 49 # Space 131 59 # Cursor Left 133 61 # Cursor Down 132 60 # Cursor Right 90 82 # KP 0 73 65 # KP . # # SunOS/OpenWindows # Sun Microsystems, Inc. 36 53 # Esc 12 122 # F1 13 120 # F2 15 99 # F3 17 118 # F4 19 96 # F5 21 97 # F6 23 98 # F7 24 100 # F8 25 101 # F9 14 109 # F10 16 103 # F11 18 111 # F12 29 105 # PrintScrn 30 107 # Scroll Lock 28 113 # Pause 49 10 # ` 37 18 # 1 38 19 # 2 39 20 # 3 40 21 # 4 41 23 # 5 42 22 # 6 43 26 # 7 44 28 # 8 45 25 # 9 46 29 # 10 47 27 # - 48 24 # = 50 51 # Backspace 51 114 # Help/Insert 59 115 # Home 103 116 # Page Up 105 71 # Num Lock 53 75 # KP / 54 67 # KP * 78 78 # KP - 60 48 # Tab 61 12 # Q 62 13 # W 63 14 # E 64 15 # R 65 17 # T 66 16 # Y 67 32 # U 68 34 # I 69 31 # O 70 35 # P 71 33 # [ 72 30 # ] 96 36 # Return 73 117 # Delete 81 119 # End 130 121 # Page Down 75 89 # KP 7 76 91 # KP 8 77 92 # KP 9 132 69 # KP + 126 57 # Caps Lock 84 0 # A 85 1 # S 86 2 # D 87 3 # F 88 5 # G 89 4 # H 90 38 # J 91 40 # K 92 37 # L 93 41 # ; 94 39 # ' 98 86 # KP 4 99 87 # KP 5 100 88 # KP 6 106 56 # Shift Left 131 50 # International 107 6 # Z 108 7 # X 109 8 # C 110 9 # V 111 11 # B 112 45 # N 113 46 # M 114 43 # , 115 47 # . 116 44 # / 117 56 # Shift Right 95 42 # \ 27 62 # Cursor Up 119 83 # KP 1 120 84 # KP 2 121 85 # KP 3 97 76 # KP Enter 83 54 # Ctrl Left 26 58 # Option Left 127 55 # Command Left 128 49 # Space 129 55 # Command Right 74 58 # Option Right 20 54 # Ctrl Right 31 59 # Cursor Left 34 61 # Cursor Down 35 60 # Cursor Right 101 82 # KP 0 57 65 # KP . # # AmiWin # AmiWin 77 53 # Esc 88 122 # F1 89 120 # F2 90 99 # F3 91 118 # F4 92 96 # F5 93 97 # F6 94 98 # F7 95 100 # F8 96 101 # F9 97 109 # F10 8 10 # ` 9 18 # 1 10 19 # 2 11 20 # 3 12 21 # 4 13 23 # 5 14 22 # 6 15 26 # 7 16 28 # 8 17 25 # 9 18 29 # 10 19 27 # - 20 24 # = 21 42 # \ 73 51 # Backspace 78 117 # Delete 103 114 # Help (-> Help/Insert) 98 71 # KP [ (-> Num Lock) 99 81 # KP ] (-> KP =) 100 75 # KP / 101 67 # KP * 74 48 # Tab 24 12 # Q 25 13 # W 26 14 # E 27 15 # R 28 17 # T 29 16 # Y 30 32 # U 31 34 # I 32 31 # O 33 35 # P 34 33 # [ 35 30 # ] 76 36 # Return 69 89 # KP 7 70 91 # KP 8 71 92 # KP 9 82 78 # KP - 107 54 # Ctrl 106 57 # Caps Lock 40 0 # A 41 1 # S 42 2 # D 43 3 # F 44 5 # G 45 4 # H 46 38 # J 47 40 # K 48 37 # L 49 41 # ; 50 39 # ' 51 42 # International (-> \) 84 62 # Cursor Up 53 86 # KP 4 54 87 # KP 5 55 88 # KP 6 102 69 # KP + 104 56 # Shift Left 56 50 # International 57 6 # Z 58 7 # X 59 8 # C 60 9 # V 61 11 # B 62 45 # N 63 46 # M 64 43 # , 65 47 # . 66 44 # / 105 56 # Shift Right 87 59 # Cursor Left 85 61 # Cursor Down 86 60 # Cursor Right 37 83 # KP 1 38 84 # KP 2 39 85 # KP 3 75 76 # KP Enter 108 58 # Alt Left (-> Option) 110 55 # Amiga Left (-> Command) 72 49 # Space 111 55 # Amiga Right (-> Command) 109 58 # Alt Right (-> Option) 23 82 # KP 0 68 65 # KP . BasiliskII/src/Unix/sigsegv.h0000644000175000017500000001536511460647761016321 0ustar centriscentris/* * sigsegv.h - SIGSEGV signals support * * Derived from Bruno Haible's work on his SIGSEGV library for clisp * * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SIGSEGV_H #define SIGSEGV_H #define SIGSEGV_MAJOR_VERSION 1 #define SIGSEGV_MINOR_VERSION 0 #define SIGSEGV_MICRO_VERSION 0 #define SIGSEGV_CHECK_VERSION(MAJOR, MINOR, MICRO) \ (SIGSEGV_MAJOR_VERSION > (MAJOR) || \ (SIGSEGV_MAJOR_VERSION == (MAJOR) && SIGSEGV_MINOR_VERSION > (MINOR)) || \ (SIGSEGV_MAJOR_VERSION == (MAJOR) && SIGSEGV_MINOR_VERSION == (MINOR) && SIGSEGV_MICRO_VERSION >= (MICRO))) // Address type typedef char *sigsegv_address_t; // SIGSEGV handler argument (forward declaration) #if HAVE_MACH_EXCEPTIONS #if defined(__APPLE__) && defined(__MACH__) extern "C" { #include #include } #ifdef __ppc__ #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE #define MACH_FIELD_NAME(X) __CONCAT(__,X) #endif #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state_t #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE_COUNT #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(dar) #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(srr0) #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0) #endif #ifdef __ppc64__ #if __DARWIN_UNIX03 && defined _STRUCT_PPC_THREAD_STATE64 #define MACH_FIELD_NAME(X) __CONCAT(__,X) #endif #define SIGSEGV_EXCEPTION_STATE_TYPE ppc_exception_state64_t #define SIGSEGV_EXCEPTION_STATE_FLAVOR PPC_EXCEPTION_STATE64 #define SIGSEGV_EXCEPTION_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(dar) #define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state64_t #define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE64 #define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(srr0) #define SIGSEGV_SKIP_INSTRUCTION powerpc_skip_instruction #define SIGSEGV_REGISTER_FILE (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(srr0), (unsigned long *)&SIP->thr_state.MACH_FIELD_NAME(r0) #endif #ifdef __i386__ #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE32 #define MACH_FIELD_NAME(X) __CONCAT(__,X) #endif #define SIGSEGV_EXCEPTION_STATE_TYPE i386_exception_state_t #define SIGSEGV_EXCEPTION_STATE_FLAVOR i386_EXCEPTION_STATE #define SIGSEGV_EXCEPTION_STATE_COUNT i386_EXCEPTION_STATE_COUNT #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(faultvaddr) #define SIGSEGV_THREAD_STATE_TYPE i386_thread_state_t #define SIGSEGV_THREAD_STATE_FLAVOR i386_THREAD_STATE #define SIGSEGV_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(eip) #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(eax)) /* EAX is the first GPR we consider */ #endif #ifdef __x86_64__ #if __DARWIN_UNIX03 && defined _STRUCT_X86_THREAD_STATE64 #define MACH_FIELD_NAME(X) __CONCAT(__,X) #endif #define SIGSEGV_EXCEPTION_STATE_TYPE x86_exception_state64_t #define SIGSEGV_EXCEPTION_STATE_FLAVOR x86_EXCEPTION_STATE64 #define SIGSEGV_EXCEPTION_STATE_COUNT x86_EXCEPTION_STATE64_COUNT #define SIGSEGV_FAULT_ADDRESS SIP->exc_state.MACH_FIELD_NAME(faultvaddr) #define SIGSEGV_THREAD_STATE_TYPE x86_thread_state64_t #define SIGSEGV_THREAD_STATE_FLAVOR x86_THREAD_STATE64 #define SIGSEGV_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT #define SIGSEGV_FAULT_INSTRUCTION SIP->thr_state.MACH_FIELD_NAME(rip) #define SIGSEGV_SKIP_INSTRUCTION ix86_skip_instruction #define SIGSEGV_REGISTER_FILE ((SIGSEGV_REGISTER_TYPE *)&SIP->thr_state.MACH_FIELD_NAME(rax)) /* RAX is the first GPR we consider */ #endif #ifdef __x86_64__ #define SIGSEGV_FAULT_ADDRESS_FAST (((uint64_t)code[1])|0x100000000) #else #define SIGSEGV_FAULT_ADDRESS_FAST code[1] #endif #define SIGSEGV_FAULT_INSTRUCTION_FAST SIGSEGV_INVALID_ADDRESS #define SIGSEGV_FAULT_HANDLER_ARGLIST mach_port_t thread, mach_exception_data_t code #define SIGSEGV_FAULT_HANDLER_ARGS thread, code #endif #endif struct sigsegv_info_t { sigsegv_address_t addr; sigsegv_address_t pc; #ifdef HAVE_MACH_EXCEPTIONS mach_port_t thread; bool has_exc_state; SIGSEGV_EXCEPTION_STATE_TYPE exc_state; mach_msg_type_number_t exc_state_count; bool has_thr_state; SIGSEGV_THREAD_STATE_TYPE thr_state; mach_msg_type_number_t thr_state_count; #endif }; // SIGSEGV handler return state enum sigsegv_return_t { SIGSEGV_RETURN_SUCCESS, SIGSEGV_RETURN_FAILURE, SIGSEGV_RETURN_SKIP_INSTRUCTION }; // Type of a SIGSEGV handler. Returns boolean expressing successful operation typedef sigsegv_return_t (*sigsegv_fault_handler_t)(sigsegv_info_t *sip); // Type of a SIGSEGV state dump function typedef void (*sigsegv_state_dumper_t)(sigsegv_info_t *sip); // Install a SIGSEGV handler. Returns boolean expressing success extern bool sigsegv_install_handler(sigsegv_fault_handler_t handler); // Remove the user SIGSEGV handler, revert to default behavior extern void sigsegv_uninstall_handler(void); // Set callback function when we cannot handle the fault extern void sigsegv_set_dump_state(sigsegv_state_dumper_t handler); // Return the address of the invalid memory reference extern sigsegv_address_t sigsegv_get_fault_address(sigsegv_info_t *sip); // Return the address of the instruction that caused the fault, or // SIGSEGV_INVALID_ADDRESS if we could not retrieve this information extern sigsegv_address_t sigsegv_get_fault_instruction_address(sigsegv_info_t *sip); // Define an address that is bound to be invalid for a program counter const sigsegv_address_t SIGSEGV_INVALID_ADDRESS = (sigsegv_address_t)(-1UL); #endif /* SIGSEGV_H */ BasiliskII/src/AmigaOS/0000755000175000017500000000000011735674751015030 5ustar centriscentrisBasiliskII/src/AmigaOS/Makefile0000644000175000017500000000366307421041632016457 0ustar centriscentris# AmigaOS makefile for Basilisk II (GeekGadgets tool chain) ## System specific configuration CC = gcc CXX = c++ CXXFLAGS = -g -O1 -noixemul -m68020 -msmall-code -Wno-multichar CPPFLAGS = -I../include -I../native_cpu -I. DEFS = LDFLAGS = -noixemul LIBS = /gg/lib/libnix/swapstack.o AS = PhxAss ASFLAGS = OPT ! INCPATH GG:os-include FPU=1 ## Files SRCS = ../main.cpp main_amiga.cpp ../prefs.cpp ../prefs_items.cpp \ prefs_amiga.cpp prefs_editor_amiga.cpp sys_amiga.cpp ../rom_patches.cpp \ ../slot_rom.cpp ../rsrc_patches.cpp ../emul_op.cpp \ ../macos_util.cpp ../xpram.cpp xpram_amiga.cpp ../timer.cpp \ timer_amiga.cpp clip_amiga.cpp ../adb.cpp ../serial.cpp \ serial_amiga.cpp ../ether.cpp ether_amiga.cpp ../sony.cpp ../disk.cpp \ ../cdrom.cpp ../scsi.cpp scsi_amiga.cpp ../video.cpp video_amiga.cpp \ ../audio.cpp audio_amiga.cpp ../extfs.cpp extfs_amiga.cpp \ ../user_strings.cpp user_strings_amiga.cpp asm_support.asm APP = BasiliskII ## Rules .PHONY: clean distclean .SUFFIXES: .SUFFIXES: .c .cpp .asm .o .h all: $(APP) OBJ_DIR = obj $(OBJ_DIR):: @[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1 define SRCS_LIST_TO_OBJS $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(SRCS), \ $(basename $(notdir $(file)))))) endef OBJS = $(SRCS_LIST_TO_OBJS) SRC_PATHS += $(sort $(foreach file, $(SRCS), $(dir $(file)))) VPATH := VPATH += $(addprefix :, $(subst ,:, $(filter-out $($(subst, :, ,$(VPATH))), $(SRC_PATHS)))) $(APP): $(OBJ_DIR) $(OBJS) $(CXX) -o $(APP) $(LDFLAGS) $(LIBS) $(OBJS) clean: rm -f $(APP) $(OBJ_DIR)/* *~ *.bak obj.0000.* distclean: clean rm -rf $(OBJ_DIR) $(OBJ_DIR)/%.o : %.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.asm $(AS) $(ASFLAGS) $< TO $(OBJ_DIR)/$*.obj hunk2aout $(OBJ_DIR)/$*.obj >/dev/null mv obj.0000.* $@ #------------------------------------------------------------------------- # DO NOT DELETE THIS LINE -- make depend depends on it. BasiliskII/src/AmigaOS/prefs_editor_amiga.cpp0000644000175000017500000012457610736405217021363 0ustar centriscentris/* * prefs_editor_amiga.cpp - Preferences editor, AmigaOS implementation (using gtlayout.library) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #include #include #include #include #define __USE_SYSBASE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "main.h" #include "xpram.h" #include "cdrom.h" #include "user_strings.h" #include "version.h" #include "prefs.h" #include "prefs_editor.h" // Gadget/menu IDs const int MSG_OK = 0x0100; // "Start" button const int MSG_CANCEL = 0x0101; // "Quit" button const int MSG_ABOUT = 0x0102; // "About..." menu item const int MSG_ZAP_PRAM = 0x0103; // "Zap PRAM" menu item const int GAD_PAGEGROUP = 0x0200; const int GAD_DISK_LIST = 0x0300; // "Volumes" pane const int GAD_ADD_VOLUME = 0x0301; const int GAD_EDIT_VOLUME = 0x0302; const int GAD_REMOVE_VOLUME = 0x0303; const int GAD_CDROM_DEVICE = 0x0304; const int GAD_CDROM_UNIT = 0x0305; const int GAD_BOOTDRIVER = 0x0306; const int GAD_NOCDROM = 0x0307; const int GAD_EXTFS = 0x0308; const int GAD_VOLUME_READONLY = 0x0310; // "Add/Edit Volume" window const int GAD_VOLUME_TYPE = 0x0311; const int GAD_VOLUME_FILE = 0x0312; const int GAD_VOLUME_DEVICE = 0x0313; const int GAD_VOLUME_UNIT = 0x0314; const int GAD_VOLUME_OPENFLAGS = 0x0315; const int GAD_VOLUME_STARTBLOCK = 0x0316; const int GAD_VOLUME_SIZE = 0x0317; const int GAD_VOLUME_BLOCKSIZE = 0x0318; const int GAD_VOLUME_PAGEGROUP = 0x0319; const int GAD_SCSI0_DEVICE = 0x0400; // "SCSI" pane const int GAD_SCSI1_DEVICE = 0x0401; const int GAD_SCSI2_DEVICE = 0x0402; const int GAD_SCSI3_DEVICE = 0x0403; const int GAD_SCSI4_DEVICE = 0x0404; const int GAD_SCSI5_DEVICE = 0x0405; const int GAD_SCSI6_DEVICE = 0x0406; const int GAD_SCSI0_UNIT = 0x0410; const int GAD_SCSI1_UNIT = 0x0411; const int GAD_SCSI2_UNIT = 0x0412; const int GAD_SCSI3_UNIT = 0x0413; const int GAD_SCSI4_UNIT = 0x0414; const int GAD_SCSI5_UNIT = 0x0415; const int GAD_SCSI6_UNIT = 0x0416; const int GAD_SCSI_MEMTYPE = 0x0420; const int GAD_VIDEO_TYPE = 0x0500; // "Graphics/Sound" pane const int GAD_DISPLAY_X = 0x0501; const int GAD_DISPLAY_Y = 0x0502; const int GAD_FRAMESKIP = 0x0503; const int GAD_SCREEN_MODE = 0x0504; const int GAD_AHI_MODE = 0x0505; const int GAD_NOSOUND = 0x0506; const int GAD_SERIALA_DEVICE = 0x0600; // "Serial/Network" pane const int GAD_SERIALA_UNIT = 0x0601; const int GAD_SERIALA_ISPAR = 0x0602; const int GAD_SERIALB_DEVICE = 0x0603; const int GAD_SERIALB_UNIT = 0x0604; const int GAD_SERIALB_ISPAR = 0x0605; const int GAD_ETHER_DEVICE = 0x0606; const int GAD_ETHER_UNIT = 0x00607; const int GAD_RAMSIZE = 0x0700; // "Memory/Misc" pane const int GAD_MODELID = 0x0701; const int GAD_ROM_FILE = 0x0702; // Global variables struct Library *GTLayoutBase = NULL; static struct FileRequester *dev_request = NULL, *file_request = NULL; // gtlayout.library macros #define VGROUP LT_New(h, LA_Type, VERTICAL_KIND, TAG_END) #define HGROUP LT_New(h, LA_Type, HORIZONTAL_KIND, TAG_END) #define ENDGROUP LT_EndGroup(h) // Prototypes static void create_volumes_pane(struct LayoutHandle *h); static void create_scsi_pane(struct LayoutHandle *h); static void create_graphics_pane(struct LayoutHandle *h); static void create_serial_pane(struct LayoutHandle *h); static void create_memory_pane(struct LayoutHandle *h); static void add_edit_volume(struct LayoutHandle *h, bool adding); static void remove_volume(struct LayoutHandle *h); static void ghost_volumes_gadgets(struct LayoutHandle *h); static void ghost_graphics_gadgets(struct LayoutHandle *h); static void screen_mode_req(struct Window *win, struct LayoutHandle *h); static void ahi_mode_req(struct Window *win, struct LayoutHandle *h); static void read_settings(struct LayoutHandle *h); /* * Locale hook - returns string for given ID */ static __saveds __attribute__((regparm(3))) const char *locale_hook_func(struct Hook *hook /*a0*/, void *id /*a1*/, struct LayoutHandle *h /*a2*/) { return GetString((uint32)id); } struct Hook locale_hook = {{NULL, NULL}, (HOOKFUNC)locale_hook_func, NULL, NULL}; /* * Show preferences editor * Returns true when user clicked on "Start", false otherwise */ bool PrefsEditor(void) { bool retval = true, done = false; struct LayoutHandle *h = NULL; struct Window *win = NULL; struct Menu *menu = NULL; // Pane tabs static const LONG labels[] = { STR_VOLUMES_PANE_TITLE, STR_SCSI_PANE_TITLE, STR_GRAPHICS_SOUND_PANE_TITLE, STR_SERIAL_NETWORK_PANE_TITLE, STR_MEMORY_MISC_PANE_TITLE, -1 }; // Open gtlayout.library GTLayoutBase = (struct Library *)OpenLibrary("gtlayout.library", 39); if (GTLayoutBase == NULL) { WarningAlert(GetString(STR_NO_GTLAYOUT_LIB_WARN)); return true; } // Create layout handle h = LT_CreateHandleTags(NULL, LAHN_AutoActivate, FALSE, LAHN_LocaleHook, (ULONG)&locale_hook, TAG_END ); if (h == NULL) goto quit; // Create menus menu = LT_NewMenuTags( LAMN_LayoutHandle, (ULONG)h, LAMN_TitleID, STR_PREFS_MENU, LAMN_ItemID, STR_PREFS_ITEM_ABOUT, LAMN_UserData, MSG_ABOUT, LAMN_ItemText, (ULONG)NM_BARLABEL, LAMN_ItemID, STR_PREFS_ITEM_START, LAMN_UserData, MSG_OK, LAMN_ItemID, STR_PREFS_ITEM_ZAP_PRAM, LAMN_UserData, MSG_ZAP_PRAM, LAMN_ItemText, (ULONG)NM_BARLABEL, LAMN_ItemID, STR_PREFS_ITEM_QUIT, LAMN_UserData, MSG_CANCEL, LAMN_KeyText, (ULONG)"Q", TAG_END ); // Create window contents VGROUP; VGROUP; LT_New(h, LA_Type, TAB_KIND, LATB_LabelTable, (ULONG)labels, LATB_AutoPageID, GAD_PAGEGROUP, LATB_FullWidth, TRUE, TAG_END ); ENDGROUP; // Panes LT_New(h, LA_Type, VERTICAL_KIND, LA_ID, GAD_PAGEGROUP, LAGR_ActivePage, 0, TAG_END ); create_volumes_pane(h); create_scsi_pane(h); create_graphics_pane(h); create_serial_pane(h); create_memory_pane(h); ENDGROUP; // Separator between tabs and buttons VGROUP; LT_New(h, LA_Type, XBAR_KIND, LAXB_FullSize, TRUE, TAG_END ); ENDGROUP; // "Start" and "Quit" buttons LT_New(h, LA_Type, HORIZONTAL_KIND, LAGR_SameSize, TRUE, LAGR_Spread, TRUE, TAG_END ); LT_New(h, LA_Type, BUTTON_KIND, LA_LabelID, STR_START_BUTTON, LA_ID, MSG_OK, LABT_ReturnKey, TRUE, TAG_END ); LT_New(h, LA_Type, BUTTON_KIND, LA_LabelID, STR_QUIT_BUTTON, LA_ID, MSG_CANCEL, LABT_EscKey, TRUE, TAG_END ); ENDGROUP; ENDGROUP; // Open window win = LT_Build(h, LAWN_TitleID, STR_PREFS_TITLE, LAWN_Menu, (ULONG)menu, LAWN_IDCMP, IDCMP_CLOSEWINDOW, LAWN_BelowMouse, TRUE, LAWN_SmartZoom, TRUE, WA_SimpleRefresh, TRUE, WA_Activate, TRUE, WA_CloseGadget, TRUE, WA_DepthGadget, TRUE, WA_DragBar, TRUE, TAG_END ); if (win == NULL) goto quit; // Create file requesters dev_request = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest, ASLFR_DoPatterns, TRUE, ASLFR_RejectIcons, TRUE, ASLFR_InitialDrawer, (ULONG)"DEVS:", ASLFR_InitialPattern, (ULONG)"#?.device", TAG_END ); file_request = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest, ASLFR_DoPatterns, TRUE, ASLFR_RejectIcons, TRUE, ASLFR_InitialPattern, (ULONG)"#?", TAG_END ); // Event loop do { struct IntuiMessage *msg; // Wait for message WaitPort(win->UserPort); // Get pending messages while (msg = LT_GetIMsg(h)) { // Get data from message and reply ULONG cl = msg->Class; UWORD code = msg->Code; struct Gadget *gad = (struct Gadget *)msg->IAddress; LT_ReplyIMsg(msg); // Handle message according to class switch (cl) { case IDCMP_CLOSEWINDOW: retval = false; done = true; break; case IDCMP_GADGETUP: switch (gad->GadgetID) { case MSG_OK: read_settings(h); SavePrefs(); retval = true; done = true; break; case MSG_CANCEL: retval = false; done = true; break; case GAD_DISK_LIST: ghost_volumes_gadgets(h); break; case GAD_ADD_VOLUME: LT_LockWindow(win); add_edit_volume(h, true); LT_UnlockWindow(win); break; case GAD_EDIT_VOLUME: LT_LockWindow(win); add_edit_volume(h, false); LT_UnlockWindow(win); break; case GAD_REMOVE_VOLUME: remove_volume(h); break; case GAD_BOOTDRIVER: switch (code) { case 0: PrefsReplaceInt32("bootdriver", 0); break; case 1: PrefsReplaceInt32("bootdriver", CDROMRefNum); break; } break; case GAD_SCSI_MEMTYPE: PrefsReplaceInt32("scsimemtype", code); break; case GAD_VIDEO_TYPE: ghost_graphics_gadgets(h); break; case GAD_FRAMESKIP: switch (code) { case 0: PrefsReplaceInt32("frameskip", 12); break; case 1: PrefsReplaceInt32("frameskip", 8); break; case 2: PrefsReplaceInt32("frameskip", 6); break; case 3: PrefsReplaceInt32("frameskip", 4); break; case 4: PrefsReplaceInt32("frameskip", 2); break; case 5: PrefsReplaceInt32("frameskip", 1); break; } break; case GAD_MODELID: switch (code) { case 0: PrefsReplaceInt32("modelid", 5); break; case 1: PrefsReplaceInt32("modelid", 14); break; } break; } break; case IDCMP_IDCMPUPDATE: switch (gad->GadgetID) { case GAD_DISK_LIST: // Double-click on volumes list = edit volume LT_LockWindow(win); add_edit_volume(h, false); LT_UnlockWindow(win); break; case GAD_SCREEN_MODE: screen_mode_req(win, h); break; case GAD_AHI_MODE: ahi_mode_req(win, h); break; case GAD_CDROM_DEVICE: case GAD_SCSI0_DEVICE: case GAD_SCSI1_DEVICE: case GAD_SCSI2_DEVICE: case GAD_SCSI3_DEVICE: case GAD_SCSI4_DEVICE: case GAD_SCSI5_DEVICE: case GAD_SCSI6_DEVICE: case GAD_SERIALA_DEVICE: case GAD_SERIALB_DEVICE: if (dev_request) { LT_LockWindow(win); BOOL result = AslRequestTags(dev_request, ASLFR_Window, (ULONG)win, ASLFR_InitialDrawer, (ULONG) "Devs:", TAG_END); LT_UnlockWindow(win); if (result) { char *str; GT_GetGadgetAttrs(gad, win, NULL, GTST_String, (ULONG)&str, TAG_END); strncpy(str, dev_request->rf_File, 255); // Don't copy the directory part. This is usually "DEVS:" and we don't need that. str[255] = 0; LT_SetAttributes(h, gad->GadgetID, GTST_String, (ULONG)str, TAG_END); } } break; case GAD_ETHER_DEVICE: if (dev_request) { LT_LockWindow(win); BOOL result = AslRequestTags(dev_request, ASLFR_Window, (ULONG)win, ASLFR_InitialDrawer, (ULONG) "Devs:Networks", TAG_END); LT_UnlockWindow(win); if (result) { char *str; GT_GetGadgetAttrs(gad, win, NULL, GTST_String, (ULONG)&str, TAG_END); strncpy(str, dev_request->rf_File, 255); // Don't copy the directory part. This is usually "DEVS:" and we don't need that. str[255] = 0; LT_SetAttributes(h, gad->GadgetID, GTST_String, (ULONG)str, TAG_END); } } break; case GAD_ROM_FILE: if (file_request) { LT_LockWindow(win); BOOL result = AslRequestTags(file_request, ASLFR_Window, (ULONG)win, TAG_END); LT_UnlockWindow(win); if (result) { char *str; GT_GetGadgetAttrs(gad, win, NULL, GTST_String, (ULONG)&str, TAG_END); strncpy(str, file_request->rf_Dir, 255); str[255] = 0; AddPart(str, file_request->rf_File, 255); LT_SetAttributes(h, gad->GadgetID, GTST_String, (ULONG)str, TAG_END); } } break; } break; case IDCMP_MENUPICK: while (code != MENUNULL) { struct MenuItem *item = ItemAddress(menu, code); if (item == NULL) break; switch ((ULONG)GTMENUITEM_USERDATA(item)) { case MSG_OK: read_settings(h); SavePrefs(); retval = true; done = true; break; case MSG_CANCEL: retval = false; done = true; break; case MSG_ABOUT: { char str[256]; sprintf(str, GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); strncat(str, "\n", 255); strncat(str, GetString(STR_ABOUT_TEXT2), 255); EasyStruct req; req.es_StructSize = sizeof(EasyStruct); req.es_Flags = 0; req.es_Title = (UBYTE *)GetString(STR_ABOUT_TITLE); req.es_TextFormat = (UBYTE *)str; req.es_GadgetFormat = (UBYTE *)GetString(STR_OK_BUTTON); LT_LockWindow(win); EasyRequest(win, &req, NULL); LT_UnlockWindow(win); break; } case MSG_ZAP_PRAM: ZapPRAM(); break; } code = item->NextSelect; } break; } } } while (!done); quit: // Free requesters FreeAslRequest(dev_request); FreeAslRequest(file_request); // Delete Menus LT_DisposeMenu(menu); // Delete handle LT_DeleteHandle(h); // Close gtlayout.library CloseLibrary(GTLayoutBase); return retval; } /* * "Volumes" pane */ static struct List disk_list; static char cdrom_name[256], extfs_name[256]; static ULONG cdrom_unit, cdrom_flags, cdrom_start, cdrom_size, cdrom_bsize; static BYTE bootdriver_num, nocdrom; // Read volumes preferences static void parse_volumes_prefs(void) { NewList(&disk_list); const char *str; for (int i=0; (str = PrefsFindString("disk", i)) != NULL; i++) { struct Node *item = (struct Node *)AllocMem(sizeof(struct Node), MEMF_CLEAR); item->ln_Name = (char *)str; AddTail(&disk_list, item); } cdrom_name[0] = 0; cdrom_unit = 0; cdrom_flags = 0; cdrom_start = 0; cdrom_size = 0; cdrom_bsize = 2048; str = PrefsFindString("cdrom"); if (str) sscanf(str, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", cdrom_name, &cdrom_unit, &cdrom_flags, &cdrom_start, &cdrom_size, &cdrom_bsize); bootdriver_num = 0; int bootdriver = PrefsFindInt32("bootdriver"); switch (bootdriver) { case 0: bootdriver_num = 0; break; case CDROMRefNum: bootdriver_num = 1; break; } nocdrom = PrefsFindBool("nocdrom"); extfs_name[0] = 0; str = PrefsFindString("extfs"); if (str) strncpy(extfs_name, str, sizeof(extfs_name) - 1); } // Ghost/unghost "Edit" and "Remove" buttons static void ghost_volumes_gadgets(struct LayoutHandle *h) { UWORD sel = LT_GetAttributes(h, GAD_DISK_LIST, TAG_END); if (sel == 0xffff) { LT_SetAttributes(h, GAD_EDIT_VOLUME, GA_Disabled, TRUE, TAG_END); LT_SetAttributes(h, GAD_REMOVE_VOLUME, GA_Disabled, TRUE, TAG_END); } else { LT_SetAttributes(h, GAD_EDIT_VOLUME, GA_Disabled, FALSE, TAG_END); LT_SetAttributes(h, GAD_REMOVE_VOLUME, GA_Disabled, FALSE, TAG_END); } } // Get device data from partition name static void analyze_partition(const char *part, char *dev_name, ULONG &dev_unit, ULONG &dev_flags, ULONG &dev_start, ULONG &dev_size, ULONG &dev_bsize) { // Remove everything after and including the ':' char str[256]; strncpy(str, part, sizeof(str) - 1); str[sizeof(str) - 1] = 0; char *colon = strchr(str, ':'); if (colon) *colon = 0; // Look for partition struct DosList *dl = LockDosList(LDF_DEVICES | LDF_READ); dl = FindDosEntry(dl, str, LDF_DEVICES); if (dl) { // Get File System Startup Message struct FileSysStartupMsg *fssm = (struct FileSysStartupMsg *)(dl->dol_misc.dol_handler.dol_Startup << 2); if (fssm) { // Get DOS environment vector struct DosEnvec *de = (struct DosEnvec *)(fssm->fssm_Environ << 2); if (de && de->de_TableSize >= DE_UPPERCYL) { // Read settings from FSSM and Envec strncpy(dev_name, (char *)(fssm->fssm_Device << 2) + 1, 255); dev_name[255] = 0; dev_unit = fssm->fssm_Unit; dev_flags = fssm->fssm_Flags; dev_start = de->de_BlocksPerTrack * de->de_Surfaces * de->de_LowCyl; dev_size = de->de_BlocksPerTrack * de->de_Surfaces * (de->de_HighCyl - de->de_LowCyl + 1); dev_bsize = de->de_SizeBlock << 2; } } } UnLockDosList(LDF_DEVICES | LDF_READ); } // Display and handle "Add/Edit Volume" window static void add_edit_volume(struct LayoutHandle *h2, bool adding) { bool ok_clicked = false; UWORD sel = LT_GetAttributes(h2, GAD_DISK_LIST, TAG_END); if ((sel == 0xffff) && !adding) return; char dev_name[256] = ""; char file_name[256] = ""; ULONG dev_unit = 0, dev_flags = 0, dev_start = 0, dev_size = 0, dev_bsize = 512; BYTE read_only = false, is_device = false; if (!adding) { const char *str = PrefsFindString("disk", sel); if (str == NULL) return; if (str[0] == '*') { read_only = true; str++; } if (strstr(str, "/dev/") == str) { is_device = true; sscanf(str, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", dev_name, &dev_unit, &dev_flags, &dev_start, &dev_size, &dev_bsize); } else { strncpy(file_name, str, sizeof(file_name) - 1); file_name[sizeof(file_name) - 1] = 0; } } // Create layout handle struct LayoutHandle *h = NULL; struct Window *win = NULL; h = LT_CreateHandleTags(NULL, LAHN_AutoActivate, FALSE, LAHN_LocaleHook, (ULONG)&locale_hook, TAG_END ); if (h == NULL) return; // Create window contents VGROUP; // Volume gadgets VGROUP; LT_New(h, LA_Type, CHECKBOX_KIND, LA_LabelID, STR_VOL_READONLY_CTRL, LA_ID, GAD_VOLUME_READONLY, LA_BYTE, (ULONG)&read_only, TAG_END ); LT_New(h, LA_Type, CYCLE_KIND, LA_LabelID, STR_VOL_TYPE_CTRL, LA_ID, GAD_VOLUME_TYPE, LACY_AutoPageID, GAD_VOLUME_PAGEGROUP, LACY_FirstLabel, STR_VOL_FILE_LAB, LACY_LastLabel, STR_VOL_DEVICE_LAB, LA_BYTE, (ULONG)&is_device, TAG_END ); ENDGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_ID, GAD_VOLUME_PAGEGROUP, LAGR_ActivePage, is_device, TAG_END ); VGROUP; LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_VOL_FILE_CTRL, LA_ID, GAD_VOLUME_FILE, LA_Chars, 20, LA_STRPTR, (ULONG)file_name, GTST_MaxChars, sizeof(file_name) - 1, LAST_Picker, TRUE, TAG_END ); ENDGROUP; VGROUP; LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_DEVICE_CTRL, LA_ID, GAD_VOLUME_DEVICE, LA_Chars, 20, LA_STRPTR, (ULONG)dev_name, GTST_MaxChars, sizeof(dev_name) - 1, LAST_Picker, TRUE, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_UNIT_CTRL, LA_ID, GAD_VOLUME_UNIT, LA_LONG, (ULONG)&dev_unit, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_VOL_OPENFLAGS_CTRL, LA_ID, GAD_VOLUME_OPENFLAGS, LA_LONG, (ULONG)&dev_flags, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_VOL_STARTBLOCK_CTRL, LA_ID, GAD_VOLUME_STARTBLOCK, LA_LONG, (ULONG)&dev_start, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_VOL_SIZE_CTRL, LA_ID, GAD_VOLUME_SIZE, LA_LONG, (ULONG)&dev_size, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_VOL_BLOCKSIZE_CTRL, LA_ID, GAD_VOLUME_BLOCKSIZE, LA_LONG, (ULONG)&dev_bsize, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); ENDGROUP; ENDGROUP; // Separator between gadgets and buttons VGROUP; LT_New(h, LA_Type, XBAR_KIND, LAXB_FullSize, TRUE, TAG_END ); ENDGROUP; // "OK" and "Cancel" buttons LT_New(h, LA_Type, HORIZONTAL_KIND, LAGR_SameSize, TRUE, LAGR_Spread, TRUE, TAG_END ); LT_New(h, LA_Type, BUTTON_KIND, LA_LabelID, STR_OK_BUTTON, LA_ID, MSG_OK, LABT_ReturnKey, TRUE, TAG_END ); LT_New(h, LA_Type, BUTTON_KIND, LA_LabelID, STR_CANCEL_BUTTON, LA_ID, MSG_CANCEL, LABT_EscKey, TRUE, TAG_END ); ENDGROUP; ENDGROUP; // Open window win = LT_Build(h, LAWN_TitleID, adding ? STR_ADD_VOLUME_TITLE : STR_EDIT_VOLUME_TITLE, LAWN_IDCMP, IDCMP_CLOSEWINDOW, LAWN_BelowMouse, TRUE, LAWN_SmartZoom, TRUE, WA_SimpleRefresh, TRUE, WA_Activate, TRUE, WA_CloseGadget, TRUE, WA_DepthGadget, TRUE, WA_DragBar, TRUE, TAG_END ); if (win == NULL) { LT_DeleteHandle(h); return; } // Event loop bool done = false; do { struct IntuiMessage *msg; // Wait for message WaitPort(win->UserPort); // Get pending messages while (msg = LT_GetIMsg(h)) { // Get data from message and reply ULONG cl = msg->Class; UWORD code = msg->Code; struct Gadget *gad = (struct Gadget *)msg->IAddress; LT_ReplyIMsg(msg); // Handle message according to class switch (cl) { case IDCMP_CLOSEWINDOW: done = true; break; case IDCMP_GADGETUP: switch (gad->GadgetID) { case MSG_OK: ok_clicked = true; done = true; break; case MSG_CANCEL: done = true; break; } break; case IDCMP_IDCMPUPDATE: { struct FileRequester *req = NULL; switch (gad->GadgetID) { case GAD_VOLUME_FILE: req = file_request; goto do_req; case GAD_VOLUME_DEVICE: req = dev_request; do_req: if (req) { LT_LockWindow(win); BOOL result = AslRequestTags(req, ASLFR_Window, (ULONG)win, TAG_END); LT_UnlockWindow(win); if (result) { char *str; GT_GetGadgetAttrs(gad, win, NULL, GTST_String, (ULONG)&str, TAG_END); if (gad->GadgetID == GAD_VOLUME_FILE) { strncpy(str, req->rf_Dir, 255); str[255] = 0; AddPart(str, req->rf_File, 255); } else { if (strlen(req->rf_File)) { strncpy(str, req->rf_File, 255); // Don't copy the directory part. This is usually "DEVS:" and we don't need that. str[255] = 0; } else if (strlen(req->rf_Dir) && req->rf_Dir[strlen(req->rf_Dir) - 1] == ':') { analyze_partition(req->rf_Dir, str, dev_unit, dev_flags, dev_start, dev_size, dev_bsize); LT_SetAttributes(h, GAD_VOLUME_UNIT, GTIN_Number, dev_unit, TAG_END); LT_SetAttributes(h, GAD_VOLUME_OPENFLAGS, GTIN_Number, dev_flags, TAG_END); LT_SetAttributes(h, GAD_VOLUME_STARTBLOCK, GTIN_Number, dev_start, TAG_END); LT_SetAttributes(h, GAD_VOLUME_SIZE, GTIN_Number, dev_size, TAG_END); LT_SetAttributes(h, GAD_VOLUME_BLOCKSIZE, GTIN_Number, dev_bsize, TAG_END); } } LT_SetAttributes(h, gad->GadgetID, GTST_String, (ULONG)str, TAG_END); } } break; } break; } } } } while (!done); // Update preferences and list view if (ok_clicked) { char str[256]; LT_UpdateStrings(h); if (is_device) sprintf(str, "%s/dev/%s/%ld/%ld/%ld/%ld/%ld", read_only ? "*" : "", dev_name, dev_unit, dev_flags, dev_start, dev_size, dev_bsize); else sprintf(str, "%s%s", read_only ? "*" : "", file_name); LT_SetAttributes(h2, GAD_DISK_LIST, GTLV_Labels, ~0, TAG_END); if (adding) { // Add new item int i; PrefsAddString("disk", str); struct Node *item = (struct Node *)AllocMem(sizeof(struct Node), MEMF_CLEAR); for (i=0; PrefsFindString("disk", i); i++) ; item->ln_Name = (char *)PrefsFindString("disk", i - 1); AddTail(&disk_list, item); } else { // Replace existing item PrefsReplaceString("disk", str, sel); struct Node *item = disk_list.lh_Head; for (int i=0; item->ln_Succ; i++) { if (i == sel) { item->ln_Name = (char *)PrefsFindString("disk", sel); break; } item = item->ln_Succ; } } LT_SetAttributes(h2, GAD_DISK_LIST, GTLV_Labels, (ULONG)&disk_list, TAG_END); ghost_volumes_gadgets(h2); } // Delete handle LT_DeleteHandle(h); } // Remove volume from list static void remove_volume(struct LayoutHandle *h) { UWORD sel = LT_GetAttributes(h, GAD_DISK_LIST, TAG_END); if (sel != 0xffff) { // Remove item from preferences and list view LT_SetAttributes(h, GAD_DISK_LIST, GTLV_Labels, ~0, TAG_END); PrefsRemoveItem("disk", sel); struct Node *item = disk_list.lh_Head; for (int i=0; item->ln_Succ; i++) { struct Node *next = item->ln_Succ; if (i == sel) { Remove(item); FreeMem(item, sizeof(struct Node)); break; } item = next; } LT_SetAttributes(h, GAD_DISK_LIST, GTLV_Labels, (ULONG)&disk_list, GTLV_Selected, 0xffff, TAG_END); ghost_volumes_gadgets(h); } } // Read settings from gadgets and set preferences static void read_volumes_settings(void) { struct Node *item = disk_list.lh_Head; while (item->ln_Succ) { struct Node *next = item->ln_Succ; Remove(item); FreeMem(item, sizeof(struct Node)); item = next; } if (strlen(cdrom_name)) { char str[256]; sprintf(str, "/dev/%s/%ld/%ld/%ld/%ld/%ld", cdrom_name, cdrom_unit, cdrom_flags, cdrom_start, cdrom_size, cdrom_bsize); PrefsReplaceString("cdrom", str); } else PrefsRemoveItem("cdrom"); PrefsReplaceBool("nocdrom", nocdrom); if (strlen(extfs_name)) PrefsReplaceString("extfs", extfs_name); } // Create "Volumes" pane static void create_volumes_pane(struct LayoutHandle *h) { parse_volumes_prefs(); VGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_VOLUMES_CTRL, TAG_END ); VGROUP; LT_New(h, LA_Type, LISTVIEW_KIND, LA_ID, GAD_DISK_LIST, LA_Chars, 20, GTLV_Labels, (ULONG)&disk_list, LALV_Lines, 6, LALV_Link, (ULONG)NIL_LINK, LALV_ResizeX, TRUE, LALV_ResizeY, TRUE, LALV_Selected, 0, TAG_END ); ENDGROUP; LT_New(h, LA_Type, HORIZONTAL_KIND, LAGR_SameSize, TRUE, LAGR_Spread, TRUE, TAG_END ); LT_New(h, LA_Type, BUTTON_KIND, LA_LabelID, STR_ADD_VOLUME_BUTTON, LA_ID, GAD_ADD_VOLUME, TAG_END ); LT_New(h, LA_Type, BUTTON_KIND, LA_LabelID, STR_EDIT_VOLUME_BUTTON, LA_ID, GAD_EDIT_VOLUME, TAG_END ); LT_New(h, LA_Type, BUTTON_KIND, LA_LabelID, STR_REMOVE_VOLUME_BUTTON, LA_ID, GAD_REMOVE_VOLUME, TAG_END ); ENDGROUP; ENDGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_CDROM_DRIVE_CTRL, TAG_END ); LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_DEVICE_CTRL, LA_ID, GAD_CDROM_DEVICE, LA_Chars, 20, LA_STRPTR, (ULONG)cdrom_name, GTST_MaxChars, sizeof(cdrom_name) - 1, LAST_Picker, TRUE, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_UNIT_CTRL, LA_ID, GAD_CDROM_UNIT, LA_LONG, (ULONG)&cdrom_unit, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, CYCLE_KIND, LA_LabelID, STR_BOOTDRIVER_CTRL, LA_ID, GAD_BOOTDRIVER, LACY_FirstLabel, STR_BOOT_ANY_LAB, LACY_LastLabel, STR_BOOT_CDROM_LAB, LA_BYTE, (ULONG)&bootdriver_num, TAG_END ); LT_New(h, LA_Type, CHECKBOX_KIND, LA_LabelID, STR_NOCDROM_CTRL, LA_ID, GAD_NOCDROM, LA_BYTE, (ULONG)&nocdrom, TAG_END ); ENDGROUP; VGROUP; LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_EXTFS_CTRL, LA_ID, GAD_EXTFS, LA_Chars, 20, LA_STRPTR, (ULONG)extfs_name, GTST_MaxChars, sizeof(extfs_name) - 1, TAG_END ); ENDGROUP; ENDGROUP; } /* * "SCSI" pane */ static char scsi_dev[6][256]; static LONG scsi_unit[6]; static LONG scsi_memtype; // Read SCSI preferences static void parse_scsi_prefs(void) { for (int i=0; i<7; i++) { scsi_dev[i][0] = 0; scsi_unit[i] = 0; char prefs_name[16]; sprintf(prefs_name, "scsi%d", i); const char *str = PrefsFindString(prefs_name); if (str) sscanf(str, "%[^/]/%ld", scsi_dev[i], &scsi_unit[i]); } scsi_memtype = PrefsFindInt32("scsimemtype"); } // Read settings from gadgets and set preferences static void read_scsi_settings(void) { for (int i=0; i<7; i++) { char prefs_name[16]; sprintf(prefs_name, "scsi%d", i); if (strlen(scsi_dev[i])) { char str[256]; sprintf(str, "%s/%ld", scsi_dev[i], scsi_unit[i]); PrefsReplaceString(prefs_name, str); } else PrefsRemoveItem(prefs_name); } } // Create "SCSI" pane static void create_scsi_pane(struct LayoutHandle *h) { parse_scsi_prefs(); VGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_SCSI_DEVICES_CTRL, TAG_END ); for (int i=0; i<7; i++) { HGROUP; LT_New(h, LA_Type, TEXT_KIND, LA_LabelID, STR_SCSI_ID_0 + i, TAG_END ); LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_DEVICE_CTRL, LA_ID, GAD_SCSI0_DEVICE + i, LA_Chars, 20, LA_STRPTR, (ULONG)scsi_dev[i], GTST_MaxChars, sizeof(scsi_dev[i]) - 1, LAST_Picker, TRUE, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_UNIT_CTRL, LA_ID, GAD_SCSI0_UNIT + i, LA_Chars, 4, LA_LONG, (ULONG)&scsi_unit[i], LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); ENDGROUP; } ENDGROUP; VGROUP; LT_New(h, LA_Type, CYCLE_KIND, LA_LabelID, STR_SCSI_MEMTYPE_CTRL, LA_ID, GAD_SCSI_MEMTYPE, LACY_FirstLabel, STR_MEMTYPE_CHIP_LAB, LACY_LastLabel, STR_MEMTYPE_ANY_LAB, LA_LONG, (ULONG)&scsi_memtype, TAG_END ); ENDGROUP; ENDGROUP; } /* * "Graphics/Sound" pane */ // Display types enum { DISPLAY_WINDOW, DISPLAY_PIP, DISPLAY_SCREEN }; static LONG display_type; static LONG dis_width, dis_height; static ULONG mode_id; static BYTE frameskip_num; static struct NameInfo mode_name; static ULONG ahi_id; static char ahi_mode_name[256]; static BYTE nosound; // Read graphics preferences static void parse_graphics_prefs(void) { display_type = DISPLAY_WINDOW; dis_width = 512; dis_height = 384; mode_id = 0; ahi_id = AHI_DEFAULT_ID; ahi_mode_name[0] = 0; frameskip_num = 0; int frameskip = PrefsFindInt32("frameskip"); switch (frameskip) { case 12: frameskip_num = 0; break; case 8: frameskip_num = 1; break; case 6: frameskip_num = 2; break; case 4: frameskip_num = 3; break; case 2: frameskip_num = 4; break; case 1: frameskip_num = 5; break; } const char *str = PrefsFindString("screen"); if (str) { if (sscanf(str, "win/%ld/%ld", &dis_width, &dis_height) == 2) display_type = DISPLAY_WINDOW; else if (sscanf(str, "pip/%ld/%ld", &dis_width, &dis_height) == 2) display_type = DISPLAY_PIP; else if (sscanf(str, "scr/%08lx", &mode_id) == 1) display_type = DISPLAY_SCREEN; } GetDisplayInfoData(NULL, (UBYTE *)&mode_name, sizeof(mode_name), DTAG_NAME, mode_id); str = PrefsFindString("sound"); if (str) { if (sscanf(str, "ahi/%08lx", &ahi_id) == 1 && AHIBase) { AHI_GetAudioAttrs(ahi_id, NULL, AHIDB_Name, (ULONG)ahi_mode_name, AHIDB_BufferLen, sizeof(ahi_mode_name) - 1, TAG_END ); } } nosound = PrefsFindBool("nosound"); } // Ghost/unghost graphics gadgets, depending on display type static void ghost_graphics_gadgets(struct LayoutHandle *h) { bool dis_xy, dis_skip, dis_mode; switch (display_type) { case DISPLAY_WINDOW: dis_xy = false; dis_skip = false; dis_mode = true; break; case DISPLAY_PIP: dis_xy = false; dis_skip = true; dis_mode = true; break; case DISPLAY_SCREEN: dis_xy = true; dis_skip = true; dis_mode = false; break; } LT_SetAttributes(h, GAD_DISPLAY_X, GA_Disabled, dis_xy, TAG_END); LT_SetAttributes(h, GAD_DISPLAY_Y, GA_Disabled, dis_xy, TAG_END); LT_SetAttributes(h, GAD_FRAMESKIP, GA_Disabled, dis_skip, TAG_END); LT_SetAttributes(h, GAD_SCREEN_MODE, GA_Disabled, dis_mode, TAG_END); LT_SetAttributes(h, GAD_AHI_MODE, GA_Disabled, AHIBase == NULL, TAG_END); } // Show screen mode requester static void screen_mode_req(struct Window *win, struct LayoutHandle *h) { if (P96Base == NULL && CyberGfxBase == NULL) return; LT_LockWindow(win); ULONG id; // Try P96 first, because it also provides a (fake) cybergraphics.library if (P96Base) { id = p96RequestModeIDTags( P96MA_MinDepth, 8, P96MA_FormatsAllowed, RGBFF_CLUT | RGBFF_R5G5B5 | RGBFF_A8R8G8B8, TAG_END ); } else { UWORD ModelArray[] = { PIXFMT_LUT8, PIXFMT_RGB15, PIXFMT_ARGB32, 0, ~0 }; id = (ULONG) CModeRequestTags(NULL, CYBRMREQ_MinDepth, 8, CYBRMREQ_CModelArray, (ULONG) ModelArray, TAG_END ); } LT_UnlockWindow(win); if (id != INVALID_ID) { mode_id = id; GetDisplayInfoData(NULL, (UBYTE *)&mode_name, sizeof(mode_name), DTAG_NAME, mode_id); LT_SetAttributes(h, GAD_SCREEN_MODE, GTTX_Text, (ULONG)mode_name.Name, TAG_END); } } // Show AHI mode requester static void ahi_mode_req(struct Window *win, struct LayoutHandle *h) { if (AHIBase == NULL) return; struct AHIAudioModeRequester *req = AHI_AllocAudioRequest( AHIR_Window, (ULONG)win, TAG_END ); if (req == NULL) return; LT_LockWindow(win); BOOL ok = AHI_AudioRequest(req, AHIR_InitialAudioID, ahi_id, TAG_END ); LT_UnlockWindow(win); if (ok) { ahi_id = req->ahiam_AudioID; AHI_GetAudioAttrs(ahi_id, NULL, AHIDB_Name, (ULONG)ahi_mode_name, AHIDB_BufferLen, sizeof(ahi_mode_name) - 1, TAG_END ); LT_SetAttributes(h, GAD_AHI_MODE, GTTX_Text, (ULONG)ahi_mode_name, TAG_END); } AHI_FreeAudioRequest(req); } // Read settings from gadgets and set preferences static void read_graphics_settings(void) { char str[256]; switch (display_type) { case DISPLAY_WINDOW: sprintf(str, "win/%ld/%ld", dis_width, dis_height); break; case DISPLAY_PIP: sprintf(str, "pip/%ld/%ld", dis_width, dis_height); break; case DISPLAY_SCREEN: sprintf(str, "scr/%08lx", mode_id); break; default: PrefsRemoveItem("screen"); return; } PrefsReplaceString("screen", str); sprintf(str, "ahi/%08lx", ahi_id); PrefsReplaceString("sound", str); PrefsReplaceBool("nosound", nosound); } // Create "Graphics/Sound" pane static void create_graphics_pane(struct LayoutHandle *h) { parse_graphics_prefs(); VGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_GRAPHICS_CTRL, TAG_END ); static const LONG labels[] = {STR_WINDOW_LAB, STR_PIP_LAB, STR_FULLSCREEN_LAB, -1}; LT_New(h, LA_Type, CYCLE_KIND, LA_LabelID, STR_VIDEO_TYPE_CTRL, LA_ID, GAD_VIDEO_TYPE, LACY_LabelTable, (ULONG)labels, LA_LONG, (ULONG)&display_type, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_DISPLAY_X_CTRL, LA_ID, GAD_DISPLAY_X, LA_LONG, (ULONG)&dis_width, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_DISPLAY_Y_CTRL, LA_ID, GAD_DISPLAY_Y, LA_LONG, (ULONG)&dis_height, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, POPUP_KIND, LA_LabelID, STR_FRAMESKIP_CTRL, LA_ID, GAD_FRAMESKIP, LAPU_FirstLabel, STR_REF_5HZ_LAB, LAPU_LastLabel, STR_REF_60HZ_LAB, LA_BYTE, (ULONG)&frameskip_num, TAG_END ); LT_New(h, LA_Type, TEXT_KIND, LA_LabelID, STR_SCREEN_MODE_CTRL, LA_ID, GAD_SCREEN_MODE, LA_Chars, DISPLAYNAMELEN, LATX_Picker, TRUE, GTTX_Text, (ULONG)mode_name.Name, GTTX_Border, TRUE, TAG_END ); ENDGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_SOUND_CTRL, TAG_END ); LT_New(h, LA_Type, TEXT_KIND, LA_LabelID, STR_AHI_MODE_CTRL, LA_ID, GAD_AHI_MODE, LA_Chars, DISPLAYNAMELEN, LATX_Picker, TRUE, GTTX_Text, (ULONG)ahi_mode_name, GTTX_Border, TRUE, TAG_END ); LT_New(h, LA_Type, CHECKBOX_KIND, LA_LabelID, STR_NOSOUND_CTRL, LA_ID, GAD_NOSOUND, LA_BYTE, (ULONG)&nosound, TAG_END ); ENDGROUP; ENDGROUP; ghost_graphics_gadgets(h); } /* * "Serial/Network" pane */ static char seriala_dev[256], serialb_dev[256]; static LONG seriala_unit, serialb_unit; static BYTE seriala_ispar, serialb_ispar; static char ether_dev[256]; static ULONG ether_unit; // Read serial/network preferences static void parse_ser_prefs(const char *prefs, char *dev, LONG &unit, BYTE &ispar) { dev[0] = 0; unit = 0; ispar = false; const char *str = PrefsFindString(prefs); if (str) { if (str[0] == '*') { ispar = true; str++; } sscanf(str, "%[^/]/%ld", dev, &unit); } } static void parse_serial_prefs(void) { parse_ser_prefs("seriala", seriala_dev, seriala_unit, seriala_ispar); parse_ser_prefs("serialb", serialb_dev, serialb_unit, serialb_ispar); ether_dev[0] = 0; ether_unit = 0; const char *str = PrefsFindString("ether"); if (str) { const char *FirstSlash = strchr(str, '/'); const char *LastSlash = strrchr(str, '/'); if (FirstSlash && FirstSlash && FirstSlash != LastSlash) { // Device name contains path, i.e. "Networks/xyzzy.device" const char *lp = str; char *dp = ether_dev; while (lp != LastSlash) *dp++ = *lp++; *dp = '\0'; sscanf(LastSlash, "/%ld", ðer_unit); // printf("dev=<%s> unit=%d\n", ether_dev, ether_unit); } else { sscanf(str, "%[^/]/%ld", ether_dev, ðer_unit); } } } // Set serial preference item static void make_serial_prefs(const char *prefs, const char *dev, LONG unit, BYTE ispar) { if (strlen(dev)) { char str[256]; sprintf(str, "%s%s/%ld", ispar ? "*" : "", dev, unit); PrefsReplaceString(prefs, str); } else PrefsRemoveItem(prefs); } // Read settings from gadgets and set preferences static void read_serial_settings(void) { make_serial_prefs("seriala", seriala_dev, seriala_unit, seriala_ispar); make_serial_prefs("serialb", serialb_dev, serialb_unit, serialb_ispar); if (strlen(ether_dev)) { char str[256]; sprintf(str, "%s/%ld", ether_dev, ether_unit); PrefsReplaceString("ether", str); } else PrefsRemoveItem("ether"); } // Create "Serial/Network" pane static void create_serial_pane(struct LayoutHandle *h) { parse_serial_prefs(); VGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_SERIALA_CTRL, TAG_END ); LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_DEVICE_CTRL, LA_ID, GAD_SERIALA_DEVICE, LA_Chars, 20, LA_STRPTR, (ULONG)seriala_dev, GTST_MaxChars, sizeof(seriala_dev) - 1, LAST_Picker, TRUE, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_UNIT_CTRL, LA_ID, GAD_SERIALA_UNIT, LA_LONG, (ULONG)&seriala_unit, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, CHECKBOX_KIND, LA_LabelID, STR_ISPAR_CTRL, LA_ID, GAD_SERIALA_ISPAR, LA_BYTE, (ULONG)&seriala_ispar, TAG_END ); ENDGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_SERIALB_CTRL, TAG_END ); LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_DEVICE_CTRL, LA_ID, GAD_SERIALB_DEVICE, LA_Chars, 20, LA_STRPTR, (ULONG)serialb_dev, GTST_MaxChars, sizeof(serialb_dev) - 1, LAST_Picker, TRUE, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_UNIT_CTRL, LA_ID, GAD_SERIALB_UNIT, LA_LONG, (ULONG)&serialb_unit, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); LT_New(h, LA_Type, CHECKBOX_KIND, LA_LabelID, STR_ISPAR_CTRL, LA_ID, GAD_SERIALB_ISPAR, LA_BYTE, (ULONG)&serialb_ispar, TAG_END ); ENDGROUP; LT_New(h, LA_Type, VERTICAL_KIND, LA_LabelID, STR_ETHERNET_IF_CTRL, TAG_END ); LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_DEVICE_CTRL, LA_ID, GAD_ETHER_DEVICE, LA_Chars, 20, LA_STRPTR, (ULONG)ether_dev, GTST_MaxChars, sizeof(ether_dev) - 1, LAST_Picker, TRUE, TAG_END ); LT_New(h, LA_Type, INTEGER_KIND, LA_LabelID, STR_UNIT_CTRL, LA_ID, GAD_ETHER_UNIT, LA_LONG, (ULONG)ðer_unit, LAIN_UseIncrementers, TRUE, GTIN_MaxChars, 8, TAG_END ); ENDGROUP; ENDGROUP; } /* * "Memory/Misc" pane */ static ULONG ramsize_mb; static BYTE model_num; static char rom_file[256]; // Read memory/misc preferences static void parse_memory_prefs(void) { ramsize_mb = PrefsFindInt32("ramsize") >> 20; model_num = 0; int id = PrefsFindInt32("modelid"); switch (id) { case 5: model_num = 0; break; case 14: model_num = 1; break; } rom_file[0] = 0; const char *str = PrefsFindString("rom"); if (str) { strncpy(rom_file, str, sizeof(rom_file) - 1); rom_file[sizeof(rom_file) - 1] = 0; } } // Read settings from gadgets and set preferences static void read_memory_settings(void) { PrefsReplaceInt32("ramsize", ramsize_mb << 20); if (strlen(rom_file)) PrefsReplaceString("rom", rom_file); else PrefsRemoveItem("rom"); } // Create "Memory/Misc" pane static void create_memory_pane(struct LayoutHandle *h) { parse_memory_prefs(); VGROUP; LT_New(h, LA_Type, LEVEL_KIND, LA_LabelID, STR_RAMSIZE_SLIDER, LA_ID, GAD_RAMSIZE, LA_Chars, 20, LA_LONG, (ULONG)&ramsize_mb, GTSL_LevelFormat, (ULONG)GetString(STR_RAMSIZE_FMT), GTSL_Min, 1, GTSL_Max, AvailMem(MEMF_LARGEST) >> 20, TAG_END ); LT_New(h, LA_Type, CYCLE_KIND, LA_LabelID, STR_MODELID_CTRL, LA_ID, GAD_MODELID, LACY_FirstLabel, STR_MODELID_5_LAB, LACY_LastLabel, STR_MODELID_14_LAB, LA_BYTE, (ULONG)&model_num, TAG_END ); LT_New(h, LA_Type, STRING_KIND, LA_LabelID, STR_ROM_FILE_CTRL, LA_ID, GAD_ROM_FILE, LA_Chars, 20, LA_STRPTR, (ULONG)rom_file, GTST_MaxChars, sizeof(rom_file) - 1, LAST_Picker, TRUE, TAG_END ); ENDGROUP; } /* * Read settings from gadgets and set preferences */ static void read_settings(struct LayoutHandle *h) { LT_UpdateStrings(h); read_volumes_settings(); read_scsi_settings(); read_graphics_settings(); read_serial_settings(); read_memory_settings(); } BasiliskII/src/AmigaOS/prefs_amiga.cpp0000644000175000017500000000410610736405217017777 0ustar centriscentris/* * prefs_amiga.cpp - Preferences handling, AmigaOS specifix stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include "sysdeps.h" #include "prefs.h" // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {"sound", TYPE_STRING, false, "sound output mode description"}, {"scsimemtype", TYPE_INT32, false, "SCSI buffer memory type"}, {NULL, TYPE_END, false, NULL} // End of list }; // Prefs file name const char PREFS_FILE_NAME[] = "ENV:BasiliskII_prefs"; const char PREFS_FILE_NAME_ARC[] = "ENVARC:BasiliskII_prefs"; /* * Load preferences from settings file */ void LoadPrefs(void) { // Read preferences from settings file FILE *f = fopen(PREFS_FILE_NAME, "r"); if (f != NULL) { // Prefs file found, load settings LoadPrefsFromStream(f); fclose(f); } else { // No prefs file, save defaults SavePrefs(); } } /* * Save preferences to settings file */ void SavePrefs(void) { FILE *f; if ((f = fopen(PREFS_FILE_NAME, "w")) != NULL) { SavePrefsToStream(f); fclose(f); } if ((f = fopen(PREFS_FILE_NAME_ARC, "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit() */ void AddPlatformPrefsDefaults(void) { PrefsReplaceString("extfs", "WORK:"); PrefsAddInt32("scsimemtype", 0); } BasiliskII/src/AmigaOS/sysdeps.h0000644000175000017500000000367110736405217016667 0ustar centriscentris/* * sysdeps.h - System dependent definitions for AmigaOS * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SYSDEPS_H #define SYSDEPS_H #include #include #include #include #include #include #include #include "user_strings_amiga.h" // Mac and host address space are the same #define REAL_ADDRESSING 1 // Using 68k natively #define EMULATED_68K 0 // Mac ROM is not write protected #define ROM_IS_WRITE_PROTECTED 0 #define USE_SCRATCHMEM_SUBTERFUGE 1 // ExtFS is supported #define SUPPORTS_EXTFS 1 // mon is not supported #undef ENABLE_MON // Data types typedef unsigned char uint8; typedef signed char int8; typedef unsigned short uint16; typedef signed short int16; typedef unsigned long uint32; typedef signed long int32; typedef unsigned long long uint64; typedef signed long long int64; typedef unsigned long long loff_t; // Time data type for Time Manager emulation typedef struct timeval tm_time_t; // Endianess conversion (not needed) #define ntohs(x) (x) #define ntohl(x) (x) #define htons(x) (x) #define htonl(x) (x) // Some systems don't define this (ExecBase->AttnFlags) #ifndef AFF_68060 #define AFF_68060 (1L<<7) #endif #endif BasiliskII/src/AmigaOS/xpram_amiga.cpp0000644000175000017500000000351310736405217020010 0ustar centriscentris/* * xpram_amiga.cpp - XPRAM handling, AmigaOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #define __USE_SYSBASE #include #include #include "sysdeps.h" #include "xpram.h" // XPRAM file name #if POWERPC_ROM static char XPRAM_FILE_NAME[] = "ENV:SheepShaver_NVRAM"; static char XPRAM_FILE_NAME_ARC[] = "ENVARC:SheepShaver_NVRAM"; #else static char XPRAM_FILE_NAME[] = "ENV:BasiliskII_XPRAM"; static char XPRAM_FILE_NAME_ARC[] = "ENVARC:BasiliskII_XPRAM"; #endif /* * Load XPRAM from settings file */ void LoadXPRAM(void) { BPTR fh; if ((fh = Open(XPRAM_FILE_NAME, MODE_OLDFILE)) != NULL) { Read(fh, XPRAM, XPRAM_SIZE); Close(fh); } } /* * Save XPRAM to settings file */ void SaveXPRAM(void) { BPTR fh; if ((fh = Open(XPRAM_FILE_NAME, MODE_NEWFILE)) != NULL) { Write(fh, XPRAM, XPRAM_SIZE); Close(fh); } if ((fh = Open(XPRAM_FILE_NAME_ARC, MODE_NEWFILE)) != NULL) { Write(fh, XPRAM, XPRAM_SIZE); Close(fh); } } /* * Delete PRAM file */ void ZapPRAM(void) { DeleteFile(XPRAM_FILE_NAME); DeleteFile(XPRAM_FILE_NAME_ARC); } BasiliskII/src/AmigaOS/main_amiga.cpp0000644000175000017500000004431711266640177017621 0ustar centriscentris/* * main_amiga.cpp - Startup code for AmigaOS * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #define __USE_SYSBASE #include #include #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "xpram.h" #include "timer.h" #include "sony.h" #include "disk.h" #include "cdrom.h" #include "scsi.h" #include "audio.h" #include "video.h" #include "serial.h" #include "ether.h" #include "clip.h" #include "emul_op.h" #include "rom_patches.h" #include "prefs.h" #include "prefs_editor.h" #include "sys.h" #include "user_strings.h" #include "version.h" #define DEBUG 0 #include "debug.h" // Options for libnix unsigned long __stack = 0x4000; // Stack requirement int __nocommandline = 1; // Disable command line parsing // Constants static const char ROM_FILE_NAME[] = "ROM"; static const char __ver[] = "$VER: " VERSION_STRING " " __DATE__; static const int SCRATCH_MEM_SIZE = 65536; // RAM and ROM pointers uint32 RAMBaseMac; // RAM base (Mac address space) uint8 *RAMBaseHost; // RAM base (host address space) uint32 RAMSize; // Size of RAM uint32 ROMBaseMac; // ROM base (Mac address space) uint8 *ROMBaseHost; // ROM base (host address space) uint32 ROMSize; // Size of ROM // CPU and FPU type, addressing mode int CPUType; bool CPUIs68060; int FPUType; bool TwentyFourBitAddressing; // Global variables extern ExecBase *SysBase; struct Library *GfxBase = NULL; struct IntuitionBase *IntuitionBase = NULL; struct Library *GadToolsBase = NULL; struct Library *IFFParseBase = NULL; struct Library *AslBase = NULL; struct Library *P96Base = NULL; struct Library *CyberGfxBase = NULL; struct Library *TimerBase = NULL; struct Library *AHIBase = NULL; struct Library *DiskBase = NULL; struct Task *MainTask; // Our task uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes APTR OldTrapHandler = NULL; // Old trap handler APTR OldExceptionHandler = NULL; // Old exception handler BYTE IRQSig = -1; // "Interrupt" signal number ULONG IRQSigMask = 0; // "Interrupt" signal mask static struct timerequest *timereq = NULL; // IORequest for timer static struct MsgPort *ahi_port = NULL; // Port for AHI static struct AHIRequest *ahi_io = NULL; // IORequest for AHI static struct Process *xpram_proc = NULL; // XPRAM watchdog static volatile bool xpram_proc_active = true; // Flag for quitting the XPRAM watchdog static struct Process *tick_proc = NULL; // 60Hz process static volatile bool tick_proc_active = true; // Flag for quitting the 60Hz process static bool stack_swapped = false; // Stack swapping static StackSwapStruct stack_swap; // Assembly functions struct trap_regs; extern "C" void AtomicAnd(uint32 *p, uint32 val); extern "C" void AtomicOr(uint32 *p, uint32 val); extern "C" void MoveVBR(void); extern "C" void DisableSuperBypass(void); extern "C" void TrapHandlerAsm(void); extern "C" void ExceptionHandlerAsm(void); extern "C" void IllInstrHandler(trap_regs *regs); extern "C" void PrivViolHandler(trap_regs *regs); extern "C" void quit_emulator(void); extern "C" void AsmTriggerNMI(void); uint16 EmulatedSR; // Emulated SR (supervisor bit and interrupt mask) // Prototypes static void jump_to_rom(void); static void xpram_func(void); static void tick_func(void); /* * Main program */ int main(int argc, char **argv) { // Initialize variables RAMBaseHost = NULL; ROMBaseHost = NULL; MainTask = FindTask(NULL); struct DateStamp ds; DateStamp(&ds); srand(ds.ds_Tick); // Print some info printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); printf(" %s\n", GetString(STR_ABOUT_TEXT2)); // Open libraries GfxBase = OpenLibrary((UBYTE *) "graphics.library", 39); if (GfxBase == NULL) { printf("Cannot open graphics.library V39.\n"); exit(1); } IntuitionBase = (struct IntuitionBase *)OpenLibrary((UBYTE *) "intuition.library", 39); if (IntuitionBase == NULL) { printf("Cannot open intuition.library V39.\n"); CloseLibrary(GfxBase); exit(1); } DiskBase = (struct Library *)OpenResource((UBYTE *) "disk.resource"); if (DiskBase == NULL) QuitEmulator(); GadToolsBase = OpenLibrary((UBYTE *) "gadtools.library", 39); if (GadToolsBase == NULL) { ErrorAlert(STR_NO_GADTOOLS_LIB_ERR); QuitEmulator(); } IFFParseBase = OpenLibrary((UBYTE *) "iffparse.library", 39); if (IFFParseBase == NULL) { ErrorAlert(STR_NO_IFFPARSE_LIB_ERR); QuitEmulator(); } AslBase = OpenLibrary((UBYTE *) "asl.library", 36); if (AslBase == NULL) { ErrorAlert(STR_NO_ASL_LIB_ERR); QuitEmulator(); } if (FindTask((UBYTE *) "« Enforcer »")) { ErrorAlert(STR_ENFORCER_RUNNING_ERR); QuitEmulator(); } // These two can fail (the respective gfx support won't be available, then) P96Base = OpenLibrary((UBYTE *) "Picasso96API.library", 2); CyberGfxBase = OpenLibrary((UBYTE *) "cybergraphics.library", 2); // Read preferences PrefsInit(NULL, argc, argv); // Open AHI ahi_port = CreateMsgPort(); if (ahi_port) { ahi_io = (struct AHIRequest *)CreateIORequest(ahi_port, sizeof(struct AHIRequest)); if (ahi_io) { ahi_io->ahir_Version = 2; if (OpenDevice((UBYTE *) AHINAME, AHI_NO_UNIT, (struct IORequest *)ahi_io, 0) == 0) { AHIBase = (struct Library *)ahi_io->ahir_Std.io_Device; } } } // Init system routines SysInit(); // Show preferences editor if (!PrefsFindBool("nogui")) if (!PrefsEditor()) QuitEmulator(); // Check start of Chip memory (because we need access to 0x0000..0x2000) if ((uint32)FindName(&SysBase->MemList, (UBYTE *) "chip memory") < 0x2000) { ErrorAlert(STR_NO_PREPARE_EMUL_ERR); QuitEmulator(); } // Open timer.device timereq = (struct timerequest *)AllocVec(sizeof(timerequest), MEMF_PUBLIC | MEMF_CLEAR); if (timereq == NULL) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } if (OpenDevice((UBYTE *) TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timereq, 0)) { ErrorAlert(STR_NO_TIMER_DEV_ERR); QuitEmulator(); } TimerBase = (struct Library *)timereq->tr_node.io_Device; // Allocate scratch memory ScratchMem = (uint8 *)AllocMem(SCRATCH_MEM_SIZE, MEMF_PUBLIC); if (ScratchMem == NULL) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block // Create area for Mac RAM and ROM (ROM must be higher in memory, // so we allocate one big chunk and put the ROM at the top of it) RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary if (RAMSize < 1024*1024) { WarningAlert(GetString(STR_SMALL_RAM_WARN)); RAMSize = 1024*1024; } RAMBaseHost = (uint8 *)AllocVec(RAMSize + 0x100000, MEMF_PUBLIC); if (RAMBaseHost == NULL) { uint32 newRAMSize = AvailMem(MEMF_LARGEST) - 0x100000; char xText[120]; sprintf(xText, GetString(STR_NOT_ENOUGH_MEM_WARN), RAMSize, newRAMSize); if (ChoiceAlert(xText, "Use", "Quit") != 1) QuitEmulator(); RAMSize = newRAMSize; RAMBaseHost = (uint8 *)AllocVec(RAMSize - 0x100000, MEMF_PUBLIC); if (RAMBaseHost == NULL) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } } RAMBaseMac = (uint32)RAMBaseHost; D(bug("Mac RAM starts at %08lx\n", RAMBaseHost)); ROMBaseHost = RAMBaseHost + RAMSize; ROMBaseMac = (uint32)ROMBaseHost; D(bug("Mac ROM starts at %08lx\n", ROMBaseHost)); // Get rom file path from preferences const char *rom_path = PrefsFindString("rom"); // Load Mac ROM BPTR rom_fh = Open(rom_path ? (char *)rom_path : (char *)ROM_FILE_NAME, MODE_OLDFILE); if (rom_fh == 0) { ErrorAlert(STR_NO_ROM_FILE_ERR); QuitEmulator(); } printf(GetString(STR_READING_ROM_FILE)); Seek(rom_fh, 0, OFFSET_END); ROMSize = Seek(rom_fh, 0, OFFSET_CURRENT); if (ROMSize != 512*1024 && ROMSize != 1024*1024) { ErrorAlert(STR_ROM_SIZE_ERR); Close(rom_fh); QuitEmulator(); } Seek(rom_fh, 0, OFFSET_BEGINNING); if (Read(rom_fh, ROMBaseHost, ROMSize) != ROMSize) { ErrorAlert(STR_ROM_FILE_READ_ERR); Close(rom_fh); QuitEmulator(); } // Set CPU and FPU type UWORD attn = SysBase->AttnFlags; CPUType = attn & AFF_68040 ? 4 : (attn & AFF_68030 ? 3 : 2); CPUIs68060 = attn & AFF_68060; FPUType = attn & AFF_68881 ? 1 : 0; // Initialize everything if (!InitAll(NULL)) QuitEmulator(); // Move VBR away from 0 if neccessary MoveVBR(); // On 68060, disable Super Bypass mode because of a CPU bug that is triggered by MacOS 8 if (CPUIs68060) DisableSuperBypass(); memset((UBYTE *) 8, 0, 0x2000-8); // Install trap handler EmulatedSR = 0x2700; OldTrapHandler = MainTask->tc_TrapCode; MainTask->tc_TrapCode = (APTR)TrapHandlerAsm; // Allocate signal for interrupt emulation and install exception handler IRQSig = AllocSignal(-1); IRQSigMask = 1 << IRQSig; OldExceptionHandler = MainTask->tc_ExceptCode; MainTask->tc_ExceptCode = (APTR)ExceptionHandlerAsm; SetExcept(SIGBREAKF_CTRL_C | IRQSigMask, SIGBREAKF_CTRL_C | IRQSigMask); // Start XPRAM watchdog process xpram_proc = CreateNewProcTags( NP_Entry, (ULONG)xpram_func, NP_Name, (ULONG)"Basilisk II XPRAM Watchdog", NP_Priority, 0, TAG_END ); // Start 60Hz process tick_proc = CreateNewProcTags( NP_Entry, (ULONG)tick_func, NP_Name, (ULONG)"Basilisk II 60Hz", NP_Priority, 5, TAG_END ); // Set task priority to -1 so we don't use all processing time SetTaskPri(MainTask, -1); WriteMacInt32(0xbff, 0); // MacsBugFlags // Swap stack to Mac RAM area stack_swap.stk_Lower = RAMBaseHost; stack_swap.stk_Upper = (ULONG)RAMBaseHost + RAMSize; stack_swap.stk_Pointer = RAMBaseHost + 0x8000; StackSwap(&stack_swap); stack_swapped = true; // Jump to ROM boot routine Start680x0(); QuitEmulator(); return 0; } void Start680x0(void) { typedef void (*rom_func)(void); rom_func fp = (rom_func)(ROMBaseHost + 0x2a); fp(); } /* * Quit emulator (__saveds because it might be called from an exception) */ // Assembly entry point void __saveds quit_emulator(void) { QuitEmulator(); } void QuitEmulator(void) { // Stop 60Hz process if (tick_proc) { SetSignal(0, SIGF_SINGLE); tick_proc_active = false; Wait(SIGF_SINGLE); } // Stop XPRAM watchdog process if (xpram_proc) { SetSignal(0, SIGF_SINGLE); xpram_proc_active = false; Wait(SIGF_SINGLE); } // Restore stack if (stack_swapped) { stack_swapped = false; StackSwap(&stack_swap); } // Remove exception handler if (IRQSig >= 0) { SetExcept(0, SIGBREAKF_CTRL_C | IRQSigMask); MainTask->tc_ExceptCode = OldExceptionHandler; FreeSignal(IRQSig); } // Remove trap handler MainTask->tc_TrapCode = OldTrapHandler; // Deinitialize everything ExitAll(); // Delete RAM/ROM area if (RAMBaseHost) FreeVec(RAMBaseHost); // Delete scratch memory area if (ScratchMem) FreeMem((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE); // Close timer.device if (TimerBase) CloseDevice((struct IORequest *)timereq); if (timereq) FreeVec(timereq); // Exit system routines SysExit(); // Close AHI if (AHIBase) CloseDevice((struct IORequest *)ahi_io); if (ahi_io) DeleteIORequest((struct IORequest *)ahi_io); if (ahi_port) DeleteMsgPort(ahi_port); // Exit preferences PrefsExit(); // Close libraries if (CyberGfxBase) CloseLibrary(CyberGfxBase); if (P96Base) CloseLibrary(P96Base); if (AslBase) CloseLibrary(AslBase); if (IFFParseBase) CloseLibrary(IFFParseBase); if (GadToolsBase) CloseLibrary(GadToolsBase); if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase); if (GfxBase) CloseLibrary(GfxBase); exit(0); } /* * Code was patched, flush caches if neccessary (i.e. when using a real 680x0 * or a dynamically recompiling emulator) */ void FlushCodeCache(void *start, uint32 size) { CacheClearE(start, size, CACRF_ClearI | CACRF_ClearD); } /* * Mutexes */ struct B2_mutex { int dummy; //!! }; B2_mutex *B2_create_mutex(void) { return new B2_mutex; } void B2_lock_mutex(B2_mutex *mutex) { } void B2_unlock_mutex(B2_mutex *mutex) { } void B2_delete_mutex(B2_mutex *mutex) { delete mutex; } /* * Interrupt flags (must be handled atomically!) */ uint32 InterruptFlags; void SetInterruptFlag(uint32 flag) { AtomicOr(&InterruptFlags, flag); } void ClearInterruptFlag(uint32 flag) { AtomicAnd(&InterruptFlags, ~flag); } void TriggerInterrupt(void) { Signal(MainTask, IRQSigMask); } void TriggerNMI(void) { AsmTriggerNMI(); } /* * 60Hz thread (really 60.15Hz) */ static __saveds void tick_func(void) { int tick_counter = 0; struct MsgPort *timer_port = NULL; struct timerequest *timer_io = NULL; ULONG timer_mask = 0; // Start 60Hz timer timer_port = CreateMsgPort(); if (timer_port) { timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest)); if (timer_io) { if (!OpenDevice((UBYTE *) TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) { timer_mask = 1 << timer_port->mp_SigBit; timer_io->tr_node.io_Command = TR_ADDREQUEST; timer_io->tr_time.tv_secs = 0; timer_io->tr_time.tv_micro = 16625; SendIO((struct IORequest *)timer_io); } } } while (tick_proc_active) { // Wait for timer tick Wait(timer_mask); // Restart timer timer_io->tr_node.io_Command = TR_ADDREQUEST; timer_io->tr_time.tv_secs = 0; timer_io->tr_time.tv_micro = 16625; SendIO((struct IORequest *)timer_io); // Pseudo Mac 1Hz interrupt, update local time if (++tick_counter > 60) { tick_counter = 0; WriteMacInt32(0x20c, TimerDateTime()); SetInterruptFlag(INTFLAG_1HZ); TriggerInterrupt(); } // Trigger 60Hz interrupt SetInterruptFlag(INTFLAG_60HZ); TriggerInterrupt(); } // Stop timer if (timer_io) { if (!CheckIO((struct IORequest *)timer_io)) AbortIO((struct IORequest *)timer_io); WaitIO((struct IORequest *)timer_io); CloseDevice((struct IORequest *)timer_io); DeleteIORequest(timer_io); } if (timer_port) DeleteMsgPort(timer_port); // Main task asked for termination, send signal Forbid(); Signal(MainTask, SIGF_SINGLE); } /* * XPRAM watchdog thread (saves XPRAM every minute) */ static __saveds void xpram_func(void) { uint8 last_xpram[XPRAM_SIZE]; memcpy(last_xpram, XPRAM, XPRAM_SIZE); while (xpram_proc_active) { for (int i=0; i<60 && xpram_proc_active; i++) Delay(50); // Only wait 1 second so we quit promptly when xpram_proc_active becomes false if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) { memcpy(last_xpram, XPRAM, XPRAM_SIZE); SaveXPRAM(); } } // Main task asked for termination, send signal Forbid(); Signal(MainTask, SIGF_SINGLE); } /* * Display error alert */ void ErrorAlert(const char *text) { if (PrefsFindBool("nogui")) { printf(GetString(STR_SHELL_ERROR_PREFIX), text); return; } EasyStruct req; req.es_StructSize = sizeof(EasyStruct); req.es_Flags = 0; req.es_Title = (UBYTE *)GetString(STR_ERROR_ALERT_TITLE); req.es_TextFormat = (UBYTE *)GetString(STR_GUI_ERROR_PREFIX); req.es_GadgetFormat = (UBYTE *)GetString(STR_QUIT_BUTTON); EasyRequest(NULL, &req, NULL, (ULONG)text); } /* * Display warning alert */ void WarningAlert(const char *text) { if (PrefsFindBool("nogui")) { printf(GetString(STR_SHELL_WARNING_PREFIX), text); return; } EasyStruct req; req.es_StructSize = sizeof(EasyStruct); req.es_Flags = 0; req.es_Title = (UBYTE *)GetString(STR_WARNING_ALERT_TITLE); req.es_TextFormat = (UBYTE *)GetString(STR_GUI_WARNING_PREFIX); req.es_GadgetFormat = (UBYTE *)GetString(STR_OK_BUTTON); EasyRequest(NULL, &req, NULL, (ULONG)text); } /* * Display choice alert */ bool ChoiceAlert(const char *text, const char *pos, const char *neg) { char str[256]; sprintf(str, "%s|%s", pos, neg); EasyStruct req; req.es_StructSize = sizeof(EasyStruct); req.es_Flags = 0; req.es_Title = (UBYTE *)GetString(STR_WARNING_ALERT_TITLE); req.es_TextFormat = (UBYTE *)GetString(STR_GUI_WARNING_PREFIX); req.es_GadgetFormat = (UBYTE *)str; return EasyRequest(NULL, &req, NULL, (ULONG)text); } /* * Illegal Instruction and Privilege Violation trap handlers */ struct trap_regs { // This must match the layout of M68kRegisters uint32 d[8]; uint32 a[8]; uint16 sr; uint32 pc; }; void __saveds IllInstrHandler(trap_regs *r) { // D(bug("IllInstrHandler/%ld\n", __LINE__)); uint16 opcode = *(uint16 *)(r->pc); if ((opcode & 0xff00) != 0x7100) { printf("Illegal Instruction %04x at %08lx\n", *(uint16 *)(r->pc), r->pc); printf("d0 %08lx d1 %08lx d2 %08lx d3 %08lx\n" "d4 %08lx d5 %08lx d6 %08lx d7 %08lx\n" "a0 %08lx a1 %08lx a2 %08lx a3 %08lx\n" "a4 %08lx a5 %08lx a6 %08lx a7 %08lx\n" "sr %04x\n", r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7], r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7], r->sr); QuitEmulator(); } else { // Disable interrupts uint16 sr = EmulatedSR; EmulatedSR |= 0x0700; // Call opcode routine EmulOp(opcode, (M68kRegisters *)r); r->pc += 2; // Restore interrupts EmulatedSR = sr; if ((EmulatedSR & 0x0700) == 0 && InterruptFlags) Signal(MainTask, IRQSigMask); } } void __saveds PrivViolHandler(trap_regs *r) { printf("Privileged instruction %04x %04x at %08lx\n", *(uint16 *)(r->pc), *(uint16 *)(r->pc + 2), r->pc); printf("d0 %08lx d1 %08lx d2 %08lx d3 %08lx\n" "d4 %08lx d5 %08lx d6 %08lx d7 %08lx\n" "a0 %08lx a1 %08lx a2 %08lx a3 %08lx\n" "a4 %08lx a5 %08lx a6 %08lx a7 %08lx\n" "sr %04x\n", r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7], r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7], r->sr); QuitEmulator(); } BasiliskII/src/AmigaOS/BasiliskII.info0000644000175000017500000000275706775662471017707 0ustar centriscentrisã[_60ÉÈ)5Ô€€€6pÿ € À ?À ?à ÿø ÿÿþ ÿÿø ÿÿð UUP    € ` x` ‡€ ÿÿÿÿÿüÿÿÿÿÿÿøÕUUUUUPÕUUUUUPÕUUPUUPÕUU@UPÕUU@UPÕU@@UPÕUUPÕTUPÕUÿÿõUPÕUÿÿåUPÕUUUEUPÕTUPÕTUPÕTUUUUPÕU*ª©UPÕUÿåUPÕUG‡•UPÕUPPUUPÕUUUUUPÕUUUUUP€€àÿøÿÿðÿÿàÿÿàÿÿðÿÿþÿÿüÿøÿà‡€€àÿøÿÿðÿÿàÿÿàÿÿðÿÿþÿÿüÿøÿà‡€€àÿøÿÿðÿÿàÿÿàÿÿðÿÿþÿÿüÿøÿà‡€€àÿøÿÿðÿÿàÿÿàÿÿðÿÿþÿÿüÿøÿà‡€€àÿøÿÿðÿÿàÿÿàÿÿðÿÿþÿÿüÿøÿà‡€€àÿøÿÿðÿÿàÿÿàÿÿðÿÿþÿÿüÿøÿà‡€JUNKBasiliskII/src/AmigaOS/serial_amiga.cpp0000644000175000017500000005521010736405217020141 0ustar centriscentris/* * serial_amiga.cpp - Serial device driver, AmigaOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #define __USE_SYSBASE #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "serial.h" #include "serial_defs.h" #define DEBUG 0 #include "debug.h" #define MONITOR 0 // These messages are sent to the serial process const uint32 MSG_QUERY = 'qery'; // Query port status, return status in control_io const uint32 MSG_SET_PARAMS = 'setp'; // Set serial parameters (parameters in control_io) const uint32 MSG_SET_PAR_PARAMS = 'pstp'; // Set parallel parameters (parameters in control_io) const uint32 MSG_KILL_IO = 'kill'; // Kill pending I/O requests const uint32 MSG_BREAK = 'brek'; // Send break const uint32 MSG_RESET = 'rset'; // Reset channel const uint32 MSG_PRIME_IN = 'prin'; // Data input const uint32 MSG_PRIME_OUT = 'pout'; // Data output struct SerMessage : public Message { SerMessage(uint32 what_, const struct MsgPort *reply_port = NULL) { what = what_; mn_ReplyPort = (struct MsgPort *)reply_port; mn_Length = sizeof(*this); } uint32 what; uint32 pb; }; // Driver private variables class ASERDPort : public SERDPort { public: ASERDPort(const char *dev) { device_name = dev; if (dev && dev[0] == '*') { is_parallel = true; device_name++; } else is_parallel = false; control_io = NULL; serial_proc = NULL; reply_port = NULL; } virtual ~ASERDPort() { } virtual int16 open(uint16 config); virtual int16 prime_in(uint32 pb, uint32 dce); virtual int16 prime_out(uint32 pb, uint32 dce); virtual int16 control(uint32 pb, uint32 dce, uint16 code); virtual int16 status(uint32 pb, uint32 dce, uint16 code); virtual int16 close(void); private: bool configure(uint16 config); void set_handshake(uint32 s, bool with_dtr); void send_to_proc(uint32 what, uint32 pb = 0); bool query(void); bool set_params(void); bool set_par_params(void); void conv_error(struct IOExtSer *io, uint32 dt); static void serial_func(void); const char *device_name; // Device name bool is_parallel; // Flag: Port is parallel IOExtSer *control_io; // IORequest for setting serial port characteristics etc. struct Process *serial_proc; // Serial device handler process bool proc_error; // Flag: process didn't initialize struct MsgPort *proc_port; // Message port of process, for communication with main task struct MsgPort *reply_port; // Reply port for communication with process uint8 err_mask; // shkErrs }; // Global variables static void *proc_arg; // Argument to process extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp) /* * Initialization */ void SerialInit(void) { // Read serial preferences and create structs for both ports the_serd_port[0] = new ASERDPort(PrefsFindString("seriala")); the_serd_port[1] = new ASERDPort(PrefsFindString("serialb")); } /* * Deinitialization */ void SerialExit(void) { delete (ASERDPort *)the_serd_port[0]; delete (ASERDPort *)the_serd_port[1]; } /* * Open serial port */ int16 ASERDPort::open(uint16 config) { // Don't open NULL name devices if (device_name == NULL) return openErr; // Init variables err_mask = 0; // Create message port reply_port = CreateMsgPort(); if (reply_port == NULL) goto open_error; // Start process proc_error = false; proc_arg = this; SetSignal(0, SIGF_SINGLE); serial_proc = CreateNewProcTags( NP_Entry, (ULONG)serial_func, NP_Name, (ULONG)"Basilisk II Serial Task", NP_Priority, 1, TAG_END ); if (serial_proc == NULL) goto open_error; // Wait for signal from process Wait(SIGF_SINGLE); // Initialization error? Then bail out if (proc_error) goto open_error; // Configure port configure(config); return noErr; open_error: serial_proc = NULL; if (reply_port) { DeleteMsgPort(reply_port); reply_port = NULL; } return openErr; } /* * Read data from port */ int16 ASERDPort::prime_in(uint32 pb, uint32 dce) { // Send input command to serial process D(bug("primein\n")); read_done = false; read_pending = true; WriteMacInt32(input_dt + serdtDCE, dce); send_to_proc(MSG_PRIME_IN, pb); return 1; // Command in progress } /* * Write data to port */ int16 ASERDPort::prime_out(uint32 pb, uint32 dce) { // Send output command to serial process D(bug("primeout\n")); write_done = false; write_pending = true; WriteMacInt32(output_dt + serdtDCE, dce); send_to_proc(MSG_PRIME_OUT, pb); return 1; // Command in progress } /* * Control calls */ int16 ASERDPort::control(uint32 pb, uint32 dce, uint16 code) { D(bug("control(%ld)\n", (uint32)code)); switch (code) { case 1: // KillIO send_to_proc(MSG_KILL_IO); return noErr; case kSERDConfiguration: if (configure(ReadMacInt16(pb + csParam))) return noErr; else return paramErr; case kSERDInputBuffer: { if (is_parallel) return noErr; int buf = ReadMacInt16(pb + csParam + 4) & 0xffffffc0; if (buf < 1024) // 1k minimum buf = 1024; D(bug(" buffer size is now %08lx\n", buf)); control_io->io_RBufLen = buf; return set_params() ? noErr : paramErr; } case kSERDSerHShake: set_handshake(pb + csParam, false); return noErr; case kSERDSetBreak: if (!is_parallel) send_to_proc(MSG_BREAK); return noErr; case kSERDClearBreak: return noErr; case kSERDBaudRate: if (is_parallel) return noErr; control_io->io_Baud = ReadMacInt16(pb + csParam); D(bug(" baud rate %ld\n", control_io->io_Baud)); return set_params() ? noErr : paramErr; case kSERDHandshake: case kSERDHandshakeRS232: set_handshake(pb + csParam, true); return noErr; case kSERDClockMIDI: if (is_parallel) return noErr; control_io->io_Baud = 31250; control_io->io_SerFlags = SERF_XDISABLED | SERF_SHARED; control_io->io_StopBits = 1; control_io->io_ReadLen = control_io->io_WriteLen = 8; return set_params() ? noErr : paramErr; case kSERDMiscOptions: case kSERDAssertDTR: case kSERDNegateDTR: case kSERDSetPEChar: case kSERDSetPEAltChar: case kSERDAssertRTS: case kSERDNegateRTS: return noErr; // Not supported under AmigaOS case kSERD115KBaud: if (is_parallel) return noErr; control_io->io_Baud = 115200; return set_params() ? noErr : paramErr; case kSERD230KBaud: case kSERDSetHighSpeed: if (is_parallel) return noErr; control_io->io_Baud = 230400; return set_params() ? noErr : paramErr; case kSERDResetChannel: send_to_proc(MSG_RESET); return noErr; default: printf("WARNING: SerialControl(): unimplemented control code %d\n", code); return controlErr; } } /* * Status calls */ int16 ASERDPort::status(uint32 pb, uint32 dce, uint16 code) { D(bug("status(%ld)\n", (uint32)code)); switch (code) { case kSERDInputCount: WriteMacInt32(pb + csParam, 0); if (!is_parallel) { if (!query()) return noErr; D(bug("status(2) successful, returning %08lx\n", control_io->IOSer.io_Actual)); WriteMacInt32(pb + csParam, control_io->IOSer.io_Actual); } return noErr; case kSERDStatus: { uint32 p = pb + csParam; WriteMacInt8(p + staCumErrs, cum_errors); cum_errors = 0; WriteMacInt8(p + staRdPend, read_pending); WriteMacInt8(p + staWrPend, write_pending); if (is_parallel) { WriteMacInt8(p + staXOffSent, 0); WriteMacInt8(p + staXOffHold, 0); WriteMacInt8(p + staCtsHold, 0); WriteMacInt8(p + staDsrHold, 0); WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent); } else { query(); WriteMacInt8(p + staXOffSent, (control_io->io_Status & IO_STATF_XOFFREAD ? xOffWasSent : 0) | (control_io->io_Status & (1 << 6) ? dtrNegated : 0)); // RTS WriteMacInt8(p + staXOffHold, control_io->io_Status & IO_STATF_XOFFWRITE); WriteMacInt8(p + staCtsHold, control_io->io_Status & (1 << 4)); // CTS WriteMacInt8(p + staDsrHold, control_io->io_Status & (1 << 3)); // DSR WriteMacInt8(p + staModemStatus, (control_io->io_Status & (1 << 3) ? 0 : dsrEvent) | (control_io->io_Status & (1 << 2) ? riEvent : 0) | (control_io->io_Status & (1 << 5) ? 0 : dcdEvent) | (control_io->io_Status & (1 << 4) ? 0 : ctsEvent) | (control_io->io_Status & IO_STATF_READBREAK ? breakEvent : 0)); } return noErr; } default: printf("WARNING: SerialStatus(): unimplemented status code %d\n", code); return statusErr; } } /* * Close serial port */ int16 ASERDPort::close() { // Stop process if (serial_proc) { SetSignal(0, SIGF_SINGLE); Signal(&serial_proc->pr_Task, SIGBREAKF_CTRL_C); Wait(SIGF_SINGLE); } // Delete reply port if (reply_port) { DeleteMsgPort(reply_port); reply_port = NULL; } return noErr; } /* * Configure serial port with MacOS config word */ bool ASERDPort::configure(uint16 config) { D(bug(" configure %04lx\n", (uint32)config)); if (is_parallel) return true; // Set number of stop bits switch (config & 0xc000) { case stop10: control_io->io_StopBits = 1; break; case stop20: control_io->io_StopBits = 2; break; default: return false; } // Set parity mode switch (config & 0x3000) { case noParity: control_io->io_SerFlags &= ~SERF_PARTY_ON; break; case oddParity: control_io->io_SerFlags |= SERF_PARTY_ON | SERF_PARTY_ODD; break; case evenParity: control_io->io_SerFlags |= SERF_PARTY_ON; control_io->io_SerFlags &= ~SERF_PARTY_ODD; break; default: return false; } // Set number of data bits switch (config & 0x0c00) { case data5: control_io->io_ReadLen = control_io->io_WriteLen = 5; break; case data6: control_io->io_ReadLen = control_io->io_WriteLen = 6; break; case data7: control_io->io_ReadLen = control_io->io_WriteLen = 7; break; case data8: control_io->io_ReadLen = control_io->io_WriteLen = 8; break; } // Set baud rate control_io->io_Baud = 115200 / ((config & 0x03ff) + 2); return set_params(); } /* * Set serial handshaking */ void ASERDPort::set_handshake(uint32 s, bool with_dtr) { D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n", ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3), ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7))); err_mask = ReadMacInt8(s + shkErrs); if (is_parallel) { // Parallel handshake if (with_dtr) { if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR)) ((IOExtPar *)control_io)->io_ParFlags |= PARF_ACKMODE; else ((IOExtPar *)control_io)->io_ParFlags &= ~PARF_ACKMODE; } else { if (ReadMacInt8(s + shkFCTS)) ((IOExtPar *)control_io)->io_ParFlags |= PARF_ACKMODE; else ((IOExtPar *)control_io)->io_ParFlags &= ~PARF_ACKMODE; } set_par_params(); } else { // Serial handshake if (ReadMacInt8(s + shkFXOn) || ReadMacInt8(s + shkFInX)) control_io->io_SerFlags &= ~SERF_XDISABLED; else control_io->io_SerFlags |= SERF_XDISABLED; if (with_dtr) { if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR)) control_io->io_SerFlags |= SERF_7WIRE; else control_io->io_SerFlags &= ~SERF_7WIRE; } else { if (ReadMacInt8(s + shkFCTS)) control_io->io_SerFlags |= SERF_7WIRE; else control_io->io_SerFlags &= ~SERF_7WIRE; } control_io->io_CtlChar = ReadMacInt16(s + shkXOn) << 16; set_params(); } } /* * Send message to serial process */ void ASERDPort::send_to_proc(uint32 what, uint32 pb) { D(bug("sending %08lx to serial_proc\n", what)); SerMessage msg(what, reply_port); msg.pb = pb; PutMsg(proc_port, &msg); WaitPort(reply_port); GetMsg(reply_port); D(bug(" sent\n")); } /* * Query serial port status */ bool ASERDPort::query(void) { send_to_proc(MSG_QUERY); return control_io->IOSer.io_Error == 0; } /* * Set serial parameters */ bool ASERDPort::set_params(void) { // Set/clear RadBoogie UBYTE flags = control_io->io_SerFlags; if (!(flags & SERF_PARTY_ON) && (flags & SERF_XDISABLED) && control_io->io_ReadLen == 8) control_io->io_SerFlags |= SERF_RAD_BOOGIE; else control_io->io_SerFlags &= ~SERF_RAD_BOOGIE; // Send message to serial process send_to_proc(MSG_SET_PARAMS); return control_io->IOSer.io_Error == 0; } /* * Set parallel parameters */ bool ASERDPort::set_par_params(void) { send_to_proc(MSG_SET_PAR_PARAMS); return control_io->IOSer.io_Error == 0; } /* * Convert AmigaOS error code to MacOS error code, set serdtResult and cum_errors */ void ASERDPort::conv_error(struct IOExtSer *io, uint32 dt) { int16 oserr; uint8 cum; BYTE err = io->IOSer.io_Error; if (err == 0 || err == IOERR_NOCMD) { oserr = 0; cum = 0; } else { if (is_parallel) { oserr = (err_mask & framingErr) ? rcvrErr : 0; cum = framingErr; } else { switch (io->IOSer.io_Error) { case SerErr_DetectedBreak: oserr = breakRecd; cum = breakErr; break; case SerErr_ParityErr: oserr = (err_mask & parityErr) ? rcvrErr : 0; cum = parityErr; break; case SerErr_BufOverflow: oserr = (err_mask & swOverrunErr) ? rcvrErr : 0; cum = swOverrunErr; break; case SerErr_LineErr: oserr = (err_mask & hwOverrunErr) ? rcvrErr : 0; cum = hwOverrunErr; break; default: oserr = (err_mask & framingErr) ? rcvrErr : 0; cum = framingErr; break; } } } WriteMacInt32(dt + serdtResult, oserr); cum_errors |= cum; } /* * Process for communication with the serial.device */ __saveds void ASERDPort::serial_func(void) { struct ASERDPort *obj = (ASERDPort *)proc_arg; struct MsgPort *proc_port = NULL, *io_port = NULL, *control_port = NULL; struct IOExtSer *read_io = NULL, *write_io = NULL, *control_io = NULL; uint8 orig_params[sizeof(struct IOExtSer)]; bool opened = false; ULONG io_mask = 0, proc_port_mask = 0; // Default: error occured obj->proc_error = true; // Create message port for communication with main task proc_port = CreateMsgPort(); if (proc_port == NULL) goto quit; proc_port_mask = 1 << proc_port->mp_SigBit; // Create message ports for serial.device I/O io_port = CreateMsgPort(); if (io_port == NULL) goto quit; io_mask = 1 << io_port->mp_SigBit; control_port = CreateMsgPort(); if (control_port == NULL) goto quit; // Create IORequests read_io = (struct IOExtSer *)CreateIORequest(io_port, sizeof(struct IOExtSer)); write_io = (struct IOExtSer *)CreateIORequest(io_port, sizeof(struct IOExtSer)); control_io = (struct IOExtSer *)CreateIORequest(control_port, sizeof(struct IOExtSer)); if (read_io == NULL || write_io == NULL || control_io == NULL) goto quit; read_io->IOSer.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug write_io->IOSer.io_Message.mn_Node.ln_Type = 0; control_io->IOSer.io_Message.mn_Node.ln_Type = 0; // Parse device name char dev_name[256]; ULONG dev_unit; if (sscanf(obj->device_name, "%[^/]/%ld", dev_name, &dev_unit) < 2) goto quit; // Open device if (obj->is_parallel) ((IOExtPar *)read_io)->io_ParFlags = PARF_SHARED; else read_io->io_SerFlags = SERF_SHARED | SERF_7WIRE; if (OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)read_io, 0) || read_io->IOSer.io_Device == NULL) goto quit; opened = true; // Copy IORequests memcpy(write_io, read_io, sizeof(struct IOExtSer)); memcpy(control_io, read_io, sizeof(struct IOExtSer)); // Attach control_io to control_port and set default values control_io->IOSer.io_Message.mn_ReplyPort = control_port; if (!obj->is_parallel) { control_io->io_CtlChar = SER_DEFAULT_CTLCHAR; control_io->io_RBufLen = 64; control_io->io_ExtFlags = 0; control_io->io_Baud = 9600; control_io->io_BrkTime = 250000; control_io->io_ReadLen = control_io->io_WriteLen = 8; control_io->io_StopBits = 1; control_io->io_SerFlags = SERF_SHARED; control_io->IOSer.io_Command = SDCMD_SETPARAMS; DoIO((struct IORequest *)control_io); memcpy(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); } // Initialization went well, inform main task obj->proc_port = proc_port; obj->control_io = control_io; obj->proc_error = false; Signal(MainTask, SIGF_SINGLE); // Main loop for (;;) { // Wait for I/O and messages (CTRL_C is used for quitting the task) ULONG sig = Wait(proc_port_mask | io_mask | SIGBREAKF_CTRL_C); // Main task wants to quit us if (sig & SIGBREAKF_CTRL_C) break; // Main task sent a command to us if (sig & proc_port_mask) { struct SerMessage *msg; while (msg = (SerMessage *)GetMsg(proc_port)) { D(bug("serial_proc received %08lx\n", msg->what)); switch (msg->what) { case MSG_QUERY: control_io->IOSer.io_Command = SDCMD_QUERY; DoIO((struct IORequest *)control_io); D(bug(" query returned %08lx, actual %08lx\n", control_io->IOSer.io_Error, control_io->IOSer.io_Actual)); break; case MSG_SET_PARAMS: // Only send SDCMD_SETPARAMS when configuration has changed if (memcmp(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar))) { memcpy(orig_params, &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); memcpy(&(read_io->io_CtlChar), &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); memcpy(&(write_io->io_CtlChar), &(control_io->io_CtlChar), (uint8 *)&(control_io->io_Status) - (uint8 *)&(control_io->io_CtlChar)); control_io->IOSer.io_Command = SDCMD_SETPARAMS; D(bug(" params %08lx %08lx %08lx %08lx %08lx %08lx\n", control_io->io_CtlChar, control_io->io_RBufLen, control_io->io_ExtFlags, control_io->io_Baud, control_io->io_BrkTime, *(uint32 *)((uint8 *)control_io + 76))); DoIO((struct IORequest *)control_io); D(bug(" set_parms returned %08lx\n", control_io->IOSer.io_Error)); } break; case MSG_SET_PAR_PARAMS: control_io->IOSer.io_Command = PDCMD_SETPARAMS; DoIO((struct IORequest *)control_io); D(bug(" set_par_parms returned %08lx\n", control_io->IOSer.io_Error)); break; case MSG_BREAK: control_io->IOSer.io_Command = SDCMD_BREAK; DoIO((struct IORequest *)control_io); D(bug(" break returned %08lx\n", control_io->IOSer.io_Error)); break; case MSG_RESET: control_io->IOSer.io_Command = CMD_RESET; DoIO((struct IORequest *)control_io); D(bug(" reset returned %08lx\n", control_io->IOSer.io_Error)); break; case MSG_KILL_IO: AbortIO((struct IORequest *)read_io); AbortIO((struct IORequest *)write_io); WaitIO((struct IORequest *)read_io); WaitIO((struct IORequest *)write_io); obj->read_pending = obj->write_pending = false; obj->read_done = obj->write_done = false; break; case MSG_PRIME_IN: read_io->IOSer.io_Message.mn_Node.ln_Name = (char *)msg->pb; read_io->IOSer.io_Data = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); read_io->IOSer.io_Length = ReadMacInt32(msg->pb + ioReqCount); read_io->IOSer.io_Actual = 0; read_io->IOSer.io_Command = CMD_READ; D(bug("serial_proc receiving %ld bytes from %08lx\n", read_io->IOSer.io_Length, read_io->IOSer.io_Data)); SendIO((struct IORequest *)read_io); break; case MSG_PRIME_OUT: { write_io->IOSer.io_Message.mn_Node.ln_Name = (char *)msg->pb; write_io->IOSer.io_Data = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); write_io->IOSer.io_Length = ReadMacInt32(msg->pb + ioReqCount); write_io->IOSer.io_Actual = 0; write_io->IOSer.io_Command = CMD_WRITE; D(bug("serial_proc transmitting %ld bytes from %08lx\n", write_io->IOSer.io_Length, write_io->IOSer.io_Data)); #if MONITOR bug("Sending serial data:\n"); uint8 *adr = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); for (int i=0; iIOSer.io_Actual, read_io->IOSer.io_Error)); uint32 pb = (uint32)read_io->IOSer.io_Message.mn_Node.ln_Name; #if MONITOR bug("Receiving serial data:\n"); uint8 *adr = Mac2HostAddr(ReadMacInt32(msg->pb + ioBuffer)); for (int i=0; iIOSer.io_Actual; i++) { bug("%02lx ", adr[i]); } bug("\n"); #endif WriteMacInt32(pb + ioActCount, read_io->IOSer.io_Actual); obj->conv_error(read_io, obj->input_dt); obj->read_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } else if (io == write_io) { D(bug("write_io complete, %ld bytes sent, error %ld\n", write_io->IOSer.io_Actual, write_io->IOSer.io_Error)); uint32 pb = (uint32)write_io->IOSer.io_Message.mn_Node.ln_Name; WriteMacInt32(pb + ioActCount, write_io->IOSer.io_Actual); obj->conv_error(write_io, obj->output_dt); obj->write_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } } } quit: // Close everything if (opened) { if (CheckIO((struct IORequest *)write_io) == 0) { AbortIO((struct IORequest *)write_io); WaitIO((struct IORequest *)write_io); } if (CheckIO((struct IORequest *)read_io) == 0) { AbortIO((struct IORequest *)read_io); WaitIO((struct IORequest *)read_io); } CloseDevice((struct IORequest *)read_io); } if (control_io) DeleteIORequest(control_io); if (write_io) DeleteIORequest(write_io); if (read_io) DeleteIORequest(read_io); if (control_port) DeleteMsgPort(control_port); if (io_port) DeleteMsgPort(io_port); // Send signal to main task to confirm termination Forbid(); Signal(MainTask, SIGF_SINGLE); } BasiliskII/src/AmigaOS/timer_amiga.cpp0000644000175000017500000000623310736405217020003 0ustar centriscentris/* * timer_amiga.cpp - Time Manager emulation, AmigaOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #define __USE_SYSBASE #include #include #include #include #include "sysdeps.h" #include "timer.h" #define DEBUG 0 #include "debug.h" /* * Return microseconds since boot (64 bit) */ void Microseconds(uint32 &hi, uint32 &lo) { D(bug("Microseconds\n")); struct timeval tv; GetSysTime(&tv); uint64 tl = (uint64)tv.tv_secs * 1000000 + tv.tv_micro; hi = tl >> 32; lo = tl; } /* * Return local date/time in Mac format (seconds since 1.1.1904) */ uint32 TimerDateTime(void) { ULONG secs, mics; CurrentTime(&secs, &mics); return secs + 0x8b31ef80; } /* * Get current time */ void timer_current_time(tm_time_t &t) { GetSysTime(&t); } /* * Add times */ void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b) { res = a; AddTime(&res, &b); } /* * Subtract times */ void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b) { res = a; SubTime(&res, &b); } /* * Compare times (<0: a < b, =0: a = b, >0: a > b) */ int timer_cmp_time(tm_time_t a, tm_time_t b) { return CmpTime(&b, &a); } /* * Convert Mac time value (>0: microseconds, <0: microseconds) to tm_time_t */ void timer_mac2host_time(tm_time_t &res, int32 mactime) { if (mactime > 0) { res.tv_secs = mactime / 1000; // Time in milliseconds res.tv_micro = (mactime % 1000) * 1000; } else { res.tv_secs = -mactime / 1000000; // Time in negative microseconds res.tv_micro = -mactime % 1000000; } } /* * Convert positive tm_time_t to Mac time value (>0: microseconds, <0: microseconds) * A negative input value for hosttime results in a zero return value * As long as the microseconds value fits in 32 bit, it must not be converted to milliseconds! */ int32 timer_host2mac_time(tm_time_t hosttime) { if (hosttime.tv_secs < 0) return 0; else { uint64 t = (uint64)hosttime.tv_secs * 1000000 + hosttime.tv_micro; if (t > 0x7fffffff) return t / 1000; // Time in milliseconds else return -t; // Time in negative microseconds } } /* * Suspend emulator thread, virtual CPU in idle mode */ void idle_wait(void) { // XXX if you implement this make sure to call idle_resume() from TriggerInterrupt() } /* * Resume execution of emulator thread, events just arrived */ void idle_resume(void) { } BasiliskII/src/AmigaOS/video_amiga.cpp0000644000175000017500000007252410736405217017777 0ustar centriscentris/* * video_amiga.cpp - Video/graphics emulation, AmigaOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #define __USE_SYSBASE #include #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "adb.h" #include "prefs.h" #include "user_strings.h" #include "video.h" #define DEBUG 0 #include "debug.h" // Supported video modes static vector VideoModes; // Display types enum { DISPLAY_WINDOW, DISPLAY_PIP, DISPLAY_SCREEN_P96, DISPLAY_SCREEN_CGFX }; // Global variables static int32 frame_skip; static UWORD *null_pointer = NULL; // Blank mouse pointer data static UWORD *current_pointer = (UWORD *)-1; // Currently visible mouse pointer data static struct Process *periodic_proc = NULL; // Periodic process extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp) // Amiga -> Mac raw keycode translation table static const uint8 keycode2mac[0x80] = { 0x0a, 0x12, 0x13, 0x14, 0x15, 0x17, 0x16, 0x1a, // ` 1 2 3 4 5 6 7 0x1c, 0x19, 0x1d, 0x1b, 0x18, 0x2a, 0xff, 0x52, // 8 9 0 - = \ inv 0 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x10, 0x20, 0x22, // Q W E R T Y U I 0x1f, 0x23, 0x21, 0x1e, 0xff, 0x53, 0x54, 0x55, // O P [ ] inv 1 2 3 0x00, 0x01, 0x02, 0x03, 0x05, 0x04, 0x26, 0x28, // A S D F G H J K 0x25, 0x29, 0x27, 0x2a, 0xff, 0x56, 0x57, 0x58, // L ; ' # inv 4 5 6 0x32, 0x06, 0x07, 0x08, 0x09, 0x0b, 0x2d, 0x2e, // < Z X C V B N M 0x2b, 0x2f, 0x2c, 0xff, 0x41, 0x59, 0x5b, 0x5c, // , . / inv . 7 8 9 0x31, 0x33, 0x30, 0x4c, 0x24, 0x35, 0x75, 0xff, // SPC BSP TAB ENT RET ESC DEL inv 0xff, 0xff, 0x4e, 0xff, 0x3e, 0x3d, 0x3c, 0x3b, // inv inv - inv CUP CDN CRT CLF 0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, 0x62, 0x64, // F1 F2 F3 F4 F5 F6 F7 F8 0x65, 0x6d, 0x47, 0x51, 0x4b, 0x43, 0x45, 0x72, // F9 F10 ( ) / * + HLP 0x38, 0x38, 0x39, 0x36, 0x3a, 0x3a, 0x37, 0x37, // SHL SHR CAP CTL ALL ALR AML AMR 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv }; class Amiga_monitor_desc : public monitor_desc { public: Amiga_monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id, int default_display_type) : monitor_desc(available_modes, default_depth, default_id), display_type(default_display_type) {}; ~Amiga_monitor_desc() {}; virtual void switch_to_current_mode(void); virtual void set_palette(uint8 *pal, int num); bool video_open(void); void video_close(void); public: int display_type; // See enum above }; /* * Display "driver" classes */ class driver_base { public: driver_base(Amiga_monitor_desc &m); virtual ~driver_base(); virtual void set_palette(uint8 *pal, int num) {}; virtual struct BitMap *get_bitmap() { return NULL; }; public: Amiga_monitor_desc &monitor; // Associated video monitor const video_mode &mode; // Video mode handled by the driver BOOL init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer) struct Window *the_win; }; class driver_window : public driver_base { public: driver_window(Amiga_monitor_desc &m, int width, int height); ~driver_window(); struct BitMap *get_bitmap() { return the_bitmap; }; private: LONG black_pen, white_pen; struct BitMap *the_bitmap; }; class driver_pip : public driver_base { public: driver_pip(Amiga_monitor_desc &m, int width, int height); ~driver_pip(); struct BitMap *get_bitmap() { return the_bitmap; }; private: struct BitMap *the_bitmap; }; class driver_screen_p96 : public driver_base { public: driver_screen_p96(Amiga_monitor_desc &m, ULONG mode_id); ~driver_screen_p96(); void set_palette(uint8 *pal, int num); private: struct Screen *the_screen; }; class driver_screen_cgfx : public driver_base { public: driver_screen_cgfx(Amiga_monitor_desc &m, ULONG mode_id); ~driver_screen_cgfx(); void set_palette(uint8 *pal, int num); private: struct Screen *the_screen; }; static driver_base *drv = NULL; // Pointer to currently used driver object // Prototypes static void periodic_func(void); static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth); static void add_modes(uint32 width, uint32 height, video_depth depth); static ULONG find_mode_for_depth(uint32 width, uint32 height, uint32 depth); static ULONG bits_from_depth(video_depth depth); static bool is_valid_modeid(int display_type, ULONG mode_id); static bool check_modeid_p96(ULONG mode_id); static bool check_modeid_cgfx(ULONG mode_id); /* * Initialization */ bool VideoInit(bool classic) { video_depth default_depth = VDEPTH_1BIT; int default_width, default_height; int default_display_type = DISPLAY_WINDOW; int window_width, window_height; // width and height for window display ULONG screen_mode_id; // mode ID for screen display // Allocate blank mouse pointer data null_pointer = (UWORD *)AllocMem(12, MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR); if (null_pointer == NULL) { ErrorAlert(STR_NO_MEM_ERR); return false; } // Read frame skip prefs frame_skip = PrefsFindInt32("frameskip"); if (frame_skip == 0) frame_skip = 1; // Get screen mode from preferences const char *mode_str; if (classic) mode_str = "win/512/342"; else mode_str = PrefsFindString("screen"); default_width = window_width = 512; default_height = window_height = 384; if (mode_str) { if (sscanf(mode_str, "win/%d/%d", &window_width, &window_height) == 2) default_display_type = DISPLAY_WINDOW; else if (sscanf(mode_str, "pip/%d/%d", &window_width, &window_height) == 2 && P96Base) default_display_type = DISPLAY_PIP; else if (sscanf(mode_str, "scr/%08lx", &screen_mode_id) == 1 && (CyberGfxBase || P96Base)) { if (P96Base && p96GetModeIDAttr(screen_mode_id, P96IDA_ISP96)) default_display_type = DISPLAY_SCREEN_P96; else if (CyberGfxBase && IsCyberModeID(screen_mode_id)) default_display_type = DISPLAY_SCREEN_CGFX; else { ErrorAlert(STR_NO_P96_MODE_ERR); return false; } } } D(bug("default_display_type %d, window_width %d, window_height %d\n", default_display_type, window_width, window_height)); // Construct list of supported modes switch (default_display_type) { case DISPLAY_WINDOW: default_width = window_width; default_height = window_height; default_depth = VDEPTH_1BIT; add_modes(window_width, window_height, VDEPTH_1BIT); break; case DISPLAY_PIP: default_width = window_width; default_height = window_height; default_depth = VDEPTH_16BIT; add_modes(window_width, window_height, VDEPTH_16BIT); break; case DISPLAY_SCREEN_P96: case DISPLAY_SCREEN_CGFX: struct DimensionInfo dimInfo; DisplayInfoHandle handle = FindDisplayInfo(screen_mode_id); if (handle == NULL) return false; if (GetDisplayInfoData(handle, (UBYTE *) &dimInfo, sizeof(dimInfo), DTAG_DIMS, 0) <= 0) return false; default_width = 1 + dimInfo.Nominal.MaxX - dimInfo.Nominal.MinX; default_height = 1 + dimInfo.Nominal.MaxY - dimInfo.Nominal.MinY; switch (dimInfo.MaxDepth) { case 1: default_depth = VDEPTH_1BIT; break; case 8: default_depth = VDEPTH_8BIT; break; case 15: case 16: default_depth = VDEPTH_16BIT; break; case 24: case 32: default_depth = VDEPTH_32BIT; break; } for (unsigned d=VDEPTH_8BIT; d<=VDEPTH_32BIT; d++) { ULONG mode_id = find_mode_for_depth(default_width, default_height, bits_from_depth(video_depth(d))); if (is_valid_modeid(default_display_type, mode_id)) add_modes(default_width, default_height, video_depth(d)); } break; } #if DEBUG bug("Available video modes:\n"); vector::const_iterator i = VideoModes.begin(), end = VideoModes.end(); while (i != end) { bug(" %ld x %ld (ID %02lx), %ld colors\n", i->x, i->y, i->resolution_id, 1 << bits_from_depth(i->depth)); ++i; } #endif D(bug("VideoInit/%ld: def_width=%ld def_height=%ld def_depth=%ld\n", \ __LINE__, default_width, default_height, default_depth)); // Find requested default mode and open display if (VideoModes.size() == 1) { uint32 default_id ; // Create Amiga_monitor_desc for this (the only) display default_id = VideoModes[0].resolution_id; D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id)); Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type); VideoMonitors.push_back(monitor); // Open display return monitor->video_open(); } else { // Find mode with specified dimensions std::vector::const_iterator i, end = VideoModes.end(); for (i = VideoModes.begin(); i != end; ++i) { D(bug("VideoInit/%ld: w=%ld h=%ld d=%ld\n", __LINE__, i->x, i->y, bits_from_depth(i->depth))); if (i->x == default_width && i->y == default_height && i->depth == default_depth) { // Create Amiga_monitor_desc for this (the only) display uint32 default_id = i->resolution_id; D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id)); Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type); VideoMonitors.push_back(monitor); // Open display return monitor->video_open(); } } // Create Amiga_monitor_desc for this (the only) display uint32 default_id = VideoModes[0].resolution_id; D(bug("VideoInit/%ld: default_id=%ld\n", __LINE__, default_id)); Amiga_monitor_desc *monitor = new Amiga_monitor_desc(VideoModes, default_depth, default_id, default_display_type); VideoMonitors.push_back(monitor); // Open display return monitor->video_open(); } return true; } bool Amiga_monitor_desc::video_open() { const video_mode &mode = get_current_mode(); ULONG depth_bits = bits_from_depth(mode.depth); ULONG ID = find_mode_for_depth(mode.x, mode.y, depth_bits); D(bug("video_open/%ld: width=%ld height=%ld depth=%ld ID=%08lx\n", __LINE__, mode.x, mode.y, depth_bits, ID)); if (ID == INVALID_ID) { ErrorAlert(STR_NO_VIDEO_MODE_ERR); return false; } D(bug("video_open/%ld: display_type=%ld\n", __LINE__, display_type)); // Open display switch (display_type) { case DISPLAY_WINDOW: drv = new driver_window(*this, mode.x, mode.y); break; case DISPLAY_PIP: drv = new driver_pip(*this, mode.x, mode.y); break; case DISPLAY_SCREEN_P96: drv = new driver_screen_p96(*this, ID); break; case DISPLAY_SCREEN_CGFX: drv = new driver_screen_cgfx(*this, ID); break; } D(bug("video_open/%ld: drv=%08lx\n", __LINE__, drv)); if (drv == NULL) return false; D(bug("video_open/%ld: init_ok=%ld\n", __LINE__, drv->init_ok)); if (!drv->init_ok) { delete drv; drv = NULL; return false; } // Start periodic process periodic_proc = CreateNewProcTags( NP_Entry, (ULONG)periodic_func, NP_Name, (ULONG)"Basilisk II IDCMP Handler", NP_Priority, 0, TAG_END ); D(bug("video_open/%ld: periodic_proc=%08lx\n", __LINE__, periodic_proc)); if (periodic_proc == NULL) { ErrorAlert(STR_NO_MEM_ERR); return false; } return true; } void Amiga_monitor_desc::video_close() { // Stop periodic process if (periodic_proc) { SetSignal(0, SIGF_SINGLE); Signal(&periodic_proc->pr_Task, SIGBREAKF_CTRL_C); Wait(SIGF_SINGLE); } delete drv; drv = NULL; // Free mouse pointer if (null_pointer) { FreeMem(null_pointer, 12); null_pointer = NULL; } } /* * Deinitialization */ void VideoExit(void) { // Close displays vector::iterator i, end = VideoMonitors.end(); for (i = VideoMonitors.begin(); i != end; ++i) dynamic_cast(*i)->video_close(); } /* * Set palette */ void Amiga_monitor_desc::set_palette(uint8 *pal, int num) { drv->set_palette(pal, num); } /* * Switch video mode */ void Amiga_monitor_desc::switch_to_current_mode() { // Close and reopen display video_close(); if (!video_open()) { ErrorAlert(STR_OPEN_WINDOW_ERR); QuitEmulator(); } } /* * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode) */ void VideoQuitFullScreen(void) { } /* * Video message handling (not neccessary under AmigaOS, handled by periodic_func()) */ void VideoInterrupt(void) { } /* * Process for window refresh and message handling */ static __saveds void periodic_func(void) { struct MsgPort *timer_port = NULL; struct timerequest *timer_io = NULL; struct IntuiMessage *msg; ULONG win_mask = 0, timer_mask = 0; D(bug("periodic_func/%ld: \n", __LINE__)); // Create message port for window and attach it struct MsgPort *win_port = CreateMsgPort(); if (win_port) { win_mask = 1 << win_port->mp_SigBit; drv->the_win->UserPort = win_port; ModifyIDCMP(drv->the_win, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_RAWKEY | ((drv->monitor.display_type == DISPLAY_SCREEN_P96 || drv->monitor.display_type == DISPLAY_SCREEN_CGFX) ? IDCMP_DELTAMOVE : 0)); } D(bug("periodic_func/%ld: \n", __LINE__)); // Start 60Hz timer for window refresh if (drv->monitor.display_type == DISPLAY_WINDOW) { timer_port = CreateMsgPort(); if (timer_port) { timer_io = (struct timerequest *)CreateIORequest(timer_port, sizeof(struct timerequest)); if (timer_io) { if (!OpenDevice((UBYTE *) TIMERNAME, UNIT_MICROHZ, (struct IORequest *)timer_io, 0)) { timer_mask = 1 << timer_port->mp_SigBit; timer_io->tr_node.io_Command = TR_ADDREQUEST; timer_io->tr_time.tv_secs = 0; timer_io->tr_time.tv_micro = 16667 * frame_skip; SendIO((struct IORequest *)timer_io); } } } } D(bug("periodic_func/%ld: \n", __LINE__)); // Main loop for (;;) { const video_mode &mode = drv->monitor.get_current_mode(); // Wait for timer and/or window (CTRL_C is used for quitting the task) ULONG sig = Wait(win_mask | timer_mask | SIGBREAKF_CTRL_C); if (sig & SIGBREAKF_CTRL_C) break; // D(bug("periodic_func/%ld: display_type=%ld the_win=%08lx\n", __LINE__, drv->monitor.display_type, drv->the_win)); if (sig & timer_mask) { if (drv->get_bitmap()) { // Timer tick, update display BltTemplate(drv->get_bitmap()->Planes[0], 0, drv->get_bitmap()->BytesPerRow, drv->the_win->RPort, drv->the_win->BorderLeft, drv->the_win->BorderTop, mode.x, mode.y); } // Restart timer timer_io->tr_node.io_Command = TR_ADDREQUEST; timer_io->tr_time.tv_secs = 0; timer_io->tr_time.tv_micro = 16667 * frame_skip; SendIO((struct IORequest *)timer_io); } if (sig & win_mask) { // Handle window messages while (msg = (struct IntuiMessage *)GetMsg(win_port)) { // Get data from message and reply ULONG cl = msg->Class; UWORD code = msg->Code; UWORD qualifier = msg->Qualifier; WORD mx = msg->MouseX; WORD my = msg->MouseY; ReplyMsg((struct Message *)msg); // Handle message according to class switch (cl) { case IDCMP_MOUSEMOVE: switch (drv->monitor.display_type) { case DISPLAY_SCREEN_P96: case DISPLAY_SCREEN_CGFX: // D(bug("periodic_func/%ld: IDCMP_MOUSEMOVE mx=%ld my=%ld\n", __LINE__, mx, my)); ADBMouseMoved(mx, my); break; default: // D(bug("periodic_func/%ld: IDCMP_MOUSEMOVE mx=%ld my=%ld\n", __LINE__, mx - drv->the_win->BorderLeft, my - drv->the_win->BorderTop)); ADBMouseMoved(mx - drv->the_win->BorderLeft, my - drv->the_win->BorderTop); if (mx < drv->the_win->BorderLeft || my < drv->the_win->BorderTop || mx >= drv->the_win->BorderLeft + mode.x || my >= drv->the_win->BorderTop + mode.y) { if (current_pointer) { ClearPointer(drv->the_win); current_pointer = NULL; } } else { if (current_pointer != null_pointer) { // Hide mouse pointer inside window SetPointer(drv->the_win, null_pointer, 1, 16, 0, 0); current_pointer = null_pointer; } } break; } break; case IDCMP_MOUSEBUTTONS: if (code == SELECTDOWN) ADBMouseDown(0); else if (code == SELECTUP) ADBMouseUp(0); else if (code == MENUDOWN) ADBMouseDown(1); else if (code == MENUUP) ADBMouseUp(1); else if (code == MIDDLEDOWN) ADBMouseDown(2); else if (code == MIDDLEUP) ADBMouseUp(2); break; case IDCMP_RAWKEY: if (qualifier & IEQUALIFIER_REPEAT) // Keyboard repeat is done by MacOS break; if ((qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL)) == (IEQUALIFIER_LALT | IEQUALIFIER_LSHIFT | IEQUALIFIER_CONTROL) && code == 0x5f) { SetInterruptFlag(INTFLAG_NMI); TriggerInterrupt(); break; } if (code & IECODE_UP_PREFIX) ADBKeyUp(keycode2mac[code & 0x7f]); else ADBKeyDown(keycode2mac[code & 0x7f]); break; } } } } D(bug("periodic_func/%ld: \n", __LINE__)); // Stop timer if (timer_io) { if (!CheckIO((struct IORequest *)timer_io)) AbortIO((struct IORequest *)timer_io); WaitIO((struct IORequest *)timer_io); CloseDevice((struct IORequest *)timer_io); DeleteIORequest(timer_io); } if (timer_port) DeleteMsgPort(timer_port); // Remove port from window and delete it Forbid(); msg = (struct IntuiMessage *)win_port->mp_MsgList.lh_Head; struct Node *succ; while (succ = msg->ExecMessage.mn_Node.ln_Succ) { if (msg->IDCMPWindow == drv->the_win) { Remove((struct Node *)msg); ReplyMsg((struct Message *)msg); } msg = (struct IntuiMessage *)succ; } drv->the_win->UserPort = NULL; ModifyIDCMP(drv->the_win, 0); Permit(); DeleteMsgPort(win_port); // Main task asked for termination, send signal Forbid(); Signal(MainTask, SIGF_SINGLE); } // Add mode to list of supported modes static void add_mode(uint32 width, uint32 height, uint32 resolution_id, uint32 bytes_per_row, video_depth depth) { video_mode mode; mode.x = width; mode.y = height; mode.resolution_id = resolution_id; mode.bytes_per_row = bytes_per_row; mode.depth = depth; D(bug("Added video mode: w=%ld h=%ld d=%ld\n", width, height, depth)); VideoModes.push_back(mode); } // Add standard list of modes for given color depth static void add_modes(uint32 width, uint32 height, video_depth depth) { D(bug("add_modes: w=%ld h=%ld d=%ld\n", width, height, depth)); if (width >= 512 && height >= 384) add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), depth); if (width >= 640 && height >= 480) add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), depth); if (width >= 800 && height >= 600) add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), depth); if (width >= 1024 && height >= 768) add_mode(1024, 768, 0x83, TrivialBytesPerRow(1024, depth), depth); if (width >= 1152 && height >= 870) add_mode(1152, 870, 0x84, TrivialBytesPerRow(1152, depth), depth); if (width >= 1280 && height >= 1024) add_mode(1280, 1024, 0x85, TrivialBytesPerRow(1280, depth), depth); if (width >= 1600 && height >= 1200) add_mode(1600, 1200, 0x86, TrivialBytesPerRow(1600, depth), depth); } static ULONG find_mode_for_depth(uint32 width, uint32 height, uint32 depth) { ULONG ID = BestModeID(BIDTAG_NominalWidth, width, BIDTAG_NominalHeight, height, BIDTAG_Depth, depth, BIDTAG_DIPFMustNotHave, DIPF_IS_ECS | DIPF_IS_HAM | DIPF_IS_AA, TAG_END); return ID; } static ULONG bits_from_depth(video_depth depth) { int bits = 1 << depth; if (bits == 16) bits = 15; else if (bits == 32) bits = 24; return bits; } static bool is_valid_modeid(int display_type, ULONG mode_id) { if (INVALID_ID == mode_id) return false; switch (display_type) { case DISPLAY_SCREEN_P96: return check_modeid_p96(mode_id); break; case DISPLAY_SCREEN_CGFX: return check_modeid_cgfx(mode_id); break; default: return false; break; } } static bool check_modeid_p96(ULONG mode_id) { // Check if the mode is one we can handle uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH); uint32 format = p96GetModeIDAttr(mode_id, P96IDA_RGBFORMAT); D(bug("check_modeid_p96: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format)); if (!p96GetModeIDAttr(mode_id, P96IDA_ISP96)) return false; switch (depth) { case 8: break; case 15: case 16: if (format != RGBFB_R5G5B5) return false; break; case 24: case 32: if (format != RGBFB_A8R8G8B8) return false; break; default: return false; } return true; } static bool check_modeid_cgfx(ULONG mode_id) { uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id); uint32 format = GetCyberIDAttr(CYBRIDATTR_PIXFMT, mode_id); D(bug("check_modeid_cgfx: mode_id=%08lx depth=%ld format=%ld\n", mode_id, depth, format)); if (!IsCyberModeID(mode_id)) return false; switch (depth) { case 8: break; case 15: case 16: if (format != PIXFMT_RGB15) return false; break; case 24: case 32: if (format != PIXFMT_ARGB32) return false; break; default: return false; } return true; } driver_base::driver_base(Amiga_monitor_desc &m) : monitor(m), mode(m.get_current_mode()), init_ok(false) { } driver_base::~driver_base() { } // Open window driver_window::driver_window(Amiga_monitor_desc &m, int width, int height) : black_pen(-1), white_pen(-1), driver_base(m) { // Set absolute mouse mode ADBSetRelMouseMode(false); // Open window the_win = OpenWindowTags(NULL, WA_Left, 0, WA_Top, 0, WA_InnerWidth, width, WA_InnerHeight, height, WA_SimpleRefresh, true, WA_NoCareRefresh, true, WA_Activate, true, WA_RMBTrap, true, WA_ReportMouse, true, WA_DragBar, true, WA_DepthGadget, true, WA_SizeGadget, false, WA_Title, (ULONG)GetString(STR_WINDOW_TITLE), TAG_END ); if (the_win == NULL) { init_ok = false; ErrorAlert(STR_OPEN_WINDOW_ERR); return; } // Create bitmap ("height + 2" for safety) the_bitmap = AllocBitMap(width, height + 2, 1, BMF_CLEAR, NULL); if (the_bitmap == NULL) { init_ok = false; ErrorAlert(STR_NO_MEM_ERR); return; } // Add resolution and set VideoMonitor monitor.set_mac_frame_base((uint32)the_bitmap->Planes[0]); // Set FgPen and BgPen black_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0, 0, 0, NULL); white_pen = ObtainBestPenA(the_win->WScreen->ViewPort.ColorMap, 0xffffffff, 0xffffffff, 0xffffffff, NULL); SetAPen(the_win->RPort, black_pen); SetBPen(the_win->RPort, white_pen); SetDrMd(the_win->RPort, JAM2); init_ok = true; } driver_window::~driver_window() { // Window mode, free bitmap if (the_bitmap) { WaitBlit(); FreeBitMap(the_bitmap); } // Free pens and close window if (the_win) { ReleasePen(the_win->WScreen->ViewPort.ColorMap, black_pen); ReleasePen(the_win->WScreen->ViewPort.ColorMap, white_pen); CloseWindow(the_win); the_win = NULL; } } // Open PIP (requires Picasso96) driver_pip::driver_pip(Amiga_monitor_desc &m, int width, int height) : driver_base(m) { // Set absolute mouse mode ADBSetRelMouseMode(false); D(bug("driver_pip(%d,%d)\n", width, height)); // Open window ULONG error = 0; the_win = p96PIP_OpenTags( P96PIP_SourceFormat, RGBFB_R5G5B5, P96PIP_SourceWidth, width, P96PIP_SourceHeight, height, P96PIP_ErrorCode, (ULONG)&error, P96PIP_AllowCropping, true, WA_Left, 0, WA_Top, 0, WA_InnerWidth, width, WA_InnerHeight, height, WA_SimpleRefresh, true, WA_NoCareRefresh, true, WA_Activate, true, WA_RMBTrap, true, WA_ReportMouse, true, WA_DragBar, true, WA_DepthGadget, true, WA_SizeGadget, false, WA_Title, (ULONG)GetString(STR_WINDOW_TITLE), WA_PubScreenName, (ULONG)"Workbench", TAG_END ); if (the_win == NULL || error) { init_ok = false; ErrorAlert(STR_OPEN_WINDOW_ERR); return; } // Find bitmap p96PIP_GetTags(the_win, P96PIP_SourceBitMap, (ULONG)&the_bitmap, TAG_END); // Add resolution and set VideoMonitor monitor.set_mac_frame_base(p96GetBitMapAttr(the_bitmap, P96BMA_MEMORY)); init_ok = true; } driver_pip::~driver_pip() { // Close PIP if (the_win) p96PIP_Close(the_win); } // Open Picasso96 screen driver_screen_p96::driver_screen_p96(Amiga_monitor_desc &m, ULONG mode_id) : driver_base(m) { // Set relative mouse mode ADBSetRelMouseMode(true); // Check if the mode is one we can handle if (!check_modeid_p96(mode_id)) { init_ok = false; ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR); return; } // Yes, get width and height uint32 depth = p96GetModeIDAttr(mode_id, P96IDA_DEPTH); uint32 width = p96GetModeIDAttr(mode_id, P96IDA_WIDTH); uint32 height = p96GetModeIDAttr(mode_id, P96IDA_HEIGHT); // Open screen the_screen = p96OpenScreenTags( P96SA_DisplayID, mode_id, P96SA_Title, (ULONG)GetString(STR_WINDOW_TITLE), P96SA_Quiet, true, P96SA_NoMemory, true, P96SA_NoSprite, true, P96SA_Exclusive, true, TAG_END ); if (the_screen == NULL) { ErrorAlert(STR_OPEN_SCREEN_ERR); init_ok = false; return; } // Open window the_win = OpenWindowTags(NULL, WA_Left, 0, WA_Top, 0, WA_Width, width, WA_Height, height, WA_SimpleRefresh, true, WA_NoCareRefresh, true, WA_Borderless, true, WA_Activate, true, WA_RMBTrap, true, WA_ReportMouse, true, WA_CustomScreen, (ULONG)the_screen, TAG_END ); if (the_win == NULL) { ErrorAlert(STR_OPEN_WINDOW_ERR); init_ok = false; return; } ScreenToFront(the_screen); // Add resolution and set VideoMonitor monitor.set_mac_frame_base(p96GetBitMapAttr(the_screen->RastPort.BitMap, P96BMA_MEMORY)); init_ok = true; } driver_screen_p96::~driver_screen_p96() { // Close window if (the_win) { CloseWindow(the_win); the_win = NULL; } // Close screen if (the_screen) { p96CloseScreen(the_screen); the_screen = NULL; } } void driver_screen_p96::set_palette(uint8 *pal, int num) { // Convert palette to 32 bits ULONG table[2 + 256 * 3]; table[0] = num << 16; table[num * 3 + 1] = 0; for (int i=0; iViewPort, table); } // Open CyberGraphX screen driver_screen_cgfx::driver_screen_cgfx(Amiga_monitor_desc &m, ULONG mode_id) : driver_base(m) { D(bug("driver_screen_cgfx/%ld: mode_id=%08lx\n", __LINE__, mode_id)); // Set absolute mouse mode ADBSetRelMouseMode(true); // Check if the mode is one we can handle if (!check_modeid_cgfx(mode_id)) { ErrorAlert(STR_WRONG_SCREEN_FORMAT_ERR); init_ok = false; return; } // Yes, get width and height uint32 depth = GetCyberIDAttr(CYBRIDATTR_DEPTH, mode_id); uint32 width = GetCyberIDAttr(CYBRIDATTR_WIDTH, mode_id); uint32 height = GetCyberIDAttr(CYBRIDATTR_HEIGHT, mode_id); // Open screen the_screen = OpenScreenTags(NULL, SA_DisplayID, mode_id, SA_Title, (ULONG)GetString(STR_WINDOW_TITLE), SA_Quiet, true, SA_Exclusive, true, TAG_END ); if (the_screen == NULL) { ErrorAlert(STR_OPEN_SCREEN_ERR); init_ok = false; return; } // Open window the_win = OpenWindowTags(NULL, WA_Left, 0, WA_Top, 0, WA_Width, width, WA_Height, height, WA_SimpleRefresh, true, WA_NoCareRefresh, true, WA_Borderless, true, WA_Activate, true, WA_RMBTrap, true, WA_ReportMouse, true, WA_CustomScreen, (ULONG)the_screen, TAG_END ); if (the_win == NULL) { ErrorAlert(STR_OPEN_WINDOW_ERR); init_ok = false; return; } ScreenToFront(the_screen); static UWORD ptr[] = { 0, 0, 0, 0 }; SetPointer(the_win, ptr, 0, 0, 0, 0); // Hide mouse pointer // Set VideoMonitor ULONG frame_base; APTR handle = LockBitMapTags(the_screen->RastPort.BitMap, LBMI_BASEADDRESS, (ULONG)&frame_base, TAG_END ); UnLockBitMap(handle); D(bug("driver_screen_cgfx/%ld: frame_base=%08lx\n", __LINE__, frame_base)); monitor.set_mac_frame_base(frame_base); init_ok = true; } driver_screen_cgfx::~driver_screen_cgfx() { D(bug("~driver_screen_cgfx/%ld: \n", __LINE__)); // Close window if (the_win) { CloseWindow(the_win); the_win = NULL; } // Close screen if (the_screen) { CloseScreen(the_screen); the_screen = NULL; } } void driver_screen_cgfx::set_palette(uint8 *pal, int num) { // Convert palette to 32 bits ULONG table[2 + 256 * 3]; table[0] = num << 16; table[num * 3 + 1] = 0; for (int i=0; iViewPort, table); } BasiliskII/src/AmigaOS/audio_amiga.cpp0000644000175000017500000003277610736405217017777 0ustar centriscentris/* * audio_amiga.cpp - Audio support, AmigaOS implementation using AHI * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #define __USE_SYSBASE #include #include #include #include #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "audio.h" #include "audio_defs.h" #define DEBUG 0 #include "debug.h" #define D1(x) ; // Global variables static ULONG ahi_id = AHI_DEFAULT_ID; // AHI audio ID static struct AHIAudioCtrl *ahi_ctrl = NULL; static struct AHISampleInfo sample[2]; // Two sample infos for double-buffering static struct Hook sf_hook; static int play_buf = 0; // Number of currently played buffer static long sound_buffer_size; // Size of one audio buffer in bytes static int audio_block_fetched = 0; // Number of audio blocks fetched by interrupt routine static bool main_mute = false; static bool speaker_mute = false; static ULONG supports_volume_changes = false; static ULONG supports_stereo_panning = false; static ULONG current_main_volume; static ULONG current_speaker_volume; // Prototypes static __saveds __attribute__((regparm(3))) ULONG audio_callback(struct Hook *hook /*a0*/, struct AHISoundMessage *msg /*a1*/, struct AHIAudioCtrl *ahi_ctrl /*a2*/); void audio_set_sample_rate_byval(uint32 value); void audio_set_sample_size_byval(uint32 value); void audio_set_channels_byval(uint32 value); /* * Initialization */ // Set AudioStatus to reflect current audio stream format static void set_audio_status_format(int sample_rate_index) { AudioStatus.sample_rate = audio_sample_rates[sample_rate_index]; AudioStatus.sample_size = audio_sample_sizes[0]; AudioStatus.channels = audio_channel_counts[0]; } void AudioInit(void) { sample[0].ahisi_Address = sample[1].ahisi_Address = NULL; // Init audio status and feature flags audio_channel_counts.push_back(2); // set_audio_status_format(); AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; // AHI available? if (AHIBase == NULL) { WarningAlert(GetString(STR_NO_AHI_WARN)); return; } // Initialize callback hook sf_hook.h_Entry = (HOOKFUNC)audio_callback; // Read "sound" preferences const char *str = PrefsFindString("sound"); if (str) sscanf(str, "ahi/%08lx", &ahi_id); // Open audio control structure if ((ahi_ctrl = AHI_AllocAudio( AHIA_AudioID, ahi_id, AHIA_MixFreq, AudioStatus.sample_rate >> 16, AHIA_Channels, 1, AHIA_Sounds, 2, AHIA_SoundFunc, (ULONG)&sf_hook, TAG_END)) == NULL) { WarningAlert(GetString(STR_NO_AHI_CTRL_WARN)); return; } ULONG max_channels, sample_rate, frequencies, sample_rate_index; AHI_GetAudioAttrs(ahi_id, ahi_ctrl, AHIDB_MaxChannels, (ULONG) &max_channels, AHIDB_Frequencies, (ULONG) &frequencies, TAG_END); D(bug("AudioInit: max_channels=%ld frequencies=%ld\n", max_channels, frequencies)); for (int n=0; n> 3) * AudioStatus.channels * audio_frames_per_block; // Prepare SampleInfos and load sounds (two sounds for double buffering) sample[0].ahisi_Type = AudioStatus.sample_size == 16 ? AHIST_S16S : AHIST_S8S; sample[0].ahisi_Length = audio_frames_per_block; sample[0].ahisi_Address = AllocVec(sound_buffer_size, MEMF_PUBLIC | MEMF_CLEAR); sample[1].ahisi_Type = AudioStatus.sample_size == 16 ? AHIST_S16S : AHIST_S8S; sample[1].ahisi_Length = audio_frames_per_block; sample[1].ahisi_Address = AllocVec(sound_buffer_size, MEMF_PUBLIC | MEMF_CLEAR); if (sample[0].ahisi_Address == NULL || sample[1].ahisi_Address == NULL) return; AHI_LoadSound(0, AHIST_DYNAMICSAMPLE, &sample[0], ahi_ctrl); AHI_LoadSound(1, AHIST_DYNAMICSAMPLE, &sample[1], ahi_ctrl); // Set parameters play_buf = 0; current_main_volume = current_speaker_volume = 0x10000; AHI_SetVol(0, current_speaker_volume, 0x8000, ahi_ctrl, AHISF_IMM); AHI_SetFreq(0, AudioStatus.sample_rate >> 16, ahi_ctrl, AHISF_IMM); AHI_SetSound(0, play_buf, 0, 0, ahi_ctrl, AHISF_IMM); // Everything OK audio_open = true; } /* * Deinitialization */ void AudioExit(void) { // Free everything if (ahi_ctrl != NULL) { AHI_ControlAudio(ahi_ctrl, AHIC_Play, FALSE, TAG_END); AHI_FreeAudio(ahi_ctrl); } FreeVec(sample[0].ahisi_Address); FreeVec(sample[1].ahisi_Address); } /* * First source added, start audio stream */ void audio_enter_stream() { AHI_ControlAudio(ahi_ctrl, AHIC_Play, TRUE, TAG_END); } /* * Last source removed, stop audio stream */ void audio_exit_stream() { AHI_ControlAudio(ahi_ctrl, AHIC_Play, FALSE, TAG_END); } /* * AHI sound callback, request next buffer */ static __saveds __attribute__((regparm(3))) ULONG audio_callback(struct Hook *hook /*a0*/, struct AHISoundMessage *msg /*a1*/, struct AHIAudioCtrl *ahi_ctrl /*a2*/) { play_buf ^= 1; // New buffer available? if (audio_block_fetched) { audio_block_fetched--; if (main_mute || speaker_mute) { memset(sample[play_buf].ahisi_Address, 0, sound_buffer_size); } else { // Get size of audio data uint32 apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); if (apple_stream_info) { int32 sample_count = ReadMacInt32(apple_stream_info + scd_sampleCount); uint32 num_channels = ReadMacInt16(apple_stream_info + scd_numChannels); uint32 sample_size = ReadMacInt16(apple_stream_info + scd_sampleSize); uint32 sample_rate = ReadMacInt32(apple_stream_info + scd_sampleRate); D(bug("stream: sample_count=%ld num_channels=%ld sample_size=%ld sample_rate=%ld\n", sample_count, num_channels, sample_size, sample_rate >> 16)); // Yes, this can happen. if(sample_count != 0) { if(sample_rate != AudioStatus.sample_rate) { audio_set_sample_rate_byval(sample_rate); } if(num_channels != AudioStatus.channels) { audio_set_channels_byval(num_channels); } if(sample_size != AudioStatus.sample_size) { audio_set_sample_size_byval(sample_size); } } if (sample_count < 0) sample_count = 0; int work_size = sample_count * num_channels * (sample_size>>3); D(bug("stream: work_size=%ld sound_buffer_size=%ld\n", work_size, sound_buffer_size)); if (work_size > sound_buffer_size) work_size = sound_buffer_size; // Put data into AHI buffer (convert 8-bit data unsigned->signed) if (AudioStatus.sample_size == 16) Mac2Host_memcpy(sample[play_buf].ahisi_Address, ReadMacInt32(apple_stream_info + scd_buffer), work_size); else { uint32 *p = (uint32 *)Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)); uint32 *q = (uint32 *)sample[play_buf].ahisi_Address; int r = work_size >> 2; while (r--) *q++ = *p++ ^ 0x80808080; } if (work_size != sound_buffer_size) memset((uint8 *)sample[play_buf].ahisi_Address + work_size, 0, sound_buffer_size - work_size); } } } else memset(sample[play_buf].ahisi_Address, 0, sound_buffer_size); // Play next buffer AHI_SetSound(0, play_buf, 0, 0, ahi_ctrl, 0); // Trigger audio interrupt to get new buffer if (AudioStatus.num_sources) { D1(bug("stream: triggering irq\n")); SetInterruptFlag(INTFLAG_AUDIO); TriggerInterrupt(); } return 0; } /* * MacOS audio interrupt, read next data block */ void AudioInterrupt(void) { D1(bug("AudioInterrupt\n")); // Get data from apple mixer if (AudioStatus.mixer) { M68kRegisters r; r.a[0] = audio_data + adatStreamInfo; r.a[1] = AudioStatus.mixer; Execute68k(audio_data + adatGetSourceData, &r); D1(bug(" GetSourceData() returns %08lx\n", r.d[0])); } else WriteMacInt32(audio_data + adatStreamInfo, 0); // Signal stream function audio_block_fetched++; D1(bug("AudioInterrupt done\n")); } /* * Set sampling parameters * "index" is an index into the audio_sample_rates[] etc. arrays * It is guaranteed that AudioStatus.num_sources == 0 */ void audio_set_sample_rate_byval(uint32 value) { bool changed = (AudioStatus.sample_rate != value); if(changed) { ULONG sample_rate_index; // get index of sample rate closest to Hz AHI_GetAudioAttrs(ahi_id, ahi_ctrl, AHIDB_IndexArg, value >> 16, AHIDB_Index, (ULONG) &sample_rate_index, TAG_END); D(bug(" audio_set_sample_rate_byval requested rate=%ld Hz\n", value >> 16)); AudioStatus.sample_rate = audio_sample_rates[sample_rate_index]; AHI_SetFreq(0, AudioStatus.sample_rate >> 16, ahi_ctrl, 0); } D(bug(" audio_set_sample_rate_byval rate=%ld Hz\n", AudioStatus.sample_rate >> 16)); } void audio_set_sample_size_byval(uint32 value) { bool changed = (AudioStatus.sample_size != value); if(changed) { // AudioStatus.sample_size = value; // update_sound_parameters(); // WritePrivateProfileInt( "Audio", "SampleSize", AudioStatus.sample_size, ini_file_name ); } D(bug(" audio_set_sample_size_byval %d\n", AudioStatus.sample_size)); } void audio_set_channels_byval(uint32 value) { bool changed = (AudioStatus.channels != value); if(changed) { // AudioStatus.channels = value; // update_sound_parameters(); // WritePrivateProfileInt( "Audio", "Channels", AudioStatus.channels, ini_file_name ); } D(bug(" audio_set_channels_byval %d\n", AudioStatus.channels)); } bool audio_set_sample_rate(int index) { if(index >= 0 && index < audio_sample_rates.size() ) { audio_set_sample_rate_byval( audio_sample_rates[index] ); D(bug(" audio_set_sample_rate index=%ld rate=%ld\n", index, AudioStatus.sample_rate >> 16)); } return true; } bool audio_set_sample_size(int index) { if(index >= 0 && index < audio_sample_sizes.size() ) { audio_set_sample_size_byval( audio_sample_sizes[index] ); D(bug(" audio_set_sample_size %d,%d\n", index,AudioStatus.sample_size)); } return true; } bool audio_set_channels(int index) { if(index >= 0 && index < audio_channel_counts.size() ) { audio_set_channels_byval( audio_channel_counts[index] ); D(bug(" audio_set_channels %d,%d\n", index,AudioStatus.channels)); } return true; } /* * Get/set volume controls (volume values received/returned have the left channel * volume in the upper 16 bits and the right channel volume in the lower 16 bits; * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume")) */ bool audio_get_main_mute(void) { D(bug("audio_get_main_mute: mute=%ld\n", main_mute)); return main_mute; } uint32 audio_get_main_volume(void) { D(bug("audio_get_main_volume\n")); ULONG volume = current_main_volume >> 8; // 0x10000 => 0x100 D(bug("audio_get_main_volume: volume=%08lx\n", volume)); return (volume << 16) + volume; return 0x01000100; } bool audio_get_speaker_mute(void) { D(bug("audio_get_speaker_mute: mute=%ld\n", speaker_mute)); return speaker_mute; } uint32 audio_get_speaker_volume(void) { D(bug("audio_get_speaker_volume: \n")); if (audio_open) { ULONG volume = current_speaker_volume >> 8; // 0x10000 => 0x100 D(bug("audio_get_speaker_volume: volume=%08lx\n", volume)); return (volume << 16) + volume; } return 0x01000100; } void audio_set_main_mute(bool mute) { D(bug("audio_set_main_mute: mute=%ld\n", mute)); if (mute != main_mute) { main_mute = mute; } } void audio_set_main_volume(uint32 vol) { D(bug("audio_set_main_volume: vol=%08lx\n", vol)); if (audio_open && supports_volume_changes) { ULONG volume = 0x80 * ((vol >> 16) + (vol & 0xffff)); D(bug("audio_set_main_volume: volume=%08lx\n", volume)); current_main_volume = volume; AHI_SetVol(0, volume, 0x8000, ahi_ctrl, AHISF_IMM); } } void audio_set_speaker_mute(bool mute) { D(bug("audio_set_speaker_mute: mute=%ld\n", mute)); if (mute != speaker_mute) { speaker_mute = mute; } } void audio_set_speaker_volume(uint32 vol) { D(bug("audio_set_speaker_volume: vol=%08lx\n", vol)); if (audio_open && supports_volume_changes) { ULONG volume = 0x80 * ((vol >> 16) + (vol & 0xffff)); D(bug("audio_set_speaker_volume: volume=%08lx\n", volume)); current_speaker_volume = volume; AHI_SetVol(0, volume, 0x8000, ahi_ctrl, AHISF_IMM); } } BasiliskII/src/AmigaOS/user_strings_amiga.h0000644000175000017500000000267610736405217021066 0ustar centriscentris/* * user_strings_amiga.h - AmigaOS-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef USER_STRINGS_AMIGA_H #define USER_STRINGS_AMIGA_H enum { STR_NO_PREPARE_EMUL_ERR = 10000, STR_NO_GADTOOLS_LIB_ERR, STR_NO_IFFPARSE_LIB_ERR, STR_NO_ASL_LIB_ERR, STR_NO_TIMER_DEV_ERR, STR_NO_P96_MODE_ERR, STR_NO_VIDEO_MODE_ERR, STR_WRONG_SCREEN_DEPTH_ERR, STR_WRONG_SCREEN_FORMAT_ERR, STR_ENFORCER_RUNNING_ERR, STR_NOT_ETHERNET_WARN, STR_NO_MULTICAST_WARN, STR_NO_GTLAYOUT_LIB_WARN, STR_NO_AHI_WARN, STR_NO_AHI_CTRL_WARN, STR_NOT_ENOUGH_MEM_WARN, STR_AHI_MODE_CTRL, STR_SCSI_MEMTYPE_CTRL, STR_MEMTYPE_CHIP_LAB, STR_MEMTYPE_24BITDMA_LAB, STR_MEMTYPE_ANY_LAB, STR_SCSI_DEVICES_CTRL }; #endif BasiliskII/src/AmigaOS/asm_support.asm0000644000175000017500000007465007534400652020107 0ustar centriscentris* * asm_support.asm - AmigaOS utility functions in assembly language * * Basilisk II (C) 1997-2001 Christian Bauer * * 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 * DEBUG_DETAIL SET 1 INCLUDE "exec/types.i" INCLUDE "exec/macros.i" INCLUDE "exec/memory.i" INCLUDE "exec/tasks.i" INCLUDE "dos/dos.i" INCLUDE "devices/timer.i" ; INCLUDE "asmsupp.i" XDEF _AtomicAnd XDEF _AtomicOr XDEF _MoveVBR XDEF _DisableSuperBypass XDEF _Execute68k XDEF _Execute68kTrap XDEF _TrapHandlerAsm XDEF _ExceptionHandlerAsm XDEF _AsmTriggerNMI XREF _OldTrapHandler XREF _OldExceptionHandler XREF _IllInstrHandler XREF _PrivViolHandler XREF _EmulatedSR XREF _IRQSigMask XREF _InterruptFlags XREF _MainTask XREF _SysBase XREF _quit_emulator INFO_LEVEL equ 0 SECTION text,CODE MACHINE 68020 IFGE INFO_LEVEL subSysName: dc.b '+',0 ENDIF * * Atomic bit operations (don't trust the compiler) * _AtomicAnd move.l 4(sp),a0 move.l 8(sp),d0 and.l d0,(a0) rts _AtomicOr move.l 4(sp),a0 move.l 8(sp),d0 or.l d0,(a0) rts * * Move VBR away from 0 if neccessary * _MoveVBR movem.l d0-d1/a0-a1/a5-a6,-(sp) move.l _SysBase,a6 lea getvbr,a5 ;VBR at 0? JSRLIB Supervisor tst.l d0 bne.s 1$ move.l #$400,d0 ;Yes, allocate memory for new table move.l #MEMF_PUBLIC,d1 JSRLIB AllocMem tst.l d0 beq.s 1$ JSRLIB Disable move.l d0,a5 ;Copy old table move.l d0,a1 sub.l a0,a0 move.l #$400,d0 JSRLIB CopyMem JSRLIB CacheClearU move.l a5,d0 ;Set VBR lea setvbr,a5 JSRLIB Supervisor JSRLIB Enable 1$ movem.l (sp)+,d0-d1/a0-a1/a5-a6 rts getvbr movec vbr,d0 rte setvbr movec d0,vbr rte * * Disable 68060 Super Bypass mode * _DisableSuperBypass movem.l d0-d1/a0-a1/a5-a6,-(sp) move.l _SysBase,a6 lea dissb,a5 JSRLIB Supervisor movem.l (sp)+,d0-d1/a0-a1/a5-a6 rts MACHINE 68060 dissb movec pcr,d0 bset #5,d0 movec d0,pcr rte MACHINE 68020 * * Execute 68k subroutine (must be ended with rts) * r->a[7] and r->sr are unused! * ; void Execute68k(uint32 addr, M68kRegisters *r); _Execute68k move.l 4(sp),d0 ;Get arguments move.l 8(sp),a0 movem.l d2-d7/a2-a6,-(sp) ;Save registers move.l a0,-(sp) ;Push pointer to M68kRegisters on stack pea 1$ ;Push return address on stack move.l d0,-(sp) ;Push pointer to 68k routine on stack movem.l (a0),d0-d7/a0-a6 ;Load registers from M68kRegisters rts ;Jump into 68k routine 1$ move.l a6,-(sp) ;Save a6 move.l 4(sp),a6 ;Get pointer to M68kRegisters movem.l d0-d7/a0-a5,(a6) ;Save d0-d7/a0-a5 to M68kRegisters move.l (sp)+,56(a6) ;Save a6 to M68kRegisters addq.l #4,sp ;Remove pointer from stack movem.l (sp)+,d2-d7/a2-a6 ;Restore registers rts * * Execute MacOS 68k trap * r->a[7] and r->sr are unused! * ; void Execute68kTrap(uint16 trap, M68kRegisters *r); _Execute68kTrap move.l 4(sp),d0 ;Get arguments move.l 8(sp),a0 movem.l d2-d7/a2-a6,-(sp) ;Save registers move.l a0,-(sp) ;Push pointer to M68kRegisters on stack move.w d0,-(sp) ;Push trap word on stack subq.l #8,sp ;Create fake A-Line exception frame movem.l (a0),d0-d7/a0-a6 ;Load registers from M68kRegisters move.l a2,-(sp) ;Save a2 and d2 move.l d2,-(sp) lea 1$,a2 ;a2 points to return address move.w 16(sp),d2 ;Load trap word into d2 jmp ([$28.w],10) ;Jump into MacOS A-Line handler 1$ move.l a6,-(sp) ;Save a6 move.l 6(sp),a6 ;Get pointer to M68kRegisters movem.l d0-d7/a0-a5,(a6) ;Save d0-d7/a0-a5 to M68kRegisters move.l (sp)+,56(a6) ;Save a6 to M68kRegisters addq.l #6,sp ;Remove pointer and trap word from stack movem.l (sp)+,d2-d7/a2-a6 ;Restore registers rts * * Exception handler of main task (for interrupts) * _ExceptionHandlerAsm move.l d0,-(sp) ;Save d0 and.l #SIGBREAKF_CTRL_C,d0 ;CTRL-C? bne.s 2$ move.w _EmulatedSR,d0 ;Interrupts enabled in emulated SR? and.w #$0700,d0 bne 1$ move.w #$0064,-(sp) ;Yes, fake interrupt stack frame pea 1$ move.w _EmulatedSR,d0 move.w d0,-(sp) or.w #$2100,d0 ;Set interrupt level in SR, enter (virtual) supervisor mode move.w d0,_EmulatedSR move.l $64.w,-(sp) ;Jump to MacOS interrupt handler rts 1$ move.l (sp)+,d0 ;Restore d0 rts 2$ JSRLIB Forbid ;Waiting for Dos signal? sub.l a1,a1 JSRLIB FindTask move.l d0,a0 move.l TC_SIGWAIT(a0),d0 move.l TC_SIGRECVD(a0),d1 JSRLIB Permit btst #SIGB_DOS,d0 beq 3$ btst #SIGB_DOS,d1 bne 4$ 3$ lea TC_SIZE(a0),a0 ;No, remove pending Dos packets JSRLIB GetMsg move.w _EmulatedSR,d0 or.w #$0700,d0 ;Disable all interrupts move.w d0,_EmulatedSR moveq #0,d0 ;Disable all exception signals moveq #-1,d1 JSRLIB SetExcept jsr _quit_emulator ;CTRL-C, quit emulator 4$ move.l (sp)+,d0 rts * * Trap handler of main task * _TrapHandlerAsm: IFEQ INFO_LEVEL-1002 move.w ([6,a0]),-(sp) move.w #0,-(sp) move.l (4+6,a0),-(sp) PUTMSG 0,'%s/TrapHandlerAsm: addr=%08lx opcode=%04lx' lea (2*4,sp),sp ENDC cmp.l #4,(sp) ;Illegal instruction? beq.s doillinstr cmp.l #10,(sp) ;A-Line exception? beq.s doaline cmp.l #8,(sp) ;Privilege violation? beq.s doprivviol cmp.l #9,(sp) ;Trace? beq dotrace cmp.l #3,(sp) ;Illegal Address? beq.s doilladdr cmp.l #11,(sp) ;F-Line exception beq.s dofline cmp.l #32,(sp) blt 1$ cmp.l #47,(sp) ble doTrapXX ; Vector 32-47 : TRAP #0 - 15 Instruction Vectors 1$: cmp.l #48,(sp) blt 2$ cmp.l #55,(sp) ble doTrapFPU 2$: IFEQ INFO_LEVEL-1009 PUTMSG 0,'%s/TrapHandlerAsm: stack=%08lx %08lx %08lx %08lx' ENDC move.l _OldTrapHandler,-(sp) ;No, jump to old trap handler rts * * TRAP #0 - 15 Instruction Vectors * doTrapXX: IFEQ INFO_LEVEL-1009 PUTMSG 0,'%s/doTrapXX: stack=%08lx %08lx %08lx %08lx' ENDC movem.l a0/d0,-(sp) ;Save a0,d0 move.l (2*4,sp),d0 ;vector number 32-47 move.l usp,a0 ;Get user stack pointer move.l (4*4,sp),-(a0) ;Copy 4-word stack frame to user stack move.l (3*4,sp),-(a0) move.l a0,usp ;Update USP or.w #$2000,(a0) ;set Supervisor bit in SR lsl.l #2,d0 ;convert vector number to vector offset move.l d0,a0 move.l (a0),d0 ;get mac trap vector move.l usp,a0 ;Get user stack pointer move.l d0,-(a0) ;store vector offset as return address move.l a0,usp ;Update USP movem.l (sp)+,a0/d0 ;Restore a0,d0 addq.l #4*2,sp ;Remove exception frame from supervisor stack andi #$d8ff,sr ;Switch to user mode, enable interrupts rts * * FPU Exception Instruction Vectors * doTrapFPU: move.l d0,(sp) fmove.l fpcr,d0 and.w #$00ff,d0 ;disable FPU exceptions fmove.l d0,fpcr move.l (sp)+,d0 ;Restore d0 rte * * trace Vector * dotrace IFEQ INFO_LEVEL-1009 PUTMSG 0,'%s/dotrace: stack=%08lx %08lx %08lx %08lx' ENDC move.l a0,(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer IFEQ INFO_LEVEL-1009 move.l (12,a0),-(sp) move.l (8,a0),-(sp) move.l (4,a0),-(sp) move.l (0,a0),-(sp) move.l a0,-(sp) move.l a7,-(sp) PUTMSG 0,'%s/dotrace: sp=%08lx usp=%08lx (%08lx %08lx %08lx %08lx)' lea (6*4,sp),sp ENDC move.l 3*4(sp),-(a0) ;Copy 6-word stack frame to user stack move.l 2*4(sp),-(a0) move.l 1*4(sp),-(a0) move.l a0,usp ;Update USP or.w #$2000,(a0) ;set Supervisor bit in SR move.l (sp)+,a0 ;Restore a0 lea 6*2(sp),sp ;Remove exception frame from supervisor stack andi #$18ff,sr ;Switch to user mode, enable interrupts, disable trace move.l $24.w,-(sp) ;Jump to MacOS exception handler rts * * A-Line handler: call MacOS A-Line handler * doaline move.l a0,(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.l 8(sp),-(a0) ;Copy stack frame to user stack move.l 4(sp),-(a0) move.l a0,usp ;Update USP or.w #$2000,(a0) ;set Supervisor bit in SR move.l (sp)+,a0 ;Restore a0 addq.l #8,sp ;Remove exception frame from supervisor stack andi #$d8ff,sr ;Switch to user mode, enable interrupts ; and.w #$f8ff,_EmulatedSR ;enable interrupts in EmulatedSR move.l $28.w,-(sp) ;Jump to MacOS exception handler rts * * F-Line handler: call F-Line exception handler * dofline move.l a0,(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.l 8(sp),-(a0) ;Copy stack frame to user stack move.l 4(sp),-(a0) move.l a0,usp ;Update USP or.w #$2000,(a0) ;set Supervisor bit in SR move.l (sp)+,a0 ;Restore a0 addq.l #8,sp ;Remove exception frame from supervisor stack andi #$d8ff,sr ;Switch to user mode, enable interrupts and.w #$f8ff,_EmulatedSR ;enable interrupts in EmulatedSR move.l $2c.w,-(sp) ;Jump to MacOS exception handler rts * * Illegal address handler * doilladdr: IFEQ INFO_LEVEL-1009 PUTMSG 0,'%s/doilladdr: stack=%08lx %08lx %08lx %08lx' ENDC move.l a0,(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.l 3*4(sp),-(a0) ;Copy 6-word stack frame to user stack move.l 2*4(sp),-(a0) move.l 1*4(sp),-(a0) move.l a0,usp ;Update USP or.w #$2000,(a0) ;set Supervisor bit in SR move.l (sp)+,a0 ;Restore a0 lea 6*2(sp),sp ;Remove exception frame from supervisor stack andi #$d8ff,sr ;Switch to user mode, enable interrupts move.l $0c.w,-(sp) ;Jump to MacOS exception handler rts * * Illegal instruction handler: call IllInstrHandler() (which calls EmulOp()) * to execute extended opcodes (see emul_op.h) * doillinstr movem.l a0/d0,-(sp) move.w ([6+2*4,sp]),d0 and.w #$ff00,d0 cmp.w #$7100,d0 IFEQ INFO_LEVEL-1009 move.l d0,-(sp) PUTMSG 0,'%s/doillinst: d0=%08lx stack=%08lx %08lx %08lx %08lx' lea (1*4,sp),sp ENDC movem.l (sp)+,a0/d0 beq 1$ move.l a0,(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.l 8(sp),-(a0) ;Copy stack frame to user stack move.l 4(sp),-(a0) move.l a0,usp ;Update USP or.w #$2000,(a0) ;set Supervisor bit in SR move.l (sp)+,a0 ;Restore a0 add.w #3*4,sp ;Remove exception frame from supervisor stack andi #$d8ff,sr ;Switch to user mode, enable interrupts move.l $10.w,-(sp) ;Jump to MacOS exception handler rts 1$: move.l a6,(sp) ;Save a6 move.l usp,a6 ;Get user stack pointer move.l a6,-10(a6) ;Push USP (a7) move.l 6(sp),-(a6) ;Push PC move.w 4(sp),-(a6) ;Push SR subq.l #4,a6 ;Skip saved USP move.l (sp),-(a6) ;Push old a6 movem.l d0-d7/a0-a5,-(a6) ;Push remaining registers move.l a6,usp ;Update USP add.w #12,sp ;Remove exception frame from supervisor stack andi #$d8ff,sr ;Switch to user mode, enable interrupts move.l a6,-(sp) ;Jump to IllInstrHandler() in main.cpp jsr _IllInstrHandler addq.l #4,sp movem.l (sp)+,d0-d7/a0-a6 ;Restore registers addq.l #4,sp ;Skip saved USP (!!) rtr ;Return from exception * * Privilege violation handler: MacOS runs in supervisor mode, * so we have to emulate certain privileged instructions * doprivviol move.l d0,(sp) ;Save d0 move.w ([6,sp]),d0 ;Get instruction word IFEQ INFO_LEVEL-1001 move.w ([6,a0]),-(sp) move.w #0,-(sp) PUTMSG 0,'%s/doprivviol: opcode=%04lx' lea (1*4,sp),sp ENDC cmp.w #$40e7,d0 ;move sr,-(sp)? beq pushsr cmp.w #$46df,d0 ;move (sp)+,sr? beq popsr cmp.w #$007c,d0 ;ori #xxxx,sr? beq orisr cmp.w #$027c,d0 ;andi #xxxx,sr? beq andisr cmp.w #$46fc,d0 ;move #xxxx,sr? beq movetosrimm cmp.w #$46ef,d0 ;move (xxxx,sp),sr? beq movetosrsprel cmp.w #$46d8,d0 ;move (a0)+,sr? beq movetosra0p cmp.w #$46d9,d0 ;move (a1)+,sr? beq movetosra1p cmp.w #$40f8,d0 ;move sr,xxxx.w? beq movefromsrabs cmp.w #$40d0,d0 ;move sr,(a0)? beq movefromsra0 cmp.w #$40d7,d0 ;move sr,(sp)? beq movefromsrsp cmp.w #$f327,d0 ;fsave -(sp)? beq fsavepush cmp.w #$f35f,d0 ;frestore (sp)+? beq frestorepop cmp.w #$f32d,d0 ;fsave xxx(a5) ? beq fsavea5 cmp.w #$f36d,d0 ;frestore xxx(a5) ? beq frestorea5 cmp.w #$4e73,d0 ;rte? beq pvrte cmp.w #$40c0,d0 ;move sr,d0? beq movefromsrd0 cmp.w #$40c1,d0 ;move sr,d1? beq movefromsrd1 cmp.w #$40c2,d0 ;move sr,d2? beq movefromsrd2 cmp.w #$40c3,d0 ;move sr,d3? beq movefromsrd3 cmp.w #$40c4,d0 ;move sr,d4? beq movefromsrd4 cmp.w #$40c5,d0 ;move sr,d5? beq movefromsrd5 cmp.w #$40c6,d0 ;move sr,d6? beq movefromsrd6 cmp.w #$40c7,d0 ;move sr,d7? beq movefromsrd7 cmp.w #$46c0,d0 ;move d0,sr? beq movetosrd0 cmp.w #$46c1,d0 ;move d1,sr? beq movetosrd1 cmp.w #$46c2,d0 ;move d2,sr? beq movetosrd2 cmp.w #$46c3,d0 ;move d3,sr? beq movetosrd3 cmp.w #$46c4,d0 ;move d4,sr? beq movetosrd4 cmp.w #$46c5,d0 ;move d5,sr? beq movetosrd5 cmp.w #$46c6,d0 ;move d6,sr? beq movetosrd6 cmp.w #$46c7,d0 ;move d7,sr? beq movetosrd7 cmp.w #$4e7a,d0 ;movec cr,x? beq movecfromcr cmp.w #$4e7b,d0 ;movec x,cr? beq movectocr cmp.w #$f478,d0 ;cpusha dc? beq cpushadc cmp.w #$f4f8,d0 ;cpusha dc/ic? beq cpushadcic cmp.w #$4e69,d0 ;move usp,a1 beq moveuspa1 cmp.w #$4e68,d0 ;move usp,a0 beq moveuspa0 cmp.w #$4e61,d0 ;move a1,usp beq moved1usp pv_unhandled move.l (sp),d0 ;Unhandled instruction, jump to handler in main.cpp move.l a6,(sp) ;Save a6 move.l usp,a6 ;Get user stack pointer move.l a6,-10(a6) ;Push USP (a7) move.l 6(sp),-(a6) ;Push PC move.w 4(sp),-(a6) ;Push SR subq.l #4,a6 ;Skip saved USP move.l (sp),-(a6) ;Push old a6 movem.l d0-d7/a0-a5,-(a6) ;Push remaining registers move.l a6,usp ;Update USP add.w #12,sp ;Remove exception frame from supervisor stack andi #$d8ff,sr ;Switch to user mode, enable interrupts move.l a6,-(sp) ;Jump to PrivViolHandler() in main.cpp jsr _PrivViolHandler addq.l #4,sp movem.l (sp)+,d0-d7/a0-a6 ;Restore registers addq.l #4,sp ;Skip saved USP rtr ;Return from exception ; move sr,-(sp) pushsr move.l a0,-(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.w 8(sp),d0 ;Get CCR from exception stack frame or.w _EmulatedSR,d0 ;Add emulated supervisor bits move.w d0,-(a0) ;Store SR on user stack move.l a0,usp ;Update USP move.l (sp)+,a0 ;Restore a0 move.l (sp)+,d0 ;Restore d0 addq.l #2,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; move (sp)+,sr popsr move.l a0,-(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.w (a0)+,d0 ;Get SR from user stack move.w d0,8(sp) ;Store into CCR on exception stack frame and.w #$00ff,8(sp) and.w #$e700,d0 ;Extract supervisor bits move.w d0,_EmulatedSR ;And save them and.w #$0700,d0 ;Rethrow exception if interrupts are pending and reenabled bne 1$ tst.l _InterruptFlags beq 1$ movem.l d0-d1/a0-a1/a6,-(sp) move.l _SysBase,a6 move.l _MainTask,a1 move.l _IRQSigMask,d0 JSRLIB Signal movem.l (sp)+,d0-d1/a0-a1/a6 1$ move.l a0,usp ;Update USP move.l (sp)+,a0 ;Restore a0 move.l (sp)+,d0 ;Restore d0 addq.l #2,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; ori #xxxx,sr orisr move.w 4(sp),d0 ;Get CCR from stack or.w _EmulatedSR,d0 ;Add emulated supervisor bits or.w ([6,sp],2),d0 ;Or with immediate value move.w d0,4(sp) ;Store into CCR on stack and.w #$00ff,4(sp) and.w #$e700,d0 ;Extract supervisor bits move.w d0,_EmulatedSR ;And save them move.l (sp)+,d0 ;Restore d0 addq.l #4,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; andi #xxxx,sr andisr move.w 4(sp),d0 ;Get CCR from stack or.w _EmulatedSR,d0 ;Add emulated supervisor bits and.w ([6,sp],2),d0 ;And with immediate value storesr4 move.w d0,4(sp) ;Store into CCR on stack and.w #$00ff,4(sp) and.w #$e700,d0 ;Extract supervisor bits move.w d0,_EmulatedSR ;And save them and.w #$0700,d0 ;Rethrow exception if interrupts are pending and reenabled bne.s 1$ tst.l _InterruptFlags beq.s 1$ movem.l d0-d1/a0-a1/a6,-(sp) move.l _SysBase,a6 move.l _MainTask,a1 move.l _IRQSigMask,d0 JSRLIB Signal movem.l (sp)+,d0-d1/a0-a1/a6 1$ move.l (sp)+,d0 ;Restore d0 addq.l #4,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; move #xxxx,sr movetosrimm move.w ([6,sp],2),d0 ;Get immediate value bra.s storesr4 ; move (xxxx,sp),sr movetosrsprel move.l a0,-(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.w ([10,sp],2),d0 ;Get offset move.w (a0,d0.w),d0 ;Read word move.l (sp)+,a0 ;Restore a0 bra.s storesr4 ; move (a0)+,sr movetosra0p move.w (a0)+,d0 ;Read word bra storesr2 ; move (a1)+,sr movetosra1p move.w (a1)+,d0 ;Read word bra storesr2 ; move sr,xxxx.w movefromsrabs move.l a0,-(sp) ;Save a0 move.w ([10,sp],2),a0 ;Get address move.w 8(sp),d0 ;Get CCR or.w _EmulatedSR,d0 ;Add emulated supervisor bits move.w d0,(a0) ;Store SR move.l (sp)+,a0 ;Restore a0 move.l (sp)+,d0 ;Restore d0 addq.l #4,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; move sr,(a0) movefromsra0 move.w 4(sp),d0 ;Get CCR or.w _EmulatedSR,d0 ;Add emulated supervisor bits move.w d0,(a0) ;Store SR move.l (sp)+,d0 ;Restore d0 addq.l #2,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; move sr,(sp) movefromsrsp move.l a0,-(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.w 8(sp),d0 ;Get CCR or.w _EmulatedSR,d0 ;Add emulated supervisor bits move.w d0,(a0) ;Store SR move.l (sp)+,a0 ;Restore a0 move.l (sp)+,d0 ;Restore d0 addq.l #2,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; fsave -(sp) fsavepush move.l (sp),d0 ;Restore d0 move.l a0,(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer move.l #$41000000,-(a0) ;Push idle frame move.l a0,usp ;Update USP move.l (sp)+,a0 ;Restore a0 addq.l #2,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; fsave xxx(a5) fsavea5 move.l (sp),d0 ;Restore d0 move.l a0,(sp) ;Save a0 move.l a5,a0 ;Get base register add.w ([6,sp],2),a0 ;Add offset to base register move.l #$41000000,(a0) ;Push idle frame move.l (sp)+,a0 ;Restore a0 addq.l #4,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; frestore (sp)+ frestorepop move.l (sp),d0 ;Restore d0 move.l a0,(sp) ;Save a0 move.l usp,a0 ;Get user stack pointer addq.l #4,a0 ;Nothing to do... move.l a0,usp ;Update USP move.l (sp)+,a0 ;Restore a0 addq.l #2,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; frestore xxx(a5) frestorea5 move.l (sp),d0 ;Restore d0 move.l a0,(sp) ;Save a0 move.l (sp)+,a0 ;Restore a0 addq.l #4,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; rte pvrte movem.l a0/a1,-(sp) ;Save a0 and a1 move.l usp,a0 ;Get user stack pointer move.w (a0)+,d0 ;Get SR from user stack move.w d0,8+4(sp) ;Store into CCR on exception stack frame and.w #$c0ff,8+4(sp) and.w #$e700,d0 ;Extract supervisor bits move.w d0,_EmulatedSR ;And save them move.l (a0)+,10+4(sp) ;Store return address in exception stack frame move.w (a0)+,d0 ;get format word lsr.w #7,d0 ;get stack frame Id lsr.w #4,d0 and.w #$001e,d0 move.w (StackFormatTable,pc,d0.w),d0 ; get total stack frame length subq.w #4,d0 ; count only extra words lea 16+4(sp),a1 ; destination address (in supervisor stack) bra 1$ 2$ move.w (a0)+,(a1)+ ; copy additional stack words back to supervisor stack 1$ dbf d0,2$ move.l a0,usp ;Update USP movem.l (sp)+,a0/a1 ;Restore a0 and a1 move.l (sp)+,d0 ;Restore d0 IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; sizes of exceptions stack frames StackFormatTable: dc.w 4 ; Four-word stack frame, format $0 dc.w 4 ; Throwaway four-word stack frame, format $1 dc.w 6 ; Six-word stack frame, format $2 dc.w 6 ; MC68040 floating-point post-instruction stack frame, format $3 dc.w 8 ; MC68EC040 and MC68LC040 floating-point unimplemented stack frame, format $4 dc.w 4 ; Format $5 dc.w 4 ; Format $6 dc.w 30 ; MC68040 access error stack frame, Format $7 dc.w 29 ; MC68010 bus and address error stack frame, format $8 dc.w 10 ; MC68020 and MC68030 coprocessor mid-instruction stack frame, format $9 dc.w 16 ; MC68020 and MC68030 short bus cycle stack frame, format $a dc.w 46 ; MC68020 and MC68030 long bus cycle stack frame, format $b dc.w 12 ; CPU32 bus error for prefetches and operands stack frame, format $c dc.w 4 ; Format $d dc.w 4 ; Format $e dc.w 4 ; Format $f ; move sr,dx movefromsrd0 addq.l #4,sp ;Skip saved d0 moveq #0,d0 move.w (sp),d0 ;Get CCR or.w _EmulatedSR,d0 ;Add emulated supervisor bits addq.l #2,2(sp) ;Skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movefromsrd1 move.l (sp)+,d0 moveq #0,d1 move.w (sp),d1 or.w _EmulatedSR,d1 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movefromsrd2 move.l (sp)+,d0 moveq #0,d2 move.w (sp),d2 or.w _EmulatedSR,d2 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movefromsrd3 move.l (sp)+,d0 moveq #0,d3 move.w (sp),d3 or.w _EmulatedSR,d3 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movefromsrd4 move.l (sp)+,d0 moveq #0,d4 move.w (sp),d4 or.w _EmulatedSR,d4 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movefromsrd5 move.l (sp)+,d0 moveq #0,d5 move.w (sp),d5 or.w _EmulatedSR,d5 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movefromsrd6 move.l (sp)+,d0 moveq #0,d6 move.w (sp),d6 or.w _EmulatedSR,d6 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movefromsrd7 move.l (sp)+,d0 moveq #0,d7 move.w (sp),d7 or.w _EmulatedSR,d7 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; move dx,sr movetosrd0 move.l (sp),d0 storesr2 move.w d0,4(sp) and.w #$00ff,4(sp) and.w #$e700,d0 move.w d0,_EmulatedSR and.w #$0700,d0 ;Rethrow exception if interrupts are pending and reenabled bne.s 1$ tst.l _InterruptFlags beq.s 1$ movem.l d0-d1/a0-a1/a6,-(sp) move.l _SysBase,a6 move.l _MainTask,a1 move.l _IRQSigMask,d0 JSRLIB Signal movem.l (sp)+,d0-d1/a0-a1/a6 1$ move.l (sp)+,d0 addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movetosrd1 move.l d1,d0 bra.s storesr2 movetosrd2 move.l d2,d0 bra.s storesr2 movetosrd3 move.l d3,d0 bra.s storesr2 movetosrd4 move.l d4,d0 bra.s storesr2 movetosrd5 move.l d5,d0 bra.s storesr2 movetosrd6 move.l d6,d0 bra.s storesr2 movetosrd7 move.l d7,d0 bra.s storesr2 ; movec cr,x movecfromcr move.w ([6,sp],2),d0 ;Get next instruction word cmp.w #$8801,d0 ;movec vbr,a0? beq.s movecvbra0 cmp.w #$9801,d0 ;movec vbr,a1? beq.s movecvbra1 cmp.w #$A801,d0 ;movec vbr,a2? beq.s movecvbra2 cmp.w #$1801,d0 ;movec vbr,d1? beq movecvbrd1 cmp.w #$0002,d0 ;movec cacr,d0? beq.s moveccacrd0 cmp.w #$1002,d0 ;movec cacr,d1? beq.s moveccacrd1 cmp.w #$0003,d0 ;movec tc,d0? beq.s movectcd0 cmp.w #$1003,d0 ;movec tc,d1? beq.s movectcd1 cmp.w #$1000,d0 ;movec sfc,d1? beq movecsfcd1 cmp.w #$1001,d0 ;movec dfc,d1? beq movecdfcd1 cmp.w #$0806,d0 ;movec urp,d0? beq movecurpd0 cmp.w #$0807,d0 ;movec srp,d0? beq.s movecsrpd0 cmp.w #$0004,d0 ;movec itt0,d0 beq.s movecitt0d0 cmp.w #$0005,d0 ;movec itt1,d0 beq.s movecitt1d0 cmp.w #$0006,d0 ;movec dtt0,d0 beq.s movecdtt0d0 cmp.w #$0007,d0 ;movec dtt1,d0 beq.s movecdtt1d0 bra pv_unhandled ; movec cacr,d0 moveccacrd0 move.l (sp)+,d0 move.l #$3111,d0 ;All caches and bursts on addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec cacr,d1 moveccacrd1 move.l (sp)+,d0 move.l #$3111,d1 ;All caches and bursts on addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec vbr,a0 movecvbra0 move.l (sp)+,d0 sub.l a0,a0 ;VBR always appears to be at 0 addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec vbr,a1 movecvbra1 move.l (sp)+,d0 sub.l a1,a1 ;VBR always appears to be at 0 addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec vbr,a2 movecvbra2 move.l (sp)+,d0 sub.l a2,a2 ;VBR always appears to be at 0 addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec vbr,d1 movecvbrd1 move.l (sp)+,d0 moveq.l #0,d1 ;VBR always appears to be at 0 addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec tc,d0 movectcd0 addq.l #4,sp moveq #0,d0 ;MMU is always off addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec tc,d1 +jl+ movectcd1 move.l (sp)+,d0 ;Restore d0 moveq #0,d1 ;MMU is always off addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec sfc,d1 +jl+ movecsfcd1 move.l (sp)+,d0 ;Restore d0 moveq #0,d1 addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec dfc,d1 +jl+ movecdfcd1 move.l (sp)+,d0 ;Restore d0 moveq #0,d1 addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte movecurpd0 ; movec urp,d0 +jl+ movecsrpd0 ; movec srp,d0 movecitt0d0 ; movec itt0,d0 movecitt1d0 ; movec itt1,d0 movecdtt0d0 ; movec dtt0,d0 movecdtt1d0 ; movec dtt1,d0 addq.l #4,sp moveq.l #0,d0 ;MMU is always off addq.l #4,2(sp) ;skip instruction IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec x,cr movectocr move.w ([6,sp],2),d0 ;Get next instruction word cmp.w #$0801,d0 ;movec d0,vbr? beq.s movectovbr cmp.w #$1801,d0 ;movec d1,vbr? beq.s movectovbr cmp.w #$A801,d0 ;movec a2,vbr? beq.s movectovbr cmp.w #$0002,d0 ;movec d0,cacr? beq.s movectocacr cmp.w #$1002,d0 ;movec d1,cacr? beq.s movectocacr cmp.w #$1000,d0 ;movec d1,sfc? beq.s movectoxfc cmp.w #$1001,d0 ;movec d1,dfc? beq.s movectoxfc bra pv_unhandled ; movec x,vbr movectovbr move.l (sp)+,d0 ;Ignore moves to VBR addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec dx,cacr movectocacr movem.l d1/a0-a1/a6,-(sp) ;Move to CACR, clear caches move.l _SysBase,a6 JSRLIB CacheClearU movem.l (sp)+,d1/a0-a1/a6 move.l (sp)+,d0 addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; movec x,sfc ; movec x,dfc movectoxfc move.l (sp)+,d0 ;Ignore moves to SFC, DFC addq.l #4,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; cpusha cpushadc cpushadcic IFEQ INFO_LEVEL-1003 move.l (4),-(sp) move.l d0,-(sp) PUTMSG 0,'%s/cpushadc: opcode=%04lx Execbase=%08lx' lea (2*4,sp),sp ENDC movem.l d1/a0-a1/a6,-(sp) ;Clear caches move.l _SysBase,a6 JSRLIB CacheClearU movem.l (sp)+,d1/a0-a1/a6 move.l (sp)+,d0 addq.l #2,2(sp) rte ; move usp,a1 +jl+ moveuspa1 move.l (sp)+,d0 move usp,a1 addq.l #2,2(sp) IFEQ INFO_LEVEL-1009 move.l a1,-(sp) move.l a7,-(sp) PUTMSG 0,'%s/moveuspa1: a7=%08lx a1=%08lx' lea (2*4,sp),sp ENDC rte ; move usp,a0 +jl+ moveuspa0 move.l (sp)+,d0 move usp,a0 addq.l #2,2(sp) IFEQ INFO_LEVEL-1009 move.l a0,-(sp) move.l a7,-(sp) PUTMSG 0,'%s/moveuspa0: a7=%08lx a0=%08lx' lea (2*4,sp),sp ENDC rte ; move a1,usp +jl+ moved1usp move.l (sp)+,d0 move a1,usp addq.l #2,2(sp) IFEQ INFO_LEVEL-1001 move.l (4),-(sp) PUTMSG 0,'%s/doprivviol END: Execbase=%08lx' lea (1*4,sp),sp ENDC rte ; ; Trigger NMI (Pop up debugger) ; _AsmTriggerNMI move.l d0,-(sp) ;Save d0 move.w #$007c,-(sp) ;Yes, fake NMI stack frame pea 1$ move.w _EmulatedSR,d0 and.w #$f8ff,d0 ;Set interrupt level in SR move.w d0,-(sp) move.w d0,_EmulatedSR move.l $7c.w,-(sp) ;Jump to MacOS NMI handler rts 1$ move.l (sp)+,d0 ;Restore d0 rts CopyTrapStack: movem.l d0/a0/a1,-(sp) move.w (5*4+6,sp),d0 ;get format word lsr.w #7,d0 ;get stack frame Id lsr.w #4,d0 and.w #$001e,d0 move.w (StackFormatTable,pc,d0.w),d0 ; get total stack frame length lea (5*4,sp),a0 ;get start of exception stack frame move.l usp,a1 ;Get user stack pointer bra 1$ 2$ move.w (a0)+,(a1)+ ; copy additional stack words back to supervisor stack 1$ dbf d0,2$ move.l (3*4,sp),-(a0) ;copy return address to new top of stack move.l a0,sp rts END BasiliskII/src/AmigaOS/extfs_amiga.cpp0000644000175000017500000002547410736405217020024 0ustar centriscentris/* * extfs_amiga.cpp - MacOS file system for access native file system access, AmigaOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #define __USE_SYSBASE #include #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "extfs.h" #include "extfs_defs.h" #define DEBUG 0 #include "debug.h" // Default Finder flags const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; /* * Initialization */ void extfs_init(void) { } /* * Deinitialization */ void extfs_exit(void) { } /* * Add component to path name */ void add_path_component(char *path, const char *component) { AddPart(path, (char *)component, MAX_PATH_LENGTH); } /* * Finder info and resource forks are kept in helper files * * Finder info: * /path/.finf/file * Resource fork: * /path/.rsrc/file * * The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo * (16+16 bytes) */ static void make_helper_path(const char *src, char *dest, const char *add, bool only_dir = false) { dest[0] = 0; // Get pointer to last component of path const char *last_part = FilePart((char *)src); // Copy everything before strncpy(dest, src, last_part-src); dest[last_part-src] = 0; // Add additional component AddPart(dest, (char *)add, MAX_PATH_LENGTH); // Add last component if (!only_dir) AddPart(dest, (char *)last_part, MAX_PATH_LENGTH); } static int create_helper_dir(const char *path, const char *add) { char helper_dir[MAX_PATH_LENGTH]; make_helper_path(path, helper_dir, add, true); if (helper_dir[strlen(helper_dir) - 1] == '/') // Remove trailing "/" helper_dir[strlen(helper_dir) - 1] = 0; return mkdir(helper_dir, 0777); } static int open_helper(const char *path, const char *add, int flag) { char helper_path[MAX_PATH_LENGTH]; make_helper_path(path, helper_path, add); if ((flag & O_ACCMODE) == O_RDWR || (flag & O_ACCMODE) == O_WRONLY) flag |= O_CREAT; int fd = open(helper_path, flag, 0666); if (fd < 0) { if (errno == ENOENT && (flag & O_CREAT)) { // One path component was missing, probably the helper // directory. Try to create it and re-open the file. int ret = create_helper_dir(path, add); if (ret < 0) return ret; fd = open(helper_path, flag, 0666); } } return fd; } static int open_finf(const char *path, int flag) { return open_helper(path, ".finf/", flag); } static int open_rsrc(const char *path, int flag) { return open_helper(path, ".rsrc/", flag); } /* * Get/set finder type/creator for file specified by full path */ struct ext2type { const char *ext; uint32 type; uint32 creator; }; static const ext2type e2t_translation[] = { {".z", FOURCC('Z','I','V','M'), FOURCC('L','Z','I','V')}, {".gz", FOURCC('G','z','i','p'), FOURCC('G','z','i','p')}, {".hqx", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".bin", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".pdf", FOURCC('P','D','F',' '), FOURCC('C','A','R','O')}, {".ps", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".sit", FOURCC('S','I','T','!'), FOURCC('S','I','T','x')}, {".tar", FOURCC('T','A','R','F'), FOURCC('T','A','R',' ')}, {".uu", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".uue", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".zip", FOURCC('Z','I','P',' '), FOURCC('Z','I','P',' ')}, {".8svx", FOURCC('8','S','V','X'), FOURCC('S','N','D','M')}, {".aifc", FOURCC('A','I','F','C'), FOURCC('T','V','O','D')}, {".aiff", FOURCC('A','I','F','F'), FOURCC('T','V','O','D')}, {".au", FOURCC('U','L','A','W'), FOURCC('T','V','O','D')}, {".mid", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".midi", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".mp2", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".mp3", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".wav", FOURCC('W','A','V','E'), FOURCC('T','V','O','D')}, {".bmp", FOURCC('B','M','P','f'), FOURCC('o','g','l','e')}, {".gif", FOURCC('G','I','F','f'), FOURCC('o','g','l','e')}, {".lbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".ilbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".jpg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".jpeg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".pict", FOURCC('P','I','C','T'), FOURCC('o','g','l','e')}, {".png", FOURCC('P','N','G','f'), FOURCC('o','g','l','e')}, {".sgi", FOURCC('.','S','G','I'), FOURCC('o','g','l','e')}, {".tga", FOURCC('T','P','I','C'), FOURCC('o','g','l','e')}, {".tif", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".tiff", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".htm", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".html", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".txt", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".rtf", FOURCC('T','E','X','T'), FOURCC('M','S','W','D')}, {".c", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cc", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".h", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hh", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".s", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".i", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".mpg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mpeg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mov", FOURCC('M','o','o','V'), FOURCC('T','V','O','D')}, {".fli", FOURCC('F','L','I',' '), FOURCC('T','V','O','D')}, {".avi", FOURCC('V','f','W',' '), FOURCC('T','V','O','D')}, {".qxd", FOURCC('X','D','O','C'), FOURCC('X','P','R','3')}, {".hfv", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".dsk", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".img", FOURCC('r','o','h','d'), FOURCC('d','d','s','k')}, {NULL, 0, 0} // End marker }; void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Read Finder info file int fd = open_finf(path, O_RDONLY); if (fd >= 0) { ssize_t actual = read(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) actual += read(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); if (actual >= SIZEOF_FInfo) return; } // No Finder info file, translate file name extension to MacOS type/creator if (!is_dir) { int path_len = strlen(path); for (int i=0; e2t_translation[i].ext; i++) { int ext_len = strlen(e2t_translation[i].ext); if (path_len < ext_len) continue; if (!strcasecmp(path + path_len - ext_len, e2t_translation[i].ext)) { WriteMacInt32(finfo + fdType, e2t_translation[i].type); WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator); break; } } } } void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Open Finder info file int fd = open_finf(path, O_RDWR); if (fd < 0) return; // Write file write(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) write(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); } /* * Resource fork emulation functions */ uint32 get_rfork_size(const char *path) { // Open resource file int fd = open_rsrc(path, O_RDONLY); if (fd < 0) return 0; // Get size off_t size = lseek(fd, 0, SEEK_END); // Close file and return size close(fd); return size < 0 ? 0 : size; } int open_rfork(const char *path, int flag) { return open_rsrc(path, flag); } void close_rfork(const char *path, int fd) { close(fd); } /* * Read "length" bytes from file to "buffer", * returns number of bytes read (or -1 on error) */ ssize_t extfs_read(int fd, void *buffer, size_t length) { return read(fd, buffer, length); } /* * Write "length" bytes from "buffer" to file, * returns number of bytes written (or -1 on error) */ ssize_t extfs_write(int fd, void *buffer, size_t length) { return write(fd, buffer, length); } /* * Remove file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_remove(const char *path) { // Remove helpers first, don't complain if this fails char helper_path[MAX_PATH_LENGTH]; make_helper_path(path, helper_path, ".finf/", false); remove(helper_path); make_helper_path(path, helper_path, ".rsrc/", false); remove(helper_path); // Now remove file or directory (and helper directories in the directory) if (remove(path) < 0) { if (errno == EISDIR || errno == ENOTEMPTY) { helper_path[0] = 0; strncpy(helper_path, path, MAX_PATH_LENGTH-1); add_path_component(helper_path, ".finf"); rmdir(helper_path); helper_path[0] = 0; strncpy(helper_path, path, MAX_PATH_LENGTH-1); add_path_component(helper_path, ".rsrc"); rmdir(helper_path); return rmdir(path) == 0; } else return false; } return true; } /* * Rename/move file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_rename(const char *old_path, const char *new_path) { // Rename helpers first, don't complain if this fails char old_helper_path[MAX_PATH_LENGTH], new_helper_path[MAX_PATH_LENGTH]; make_helper_path(old_path, old_helper_path, ".finf/", false); make_helper_path(new_path, new_helper_path, ".finf/", false); create_helper_dir(new_path, ".finf/"); rename(old_helper_path, new_helper_path); make_helper_path(old_path, old_helper_path, ".rsrc/", false); make_helper_path(new_path, new_helper_path, ".rsrc/", false); create_helper_dir(new_path, ".rsrc/"); rename(old_helper_path, new_helper_path); // Now rename file return rename(old_path, new_path) == 0; } /* * ftruncate() is missing from libnix */ extern unsigned long *__stdfiledes; int ftruncate(int fd, off_t size) { if (SetFileSize(__stdfiledes[fd], size, OFFSET_BEGINNING) < 0) return -1; else return 0; } BasiliskII/src/AmigaOS/sys_amiga.cpp0000644000175000017500000006313410736405217017504 0ustar centriscentris/* * sys_amiga.cpp - System dependent routines, Amiga implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #define __USE_SYSBASE #include #include #include #include #include #include #include "sysdeps.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "sys.h" #define DEBUG 0 #include "debug.h" // File handles are pointers to these structures struct file_handle { bool is_file; // Flag: plain file or /dev/something? bool read_only; // Copy of Sys_open() flag loff_t start_byte; // Size of file header (if any) loff_t size; // Size of file/device (minus header) BPTR f; // AmigaDOS file handle (if is_file == true) struct IOStdReq *io; // Pointer to IORequest (if is_file == false) ULONG block_size; // Block size of device (must be a power of two) bool is_nsd; // New style device? bool does_64bit; // Supports 64 bit trackdisk commands? bool is_ejected; // Volume has been (logically) ejected bool is_2060scsi; // Enable workaround for 2060scsi.device CD-ROM TD_READ bug }; // FileInfoBlock (must be global because it has to be on a longword boundary) static struct FileInfoBlock FIB; // Message port for device communication static struct MsgPort *the_port = NULL; // Temporary buffer in chip memory const int TMP_BUF_SIZE = 0x10000; static UBYTE *tmp_buf = NULL; /* * Initialization */ void SysInit(void) { // Create port and temporary buffer the_port = CreateMsgPort(); tmp_buf = (UBYTE *)AllocMem(TMP_BUF_SIZE, MEMF_CHIP | MEMF_PUBLIC); if (the_port == NULL || tmp_buf == NULL) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } } /* * Deinitialization */ void SysExit(void) { // Delete port and temporary buffer if (the_port) { DeleteMsgPort(the_port); the_port = NULL; } if (tmp_buf) { FreeMem(tmp_buf, TMP_BUF_SIZE); tmp_buf = NULL; } } /* * This gets called when no "floppy" prefs items are found * It scans for available floppy drives and adds appropriate prefs items */ void SysAddFloppyPrefs(void) { for (int i=0; i<4; i++) { ULONG id = GetUnitID(i); if (id == DRT_150RPM) { // We need an HD drive char str[256]; sprintf(str, "/dev/mfm.device/%d/0/0/2880/512", i); PrefsAddString("floppy", str); } } } /* * This gets called when no "disk" prefs items are found * It scans for available HFS volumes and adds appropriate prefs items */ void SysAddDiskPrefs(void) { // AmigaOS doesn't support MacOS partitioning, so this probably doesn't make much sense... } /* * This gets called when no "cdrom" prefs items are found * It scans for available CD-ROM drives and adds appropriate prefs items */ void SysAddCDROMPrefs(void) { // Don't scan for drives if nocdrom option given if (PrefsFindBool("nocdrom")) return; //!! } /* * Add default serial prefs (must be added, even if no ports present) */ void SysAddSerialPrefs(void) { PrefsAddString("seriala", "serial.device/0"); PrefsAddString("serialb", "*parallel.device/0"); } /* * Open file/device, create new file handle (returns NULL on error) * * Format for device names: /dev////// */ void *Sys_open(const char *name, bool read_only) { bool is_file = (strstr(name, "/dev/") != name); D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write")); // File or device? if (is_file) { // File, open it and get stats BPTR f = Open((char *)name, MODE_OLDFILE); if (!f) return NULL; if (!ExamineFH(f, &FIB)) { Close(f); return NULL; } // Check if file is write protected if (FIB.fib_Protection & FIBF_WRITE) read_only = true; // Create file_handle file_handle *fh = new file_handle; fh->f = f; fh->is_file = true; fh->read_only = read_only; // Detect disk image file layout loff_t size = FIB.fib_Size; Seek(fh->f, 0, OFFSET_BEGINNING); Read(fh->f, tmp_buf, 256); FileDiskLayout(size, tmp_buf, fh->start_byte, fh->size); return fh; } else { // Device, parse string char dev_name[256]; ULONG dev_unit = 0, dev_flags = 0, dev_start = 0, dev_size = 16, dev_bsize = 512; if (sscanf(name, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", dev_name, &dev_unit, &dev_flags, &dev_start, &dev_size, &dev_bsize) < 2) return NULL; // Create IORequest struct IOStdReq *io = (struct IOStdReq *)CreateIORequest(the_port, sizeof(struct IOExtTD)); if (io == NULL) return NULL; // Open device if (OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)io, dev_flags)) { D(bug(" couldn't open device\n")); DeleteIORequest(io); return NULL; } // Check for new style device bool is_nsd = false, does_64bit = false; struct NSDeviceQueryResult nsdqr; nsdqr.DevQueryFormat = 0; nsdqr.SizeAvailable = 0; io->io_Command = NSCMD_DEVICEQUERY; io->io_Length = sizeof(nsdqr); io->io_Data = (APTR)&nsdqr; LONG error = DoIO((struct IORequest *)io); D(bug("DEVICEQUERY returned %ld (length %ld, actual %ld)\n", error, io->io_Length, io->io_Actual)); if ((!error) && (io->io_Actual >= 16) && (io->io_Actual <= sizeof(nsdqr)) && (nsdqr.SizeAvailable == io->io_Actual)) { // Looks like an NSD is_nsd = true; D(bug(" new style device, type %ld\n", nsdqr.DeviceType)); // We only work with trackdisk-like devices if (nsdqr.DeviceType != NSDEVTYPE_TRACKDISK) { CloseDevice((struct IORequest *)io); DeleteIORequest(io); return NULL; } // Check whether device is 64 bit capable UWORD *cmdcheck; for (cmdcheck = nsdqr.SupportedCommands; *cmdcheck; cmdcheck++) { if (*cmdcheck == NSCMD_TD_READ64) { D(bug(" supports 64 bit commands\n")); does_64bit = true; } } } // Create file_handle file_handle *fh = new file_handle; fh->io = io; fh->is_file = false; fh->read_only = read_only; fh->start_byte = (loff_t)dev_start * dev_bsize; fh->size = (loff_t)dev_size * dev_bsize; fh->block_size = dev_bsize; fh->is_nsd = is_nsd; fh->does_64bit = does_64bit; fh->is_ejected = false; fh->is_2060scsi = (strcmp(dev_name, "2060scsi.device") == 0); return fh; } } /* * Close file/device, delete file handle */ void Sys_close(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; D(bug("Sys_close(%08lx)\n", arg)); // File or device? if (fh->is_file) { // File, simply close it Close(fh->f); } else { // Device, close it and delete IORequest fh->io->io_Command = CMD_UPDATE; DoIO((struct IORequest *)fh->io); fh->io->io_Command = TD_MOTOR; fh->io->io_Length = 0; DoIO((struct IORequest *)fh->io); CloseDevice((struct IORequest *)fh->io); DeleteIORequest(fh->io); } delete fh; } /* * Send one I/O request, using 64-bit addressing if the device supports it */ static loff_t send_io_request(file_handle *fh, bool writing, ULONG length, loff_t offset, APTR data) { if (fh->does_64bit) { fh->io->io_Command = writing ? NSCMD_TD_WRITE64 : NSCMD_TD_READ64; fh->io->io_Actual = offset >> 32; } else { fh->io->io_Command = writing ? CMD_WRITE : CMD_READ; fh->io->io_Actual = 0; } fh->io->io_Length = length; fh->io->io_Offset = offset; fh->io->io_Data = data; if (fh->is_2060scsi && fh->block_size == 2048) { // 2060scsi.device has serious problems reading CD-ROMs via TD_READ static struct SCSICmd scsi; const int SENSE_LENGTH = 256; static UBYTE sense_buffer[SENSE_LENGTH]; // Buffer for autosense data static UBYTE cmd_buffer[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; D(bug("send_io_request length=%lu offset=%lu\n", length, (ULONG) offset)); memset(sense_buffer, 0, sizeof(sense_buffer)); scsi.scsi_Command = cmd_buffer; scsi.scsi_CmdLength = sizeof(cmd_buffer); scsi.scsi_SenseData = sense_buffer; scsi.scsi_SenseLength = SENSE_LENGTH; scsi.scsi_Flags = SCSIF_AUTOSENSE | (writing ? SCSIF_WRITE : SCSIF_READ); scsi.scsi_Data = (UWORD *) data; scsi.scsi_Length = length; ULONG block_offset = (ULONG) offset / fh->block_size; ULONG block_length = length / fh->block_size; cmd_buffer[2] = block_offset >> 24; cmd_buffer[3] = block_offset >> 16; cmd_buffer[4] = block_offset >> 8; cmd_buffer[5] = block_offset & 0xff; cmd_buffer[7] = block_length >> 8; cmd_buffer[8] = block_length & 0xff; fh->io->io_Command = HD_SCSICMD; fh->io->io_Actual = 0; fh->io->io_Offset = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); BYTE result = DoIO((struct IORequest *)fh->io); if (result) { D(bug("send_io_request SCSI FAIL result=%lu\n", result)); if (result == HFERR_BadStatus) { D(bug("send_io_request SCSI Status=%lu\n", scsi.scsi_Status)); if (scsi.scsi_Status == 2) { D(bug("send_io_request Sense Key=%02lx\n", sense_buffer[2] & 0x0f)); D(bug("send_io_request ASC=%02lx ASCQ=%02lx\n", sense_buffer[12], sense_buffer[13])); } } return 0; } D(bug("send_io_request SCSI Actual=%lu\n", scsi.scsi_Actual)); if (scsi.scsi_Actual != length) return 0; return scsi.scsi_Actual; } else { // if (DoIO((struct IORequest *)fh->io) || fh->io->io_Actual != length) if (DoIO((struct IORequest *)fh->io)) { D(bug("send_io_request/%ld: Actual=%lu length=%lu Err=%ld\n", __LINE__, fh->io->io_Actual, length, fh->io->io_Error)); return 0; } return fh->io->io_Actual; } } /* * Read "length" bytes from file/device, starting at "offset", to "buffer", * returns number of bytes read (or 0) */ size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length) { file_handle *fh = (file_handle *)arg; if (!fh) { D(bug("Sys_read/%ld return 0\n", __LINE__)); return 0; } D(bug("Sys_read/%ld length=%ld\n", __LINE__, length)); // File or device? if (fh->is_file) { // File, seek to position if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1) { D(bug("Sys_read/%ld return 0\n", __LINE__)); return 0; } // Read data LONG actual = Read(fh->f, buffer, length); if (actual == -1) { D(bug("Sys_read/%ld return 0\n", __LINE__)); return 0; } else { D(bug("Sys_read/%ld return %ld\n", __LINE__, actual)); return actual; } } else { // Device, pre-read (partial read of first block) necessary? loff_t pos = offset + fh->start_byte; size_t actual = 0; uint32 pre_offset = pos % fh->block_size; if (pre_offset) { // Yes, read one block if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0) { D(bug("Sys_read/%ld return %ld\n", __LINE__, 0)); return 0; } // Copy data to destination buffer size_t pre_length = fh->block_size - pre_offset; if (pre_length > length) pre_length = length; memcpy(buffer, tmp_buf + pre_offset, pre_length); // Adjust data pointers buffer = (uint8 *)buffer + pre_length; pos += pre_length; length -= pre_length; actual += pre_length; } // Main read (complete reads of middle blocks) possible? if (length >= fh->block_size) { // Yes, read blocks size_t main_length = length & ~(fh->block_size - 1); if (send_io_request(fh, false, main_length, pos, buffer) == 0) { D(bug("Sys_read/%ld return %ld\n", __LINE__, 0)); return 0; } // Adjust data pointers buffer = (uint8 *)buffer + main_length; pos += main_length; length -= main_length; actual += main_length; } // Post-read (partial read of last block) necessary? if (length) { // Yes, read one block if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0) { D(bug("Sys_read/%ld return %ld\n", __LINE__, 0)); return 0; } // Copy data to destination buffer memcpy(buffer, tmp_buf, length); actual += length; } D(bug("Sys_read/%ld return %ld\n", __LINE__, actual)); return actual; } } /* * Write "length" bytes from "buffer" to file/device, starting at "offset", * returns number of bytes written (or 0) */ size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length) { file_handle *fh = (file_handle *)arg; if (!fh) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } D(bug("Sys_write/%ld length=%ld\n", __LINE__, length)); // File or device? if (fh->is_file) { // File, seek to position if necessary if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } // Write data LONG actual = Write(fh->f, buffer, length); if (actual == -1) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } else { D(bug("Sys_write/%ld return %ld\n", __LINE__, actual)); return actual; } } else { // Device, pre-write (partial write of first block) necessary loff_t pos = offset + fh->start_byte; size_t actual = 0; uint32 pre_offset = pos % fh->block_size; if (pre_offset) { // Yes, read one block if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } // Copy data from source buffer size_t pre_length = fh->block_size - pre_offset; if (pre_length > length) pre_length = length; memcpy(tmp_buf + pre_offset, buffer, pre_length); // Write block back if (send_io_request(fh, true, fh->block_size, pos - pre_offset, tmp_buf) == 0) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } // Adjust data pointers buffer = (uint8 *)buffer + pre_length; pos += pre_length; length -= pre_length; actual += pre_length; } // Main write (complete writes of middle blocks) possible? if (length >= fh->block_size) { // Yes, write blocks size_t main_length = length & ~(fh->block_size - 1); if (send_io_request(fh, true, main_length, pos, buffer) == 0) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } // Adjust data pointers buffer = (uint8 *)buffer + main_length; pos += main_length; length -= main_length; actual += main_length; } // Post-write (partial write of last block) necessary? if (length) { // Yes, read one block if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } // Copy data from source buffer memcpy(buffer, tmp_buf, length); // Write block back if (send_io_request(fh, true, fh->block_size, pos, tmp_buf) == 0) { D(bug("Sys_write/%ld return %ld\n", __LINE__, 0)); return 0; } actual += length; } D(bug("Sys_write/%ld return %ld\n", __LINE__, actual)); return actual; } } /* * Return size of file/device (minus header) */ loff_t SysGetFileSize(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; return fh->size; } /* * Eject volume (if applicable) */ void SysEject(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) { // Flush buffer, turn off the drive motor and eject volume fh->io->io_Command = CMD_UPDATE; DoIO((struct IORequest *)fh->io); fh->io->io_Command = TD_MOTOR; fh->io->io_Length = 0; DoIO((struct IORequest *)fh->io); fh->io->io_Command = TD_EJECT; fh->io->io_Length = 1; DoIO((struct IORequest *)fh->io); fh->is_ejected = true; } } /* * Format volume (if applicable) */ bool SysFormat(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; //!! return true; } /* * Check if file/device is read-only (this includes the read-only flag on Sys_open()) */ bool SysIsReadOnly(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; if (fh->is_file) { // File, return flag given to Sys_open return fh->read_only; } else { // Device, check write protection fh->io->io_Command = TD_PROTSTATUS; DoIO((struct IORequest *)fh->io); if (fh->io->io_Actual) return true; else return fh->read_only; } } /* * Check if the given file handle refers to a fixed or a removable disk */ bool SysIsFixedDisk(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; return true; } /* * Check if a disk is inserted in the drive (always true for files) */ bool SysIsDiskInserted(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return true; else { // Check medium status fh->io->io_Command = TD_CHANGESTATE; fh->io->io_Actual = 0; DoIO((struct IORequest *)fh->io); bool inserted = (fh->io->io_Actual == 0); if (!inserted) { // Disk was ejected and has now been taken out fh->is_ejected = false; } if (fh->is_ejected) { // Disk was ejected but has not yet been taken out, report it as // no longer in the drive return false; } else return inserted; } } /* * Prevent medium removal (if applicable) */ void SysPreventRemoval(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) { // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command struct SCSICmd scsi; static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 1, 0}; scsi.scsi_Length = 0; scsi.scsi_Command = (UBYTE *)the_cmd; scsi.scsi_CmdLength = 6; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; DoIO((struct IORequest *)fh->io); } } /* * Allow medium removal (if applicable) */ void SysAllowRemoval(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) { // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command struct SCSICmd scsi; static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 0, 0}; scsi.scsi_Length = 0; scsi.scsi_Command = (UBYTE *)the_cmd; scsi.scsi_CmdLength = 6; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; DoIO((struct IORequest *)fh->io); } } /* * Read CD-ROM TOC (binary MSF format, 804 bytes max.) */ bool SysCDReadTOC(void *arg, uint8 *toc) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return false; else { // Send READ TOC MSF SCSI command struct SCSICmd scsi; static const UBYTE read_toc_cmd[10] = {0x43, 0x02, 0, 0, 0, 0, 0, 0x03, 0x24, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 804; scsi.scsi_Command = (UBYTE *)read_toc_cmd; scsi.scsi_CmdLength = 10; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return false; memcpy(toc, tmp_buf, 804); return true; } } /* * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard) */ bool SysCDGetPosition(void *arg, uint8 *pos) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return false; else { // Send READ SUB-CHANNEL SCSI command struct SCSICmd scsi; static const UBYTE read_subq_cmd[10] = {0x42, 0x02, 0x40, 0x01, 0, 0, 0, 0, 0x10, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 16; scsi.scsi_Command = (UBYTE *)read_subq_cmd; scsi.scsi_CmdLength = 10; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return false; memcpy(pos, tmp_buf, 16); return true; } } /* * Play CD audio */ bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return false; else { // Send PLAY AUDIO MSF SCSI command struct SCSICmd scsi; UBYTE play_cmd[10] = {0x47, 0, 0, start_m, start_s, start_f, end_m, end_s, end_f, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 0; scsi.scsi_Command = play_cmd; scsi.scsi_CmdLength = 10; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return false; return true; } } /* * Pause CD audio */ bool SysCDPause(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return false; else { // Send PAUSE RESUME SCSI command struct SCSICmd scsi; static const UBYTE pause_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 0, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 0; scsi.scsi_Command = (UBYTE *)pause_cmd; scsi.scsi_CmdLength = 10; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return false; return true; } } /* * Resume paused CD audio */ bool SysCDResume(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return false; else { // Send PAUSE RESUME SCSI command struct SCSICmd scsi; static const UBYTE resume_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 1, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 0; scsi.scsi_Command = (UBYTE *)resume_cmd; scsi.scsi_CmdLength = 10; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return false; return true; } } /* * Stop CD audio */ bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return false; else { uint8 end_m = lead_out_m; uint8 end_s = lead_out_s; uint8 end_f = lead_out_f + 1; if (end_f >= 75) { end_f = 0; end_s++; if (end_s >= 60) { end_s = 0; end_m++; } } // Send PLAY AUDIO MSF SCSI command (play first frame of lead-out area) struct SCSICmd scsi; UBYTE play_cmd[10] = {0x47, 0, 0, lead_out_m, lead_out_s, lead_out_f, end_m, end_s, end_f, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 0; scsi.scsi_Command = play_cmd; scsi.scsi_CmdLength = 10; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return false; return true; } } /* * Perform CD audio fast-forward/fast-reverse operation starting from specified address */ bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse) { file_handle *fh = (file_handle *)arg; if (!fh) return false; //!! return false; } /* * Set CD audio volume (0..255 each channel) */ void SysCDSetVolume(void *arg, uint8 left, uint8 right) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) { // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command struct SCSICmd scsi; static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 20; scsi.scsi_Command = (UBYTE *)mode_sense_cmd; scsi.scsi_CmdLength = 6; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return; tmp_buf[6] = 0x04; // Immed tmp_buf[9] = 0; // LBA/sec format tmp_buf[10] = 0; // LBA/sec tmp_buf[11] = 0; tmp_buf[13] = left; // Port 0 volume tmp_buf[15] = right; // Port 1 volume // Send MODE SELECT (CD-ROM Audio Control Parameters Page) SCSI command static const UBYTE mode_select_cmd[6] = {0x15, 0x10, 0, 0, 20, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 20; scsi.scsi_Command = (UBYTE *)mode_select_cmd; scsi.scsi_CmdLength = 6; scsi.scsi_Flags = SCSIF_WRITE; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; DoIO((struct IORequest *)fh->io); } } /* * Get CD audio volume (0..255 each channel) */ void SysCDGetVolume(void *arg, uint8 &left, uint8 &right) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (!fh->is_file) { // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command struct SCSICmd scsi; static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0}; scsi.scsi_Data = (UWORD *)tmp_buf; scsi.scsi_Length = 20; scsi.scsi_Command = (UBYTE *)mode_sense_cmd; scsi.scsi_CmdLength = 6; scsi.scsi_Flags = SCSIF_READ; scsi.scsi_Status = 0; fh->io->io_Data = &scsi; fh->io->io_Length = sizeof(scsi); fh->io->io_Command = HD_SCSICMD; if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status) return; left = tmp_buf[13]; // Port 0 volume right = tmp_buf[15]; // Port 1 volume } } BasiliskII/src/AmigaOS/scsi_amiga.cpp0000644000175000017500000001605410736405217017626 0ustar centriscentris/* * scsi_amiga.cpp - SCSI Manager, Amiga specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #define __USE_SYSBASE #include #include #include "sysdeps.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "scsi.h" #define DEBUG 0 #include "debug.h" // Global variables static struct SCSICmd scsi; static IOStdReq *ios[8*8]; // IORequests for 8 units and 8 LUNs each static IOStdReq *io; // Active IORequest (selected target) static struct MsgPort *the_port = NULL; // Message port for device communication static ULONG buffer_size; // Size of data buffer static UBYTE *buffer = NULL; // Pointer to data buffer static ULONG buffer_memf; // Buffer memory flags static UBYTE cmd_buffer[12]; // Buffer for SCSI command const int SENSE_LENGTH = 256; static UBYTE *sense_buffer = NULL; // Buffer for autosense data static bool direct_transfers_supported = false; // Direct data transfers (bypassing the buffer) are supported /* * Initialization */ void SCSIInit(void) { int id, lun; int memtype = PrefsFindInt32("scsimemtype"); switch (memtype) { case 1: buffer_memf = MEMF_24BITDMA | MEMF_PUBLIC; break; case 2: buffer_memf = MEMF_ANY | MEMF_PUBLIC; direct_transfers_supported = true; break; default: buffer_memf = MEMF_CHIP | MEMF_PUBLIC; break; } // Create port and buffers the_port = CreateMsgPort(); buffer = (UBYTE *)AllocMem(buffer_size = 0x10000, buffer_memf); sense_buffer = (UBYTE *)AllocMem(SENSE_LENGTH, MEMF_CHIP | MEMF_PUBLIC); if (the_port == NULL || buffer == NULL || sense_buffer == NULL) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } // Create and open IORequests for all 8 units (and all 8 LUNs) for (id=0; id<8; id++) { for (lun=0; lun<8; lun++) ios[id*8+lun] = NULL; char prefs_name[16]; sprintf(prefs_name, "scsi%d", id); const char *str = PrefsFindString(prefs_name); if (str) { char dev_name[256]; ULONG dev_unit = 0; if (sscanf(str, "%[^/]/%ld", dev_name, &dev_unit) == 2) { for (lun=0; lun<8; lun++) { struct IOStdReq *io = (struct IOStdReq *)CreateIORequest(the_port, sizeof(struct IOStdReq)); if (io == NULL) continue; if (OpenDevice((UBYTE *) dev_name, dev_unit + lun * 10, (struct IORequest *)io, 0)) { DeleteIORequest(io); continue; } io->io_Data = &scsi; io->io_Length = sizeof(scsi); io->io_Command = HD_SCSICMD; ios[id*8+lun] = io; } } } } // Reset SCSI bus SCSIReset(); // Init SCSICmd memset(&scsi, 0, sizeof(scsi)); scsi.scsi_Command = cmd_buffer; scsi.scsi_SenseData = sense_buffer; scsi.scsi_SenseLength = SENSE_LENGTH; } /* * Deinitialization */ void SCSIExit(void) { // Close all devices for (int i=0; i<8; i++) for (int j=0; j<8; j++) { struct IOStdReq *io = ios[i*8+j]; if (io) { CloseDevice((struct IORequest *)io); DeleteIORequest(io); } } // Delete port and buffers if (the_port) DeleteMsgPort(the_port); if (buffer) FreeMem(buffer, buffer_size); if (sense_buffer) FreeMem(sense_buffer, SENSE_LENGTH); } /* * Check if requested data size fits into buffer, allocate new buffer if needed */ static bool try_buffer(int size) { if (size <= buffer_size) return true; UBYTE *new_buffer = (UBYTE *)AllocMem(size, buffer_memf); if (new_buffer == NULL) return false; FreeMem(buffer, buffer_size); buffer = new_buffer; buffer_size = size; return true; } /* * Set SCSI command to be sent by scsi_send_cmd() */ void scsi_set_cmd(int cmd_length, uint8 *cmd) { scsi.scsi_CmdLength = cmd_length; memcpy(cmd_buffer, cmd, cmd_length); } /* * Check for presence of SCSI target */ bool scsi_is_target_present(int id) { return ios[id * 8] != NULL; } /* * Set SCSI target (returns false on error) */ bool scsi_set_target(int id, int lun) { struct IOStdReq *new_io = ios[id * 8 + lun]; if (new_io == NULL) return false; if (new_io != io) scsi.scsi_SenseActual = 0; // Clear sense data when selecting new target io = new_io; return true; } /* * Send SCSI command to active target (scsi_set_command() must have been called), * read/write data according to S/G table (returns false on error); timeout is in 1/60 sec */ bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout) { // Bypass the buffer if there's only one S/G table entry bool do_direct_transfer = (sg_size == 1 && ((uint32)sg_ptr[0] & 1) == 0 && direct_transfers_supported); if (!do_direct_transfer) { // Check if buffer is large enough, allocate new buffer if needed if (!try_buffer(data_length)) { char str[256]; sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length); ErrorAlert(str); return false; } // Process S/G table when writing if (!reading) { D(bug(" writing to buffer\n")); uint8 *buffer_ptr = buffer; for (int i=0; i #include #include #define __USE_SYSBASE #include #include #include #include #include "clip.h" #include "prefs.h" #define DEBUG 0 #include "debug.h" // Global variables static struct IFFHandle *iffw = NULL; static struct ClipboardHandle *ch = NULL; static bool clipboard_open = false; static bool no_clip_conversion; // Conversion tables static const uint8 mac2iso[0x80] = { 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, 0x2b, 0xb0, 0xa2, 0xa3, 0xa7, 0xb7, 0xb6, 0xdf, 0xae, 0xa9, 0x20, 0xb4, 0xa8, 0x23, 0xc6, 0xd8, 0x20, 0xb1, 0x3c, 0x3e, 0xa5, 0xb5, 0xf0, 0x53, 0x50, 0x70, 0x2f, 0xaa, 0xba, 0x4f, 0xe6, 0xf8, 0xbf, 0xa1, 0xac, 0x2f, 0x66, 0x7e, 0x44, 0xab, 0xbb, 0x2e, 0x20, 0xc0, 0xc3, 0xd5, 0x4f, 0x6f, 0x2d, 0x2d, 0x22, 0x22, 0x60, 0x27, 0xf7, 0x20, 0xff, 0x59, 0x2f, 0xa4, 0x3c, 0x3e, 0x66, 0x66, 0x23, 0xb7, 0x2c, 0x22, 0x25, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, 0x20, 0xd2, 0xda, 0xdb, 0xd9, 0x69, 0x5e, 0x7e, 0xaf, 0x20, 0xb7, 0xb0, 0xb8, 0x22, 0xb8, 0x20 }; /* * Initialization */ void ClipInit(void) { no_clip_conversion = PrefsFindBool("noclipconversion"); // Create clipboard IFF handle iffw = AllocIFF(); if (iffw) { ch = OpenClipboard(PRIMARY_CLIP); if (ch) { iffw->iff_Stream = (ULONG)ch; InitIFFasClip(iffw); clipboard_open = true; } } } /* * Deinitialization */ void ClipExit(void) { if (ch) CloseClipboard(ch); if (iffw) FreeIFF(iffw); } /* * Mac application reads clipboard */ void GetScrap(void **handle, uint32 type, int32 offset) { D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); } /* * Mac application wrote to clipboard */ void PutScrap(uint32 type, void *scrap, int32 length) { D(bug("PutScrap type %08lx, data %08lx, length %ld\n", type, scrap, length)); if (length <= 0 || !clipboard_open) return; switch (type) { case 'TEXT': { D(bug(" clipping TEXT\n")); // Open IFF stream if (OpenIFF(iffw, IFFF_WRITE)) break; // Convert text from Mac charset to ISO-Latin1 uint8 *buf = new uint8[length]; uint8 *p = (uint8 *)scrap; uint8 *q = buf; for (int i=0; i LF c = 10; } else if (!no_clip_conversion) c = mac2iso[c & 0x7f]; *q++ = c; } // Write text if (!PushChunk(iffw, 'FTXT', 'FORM', IFFSIZE_UNKNOWN)) { if (!PushChunk(iffw, 0, 'CHRS', IFFSIZE_UNKNOWN)) { WriteChunkBytes(iffw, scrap, length); PopChunk(iffw); } PopChunk(iffw); } // Close IFF stream CloseIFF(iffw); delete[] buf; break; } } } BasiliskII/src/AmigaOS/user_strings_amiga.cpp0000644000175000017500000000670110736405217021412 0ustar centriscentris/* * user_strings_amiga.cpp - AmigaOS-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "user_strings.h" // Platform-specific string definitions user_string_def platform_strings[] = { // Common strings that have a platform-specific variant {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under AmigaOS. Basilisk II will try to unmount it."}, {STR_EXTFS_CTRL, "Amiga Root"}, {STR_EXTFS_NAME, "Amiga Directory Tree"}, {STR_EXTFS_VOLUME_NAME, "Amiga"}, // Purely platform-specific strings {STR_NO_PREPARE_EMUL_ERR, "PrepareEmul is not installed. Run PrepareEmul and then try again to start Basilisk II."}, {STR_NO_GADTOOLS_LIB_ERR, "Cannot open gadtools.library V39."}, {STR_NO_IFFPARSE_LIB_ERR, "Cannot open iffparse.library V39."}, {STR_NO_ASL_LIB_ERR, "Cannot open asl.library V36."}, {STR_NO_TIMER_DEV_ERR, "Cannot open timer.device."}, {STR_NO_P96_MODE_ERR, "The selected screen mode is not a Picasso96 or CyberGraphX mode."}, {STR_NO_VIDEO_MODE_ERR, "Cannot obtain selected video mode."}, {STR_WRONG_SCREEN_DEPTH_ERR, "Basilisk II only supports 8, 16 or 24 bit screens."}, {STR_WRONG_SCREEN_FORMAT_ERR, "Basilisk II only supports big-endian chunky ARGB screen modes."}, {STR_ENFORCER_RUNNING_ERR, "Enforcer/CyberGuard is running. Remove and then try again to start Basilisk II."}, {STR_NOT_ETHERNET_WARN, "The selected network device is not an Ethernet device. Networking will be disabled."}, {STR_NO_MULTICAST_WARN, "Your Ethernet card does not support multicast and is not usable with AppleTalk. Please report this to the manufacturer of the card."}, {STR_NO_GTLAYOUT_LIB_WARN, "Cannot open gtlayout.library V39. The preferences editor GUI will not be available."}, {STR_NO_AHI_WARN, "Cannot open ahi.device V2. Audio output will be disabled."}, {STR_NO_AHI_CTRL_WARN, "Cannot open AHI control structure. Audio output will be disabled."}, {STR_NOT_ENOUGH_MEM_WARN, "Could not get %lu MBytes of memory.\nShould I use the largest Block (%lu MBytes) instead ?"}, {STR_AHI_MODE_CTRL, "AHI Mode"}, {STR_SCSI_MEMTYPE_CTRL, "Buffer Memory Type"}, {STR_MEMTYPE_CHIP_LAB, "Chip"}, {STR_MEMTYPE_24BITDMA_LAB, "24-Bit DMA"}, {STR_MEMTYPE_ANY_LAB, "Any"}, {STR_SCSI_DEVICES_CTRL, "Virtual SCSI Devices"}, {-1, NULL} // End marker }; /* * Fetch pointer to string, given the string number */ const char *GetString(int num) { // First search for platform-specific string int i = 0; while (platform_strings[i].num >= 0) { if (platform_strings[i].num == num) return platform_strings[i].str; i++; } // Not found, search for common string i = 0; while (common_strings[i].num >= 0) { if (common_strings[i].num == num) return common_strings[i].str; i++; } return NULL; } BasiliskII/src/AmigaOS/ether_amiga.cpp0000644000175000017500000004370010736405217017772 0ustar centriscentris/* * ether_amiga.cpp - Ethernet device driver, AmigaOS specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #define __USE_SYSBASE #include #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "macos_util.h" #include "ether.h" #include "ether_defs.h" #define DEBUG 0 #include "debug.h" #define MONITOR 0 // These messages are sent to the network process const uint32 MSG_CLEANUP = 'clea'; // Remove all protocols const uint32 MSG_ADD_MULTI = 'addm'; // Add multicast address const uint32 MSG_DEL_MULTI = 'delm'; // Add multicast address const uint32 MSG_ATTACH_PH = 'atph'; // Attach protocol handler const uint32 MSG_DETACH_PH = 'deph'; // Attach protocol handler const uint32 MSG_WRITE = 'writ'; // Write packet struct NetMessage : public Message { NetMessage(uint32 what_, const struct MsgPort *reply_port) { what = what_; mn_ReplyPort = (struct MsgPort *)reply_port; mn_Length = sizeof(*this); } uint32 what; uint32 pointer; uint16 type; int16 result; }; // List of attached protocols static const int NUM_READ_REQUESTS = 32; // Number of read requests that are sent to device in advance struct NetProtocol : public Node { struct IOSana2Req read_io[NUM_READ_REQUESTS]; uint8 read_buf[NUM_READ_REQUESTS][1518]; // 14 bytes header, 1500 bytes data, 4 bytes CRC uint16 type; uint32 handler; }; static struct List prot_list; // Global variables static struct Process *net_proc = NULL; // Network device handler process static bool proc_error; // Flag: process didn't initialize static struct MsgPort *proc_port = NULL; // Message port of process, for communication with main task static struct MsgPort *reply_port = NULL; // Reply port for communication with process static struct MsgPort *read_port = NULL; // Reply port for read IORequests (set up and owned by network process) static bool write_done = false; // Flag: write request done extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp) // Prototypes static void net_func(void); /* * Send message to network process */ static int16 send_to_proc(uint32 what, uint32 pointer = 0, uint16 type = 0) { D(bug("sending %08lx to net_proc\n", what)); NetMessage msg(what, reply_port); msg.pointer = pointer; msg.type = type; PutMsg(proc_port, &msg); WaitPort(reply_port); GetMsg(reply_port); D(bug(" sent\n")); return msg.result; } /* * Initialization */ bool ether_init(void) { // Do nothing if no Ethernet device specified if (PrefsFindString("ether") == NULL) return false; // Initialize protocol list NewList(&prot_list); // Create message port reply_port = CreateMsgPort(); if (reply_port == NULL) goto open_error; D(bug("signal mask %08lx\n", 1 << reply_port->mp_SigBit)); // Start process proc_error = false; SetSignal(0, SIGF_SINGLE); net_proc = CreateNewProcTags( NP_Entry, (ULONG)net_func, NP_Name, (ULONG)"Basilisk II Ethernet Task", NP_Priority, 1, TAG_END ); if (net_proc == NULL) goto open_error; // Wait for signal from process Wait(SIGF_SINGLE); // Initialization error? Then bail out if (proc_error) goto open_error; // Everything OK return true; open_error: net_proc = NULL; if (reply_port) { DeleteMsgPort(reply_port); reply_port = NULL; } return false; } /* * Deinitialization */ void ether_exit(void) { // Stop process if (net_proc) { SetSignal(0, SIGF_SINGLE); Signal(&net_proc->pr_Task, SIGBREAKF_CTRL_C); Wait(SIGF_SINGLE); } // Delete reply port if (reply_port) { DeleteMsgPort(reply_port); reply_port = NULL; } } /* * Reset */ void ether_reset(void) { // Remove all protocols if (net_proc) send_to_proc(MSG_CLEANUP); } /* * Add multicast address */ int16 ether_add_multicast(uint32 pb) { return send_to_proc(MSG_ADD_MULTI, pb); } /* * Delete multicast address */ int16 ether_del_multicast(uint32 pb) { return send_to_proc(MSG_DEL_MULTI, pb); } /* * Attach protocol handler */ int16 ether_attach_ph(uint16 type, uint32 handler) { return send_to_proc(MSG_ATTACH_PH, handler, type); } /* * Detach protocol handler */ int16 ether_detach_ph(uint16 type) { return send_to_proc(MSG_DETACH_PH, type); } /* * Transmit raw ethernet packet */ int16 ether_write(uint32 wds) { send_to_proc(MSG_WRITE, wds); return 1; // Command in progress } /* * Remove protocol from protocol list */ static void remove_protocol(NetProtocol *p) { // Remove from list Forbid(); Remove(p); Permit(); // Cancel read requests for (int i=0; iread_io + i)); WaitIO((struct IORequest *)(p->read_io + i)); } // Free protocol struct FreeMem(p, sizeof(NetProtocol)); } /* * Remove all protocols */ static void remove_all_protocols(void) { NetProtocol *n = (NetProtocol *)prot_list.lh_Head, *next; while ((next = (NetProtocol *)n->ln_Succ) != NULL) { remove_protocol(n); n = next; } } /* * Copy received network packet to Mac side */ static __saveds __regargs LONG copy_to_buff(uint8 *to /*a0*/, uint8 *from /*a1*/, uint32 packet_len /*d0*/) { D(bug("CopyToBuff to %08lx, from %08lx, size %08lx\n", to, from, packet_len)); // It would be more efficient (and take up less memory) if we // could invoke the packet handler from here. But we don't know // in what context we run, so calling Execute68k() would not be // a good idea, and even worse, we might run inside a hardware // interrupt, so we can't even trigger a Basilisk interrupt from // here and wait for its completion. CopyMem(from, to, packet_len); #if MONITOR bug("Receiving Ethernet packet:\n"); for (int i=0; imp_SigBit; // Create message ports for device I/O read_port = CreateMsgPort(); if (read_port == NULL) goto quit; read_mask = 1 << read_port->mp_SigBit; write_port = CreateMsgPort(); if (write_port == NULL) goto quit; write_mask = 1 << write_port->mp_SigBit; control_port = CreateMsgPort(); if (control_port == NULL) goto quit; // Create control IORequest control_io = (struct IOSana2Req *)CreateIORequest(control_port, sizeof(struct IOSana2Req)); if (control_io == NULL) goto quit; control_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug // Parse device name char dev_name[256]; ULONG dev_unit; str = PrefsFindString("ether"); if (str) { const char *FirstSlash = strchr(str, '/'); const char *LastSlash = strrchr(str, '/'); if (FirstSlash && FirstSlash && FirstSlash != LastSlash) { // Device name contains path, i.e. "Networks/xyzzy.device" const char *lp = str; char *dp = dev_name; while (lp != LastSlash) *dp++ = *lp++; *dp = '\0'; if (strlen(dev_name) < 1) goto quit; if (sscanf(LastSlash, "/%ld", &dev_unit) != 1) goto quit; } else { if (sscanf(str, "%[^/]/%ld", dev_name, &dev_unit) != 2) goto quit; } } else goto quit; // Open device control_io->ios2_BufferManagement = buffer_tags; od_error = OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)control_io, 0); if (od_error != 0 || control_io->ios2_Req.io_Device == 0) { printf("WARNING: OpenDevice(<%s>, unit=%d) returned error %d)\n", (UBYTE *)dev_name, dev_unit, od_error); goto quit; } opened = true; // Is it Ethernet? control_io->ios2_Req.io_Command = S2_DEVICEQUERY; control_io->ios2_StatData = (void *)&query_data; DoIO((struct IORequest *)control_io); if (control_io->ios2_Req.io_Error) goto quit; if (query_data.HardwareType != S2WireType_Ethernet) { WarningAlert(GetString(STR_NOT_ETHERNET_WARN)); goto quit; } // Yes, create IORequest for writing write_io = (struct IOSana2Req *)CreateIORequest(write_port, sizeof(struct IOSana2Req)); if (write_io == NULL) goto quit; memcpy(write_io, control_io, sizeof(struct IOSana2Req)); write_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug write_io->ios2_Req.io_Message.mn_ReplyPort = write_port; // Configure Ethernet control_io->ios2_Req.io_Command = S2_GETSTATIONADDRESS; DoIO((struct IORequest *)control_io); memcpy(ether_addr, control_io->ios2_DstAddr, 6); memcpy(control_io->ios2_SrcAddr, control_io->ios2_DstAddr, 6); control_io->ios2_Req.io_Command = S2_CONFIGINTERFACE; DoIO((struct IORequest *)control_io); D(bug("Ethernet address %08lx %08lx\n", *(uint32 *)ether_addr, *(uint16 *)(ether_addr + 4))); // Initialization went well, inform main task proc_error = false; Signal(MainTask, SIGF_SINGLE); // Main loop for (;;) { // Wait for I/O and messages (CTRL_C is used for quitting the task) ULONG sig = Wait(proc_port_mask | read_mask | write_mask | SIGBREAKF_CTRL_C); // Main task wants to quit us if (sig & SIGBREAKF_CTRL_C) break; // Main task sent a command to us if (sig & proc_port_mask) { struct NetMessage *msg; while (msg = (NetMessage *)GetMsg(proc_port)) { D(bug("net_proc received %08lx\n", msg->what)); switch (msg->what) { case MSG_CLEANUP: remove_all_protocols(); break; case MSG_ADD_MULTI: control_io->ios2_Req.io_Command = S2_ADDMULTICASTADDRESS; Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6); DoIO((struct IORequest *)control_io); if (control_io->ios2_Req.io_Error == S2ERR_NOT_SUPPORTED) { WarningAlert(GetString(STR_NO_MULTICAST_WARN)); msg->result = noErr; } else if (control_io->ios2_Req.io_Error) msg->result = eMultiErr; else msg->result = noErr; break; case MSG_DEL_MULTI: control_io->ios2_Req.io_Command = S2_DELMULTICASTADDRESS; Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6); DoIO((struct IORequest *)control_io); if (control_io->ios2_Req.io_Error) msg->result = eMultiErr; else msg->result = noErr; break; case MSG_ATTACH_PH: { uint16 type = msg->type; uint32 handler = msg->pointer; // Protocol of that type already installed? NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next; while ((next = (NetProtocol *)p->ln_Succ) != NULL) { if (p->type == type) { msg->result = lapProtErr; goto reply; } p = next; } // Allocate NetProtocol, set type and handler p = (NetProtocol *)AllocMem(sizeof(NetProtocol), MEMF_PUBLIC); if (p == NULL) { msg->result = lapProtErr; goto reply; } p->type = type; p->handler = handler; // Set up and submit read requests for (int i=0; iread_io + i, control_io, sizeof(struct IOSana2Req)); p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Name = (char *)p; // Hide pointer to NetProtocol in node name p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug p->read_io[i].ios2_Req.io_Message.mn_ReplyPort = read_port; p->read_io[i].ios2_Req.io_Command = CMD_READ; p->read_io[i].ios2_PacketType = type; p->read_io[i].ios2_Data = p->read_buf[i]; p->read_io[i].ios2_Req.io_Flags = SANA2IOF_RAW; BeginIO((struct IORequest *)(p->read_io + i)); } // Add protocol to list AddTail(&prot_list, p); // Everything OK msg->result = noErr; break; } case MSG_DETACH_PH: { uint16 type = msg->type; msg->result = lapProtErr; NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next; while ((next = (NetProtocol *)p->ln_Succ) != NULL) { if (p->type == type) { remove_protocol(p); msg->result = noErr; break; } p = next; } break; } case MSG_WRITE: { // Get pointer to Write Data Structure uint32 wds = msg->pointer; write_io->ios2_Data = (void *)wds; // Calculate total packet length long len = 0; uint32 tmp = wds; for (;;) { int16 w = ReadMacInt16(tmp); if (w == 0) break; len += w; tmp += 6; } write_io->ios2_DataLength = len; // Get destination address uint32 hdr = ReadMacInt32(wds + 2); Mac2Host_memcpy(write_io->ios2_DstAddr, hdr, 6); // Get packet type uint32 type = ReadMacInt16(hdr + 12); if (type <= 1500) type = 0; // 802.3 packet write_io->ios2_PacketType = type; // Multicast/broadcard packet? if (write_io->ios2_DstAddr[0] & 1) { if (*(uint32 *)(write_io->ios2_DstAddr) == 0xffffffff && *(uint16 *)(write_io->ios2_DstAddr + 4) == 0xffff) write_io->ios2_Req.io_Command = S2_BROADCAST; else write_io->ios2_Req.io_Command = S2_MULTICAST; } else write_io->ios2_Req.io_Command = CMD_WRITE; // Send packet write_done = false; write_io->ios2_Req.io_Flags = SANA2IOF_RAW; BeginIO((IORequest *)write_io); break; } } reply: D(bug(" net_proc replying\n")); ReplyMsg(msg); } } // Packet received if (sig & read_mask) { D(bug(" packet received, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); } // Packet write completed if (sig & write_mask) { GetMsg(write_port); WriteMacInt32(ether_data + ed_Result, write_io->ios2_Req.io_Error ? excessCollsns : 0); write_done = true; D(bug(" packet write done, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); } } quit: // Close everything remove_all_protocols(); if (opened) { if (CheckIO((struct IORequest *)write_io) == 0) { AbortIO((struct IORequest *)write_io); WaitIO((struct IORequest *)write_io); } CloseDevice((struct IORequest *)control_io); } if (write_io) DeleteIORequest(write_io); if (control_io) DeleteIORequest(control_io); if (control_port) DeleteMsgPort(control_port); if (write_port) DeleteMsgPort(write_port); if (read_port) DeleteMsgPort(read_port); // Send signal to main task to confirm termination Forbid(); Signal(MainTask, SIGF_SINGLE); } /* * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers */ void EtherInterrupt(void) { D(bug("EtherIRQ\n")); // Packet write done, enqueue DT to call IODone if (write_done) { EnqueueMac(ether_data + ed_DeferredTask, 0xd92); write_done = false; } // Call protocol handler for received packets IOSana2Req *io; while (io = (struct IOSana2Req *)GetMsg(read_port)) { // Get pointer to NetProtocol (hidden in node name) NetProtocol *p = (NetProtocol *)io->ios2_Req.io_Message.mn_Node.ln_Name; // No default handler if (p->handler == 0) continue; // Copy header to RHA Host2Mac_memcpy(ether_data + ed_RHA, io->ios2_Data, 14); D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12))); // Call protocol handler M68kRegisters r; r.d[0] = *(uint16 *)((uint32)io->ios2_Data + 12); // Packet type r.d[1] = io->ios2_DataLength - 18; // Remaining packet length (without header, for ReadPacket) (-18 because the CRC is also included) r.a[0] = (uint32)io->ios2_Data + 14; // Pointer to packet (host address, for ReadPacket) r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", p->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4])); Execute68k(p->handler, &r); // Resend IORequest io->ios2_Req.io_Flags = SANA2IOF_RAW; BeginIO((struct IORequest *)io); } D(bug(" EtherIRQ done\n")); } BasiliskII/src/video.cpp0000644000175000017500000006657310736405217015370 0ustar centriscentris/* * video.cpp - Video/graphics emulation * * Basilisk II (C) 1997-2008 Christian Bauer * Portions written by Marc Hellwig * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 1 "Device Manager" * Designing Cards and Drivers for the Macintosh Family, Second Edition * Designing PCI Cards and Drivers for Power Macintosh Computers * Display Device Driver Guide */ #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "slot_rom.h" #include "video.h" #include "video_defs.h" #define DEBUG 0 #include "debug.h" // Next available NuBus slot ID uint8 monitor_desc::next_slot_id = 0x80; // Vector of pointers to available monitor descriptions, filled by VideoInit() vector VideoMonitors; /* * Find palette size for given color depth */ static int palette_size(video_depth depth) { switch (depth) { case VDEPTH_1BIT: return 2; case VDEPTH_2BIT: return 4; case VDEPTH_4BIT: return 16; case VDEPTH_8BIT: return 256; case VDEPTH_16BIT: return 32; case VDEPTH_32BIT: return 256; default: return 0; } } /* * Find pointer to monitor_desc for given slot ID (or NULL if not found) */ static monitor_desc *find_monitor(uint8 id) { vector::const_iterator i, end = VideoMonitors.end(); for (i = VideoMonitors.begin(); i != end; ++i) { if ((*i)->get_slot_id() == id) return *i; } return NULL; } /* * monitor_desc constructor */ monitor_desc::monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id) : modes(available_modes) { // Assign the next slot ID on construction slot_id = next_slot_id++; // Initialize Apple mode list uint16 mode = 0x80; for (int depth = VDEPTH_1BIT; depth <= VDEPTH_32BIT; depth++) { if (has_depth(video_depth(depth))) apple_mode_for_depth[depth] = mode++; else apple_mode_for_depth[depth] = 0; } // Set default mode current_mode = find_mode(depth_to_apple_mode(default_depth), default_id); } /* * Get bytes-per-row value for specified resolution/depth * (if the mode isn't supported, make a good guess) */ uint32 monitor_desc::get_bytes_per_row(video_depth depth, uint32 id) const { vector::const_iterator i, end = modes.end(); for (i = modes.begin(); i != end; ++i) { if (i->depth == depth && i->resolution_id == id) return i->bytes_per_row; } uint32 x, y; get_size_of_resolution(id, x, y); return TrivialBytesPerRow(x, depth); } /* * Check whether a mode with the specified depth exists on this display */ bool monitor_desc::has_depth(video_depth depth) const { vector::const_iterator i = modes.begin(), end = modes.end(); while (i != end) { if (i->depth == depth) return true; ++i; } return false; } /* * Check whether the specified resolution ID is one of the supported resolutions */ bool monitor_desc::has_resolution(uint32 id) const { vector::const_iterator i, end = modes.end(); for (i = modes.begin(); i != end; ++i) { if (i->resolution_id == id) return true; } return false; } /* * Find specified mode (depth/resolution) (or invalid_mode() if not found) */ vector::const_iterator monitor_desc::find_mode(uint16 apple_mode, uint32 id) const { vector::const_iterator i, end = modes.end(); for (i = modes.begin(); i != end; ++i) { if (i->resolution_id == id && depth_to_apple_mode(i->depth) == apple_mode) return i; } return i; } /* * Find maximum supported depth for given resolution ID */ video_depth monitor_desc::max_depth_of_resolution(uint32 id) const { video_depth m = VDEPTH_1BIT; vector::const_iterator i, end = modes.end(); for (i = modes.begin(); i != end; ++i) { if (i->depth > m) m = i->depth; } return m; } /* * Get X/Y size of specified resolution */ void monitor_desc::get_size_of_resolution(uint32 id, uint32 &x, uint32 &y) const { vector::const_iterator i, end = modes.end(); for (i = modes.begin(); i != end; ++i) { if (i->resolution_id == id) { x = i->x; y = i->y; return; } } x = y = 0; } /* * Set palette to 50% gray */ void monitor_desc::set_gray_palette(void) { for (int i=0; i<256; i++) { palette[i * 3 + 0] = 127; palette[i * 3 + 1] = 127; palette[i * 3 + 2] = 127; } set_palette(palette, 256); } /* * Load gamma-corrected black-to-white ramp to palette for direct-color mode */ void monitor_desc::load_ramp_palette(void) { // Find tables for gamma correction uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL; bool have_gamma = false; int data_width = 0; if (gamma_table) { uint32 table = gamma_table; red_gamma = Mac2HostAddr(table + gFormulaData + ReadMacInt16(table + gFormulaSize)); int chan_cnt = ReadMacInt16(table + gChanCnt); if (chan_cnt == 1) green_gamma = blue_gamma = red_gamma; else { int ofs = ReadMacInt16(table + gDataCnt); green_gamma = red_gamma + ofs; blue_gamma = green_gamma + ofs; } data_width = ReadMacInt16(table + gDataWidth); have_gamma = true; } int num = (current_mode->depth == VDEPTH_16BIT ? 32 : 256); uint8 *p = palette; for (int i=0; i> (8 - data_width)]; green = green_gamma[green >> (8 - data_width)]; blue = blue_gamma[blue >> (8 - data_width)]; } *p++ = red; *p++ = green; *p++ = blue; } set_palette(palette, num); } /* * Allocate gamma table of specified size */ bool monitor_desc::allocate_gamma_table(int size) { M68kRegisters r; if (size > alloc_gamma_table_size) { if (gamma_table) { r.a[0] = gamma_table; Execute68kTrap(0xa01f, &r); // DisposePtr() gamma_table = 0; alloc_gamma_table_size = 0; } r.d[0] = size; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) return false; gamma_table = r.a[0]; alloc_gamma_table_size = size; } return true; } /* * Set gamma table (0 = build linear ramp) */ bool monitor_desc::set_gamma_table(uint32 user_table) { if (user_table == 0) { // Build linear ramp, 256 entries // Allocate new table, if necessary if (!allocate_gamma_table(SIZEOF_GammaTbl + 256)) return memFullErr; // Initialize header WriteMacInt16(gamma_table + gVersion, 0); WriteMacInt16(gamma_table + gType, 0); WriteMacInt16(gamma_table + gFormulaSize, 0); WriteMacInt16(gamma_table + gChanCnt, 1); WriteMacInt16(gamma_table + gDataCnt, 256); WriteMacInt16(gamma_table + gDataWidth, 8); // Build ramp uint32 p = gamma_table + gFormulaData; for (int i=0; i<256; i++) WriteMacInt8(p + i, i); } else { // User-supplied gamma table // Validate header if (ReadMacInt16(user_table + gVersion)) return paramErr; if (ReadMacInt16(user_table + gType)) return paramErr; int chan_cnt = ReadMacInt16(user_table + gChanCnt); if (chan_cnt != 1 && chan_cnt != 3) return paramErr; int data_width = ReadMacInt16(user_table + gDataWidth); if (data_width > 8) return paramErr; int data_cnt = ReadMacInt16(user_table + gDataCnt); if (data_cnt != (1 << data_width)) return paramErr; // Allocate new table, if necessary int size = SIZEOF_GammaTbl + ReadMacInt16(user_table + gFormulaSize) + chan_cnt * data_cnt; if (!allocate_gamma_table(size)) return memFullErr; // Copy table Mac2Mac_memcpy(gamma_table, user_table, size); } if (IsDirectMode(*current_mode)) load_ramp_palette(); return true; } /* * Switch video mode */ void monitor_desc::switch_mode(vector::const_iterator it, uint32 param, uint32 dce) { const video_mode &mode = *it; // Switch mode set_gray_palette(); current_mode = it; switch_to_current_mode(); // Update variables current_apple_mode = depth_to_apple_mode(mode.depth); current_id = mode.resolution_id; M68kRegisters r; r.a[0] = slot_param; // Find functional sResource for this display WriteMacInt8(slot_param + spSlot, ReadMacInt8(dce + dCtlSlot)); WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId)); WriteMacInt8(slot_param + spExtDev, 0); r.d[0] = 0x0016; Execute68kTrap(0xa06e, &r); // SRsrcInfo() uint32 rsrc = ReadMacInt32(slot_param + spPointer); // Patch minorBase (otherwise rebooting won't work) WriteMacInt8(slot_param + spID, 0x0a); // minorBase r.d[0] = 0x0006; Execute68kTrap(0xa06e, &r); // SFindStruct() uint32 minor_base = ReadMacInt32(slot_param + spPointer) - ROMBaseMac; ROMBaseHost[minor_base + 0] = mac_frame_base >> 24; ROMBaseHost[minor_base + 1] = mac_frame_base >> 16; ROMBaseHost[minor_base + 2] = mac_frame_base >> 8; ROMBaseHost[minor_base + 3] = mac_frame_base; // Patch video mode parameter table WriteMacInt32(slot_param + spPointer, rsrc); WriteMacInt8(slot_param + spID, depth_to_apple_mode(mode.depth)); r.d[0] = 0x0006; Execute68kTrap(0xa06e, &r); // SFindStruct() WriteMacInt8(slot_param + spID, 0x01); r.d[0] = 0x0006; Execute68kTrap(0xa06e, &r); // SFindStruct() uint32 p = ReadMacInt32(slot_param + spPointer) - ROMBaseMac; ROMBaseHost[p + 8] = mode.bytes_per_row >> 8; ROMBaseHost[p + 9] = mode.bytes_per_row; ROMBaseHost[p + 14] = mode.y >> 8; ROMBaseHost[p + 15] = mode.y; ROMBaseHost[p + 16] = mode.x >> 8; ROMBaseHost[p + 17] = mode.x; // Recalculate slot ROM checksum ChecksumSlotROM(); // Update sResource WriteMacInt8(slot_param + spID, ReadMacInt8(dce + dCtlSlotId)); r.d[0] = 0x002b; Execute68kTrap(0xa06e, &r); // SUpdateSRT() // Update frame buffer base in DCE and param block WriteMacInt32(dce + dCtlDevBase, mac_frame_base); WriteMacInt32(param + csBaseAddr, mac_frame_base); // Patch frame buffer base address for MacOS versions <7.6 if (!dm_present) { // Only do this when no Display Manager seems to be present; otherwise, the screen will not get redrawn D(bug("No Display Manager, patching frame buffer base\n")); WriteMacInt32(0x824, mac_frame_base); // ScrnBase WriteMacInt32(0x898, mac_frame_base); // CrsrBase uint32 gdev = ReadMacInt32(0x8a4); // MainDevice D(bug("MainDevice handle at %08lx\n", gdev)); if (gdev != 0 && gdev != 0xffffffff) { gdev = ReadMacInt32(gdev); D(bug(" pointer at %08lx\n", gdev)); uint32 pmap = ReadMacInt32(gdev + 0x16); // gdPMap D(bug(" PixMap handle at %08lx\n", pmap)); pmap = ReadMacInt32(pmap); D(bug(" pointer at %08lx\n", pmap)); WriteMacInt32(pmap, mac_frame_base); // baseAddr } gdev = ReadMacInt32(0xcc8); // TheGDevice D(bug("TheGDevice handle at %08lx\n", gdev)); } } /* * Driver Open() routine */ int16 monitor_desc::driver_open(void) { // This shouldn't happen unless the platform-specific video code is broken if (modes.empty()) fprintf(stderr, "No valid video modes found (broken video driver?)\n"); // Init local variables luminance_mapping = false; interrupts_enabled = false; current_apple_mode = preferred_apple_mode = depth_to_apple_mode(current_mode->depth); current_id = preferred_id = current_mode->resolution_id; dm_present = false; // Allocate Slot Manager parameter block in Mac RAM M68kRegisters r; r.d[0] = SIZEOF_SPBlock; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) return memFullErr; slot_param = r.a[0]; D(bug("SPBlock at %08x\n", slot_param)); // Find and set default gamma table gamma_table = 0; alloc_gamma_table_size = 0; set_gamma_table(0); // Init color palette (solid gray) set_gray_palette(); return noErr; } int16 VideoDriverOpen(uint32 pb, uint32 dce) { uint8 slot_id = ReadMacInt8(dce + dCtlSlotId); D(bug("VideoDriverOpen slot %02x\n", slot_id)); monitor_desc *m = find_monitor(slot_id); if (m) return m->driver_open(); else return nsDrvErr; } /* * Driver Control() routine */ int16 monitor_desc::driver_control(uint16 code, uint32 param, uint32 dce) { switch (code) { case cscSetMode: { // Set color depth uint16 mode = ReadMacInt16(param + csMode); D(bug(" SetMode %04x\n", mode)); // Set old base address in case the switch fails WriteMacInt32(param + csBaseAddr, mac_frame_base); if (ReadMacInt16(param + csPage)) return paramErr; if (mode != current_apple_mode) { vector::const_iterator i = find_mode(mode, current_id); if (i == invalid_mode()) return paramErr; switch_mode(i, param, dce); } D(bug(" base %08x\n", mac_frame_base)); return noErr; } case cscSetEntries: // Set palette case cscDirectSetEntries: { D(bug(" (Direct)SetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart))); bool is_direct = IsDirectMode(*current_mode); if (code == cscSetEntries && is_direct) return controlErr; if (code == cscDirectSetEntries && !is_direct) return controlErr; uint32 s_pal = ReadMacInt32(param + csTable); // Source palette uint8 *d_pal; // Destination palette uint16 start = ReadMacInt16(param + csStart); uint16 count = ReadMacInt16(param + csCount); if (s_pal == 0 || count > 255) return paramErr; // Find tables for gamma correction uint8 *red_gamma = NULL, *green_gamma = NULL, *blue_gamma = NULL; bool have_gamma = false; int data_width = 0; if (gamma_table) { red_gamma = Mac2HostAddr(gamma_table + gFormulaData + ReadMacInt16(gamma_table + gFormulaSize)); int chan_cnt = ReadMacInt16(gamma_table + gChanCnt); if (chan_cnt == 1) green_gamma = blue_gamma = red_gamma; else { int ofs = ReadMacInt16(gamma_table + gDataCnt); green_gamma = red_gamma + ofs; blue_gamma = green_gamma + ofs; } data_width = ReadMacInt16(gamma_table + gDataWidth); have_gamma = true; } // Convert palette if (start == 0xffff) { // Indexed for (uint32 i=0; i<=count; i++) { d_pal = palette + (ReadMacInt16(s_pal) & 0xff) * 3; uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8; uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8; uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8; if (luminance_mapping && !is_direct) red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; if (have_gamma) { red = red_gamma[red >> (8 - data_width)]; green = green_gamma[green >> (8 - data_width)]; blue = blue_gamma[blue >> (8 - data_width)]; } *d_pal++ = red; *d_pal++ = green; *d_pal++ = blue; s_pal += 8; } } else { // Sequential if (start + count > 255) return paramErr; d_pal = palette + start * 3; for (uint32 i=0; i<=count; i++) { uint8 red = (uint16)ReadMacInt16(s_pal + 2) >> 8; uint8 green = (uint16)ReadMacInt16(s_pal + 4) >> 8; uint8 blue = (uint16)ReadMacInt16(s_pal + 6) >> 8; if (luminance_mapping && !is_direct) red = green = blue = (red * 0x4ccc + green * 0x970a + blue * 0x1c29) >> 16; if (have_gamma) { red = red_gamma[red >> (8 - data_width)]; green = green_gamma[green >> (8 - data_width)]; blue = blue_gamma[blue >> (8 - data_width)]; } *d_pal++ = red; *d_pal++ = green; *d_pal++ = blue; s_pal += 8; } } set_palette(palette, palette_size(current_mode->depth)); return noErr; } case cscSetGamma: { // Set gamma table uint32 user_table = ReadMacInt32(param + csGTable); D(bug(" SetGamma %08x\n", user_table)); return set_gamma_table(user_table) ? noErr : memFullErr; } case cscGrayPage: { // Fill page with dithered gray pattern D(bug(" GrayPage %d\n", ReadMacInt16(param + csPage))); if (ReadMacInt16(param + csPage)) return paramErr; uint32 pattern[6] = { 0xaaaaaaaa, // 1 bpp 0xcccccccc, // 2 bpp 0xf0f0f0f0, // 4 bpp 0xff00ff00, // 8 bpp 0xffff0000, // 16 bpp 0xffffffff // 32 bpp }; uint32 p = mac_frame_base; uint32 pat = pattern[current_mode->depth]; bool invert = (current_mode->depth == VDEPTH_32BIT); for (uint32 y=0; yy; y++) { for (uint32 x=0; xbytes_per_row; x+=4) { WriteMacInt32(p + x, pat); if (invert) pat = ~pat; } p += current_mode->bytes_per_row; pat = ~pat; } if (IsDirectMode(*current_mode)) load_ramp_palette(); return noErr; } case cscSetGray: // Enable/disable luminance mapping D(bug(" SetGray %02x\n", ReadMacInt8(param + csMode))); luminance_mapping = ReadMacInt8(param + csMode); return noErr; case cscSetInterrupt: // Enable/disable VBL D(bug(" SetInterrupt %02x\n", ReadMacInt8(param + csMode))); interrupts_enabled = (ReadMacInt8(param + csMode) == 0); return noErr; case cscSetDefaultMode: { // Set default color depth uint16 mode = ReadMacInt8(param + csMode); D(bug(" SetDefaultMode %02x\n", mode)); preferred_apple_mode = mode; return noErr; } case cscSwitchMode: { // Switch video mode (depth and resolution) uint16 mode = ReadMacInt16(param + csMode); uint32 id = ReadMacInt32(param + csData); D(bug(" SwitchMode %04x, %08x\n", mode, id)); // Set old base address in case the switch fails WriteMacInt32(param + csBaseAddr, mac_frame_base); if (ReadMacInt16(param + csPage)) return paramErr; if (mode != current_apple_mode || id != current_id) { vector::const_iterator i = find_mode(mode, id); if (i == invalid_mode()) return paramErr; switch_mode(i, param, dce); } D(bug(" base %08x\n", mac_frame_base)); return noErr; } case cscSavePreferredConfiguration: { uint16 mode = ReadMacInt16(param + csMode); uint32 id = ReadMacInt32(param + csData); D(bug(" SavePreferredConfiguration %04x, %08x\n", mode, id)); preferred_apple_mode = mode; preferred_id = id; return noErr; } default: printf("WARNING: Unknown VideoDriverControl(%d)\n", code); return controlErr; } } int16 VideoDriverControl(uint32 pb, uint32 dce) { uint8 slot_id = ReadMacInt8(dce + dCtlSlotId); uint16 code = ReadMacInt16(pb + csCode); uint32 param = ReadMacInt32(pb + csParam); D(bug("VideoDriverControl slot %02x, code %d\n", slot_id, code)); monitor_desc *m = find_monitor(slot_id); if (m) return m->driver_control(code, param, dce); else return nsDrvErr; } /* * Driver Status() routine */ int16 monitor_desc::driver_status(uint16 code, uint32 param) { switch (code) { case cscGetMode: // Get current color depth D(bug(" GetMode -> %04x, base %08x\n", current_apple_mode, mac_frame_base)); WriteMacInt16(param + csMode, current_apple_mode); WriteMacInt16(param + csPage, 0); WriteMacInt32(param + csBaseAddr, mac_frame_base); return noErr; case cscGetEntries: { // Read palette D(bug(" GetEntries table %08x, count %d, start %d\n", ReadMacInt32(param + csTable), ReadMacInt16(param + csCount), ReadMacInt16(param + csStart))); uint8 *s_pal; // Source palette uint32 d_pal = ReadMacInt32(param + csTable); // Destination palette uint16 start = ReadMacInt16(param + csStart); uint16 count = ReadMacInt16(param + csCount); if (d_pal == 0 || count > 255) return paramErr; if (start == 0xffff) { // Indexed for (uint32 i=0; i<=count; i++) { s_pal = palette + (ReadMacInt16(d_pal) & 0xff) * 3; uint8 red = *s_pal++; uint8 green = *s_pal++; uint8 blue = *s_pal++; WriteMacInt16(d_pal + 2, red * 0x0101); WriteMacInt16(d_pal + 4, green * 0x0101); WriteMacInt16(d_pal + 6, blue * 0x0101); d_pal += 8; } } else { // Sequential if (start + count > 255) return paramErr; s_pal = palette + start * 3; for (uint32 i=0; i<=count; i++) { uint8 red = *s_pal++; uint8 green = *s_pal++; uint8 blue = *s_pal++; WriteMacInt16(d_pal + 2, red * 0x0101); WriteMacInt16(d_pal + 4, green * 0x0101); WriteMacInt16(d_pal + 6, blue * 0x0101); d_pal += 8; } } return noErr; } case cscGetPages: // Get number of pages D(bug(" GetPages -> 1\n")); WriteMacInt16(param + csPage, 1); return noErr; case cscGetBaseAddress: // Get page base address D(bug(" GetBaseAddress -> %08x\n", mac_frame_base)); WriteMacInt32(param + csBaseAddr, mac_frame_base); if (ReadMacInt16(param + csPage)) return paramErr; else return noErr; case cscGetGray: // Get luminance mapping flag D(bug(" GetGray -> %d\n", luminance_mapping)); WriteMacInt8(param, luminance_mapping ? 1 : 0); return noErr; case cscGetInterrupt: // Get interrupt disable flag D(bug(" GetInterrupt -> %d\n", interrupts_enabled)); WriteMacInt8(param, interrupts_enabled ? 0 : 1); return noErr; case cscGetGamma: D(bug(" GetGamma -> %08x\n", gamma_table)); WriteMacInt32(param + csGTable, gamma_table); return noErr; case cscGetDefaultMode: // Get default color depth D(bug(" GetDefaultMode -> %02x\n", preferred_apple_mode)); WriteMacInt8(param + csMode, preferred_apple_mode); return noErr; case cscGetCurrentMode: // Get current video mode (depth and resolution) D(bug(" GetCurMode -> %04x/%08x, base %08x\n", current_apple_mode, current_id, mac_frame_base)); WriteMacInt16(param + csMode, current_apple_mode); WriteMacInt32(param + csData, current_id); WriteMacInt16(param + csPage, 0); WriteMacInt32(param + csBaseAddr, mac_frame_base); return noErr; case cscGetConnection: // Get monitor information D(bug(" GetConnection\n")); WriteMacInt16(param + csDisplayType, 8); // Modeless connection WriteMacInt8(param + csConnectTaggedType, 0); WriteMacInt8(param + csConnectTaggedData, 0); WriteMacInt32(param + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging WriteMacInt32(param + csDisplayComponent, 0); return noErr; case cscGetModeTiming: { // Get video timing for specified resolution uint32 id = ReadMacInt32(param + csTimingMode); D(bug(" GetModeTiming %08x\n", id)); if (!has_resolution(id)) return paramErr; WriteMacInt32(param + csTimingFormat, FOURCC('d', 'e', 'c', 'l')); WriteMacInt32(param + csTimingData, 0); // unknown uint32 flags = 0xb; // mode valid, safe and shown in Monitors panel if (id == preferred_id) flags |= 4; // default mode WriteMacInt32(param + csTimingFlags, flags); return noErr; } case cscGetModeBaseAddress: // Get frame buffer base address D(bug(" GetModeBaseAddress -> base %08x\n", mac_frame_base)); WriteMacInt32(param + csBaseAddr, mac_frame_base); return noErr; case cscGetPreferredConfiguration: // Get default video mode (depth and resolution) D(bug(" GetPreferredConfiguration -> %04x/%08x\n", preferred_apple_mode, preferred_id)); WriteMacInt16(param + csMode, preferred_apple_mode); WriteMacInt32(param + csData, preferred_id); return noErr; case cscGetNextResolution: { // Called iteratively to obtain a list of all supported resolutions uint32 id = ReadMacInt32(param + csPreviousDisplayModeID); D(bug(" GetNextResolution %08x\n", id)); switch (id) { case 0: // Return current resolution id = current_id; break; case 0xfffffffe: // Return first supported resolution id = 0x80; while (!has_resolution(id)) id++; break; default: // Get next resolution if (!has_resolution(id)) return paramErr; id++; while (!has_resolution(id) && id < 0x100) id++; if (id == 0x100) { // No more resolutions WriteMacInt32(param + csRIDisplayModeID, 0xfffffffd); return noErr; } break; } WriteMacInt32(param + csRIDisplayModeID, id); uint32 x, y; get_size_of_resolution(id, x, y); WriteMacInt32(param + csHorizontalPixels, x); WriteMacInt32(param + csVerticalLines, y); WriteMacInt32(param + csRefreshRate, 75 << 16); WriteMacInt16(param + csMaxDepthMode, depth_to_apple_mode(max_depth_of_resolution(id))); WriteMacInt32(param + csResolutionFlags, 0); return noErr; } case cscGetVideoParameters: { // Get information about specified resolution/depth uint32 id = ReadMacInt32(param + csDisplayModeID); uint16 mode = ReadMacInt16(param + csDepthMode); D(bug(" GetVideoParameters %04x/%08x\n", mode, id)); dm_present = true; // Display Manager seems to be present D(bug(" Display Manager detected\n")); vector::const_iterator i, end = modes.end(); for (i = modes.begin(); i != end; ++i) { if (depth_to_apple_mode(i->depth) == mode && i->resolution_id == id) { uint32 vp = ReadMacInt32(param + csVPBlockPtr); WriteMacInt32(vp + vpBaseOffset, 0); WriteMacInt16(vp + vpRowBytes, i->bytes_per_row); WriteMacInt16(vp + vpBounds, 0); WriteMacInt16(vp + vpBounds + 2, 0); WriteMacInt16(vp + vpBounds + 4, i->y); WriteMacInt16(vp + vpBounds + 6, i->x); WriteMacInt16(vp + vpVersion, 0); WriteMacInt16(vp + vpPackType, 0); WriteMacInt32(vp + vpPackSize, 0); WriteMacInt32(vp + vpHRes, 0x00480000); // 72 dpi WriteMacInt32(vp + vpVRes, 0x00480000); uint32 pix_type, pix_size, cmp_count, cmp_size, dev_type; switch (i->depth) { case VDEPTH_16BIT: pix_type = 0x10; pix_size = 16; cmp_count = 3; cmp_size = 5; dev_type = 2; // direct break; case VDEPTH_32BIT: pix_type = 0x10; pix_size = 32; cmp_count = 3; cmp_size = 8; dev_type = 2; // direct break; default: pix_type = 0; pix_size = 1 << i->depth; cmp_count = 1; cmp_size = 1 << i->depth; dev_type = 0; // CLUT break; } WriteMacInt16(vp + vpPixelType, pix_type); WriteMacInt16(vp + vpPixelSize, pix_size); WriteMacInt16(vp + vpCmpCount, cmp_count); WriteMacInt16(vp + vpCmpSize, cmp_size); WriteMacInt32(param + csPageCount, 1); WriteMacInt32(param + csDeviceType, dev_type); return noErr; } } return paramErr; // specified resolution/depth not supported } case cscGetMultiConnect: { uint32 conn = ReadMacInt32(param + csDisplayCountOrNumber); D(bug(" GetMultiConnect %08x\n", conn)); if (conn == 0xffffffff) { // Get number of connections WriteMacInt32(param + csDisplayCountOrNumber, 1); // Single-headed return noErr; } else if (conn == 1) { // Get information about first connection WriteMacInt16(param + csConnectInfo + csDisplayType, 8); // Modeless connection WriteMacInt8(param + csConnectInfo + csConnectTaggedType, 0); WriteMacInt8(param + csConnectInfo + csConnectTaggedData, 0); WriteMacInt32(param + csConnectInfo + csConnectFlags, 0x43); // All modes valid and safe, non-standard tagging WriteMacInt32(param + csConnectInfo + csDisplayComponent, 0); return noErr; } else return paramErr; } default: printf("WARNING: Unknown VideoDriverStatus(%d)\n", code); return statusErr; } } int16 VideoDriverStatus(uint32 pb, uint32 dce) { uint8 slot_id = ReadMacInt8(dce + dCtlSlotId); uint16 code = ReadMacInt16(pb + csCode); uint32 param = ReadMacInt32(pb + csParam); D(bug("VideoDriverStatus slot %02x, code %d\n", slot_id, code)); monitor_desc *m = find_monitor(slot_id); if (m) return m->driver_status(code, param); else return nsDrvErr; } BasiliskII/src/slot_rom.cpp0000644000175000017500000003220211340220101016051 0ustar centriscentris/* * slot_rom.cpp - Slot declaration ROM * * Basilisk II (C) Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 2 "Slot Manager" * Designing Cards and Drivers for the Macintosh Family, Second Edition */ #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "video.h" #include "emul_op.h" #include "version.h" #include "slot_rom.h" // Temporary buffer for slot ROM static uint8 srom[4096]; // Index in srom static uint32 p; // Length of slot ROM static int slot_rom_size = 0; /* * Construct slot declaration ROM and copy it into the Mac ROM (must be called after VideoInit()) */ static void Offs(uint8 type, uint32 ptr) { uint32 offs = ptr - p; srom[p++] = type; srom[p++] = offs >> 16; srom[p++] = offs >> 8; srom[p++] = offs; } static void Rsrc(uint8 type, uint32 data) { srom[p++] = type; srom[p++] = data >> 16; srom[p++] = data >> 8; srom[p++] = data; } static void EndOfList(void) { srom[p++] = 0xff; srom[p++] = 0; srom[p++] = 0; srom[p++] = 0; } static void Long(uint32 data) { srom[p++] = data >> 24; srom[p++] = data >> 16; srom[p++] = data >> 8; srom[p++] = data; } static void Word(uint16 data) { srom[p++] = data >> 8; srom[p++] = data; } static void String(const char *str) { while ((srom[p++] = *str++) != 0) ; if (p & 1) srom[p++] = 0; } static void PString(const char *str) { srom[p++] = strlen(str); while ((srom[p++] = *str++) != 0) ; p--; if (p & 1) srom[p++] = 0; } static uint32 VModeParms(const monitor_desc &m, video_depth depth) { const video_mode &mode = m.get_current_mode(); uint32 ret = p; Long(50); // Length Long(0); // Base offset Word(m.get_bytes_per_row(depth, mode.resolution_id)); Word(0); // Bounds Word(0); Word(mode.y); Word(mode.x); Word(0); // Version Word(0); // Pack type Long(0); // Pack size Long(0x00480000); // HRes Long(0x00480000); // VRes switch (depth) { case VDEPTH_1BIT: Word(0); // Pixel type (indirect) Word(1); // Pixel size Word(1); // CmpCount Word(1); // CmpSize break; case VDEPTH_2BIT: Word(0); // Pixel type (indirect) Word(2); // Pixel size Word(1); // CmpCount Word(2); // CmpSize break; case VDEPTH_4BIT: Word(0); // Pixel type (indirect) Word(4); // Pixel size Word(1); // CmpCount Word(4); // CmpSize break; case VDEPTH_8BIT: Word(0); // Pixel type (indirect) Word(8); // Pixel size Word(1); // CmpCount Word(8); // CmpSize break; case VDEPTH_16BIT: Word(16); // Pixel type (direct) Word(16); // Pixel size Word(3); // CmpCount Word(5); // CmpSize break; case VDEPTH_32BIT: Word(16); // Pixel type (direct) Word(32); // Pixel size Word(3); // CmpCount Word(8); // CmpSize break; } Long(0); // Plane size Long(0); // Reserved return ret; } static uint32 VModeDesc(uint32 params, bool direct) { uint32 ret = p; Offs(0x01, params); // Video parameters Rsrc(0x03, 1); // Page count Rsrc(0x04, direct ? 2 : 0); // Device type EndOfList(); return ret; } static uint32 VMonitor(const monitor_desc &m, uint32 videoType, uint32 videoName, uint32 vidDrvrDir, uint32 gammaDir) { uint32 minorBase, minorLength; uint32 vidModeParms1, vidModeParms2, vidModeParms4, vidModeParms8, vidModeParms16, vidModeParms32; uint32 vidMode1, vidMode2, vidMode4, vidMode8, vidMode16, vidMode32; uint32 ret; minorBase = p; Long(m.get_mac_frame_base()); // Frame buffer base minorLength = p; Long(0); // Frame buffer size (unspecified) vidModeParms1 = VModeParms(m, VDEPTH_1BIT); vidModeParms2 = VModeParms(m, VDEPTH_2BIT); vidModeParms4 = VModeParms(m, VDEPTH_4BIT); vidModeParms8 = VModeParms(m, VDEPTH_8BIT); vidModeParms16 = VModeParms(m, VDEPTH_16BIT); vidModeParms32 = VModeParms(m, VDEPTH_32BIT); vidMode1 = VModeDesc(vidModeParms1, false); vidMode2 = VModeDesc(vidModeParms2, false); vidMode4 = VModeDesc(vidModeParms4, false); vidMode8 = VModeDesc(vidModeParms8, false); vidMode16 = VModeDesc(vidModeParms16, true); vidMode32 = VModeDesc(vidModeParms32, true); ret = p; Offs(0x01, videoType); // Video type descriptor Offs(0x02, videoName); // Driver name Offs(0x04, vidDrvrDir); // Driver directory Rsrc(0x08, 0x4232); // Hardware device ID ('B2') Offs(0x0a, minorBase); // Frame buffer base Offs(0x0b, minorLength); // Frame buffer length Offs(0x40, gammaDir); // Gamma directory Rsrc(0x7d, 6); // Video attributes: Default to color, built-in if (m.has_depth(VDEPTH_1BIT)) Offs(m.depth_to_apple_mode(VDEPTH_1BIT), vidMode1); // Video mode parameters for 1 bit if (m.has_depth(VDEPTH_2BIT)) Offs(m.depth_to_apple_mode(VDEPTH_2BIT), vidMode2); // Video mode parameters for 2 bit if (m.has_depth(VDEPTH_4BIT)) Offs(m.depth_to_apple_mode(VDEPTH_4BIT), vidMode4); // Video mode parameters for 4 bit if (m.has_depth(VDEPTH_8BIT)) Offs(m.depth_to_apple_mode(VDEPTH_8BIT), vidMode8); // Video mode parameters for 8 bit if (m.has_depth(VDEPTH_16BIT)) Offs(m.depth_to_apple_mode(VDEPTH_16BIT), vidMode16); // Video mode parameters for 16 bit if (m.has_depth(VDEPTH_32BIT)) Offs(m.depth_to_apple_mode(VDEPTH_32BIT), vidMode32); // Video mode parameters for 32 bit EndOfList(); return ret; } bool InstallSlotROM(void) { uint32 boardType, boardName, vendorID, revLevel, partNum, date; uint32 vendorInfo, sRsrcBoard; uint32 videoType, videoName, videoDrvr, vidDrvrDir; uint32 defaultGamma, gammaDir; uint32 cpuType, cpuName, cpuMajor, cpuMinor, sRsrcCPU; uint32 etherType, etherName, etherDrvr, etherDrvrDir, sRsrcEther; uint32 sRsrcDir; vector::const_iterator m, mend = VideoMonitors.end(); vector sRsrcVideo; char str[256]; int i; p = 0; // Board sResource boardType = p; // Literals Word(1); Word(0); Word(0); Word(0); // Board sResource boardName = p; String("Basilisk II Slot ROM"); vendorID = p; String("Christian Bauer"); revLevel = p; sprintf(str, "V%d.%d", VERSION_MAJOR, VERSION_MINOR); String(str); partNum = p; String("BasiliskII"); date = p; String(__DATE__); vendorInfo = p; // Vendor Info Offs(0x01, vendorID); // Vendor ID Offs(0x03, revLevel); // Revision level Offs(0x04, partNum); // Part number Offs(0x05, date); // ROM build date EndOfList(); sRsrcBoard = p; Offs(0x01, boardType); // Board descriptor Offs(0x02, boardName); // Board name Rsrc(0x20, 0x4232); // Board ID ('B2') Offs(0x24, vendorInfo); // Vendor Info EndOfList(); videoType = p; Word(3); Word(1); Word(1); Word(0x4232); // Display Video Apple 'B2' videoName = p; String("Display_Video_Apple_Basilisk"); videoDrvr = p; // Video driver Long(0x72); // Length Word(0x4c00); Word(0); Word(0); Word(0); Word(0x32); // Open offset Word(0x36); // Prime offset Word(0x3a); // Control offset Word(0x46); // Status offset Word(0x6c); // Close offset PString(".Display_Video_Apple_Basilisk"); Word(1); // Driver version Word(M68K_EMUL_OP_VIDEO_OPEN); // Open() Word(0x4e75); Word(0x70ff); // Prime() Word(0x600e); Word(M68K_EMUL_OP_VIDEO_CONTROL); // Control() Word(0x0c68); Word(0x0001); Word(0x001a); Word(0x6604); Word(0x4e75); Word(M68K_EMUL_OP_VIDEO_STATUS); // Status() Word(0x3228); Word(0x0006); // IOReturn Word(0x0801); Word(0x0009); Word(0x670c); Word(0x4a40); Word(0x6f02); Word(0x4240); Word(0x3140); Word(0x0010); Word(0x4e75); Word(0x4a40); Word(0x6f04); Word(0x4240); Word(0x4e75); Word(0x2f38); Word(0x08fc); Word(0x4e75); Word(0x70e8); // Close() Word(0x4e75); vidDrvrDir = p; // Driver directory Offs(0x02, videoDrvr); // sMacOS68020 EndOfList(); defaultGamma = p; // Gamma table Long(38 + 0x100); // Length Word(0x2000); // Resource ID String("Mac HiRes Std Gamma"); Word(0); // Version Word(0); // Type Word(0); // FormulaSize Word(1); // ChanCnt Word(0x0100); // DataCnt Word(8); // ChanWidth Long(0x0005090B); Long(0x0E101315); Long(0x17191B1D); Long(0x1E202224); Long(0x2527282A); Long(0x2C2D2F30); Long(0x31333436); Long(0x37383A3B); Long(0x3C3E3F40); Long(0x42434445); Long(0x4748494A); Long(0x4B4D4E4F); Long(0x50515254); Long(0x55565758); Long(0x595A5B5C); Long(0x5E5F6061); Long(0x62636465); Long(0x66676869); Long(0x6A6B6C6D); Long(0x6E6F7071); Long(0x72737475); Long(0x76777879); Long(0x7A7B7C7D); Long(0x7E7F8081); Long(0x81828384); Long(0x85868788); Long(0x898A8B8C); Long(0x8C8D8E8F); Long(0x90919293); Long(0x94959596); Long(0x9798999A); Long(0x9B9B9C9D); Long(0x9E9FA0A1); Long(0xA1A2A3A4); Long(0xA5A6A6A7); Long(0xA8A9AAAB); Long(0xABACADAE); Long(0xAFB0B0B1); Long(0xB2B3B4B4); Long(0xB5B6B7B8); Long(0xB8B9BABB); Long(0xBCBCBDBE); Long(0xBFC0C0C1); Long(0xC2C3C3C4); Long(0xC5C6C7C7); Long(0xC8C9CACA); Long(0xCBCCCDCD); Long(0xCECFD0D0); Long(0xD1D2D3D3); Long(0xD4D5D6D6); Long(0xD7D8D9D9); Long(0xDADBDCDC); Long(0xDDDEDFDF); Long(0xE0E1E1E2); Long(0xE3E4E4E5); Long(0xE6E7E7E8); Long(0xE9E9EAEB); Long(0xECECEDEE); Long(0xEEEFF0F1); Long(0xF1F2F3F3); Long(0xF4F5F5F6); Long(0xF7F8F8F9); Long(0xFAFAFBFC); Long(0xFCFDFEFF); gammaDir = p; // Gamma directory Offs(0x80, defaultGamma); EndOfList(); for (m = VideoMonitors.begin(); m != mend; ++m) sRsrcVideo.push_back(VMonitor(**m, videoType, videoName, vidDrvrDir, gammaDir)); // CPU sResource cpuType = p; // Literals Word(10); Word(3); Word(0); Word(24); // CPU 68020 cpuName = p; String("CPU_68020"); cpuMajor = p; Long(0); Long(0x7fffffff); cpuMinor = p; Long(0xf0800000); Long(0xf0ffffff); sRsrcCPU = p; Offs(0x01, cpuType); // Type descriptor Offs(0x02, cpuName); // CPU name Offs(0x81, cpuMajor); // Major RAM space Offs(0x82, cpuMinor); // Minor RAM space EndOfList(); // Ethernet sResource etherType = p; // Literals Word(4); Word(1); Word(1); Word(0x4232); // Network Ethernet Apple 'B2' etherName = p; String("Network_Ethernet_Apple_BasiliskII"); etherDrvr = p; // Video driver Long(0x88); // Length Word(0x4400); Word(0); Word(0); Word(0); Word(0x4a); // Open offset Word(0x4e); // Prime offset Word(0x52); // Control offset Word(0x4e); // Status offset Word(0x82); // Close offset PString(".ENET"); Word(0x0111); Word(0x8000); // Driver version Word(0); PString("1.1.1 "); PString("Basilisk II Ethernet Network Driver"); Word(M68K_EMUL_OP_ETHER_OPEN); // Open() Word(0x4e75); Word(0x70ef); // Prime()/Status() Word(0x600c); Word(M68K_EMUL_OP_ETHER_CONTROL); // Control() Word(0x0c68); Word(0x0001); Word(0x001a); Word(0x6602); Word(0x4e75); Word(0x3228); Word(0x0006); // IOReturn Word(0x0801); Word(0x0009); Word(0x670c); Word(0x4a40); Word(0x6f02); Word(0x4240); Word(0x3140); Word(0x0010); Word(0x4e75); Word(0x4a40); Word(0x6f04); Word(0x4240); Word(0x4e75); Word(0x2f38); Word(0x08fc); Word(0x4e75); Word(0x70e8); // Close() Word(0x4e75); etherDrvrDir = p; // Driver directory Offs(0x02, etherDrvr); // sMacOS68020 EndOfList(); sRsrcEther = p; Offs(0x01, etherType); // Type descriptor Offs(0x02, etherName); // Driver name Offs(0x04, etherDrvrDir); // Driver directory Rsrc(0x07, 2); // Flags: OpenAtStart Rsrc(0x08, 0x4232); // Hardware device ID ('B2') EndOfList(); // sResource directory sRsrcDir = p; Offs(0x01, sRsrcBoard); for (m = VideoMonitors.begin(), i = 0; m != mend; ++m, ++i) Offs((*m)->get_slot_id(), sRsrcVideo[i]); Offs(0xf0, sRsrcCPU); Offs(0xf1, sRsrcEther); EndOfList(); // Format/header block Offs(0, sRsrcDir); // sResource directory Long(p + 16); // Length of declaration data Long(0); // CRC (calculated later) Word(0x0101); // Rev. level, format Long(0x5a932bc7); // Test pattern Word(0x000f); // Byte lanes // Copy slot ROM to Mac ROM slot_rom_size = p; memcpy(ROMBaseHost + ROMSize - slot_rom_size, srom, slot_rom_size); // Calculate checksum ChecksumSlotROM(); return true; } /* * Calculate slot ROM checksum (in-place) */ void ChecksumSlotROM(void) { // Calculate CRC uint8 *p = ROMBaseHost + ROMSize - slot_rom_size; p[slot_rom_size - 12] = 0; p[slot_rom_size - 11] = 0; p[slot_rom_size - 10] = 0; p[slot_rom_size - 9] = 0; uint32 crc = 0; for (int i=0; i> 31); crc += p[i]; } p[slot_rom_size - 12] = crc >> 24; p[slot_rom_size - 11] = crc >> 16; p[slot_rom_size - 10] = crc >> 8; p[slot_rom_size - 9] = crc; } BasiliskII/src/dummy/0000755000175000017500000000000011735674751014703 5ustar centriscentrisBasiliskII/src/dummy/scsi_dummy.cpp0000644000175000017500000000323310736405222017545 0ustar centriscentris/* * scsi_dummy.cpp - SCSI Manager, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "scsi.h" #define DEBUG 0 #include "debug.h" /* * Initialization */ void SCSIInit(void) { // Reset SCSI bus SCSIReset(); } /* * Deinitialization */ void SCSIExit(void) { } /* * Set SCSI command to be sent by scsi_send_cmd() */ void scsi_set_cmd(int cmd_length, uint8 *cmd) { } /* * Check for presence of SCSI target */ bool scsi_is_target_present(int id) { return false; } /* * Set SCSI target (returns false on error) */ bool scsi_set_target(int id, int lun) { return false; } /* * Send SCSI command to active target (scsi_set_command() must have been called), * read/write data according to S/G table (returns false on error) */ bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout) { return false; } BasiliskII/src/dummy/clip_dummy.cpp0000644000175000017500000000301110736405222017525 0ustar centriscentris/* * clip_dummy.cpp - Clipboard handling, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "clip.h" #include "macos_util.h" #define DEBUG 0 #include "debug.h" /* * Initialization */ void ClipInit(void) { } /* * Deinitialization */ void ClipExit(void) { } /* * Mac application reads clipboard */ void GetScrap(void **handle, uint32 type, int32 offset) { D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); } /* * Mac application wrote to clipboard */ void PutScrap(uint32 type, void *scrap, int32 length) { D(bug("PutScrap type %08lx, data %08lx, length %ld\n", type, scrap, length)); if (length <= 0) return; switch (type) { case FOURCC('T','E','X','T'): D(bug(" clipping TEXT\n")); break; } } BasiliskII/src/dummy/user_strings_dummy.cpp0000644000175000017500000000267710736405222021346 0ustar centriscentris/* * user_strings_dummy.cpp - Localizable strings, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "user_strings.h" // Platform-specific string definitions const user_string_def platform_strings[] = { {-1, NULL} // End marker }; /* * Fetch pointer to string, given the string number */ char *GetString(int num) { // First search for platform-specific string int i = 0; while (platform_strings[i].num >= 0) { if (platform_strings[i].num == num) return platform_strings[i].str; i++; } // Not found, search for common string i = 0; while (common_strings[i].num >= 0) { if (common_strings[i].num == num) return common_strings[i].str; i++; } return NULL; } BasiliskII/src/dummy/ether_dummy.cpp0000644000175000017500000000570710736405222017723 0ustar centriscentris/* * ether_dummy.cpp - Ethernet device driver, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #if SUPPORTS_UDP_TUNNEL #include #include #endif #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "ether.h" #include "ether_defs.h" #define DEBUG 0 #include "debug.h" #define MONITOR 0 // Global variables #if SUPPORTS_UDP_TUNNEL static int fd = -1; // UDP tunnel socket fd static bool udp_tunnel_active = false; #endif /* * Initialization */ bool ether_init(void) { return true; } /* * Deinitialization */ void ether_exit(void) { } /* * Reset */ void ether_reset(void) { } /* * Add multicast address */ int16 ether_add_multicast(uint32 pb) { return noErr; } /* * Delete multicast address */ int16 ether_del_multicast(uint32 pb) { return noErr; } /* * Attach protocol handler */ int16 ether_attach_ph(uint16 type, uint32 handler) { return noErr; } /* * Detach protocol handler */ int16 ether_detach_ph(uint16 type) { return noErr; } /* * Transmit raw ethernet packet */ int16 ether_write(uint32 wds) { // Set source address uint32 hdr = ReadMacInt32(wds + 2); memcpy(Mac2HostAddr(hdr + 6), ether_addr, 6); return noErr; } /* * Start UDP packet reception thread */ bool ether_start_udp_thread(int socket_fd) { #if SUPPORTS_UDP_TUNNEL fd = socket_fd; udp_tunnel_active = true; return true; #else return false; #endif } /* * Stop UDP packet reception thread */ void ether_stop_udp_thread(void) { #if SUPPORTS_UDP_TUNNEL udp_tunnel_active = false; #endif } /* * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers */ void EtherInterrupt(void) { #if SUPPORTS_UDP_TUNNEL if (udp_tunnel_active) { EthernetPacket ether_packet; uint32 packet = ether_packet.addr(); ssize_t length; // Read packets from socket and hand to ether_udp_read() for processing while (true) { struct sockaddr_in from; socklen_t from_len = sizeof(from); length = recvfrom(fd, Mac2HostAddr(packet), 1514, 0, (struct sockaddr *)&from, &from_len); if (length < 14) break; ether_udp_read(packet, length, &from); } } #endif } BasiliskII/src/dummy/prefs_editor_dummy.cpp0000644000175000017500000000210010736405222021261 0ustar centriscentris/* * prefs_editor_dummy.cpp - Preferences editor, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "prefs.h" #include "prefs_editor.h" #include "user_strings.h" /* * Show preferences editor * Returns true when user clicked on "Start", false otherwise */ bool PrefsEditor(void) { return true; } BasiliskII/src/dummy/prefs_dummy.cpp0000644000175000017500000000336210736405222017726 0ustar centriscentris/* * prefs_dummy.cpp - Preferences handling, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include "prefs.h" // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {NULL, TYPE_END, false} // End of list }; // Prefs file name and path const char PREFS_FILE_NAME[] = "BasiliskII_Prefs"; /* * Load preferences from settings file */ void LoadPrefs(void) { // Read preferences from settings file FILE *f = fopen(PREFS_FILE_NAME, "r"); if (f != NULL) { // Prefs file found, load settings LoadPrefsFromStream(f); fclose(f); } else { // No prefs file, save defaults SavePrefs(); } } /* * Save preferences to settings file */ void SavePrefs(void) { FILE *f; if ((f = fopen(PREFS_FILE_NAME, "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit() */ void AddPlatformPrefsDefaults(void) { } BasiliskII/src/dummy/xpram_dummy.cpp0000644000175000017500000000263711255572001017737 0ustar centriscentris/* * xpram_dummy.cpp - XPRAM handling, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include "xpram.h" // XPRAM file name and path const char XPRAM_FILE_NAME[] = "BasiliskII_XPRAM"; /* * Load XPRAM from settings file */ void LoadXPRAM(const char *vmdir) { FILE *f = fopen(XPRAM_FILE_NAME, "rb"); if (f != NULL) { fread(XPRAM, 256, 1, f); fclose(f); } } /* * Save XPRAM to settings file */ void SaveXPRAM(void) { FILE *f = fopen(XPRAM_FILE_NAME, "wb"); if (f != NULL) { fwrite(XPRAM, 256, 1, f); fclose(f); } } /* * Delete PRAM file */ void ZapPRAM(void) { remove(XPRAM_FILE_NAME); } BasiliskII/src/dummy/serial_dummy.cpp0000644000175000017500000000471510736405222020071 0ustar centriscentris/* * serial_dummy.cpp - Serial device driver, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "serial.h" #include "serial_defs.h" #define DEBUG 0 #include "debug.h" // Driver private variables class DSERDPort : public SERDPort { public: DSERDPort(const char *dev) { device_name = (char *)dev; } virtual ~DSERDPort() { } virtual int16 open(uint16 config); virtual int16 prime_in(uint32 pb, uint32 dce); virtual int16 prime_out(uint32 pb, uint32 dce); virtual int16 control(uint32 pb, uint32 dce, uint16 code); virtual int16 status(uint32 pb, uint32 dce, uint16 code); virtual int16 close(void); private: char *device_name; // Device name }; /* * Initialization */ void SerialInit(void) { // Read serial preferences and create structs for both ports the_serd_port[0] = new DSERDPort(PrefsFindString("seriala")); the_serd_port[1] = new DSERDPort(PrefsFindString("serialb")); } /* * Deinitialization */ void SerialExit(void) { delete (DSERDPort *)the_serd_port[0]; delete (DSERDPort *)the_serd_port[1]; } /* * Open serial port */ int16 DSERDPort::open(uint16 config) { return openErr; } /* * Read data from port */ int16 DSERDPort::prime_in(uint32 pb, uint32 dce) { return readErr; } /* * Write data to port */ int16 DSERDPort::prime_out(uint32 pb, uint32 dce) { return writErr; } /* * Control calls */ int16 DSERDPort::control(uint32 pb, uint32 dce, uint16 code) { return controlErr; } /* * Status calls */ int16 DSERDPort::status(uint32 pb, uint32 dce, uint16 code) { return statusErr; } /* * Close serial port */ int16 DSERDPort::close() { return noErr; } BasiliskII/src/dummy/audio_dummy.cpp0000644000175000017500000000545010736405222017710 0ustar centriscentris/* * audio_dummy.cpp - Audio support, dummy implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "prefs.h" #include "audio.h" #include "audio_defs.h" #define DEBUG 0 #include "debug.h" /* * Initialization */ void AudioInit(void) { // Init audio status and feature flags AudioStatus.sample_rate = 44100 << 16; AudioStatus.sample_size = 16; AudioStatus.channels = 2; AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; // Only one sample format is supported audio_sample_rates.push_back(44100 << 16); audio_sample_sizes.push_back(16); audio_channel_counts.push_back(2); // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; // Audio not available audio_open = false; } /* * Deinitialization */ void AudioExit(void) { } /* * First source added, start audio stream */ void audio_enter_stream() { } /* * Last source removed, stop audio stream */ void audio_exit_stream() { } /* * MacOS audio interrupt, read next data block */ void AudioInterrupt(void) { D(bug("AudioInterrupt\n")); } /* * Set sampling parameters * "index" is an index into the audio_sample_rates[] etc. vectors * It is guaranteed that AudioStatus.num_sources == 0 */ bool audio_set_sample_rate(int index) { } bool audio_set_sample_size(int index) { } bool audio_set_channels(int index) { } /* * Get/set volume controls (volume values received/returned have the left channel * volume in the upper 16 bits and the right channel volume in the lower 16 bits; * both volumes are 8.8 fixed point values with 0x0100 meaning "maximum volume")) */ bool audio_get_main_mute(void) { return false; } uint32 audio_get_main_volume(void) { return 0x01000100; } bool audio_get_speaker_mute(void) { return false; } uint32 audio_get_speaker_volume(void) { return 0x01000100; } void audio_set_main_mute(bool mute) { } void audio_set_main_volume(uint32 vol) { } void audio_set_speaker_mute(bool mute) { } void audio_set_speaker_volume(uint32 vol) { } BasiliskII/src/sony.cpp0000644000175000017500000003570310736405217015241 0ustar centriscentris/* * sony.cpp - Replacement .Sony driver (floppy drives) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 1 "Device Manager" * Technote DV 05: "Drive Queue Elements" * Technote DV 07: "Forcing Floppy Disk Size to be Either 400K or 800K" * Technote DV 17: "Sony Driver: What Your Sony Drives For You" * Technote DV 23: "Driver Education" * Technote FL 24: "Don't Look at ioPosOffset for Devices" */ #include "sysdeps.h" #include #include #ifndef NO_STD_NAMESPACE using std::vector; #endif #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "rom_patches.h" #include "sys.h" #include "prefs.h" #include "sony.h" #define DEBUG 0 #include "debug.h" // Check for inserted disks by polling? #ifdef AMIGA #define DISK_INSERT_CHECK 1 #else #define DISK_INSERT_CHECK 0 #endif // Floppy disk icon const uint8 SonyDiskIcon[258] = { 0x7f, 0xff, 0xff, 0xf8, 0x81, 0x00, 0x01, 0x04, 0x81, 0x00, 0x71, 0x02, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x71, 0x01, 0x81, 0x00, 0x01, 0x01, 0x80, 0xff, 0xfe, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x87, 0xff, 0xff, 0xe1, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfe, 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, 0x7f, 0xff, 0xff, 0xfe, 0, 0 }; // Floppy drive icon const uint8 SonyDriveIcon[258] = { 0x7f, 0xff, 0xff, 0xf8, 0x81, 0x00, 0x01, 0x04, 0x81, 0x00, 0x71, 0x02, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x71, 0x01, 0x81, 0x00, 0x01, 0x01, 0x80, 0xff, 0xfe, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x87, 0xff, 0xff, 0xe1, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfe, 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, 0x7f, 0xff, 0xff, 0xfe, 0, 0 }; // Struct for each drive struct sony_drive_info { sony_drive_info() : num(0), fh(NULL), read_only(false), status(0) {} sony_drive_info(void *fh_, bool ro) : num(0), fh(fh_), read_only(ro), status(0) {} void close_fh(void) { Sys_close(fh); } int num; // Drive number void *fh; // Floppy driver file handle bool to_be_mounted; // Flag: drive must be mounted in accRun bool read_only; // Flag: force write protection uint32 tag_buffer; // Mac address of tag buffer uint32 status; // Mac address of drive status record }; // List of drives handled by this driver typedef vector drive_vec; static drive_vec drives; // Icon addresses (Mac address space, set by PatchROM()) uint32 SonyDiskIconAddr; uint32 SonyDriveIconAddr; // Flag: Control(accRun) has been called, interrupt routine is now active static bool acc_run_called = false; /* * Get reference to drive info or drives.end() if not found */ static drive_vec::iterator get_drive_info(int num) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { if (info->num == num) return info; } return info; } /* * Initialization */ void SonyInit(void) { // No drives specified in prefs? Then add defaults if (PrefsFindString("floppy", 0) == NULL) SysAddFloppyPrefs(); // Add drives specified in preferences int index = 0; const char *str; while ((str = PrefsFindString("floppy", index++)) != NULL) { bool read_only = false; if (str[0] == '*') { read_only = true; str++; } void *fh = Sys_open(str, read_only); if (fh) drives.push_back(sony_drive_info(fh, SysIsReadOnly(fh))); } } /* * Deinitialization */ void SonyExit(void) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) info->close_fh(); drives.clear(); } /* * Disk was inserted, flag for mounting */ bool SonyMountVolume(void *fh) { drive_vec::iterator info = drives.begin(), end = drives.end(); while (info != end && info->fh != fh) ++info; if (info != end) { D(bug("Looking for disk in drive %d\n", info->num)); if (SysIsDiskInserted(info->fh)) { info->read_only = SysIsReadOnly(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0); D(bug(" disk inserted, mounting\n")); info->to_be_mounted = true; } return true; } else return false; } /* * Mount volumes for which the to_be_mounted flag is set * (called during interrupt time) */ static void mount_mountable_volumes(void) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { #if DISK_INSERT_CHECK // Disk in drive? if (ReadMacInt8(info->status + dsDiskInPlace) == 0) { // No, check if disk was inserted if (SysIsDiskInserted(info->fh)) SonyMountVolume(info->fh); } #endif // Mount disk if flagged if (info->to_be_mounted) { D(bug(" mounting drive %d\n", info->num)); M68kRegisters r; r.d[0] = info->num; r.a[0] = 7; // diskEvent Execute68kTrap(0xa02f, &r); // PostEvent() info->to_be_mounted = false; } } } /* * Set error code in DskErr */ static int16 set_dsk_err(int16 err) { D(bug("set_dsk_err(%d)\n", err)); WriteMacInt16(0x142, err); return err; } /* * Driver Open() routine */ int16 SonyOpen(uint32 pb, uint32 dce) { D(bug("SonyOpen\n")); // Set up DCE WriteMacInt32(dce + dCtlPosition, 0); WriteMacInt16(dce + dCtlQHdr + qFlags, ReadMacInt16(dce + dCtlQHdr + qFlags) & 0xff00 | 3); // Version number, must be >=3 or System 8 will replace us acc_run_called = false; // Install driver again with refnum -2 (HD20) uint32 utab = ReadMacInt32(0x11c); WriteMacInt32(utab + 4, ReadMacInt32(utab + 16)); // Set up fake SonyVars WriteMacInt32(0x134, 0xdeadbeef); // Clear DskErr set_dsk_err(0); // Install drives drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { info->num = FindFreeDriveNumber(1); info->to_be_mounted = false; info->tag_buffer = 0; if (info->fh) { // Allocate drive status record M68kRegisters r; r.d[0] = SIZEOF_DrvSts; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) continue; info->status = r.a[0]; D(bug(" DrvSts at %08lx\n", info->status)); // Set up drive status WriteMacInt16(info->status + dsQType, sony); WriteMacInt8(info->status + dsInstalled, 1); WriteMacInt8(info->status + dsSides, 0xff); WriteMacInt8(info->status + dsTwoSideFmt, 0xff); WriteMacInt8(info->status + dsNewIntf, 0xff); WriteMacInt8(info->status + dsMFMDrive, 0xff); WriteMacInt8(info->status + dsMFMDisk, 0xff); WriteMacInt8(info->status + dsTwoMegFmt, 0xff); // Disk in drive? if (SysIsDiskInserted(info->fh)) { WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0); D(bug(" disk inserted, flagging for mount\n")); info->to_be_mounted = true; } // Add drive to drive queue D(bug(" adding drive %d\n", info->num)); r.d[0] = (info->num << 16) | (SonyRefNum & 0xffff); r.a[0] = info->status + dsQLink; Execute68kTrap(0xa04e, &r); // AddDrive() } } return noErr; } /* * Driver Prime() routine */ int16 SonyPrime(uint32 pb, uint32 dce) { WriteMacInt32(pb + ioActCount, 0); // Drive valid and disk inserted? drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); if (info == drives.end()) return set_dsk_err(nsDrvErr); if (!ReadMacInt8(info->status + dsDiskInPlace)) return set_dsk_err(offLinErr); WriteMacInt8(info->status + dsDiskInPlace, 2); // Disk accessed // Get parameters void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer)); size_t length = ReadMacInt32(pb + ioReqCount); loff_t position = ReadMacInt32(dce + dCtlPosition); if ((length & 0x1ff) || (position & 0x1ff)) return set_dsk_err(paramErr); size_t actual = 0; if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) { // Read actual = Sys_read(info->fh, buffer, position, length); if (actual != length) return set_dsk_err(readErr); // Clear TagBuf WriteMacInt32(0x2fc, 0); WriteMacInt32(0x300, 0); WriteMacInt32(0x304, 0); } else { // Write if (info->read_only) return set_dsk_err(wPrErr); actual = Sys_write(info->fh, buffer, position, length); if (actual != length) return set_dsk_err(writErr); } // Update ParamBlock and DCE WriteMacInt32(pb + ioActCount, actual); WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual); return set_dsk_err(noErr); } /* * Driver Control() routine */ int16 SonyControl(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("SonyControl %d\n", code)); // General codes switch (code) { case 1: // KillIO return set_dsk_err(-1); case 9: // Track cache return set_dsk_err(noErr); case 65: // Periodic action (accRun, "insert" disks on startup) mount_mountable_volumes(); PatchAfterStartup(); // Install patches after system startup WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000); // Disable periodic action acc_run_called = true; return noErr; } // Drive valid? drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); if (info == drives.end()) return set_dsk_err(nsDrvErr); // Drive-specific codes int16 err = noErr; switch (code) { case 5: // Verify disk if (ReadMacInt8(info->status + dsDiskInPlace) <= 0) err = verErr; break; case 6: // Format disk if (info->read_only) err = wPrErr; else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { if (!SysFormat(info->fh)) err = writErr; } else err = offLinErr; break; case 7: // Eject if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { SysEject(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 0); } break; case 8: // Set tag buffer info->tag_buffer = ReadMacInt32(pb + csParam); break; case 21: // Get drive icon WriteMacInt32(pb + csParam, SonyDriveIconAddr); break; case 22: // Get disk icon WriteMacInt32(pb + csParam, SonyDiskIconAddr); break; case 23: // Get drive info if (info->num == 1) WriteMacInt32(pb + csParam, 0x0004); // Internal drive else WriteMacInt32(pb + csParam, 0x0104); // External drive break; case 0x5343: // Format and write to disk ('SC'), used by DiskCopy if (!ReadMacInt8(info->status + dsDiskInPlace)) err = offLinErr; else if (info->read_only) err = wPrErr; else { void *data = Mac2HostAddr(ReadMacInt32(pb + csParam + 2)); size_t actual = Sys_write(info->fh, data, 0, 2880*512); if (actual != 2880*512) err = writErr; } break; default: printf("WARNING: Unknown SonyControl(%d)\n", code); err = controlErr; break; } return set_dsk_err(err); } /* * Driver Status() routine */ int16 SonyStatus(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("SonyStatus %d\n", code)); // Drive valid? drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); if (info == drives.end()) return set_dsk_err(nsDrvErr); int16 err = noErr; switch (code) { case 6: // Return format list if (ReadMacInt16(pb + csParam) > 0) { uint32 adr = ReadMacInt32(pb + csParam + 2); WriteMacInt16(pb + csParam, 1); // 1 format WriteMacInt32(adr, 2880); // 2880 sectors WriteMacInt32(adr + 4, 0xd2120050); // 2 heads, 18 secs/track, 80 tracks } else err = paramErr; break; case 8: // Get drive status Mac2Mac_memcpy(pb + csParam, info->status, 22); break; case 10: // Get disk type WriteMacInt32(pb + csParam, ReadMacInt32(info->status + dsMFMDrive) & 0xffffff00 | 0xfe); break; case 0x4456: // Duplicator version supported ('DV') WriteMacInt16(pb + csParam, 0x0410); break; case 0x5343: // Get address header format byte ('SC') WriteMacInt8(pb + csParam, 0x22); // 512 bytes/sector break; default: printf("WARNING: Unknown SonyStatus(%d)\n", code); err = statusErr; break; } return set_dsk_err(err); } /* * Driver interrupt routine (1Hz) - check for volumes to be mounted */ void SonyInterrupt(void) { if (!acc_run_called) return; mount_mountable_volumes(); } BasiliskII/src/MacOSX/0000755000175000017500000000000011735674751014642 5ustar centriscentrisBasiliskII/src/MacOSX/utils_macosx.mm0000644000175000017500000000203111677014372017673 0ustar centriscentris/* * utils_macosx.mm - Mac OS X utility functions. * * Copyright (C) 2011 Alexei Svitkine * * 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 */ #include #include "utils_macosx.h" // This is used from video_sdl.cpp. void NSAutoReleasePool_wrap(void (*fn)(void)) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; fn(); [pool release]; } BasiliskII/src/MacOSX/Versions.html0000644000175000017500000001373410740061712017326 0ustar centriscentris Versions of MacOS X port of Basilisk II:
  1. Initial port to Public Beta, made minor changes to get it to compile under Final Release.
    Gave a copy of this version to Gwenolé Beauchesne (one of the other porters)
  2. Ported to version 0.9 of the Basilisk II tarball.
    Re-engineered autoconfig files to give a clean autoconf and make of cpu_uae code.
    Fixed a bug in the EmulatorView class (I was customising release instead of dealloc).
    Added:
    • Transparency to icon
    • Port-specific doco: 0_HOW_TO_BUILD.txt, ToDo.html and Versions.html
    • Screen Snapshot code
    • Preferences saving and resetting
    • Delegate code, called when user attempts to close emulator window or quit application, to check whether preferences need saving or application should be allowed to quit
    • ExtFS resource and type/creator access code
    • Window resizing stuff:
      1. The screensize can be set in the preferences. If the emulator has yet to start then the window and emulator screen is resized. Otherwise, and
      2. At any time, the window can be resized, which scales the emulator screen image
    Gave a copy of this to Max Horn
  3. Some code fixes suggested by Max, doco updates, and porting to OS 10.1
  4. Event handling re-write inspired by Max (subclassing NSApplication for custom sendEvent:). Command key and double clicks are now passed correctly to the Emulator. Took out the custom "About" window stuff, and added some credits (with an html link to the official Basilisk home page) in the standard About box. Also has the standard README in the help menu.
    Gave a copy to Max
  5. Streamlining of event sending (filter mouseMoved events when not in Emulator screen)
  6. Recompile in Project Builder, because the makefile generated binary dies at startup
  7. Ported to the Basilisk II 1.0 snapshot's source and implemented video resolution switching. Also uses Objective-C++, which eliminates some of the wrapper code which was previously needed.
  8. Video preferences fixes, small tidyup of source.
  9. Full screen mode added, more source tidied up.
  10. Finally checked into CVS repository. Key event bug fixes:
    • Cursor keys are now decoded and passed to the Emulator correctly
    • New one (in version 9) reported by Kentaro Nakatani - full screen mode was not passing key events
  11. Repaired help menu item, added documentation folder.
  12. Several monitor resolution-changing fixes. Windowed mode now supports all depths, and is up to 6 times faster. I now no longer have any plans to do an OpenGL mode.
    Minor change in preferences (RAM size fields no longer require the user to press return or enter for the value to "take").
    Some modifications for compilation on 10.2 and 10.1
    Initial CD-ROM reading code.
  13. Restarting the emulator should be safe and fairly reliable, and errors in starting the emulator should now be caught.
    Resizing of window is now animated, and window is centred afterwards.
    Reduced memory leaks when changing screensize in windowed mode.
    Screen default pref is now Mac II (and not Classic) size.
    Fixed:
    • Bug where the Prefs could not be edited while the emulator was running
    • Help menu item (again) and added extra doco there
    • Preferences RAM size thing (again)
    • A minor Prefs editor button anomaly
  14. Preferences file can now be specified on the command line, and changed/loaded in the Preferences editor. Added a feature from the windows port - now supports different keyboard types. Changed:
    • Default extfs; was '/', now user's home directory (Suggestion by Olaf Pluta. Seeing all the Unix dirs is a bit scary!)
    • HowTo now displayed by default web browser (as it contains links)
    • Project Builder defaults so that debug symbols are not included
  15. Now built on 10.3 and Xcode. Also adds:
    • Xcode project files
    • Initial floppy and serial port locating code
    • Some help labels on the buttons (some users didn't understand what the triangle button meant)
    • Signal handling for crash protection (thanks to Mike Sliczniak's hard work)
  16. Now distributed as two applications; the usual one (which should be faster), and one for emulating a Mac Classic (which may also help the 10.2/10.3 users who are having problems with a black screen at startup). The difference is that the "classic" version uses virtual or "banks" memory addressing. Fixed:
    • Loading of ROM or disk images from directories or filenames which contain non-ASCII characters
    • Floppy locating code. It can't actually access a floppy, but at least it now won't add the cdrom multiple times
  17. Working ethernet, without extra drivers, thanks to Gwenolé.
    Lots of bug fixes by Bernie Zenis. Some 10.4 fixes by Kirk Kerekes.
    Some fixes by Marcus Gail ( 'Boot From: CD-ROM' vs 'Disable CD-ROM Driver' clash).
    Some cosmetic changes (widened RAM MB in prefs, added confirmation when deleting volumes).
    Now no need for "classic" version - Gwenolé fixed the black screen problem
  18. (actually 18a) Minor fixes:
    • Mouse should always woork in fullscreen mode, and
    • If snapshot fails, the dialog makes a workaround suggestion
  19. Updated the HowTo, external filesystem fix on 10.4, CD code rewrite. Added some new features:
    • Sound support by Daniel Sumorok! Thanks also to Dave Vasilevsky, who produced earlier versions of sound code that I didn't use.
    • Cut & Paste support from Gwenolé. You can now paste from the OS X clipboard into the emulator (pasting the other way doesn't work for me yet)
BasiliskII/src/MacOSX/EmulatorView.h0000644000175000017500000000531610736405220017422 0ustar centriscentris/* * EmulatorView.h - Custom NSView for Basilisk II window input & output * * $Id: EmulatorView.h,v 1.10 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifdef NSBITMAP #import #endif #import @interface EmulatorView : NSView { #ifdef CGIMAGEREF CGImageRef cgImgRep; #endif #ifdef NSBITMAP NSBitmapImageRep *bitmap; #else void *bitmap; #endif #ifdef CGDRAWBITMAP short bps, spp, bpp; int bytesPerRow; BOOL isPlanar, hasAlpha; #endif float numBytes; short x, y; BOOL drawView, // Set when the bitmap is all set up // and ready to display fullScreen; // Is this Emulator using the whole screen? NSRect displayBox; // Cached dimensions of the screen int screen_height; // Height of the screen with the key window } - (void) benchmark; - (NSData *) TIFFrep; // Used for snapshot function // Enable display of, and drawing into, the view #ifdef NSBITMAP - (void) readyToDraw: (NSBitmapImageRep *) theBitmap imageWidth: (short) width imageHeight: (short) height; #endif #ifdef CGIMAGEREF - (void) readyToDraw: (CGImageRef) image bitmap: (void *) theBitmap imageWidth: (short) width imageHeight: (short) height; #endif #ifdef CGDRAWBITMAP - (void) readyToDraw: (void *) theBitmap width: (short) width height: (short) height bps: (short) bitsPerSample spp: (short) samplesPerPixel bpp: (short) bitsPerPixel bpr: (int) bpr isPlanar: (BOOL) planar hasAlpha: (BOOL) alpha; #endif - (void) disableDrawing; - (void) startedFullScreen: (CGDirectDisplayID) theDisplay; - (void) blacken; - (void) clear; - (short) width; - (short) height; - (BOOL) isFullScreen; - (BOOL) mouseInView: (NSEvent *) event; - (BOOL) mouseInView; - (void) fullscreenMouseMove; - (BOOL) processMouseMove: (NSEvent *) event; #ifdef CGDRAWBITMAP - (void) CGDrawBitmap; #endif #ifdef CGIMAGEREF void cgDrawInto(NSRect rect, CGImageRef bitmap); #endif @end BasiliskII/src/MacOSX/video_macosx.h0000644000175000017500000000424110736405220017453 0ustar centriscentris/* * video_macosx.h - Some video constants and globals * * $Id: video_macosx.h,v 1.12 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import /* Set the strategy for drawing the bitmap in the Mac OS X window */ //#define CGDRAWBITMAP #if defined __i386__ //#define CGIMAGEREF #define NSBITMAP #else #define CGIMAGEREF //#define NSBITMAP #endif // Using Core Graphics is fastest when rendering 32bit data. // Using CGImageRefs allows us to use all the bitmaps that BasiliskII supports. // When both Basilisk II and OS X are set to 'Thousands', updating a 312x342 // window happens at over 500fps under 10.2, and over 600fps on 10.3! /* When the BasiliskII video driver respects the alpha bits, set this to let us use */ /* kCGImageAlphaPremultipliedFirst, and to have nice rounded corners on the screen. */ //#define CG_USE_ALPHA /* At the moment, it writes in the full 32bits :-( */ #define MIN_WIDTH 512 #define MIN_HEIGHT 384 #define MIN_HEIGHTC 342 // For classic emulation #define MAX_WIDTH 1240 #define MAX_HEIGHT 1024 // Display types enum { DISPLAY_OPENGL, DISPLAY_SCREEN, DISPLAY_WINDOW }; extern uint8 display_type, frame_skip; extern uint16 init_width, init_height, init_depth; extern bool parse_screen_prefs (const char *); extern void resizeWinTo (const uint16, const uint16); #import #import "EmulatorView.h" extern NSWindow *the_win; extern EmulatorView *output; BasiliskII/src/MacOSX/main_macosx.mm0000644000175000017500000004104311536450435017463 0ustar centriscentris/* * $Id: main_macosx.mm,v 1.23 2011/03/11 16:43:09 asvitkine Exp $ * * main_macosx.mm - Startup code for MacOS X * Based (in a small way) on the default main.m, and on Basilisk's main_unix.cpp * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import #undef check #define PTHREADS // Why is this here? #include "sysdeps.h" #ifdef HAVE_PTHREADS # include #endif #if REAL_ADDRESSING || DIRECT_ADDRESSING # include #endif #include using std::string; #include "cpu_emulation.h" #include "sys.h" #include "rom_patches.h" #include "xpram.h" #include "video.h" #include "prefs.h" #include "prefs_editor.h" #include "macos_util_macosx.h" #include "user_strings.h" #include "version.h" #include "main.h" #include "vm_alloc.h" #include "sigsegv.h" #if USE_JIT extern void flush_icache_range(uint8 *start, uint32 size); // from compemu_support.cpp #endif #ifdef ENABLE_MON # include "mon.h" #endif #define DEBUG 0 #include "debug.h" #include "main_macosx.h" // To bridge between main() and misc. classes // Constants const char ROM_FILE_NAME[] = "ROM"; const int SCRATCH_MEM_SIZE = 0x10000; // Size of scratch memory area static char *bundle = NULL; // If in an OS X application bundle, its path // CPU and FPU type, addressing mode int CPUType; bool CPUIs68060; int FPUType; bool TwentyFourBitAddressing; // Global variables #ifdef HAVE_PTHREADS static pthread_mutex_t intflag_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect InterruptFlags #define LOCK_INTFLAGS pthread_mutex_lock(&intflag_lock) #define UNLOCK_INTFLAGS pthread_mutex_unlock(&intflag_lock) #else #define LOCK_INTFLAGS #define UNLOCK_INTFLAGS #endif #if USE_SCRATCHMEM_SUBTERFUGE uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes #endif #ifdef ENABLE_MON static struct sigaction sigint_sa; // sigaction for SIGINT handler static void sigint_handler(...); #endif #if REAL_ADDRESSING static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped #endif /* * Helpers to map memory that can be accessed from the Mac side */ // NOTE: VM_MAP_32BIT is only used when compiling a 64-bit JIT on specific platforms void *vm_acquire_mac(size_t size) { return vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT); } static int vm_acquire_mac_fixed(void *addr, size_t size) { return vm_acquire_fixed(addr, size, VM_MAP_DEFAULT | VM_MAP_32BIT); } /* * SIGSEGV handler */ static sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip) { const uintptr fault_address = (uintptr)sigsegv_get_fault_address(sip); #if ENABLE_VOSF // Handle screen fault extern bool Screen_fault_handler(sigsegv_info_t *sip); if (Screen_fault_handler(sip)) return SIGSEGV_RETURN_SUCCESS; #endif #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION // Ignore writes to ROM if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // Ignore all other faults, if requested if (PrefsFindBool("ignoresegv")) return SIGSEGV_RETURN_SKIP_INSTRUCTION; #endif return SIGSEGV_RETURN_FAILURE; } /* * Dump state when everything went wrong after a SEGV */ static void sigsegv_dump_state(sigsegv_info_t *sip) { const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip); const sigsegv_address_t fault_instruction = sigsegv_get_fault_instruction_address(sip); fprintf(stderr, "Caught SIGSEGV at address %p", fault_address); if (fault_instruction != SIGSEGV_INVALID_ADDRESS) fprintf(stderr, " [IP=%p]", fault_instruction); fprintf(stderr, "\n"); uaecptr nextpc; extern void m68k_dumpstate(uaecptr *nextpc); m68k_dumpstate(&nextpc); #if USE_JIT && JIT_DEBUG extern void compiler_dumpstate(void); compiler_dumpstate(); #endif VideoQuitFullScreen(); #ifdef ENABLE_MON char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); #endif QuitEmulator(); } /* * Screen fault handler */ bool Screen_fault_handler(sigsegv_info_t *sip) { return true; } /* * Main program */ static void usage(const char *prg_name) { printf( "Usage: %s [OPTION...]\n" "\nUnix options:\n" " --config FILE\n read/write configuration from/to FILE\n" " --break ADDRESS\n set ROM breakpoint\n" " --rominfo\n dump ROM information\n", prg_name ); LoadPrefs(NULL); // read the prefs file so PrefsPrintUsage() will print the correct default values PrefsPrintUsage(); exit(0); } int main(int argc, char **argv) { const char *vmdir = NULL; char str[256]; // Initialize variables RAMBaseHost = NULL; ROMBaseHost = NULL; srand(time(NULL)); tzset(); // Print some info printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); printf(" %s\n", GetString(STR_ABOUT_TEXT2)); // Parse command line arguments for (int i=1; i i) { k -= i; for (int j=i+k; j 1023*1024*1024) // Cap to 1023MB (APD crashes at 1GB) RAMSize = 1023*1024*1024; #if REAL_ADDRESSING || DIRECT_ADDRESSING RAMSize = RAMSize & -getpagesize(); // Round down to page boundary #endif // Initialize VM system vm_init(); #if REAL_ADDRESSING // Flag: RAM and ROM are contigously allocated from address 0 bool memory_mapped_from_zero = false; // Make sure to map RAM & ROM at address 0 only on platforms that // supports linker scripts to relocate the Basilisk II executable // above 0x70000000 #if HAVE_LINKER_SCRIPT const bool can_map_all_memory = true; #else const bool can_map_all_memory = false; #endif // Try to allocate all memory from 0x0000, if it is not known to crash if (can_map_all_memory && (vm_acquire_mac_fixed(0, RAMSize + 0x100000) == 0)) { D(bug("Could allocate RAM and ROM from 0x0000\n")); memory_mapped_from_zero = true; } #ifndef PAGEZERO_HACK // Otherwise, just create the Low Memory area (0x0000..0x2000) else if (vm_acquire_mac_fixed(0, 0x2000) == 0) { D(bug("Could allocate the Low Memory globals\n")); lm_area_mapped = true; } // Exit on failure else { sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno)); ErrorAlert(str); QuitEmulator(); } #endif #else *str = 0; // Eliminate unused variable warning #endif /* REAL_ADDRESSING */ // Create areas for Mac RAM and ROM #if REAL_ADDRESSING if (memory_mapped_from_zero) { RAMBaseHost = (uint8 *)0; ROMBaseHost = RAMBaseHost + RAMSize; } else #endif { uint8 *ram_rom_area = (uint8 *)vm_acquire_mac(RAMSize + 0x100000); if (ram_rom_area == VM_MAP_FAILED) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } RAMBaseHost = ram_rom_area; ROMBaseHost = RAMBaseHost + RAMSize; } #if USE_SCRATCHMEM_SUBTERFUGE // Allocate scratch memory ScratchMem = (uint8 *)vm_acquire_mac(SCRATCH_MEM_SIZE); if (ScratchMem == VM_MAP_FAILED) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block #endif #if DIRECT_ADDRESSING // RAMBaseMac shall always be zero MEMBaseDiff = (uintptr)RAMBaseHost; RAMBaseMac = 0; ROMBaseMac = Host2MacAddr(ROMBaseHost); #endif #if REAL_ADDRESSING RAMBaseMac = Host2MacAddr(RAMBaseHost); ROMBaseMac = Host2MacAddr(ROMBaseHost); #endif D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac)); D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac)); // Get rom file path from preferences const char *rom_path = PrefsFindString("rom"); if ( ! rom_path ) if ( bundle ) WarningAlert("No rom pathname set. Trying BasiliskII.app/ROM"); else WarningAlert("No rom pathname set. Trying ./ROM"); // Load Mac ROM int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY); if (rom_fd < 0) { ErrorAlert(STR_NO_ROM_FILE_ERR); QuitEmulator(); } printf(GetString(STR_READING_ROM_FILE)); ROMSize = lseek(rom_fd, 0, SEEK_END); if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) { ErrorAlert(STR_ROM_SIZE_ERR); close(rom_fd); QuitEmulator(); } lseek(rom_fd, 0, SEEK_SET); if (read(rom_fd, ROMBaseHost, ROMSize) != (ssize_t)ROMSize) { ErrorAlert(STR_ROM_FILE_READ_ERR); close(rom_fd); QuitEmulator(); } // Initialize everything if (!InitAll(vmdir)) QuitEmulator(); D(bug("Initialization complete\n")); #ifdef ENABLE_MON // Setup SIGINT handler to enter mon sigemptyset(&sigint_sa.sa_mask); sigint_sa.sa_handler = (void (*)(int))sigint_handler; sigint_sa.sa_flags = 0; sigaction(SIGINT, &sigint_sa, NULL); #endif return YES; } #undef QuitEmulator() /* * Quit emulator */ void QuitEmuNoExit() { D(bug("QuitEmulator\n")); // Exit 680x0 emulation Exit680x0(); // Deinitialize everything ExitAll(); // Free ROM/RAM areas if (RAMBaseHost != VM_MAP_FAILED) { vm_release(RAMBaseHost, RAMSize + 0x100000); RAMBaseHost = NULL; ROMBaseHost = NULL; } #if USE_SCRATCHMEM_SUBTERFUGE // Delete scratch memory area if (ScratchMem != (uint8 *)VM_MAP_FAILED) { vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE); ScratchMem = NULL; } #endif #if REAL_ADDRESSING // Delete Low Memory area if (lm_area_mapped) vm_release(0, 0x2000); #endif // Exit VM wrappers vm_exit(); // Exit system routines SysExit(); // Exit preferences PrefsExit(); } void QuitEmulator(void) { QuitEmuNoExit(); // Stop run loop? [NSApp terminate: nil]; exit(0); } /* * Code was patched, flush caches if neccessary (i.e. when using a real 680x0 * or a dynamically recompiling emulator) */ void FlushCodeCache(void *start, uint32 size) { #if USE_JIT if (UseJIT) flush_icache_range((uint8 *)start, size); #endif } /* * SIGINT handler, enters mon */ #ifdef ENABLE_MON static void sigint_handler(...) { uaecptr nextpc; extern void m68k_dumpstate(uaecptr *nextpc); m68k_dumpstate(&nextpc); VideoQuitFullScreen(); char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); QuitEmulator(); } #endif #ifdef HAVE_PTHREADS /* * Pthread configuration */ void Set_pthread_attr(pthread_attr_t *attr, int priority) { pthread_attr_init(attr); #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) // Some of these only work for superuser if (geteuid() == 0) { pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(attr, SCHED_FIFO); struct sched_param fifo_param; fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2 + priority); pthread_attr_setschedparam(attr, &fifo_param); } if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) { #ifdef PTHREAD_SCOPE_BOUND_NP // If system scope is not available (eg. we're not running // with CAP_SCHED_MGT capability on an SGI box), try bound // scope. It exposes pthread scheduling to the kernel, // without setting realtime priority. pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP); #endif } #endif } #endif // HAVE_PTHREADS /* * Mutexes */ #ifdef HAVE_PTHREADS struct B2_mutex { B2_mutex() { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); // Initialize the mutex for priority inheritance -- // required for accurate timing. #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); #endif #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); #endif #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); #endif pthread_mutex_init(&m, &attr); pthread_mutexattr_destroy(&attr); } ~B2_mutex() { pthread_mutex_trylock(&m); // Make sure it's locked before pthread_mutex_unlock(&m); // unlocking it. pthread_mutex_destroy(&m); } pthread_mutex_t m; }; B2_mutex *B2_create_mutex(void) { return new B2_mutex; } void B2_lock_mutex(B2_mutex *mutex) { pthread_mutex_lock(&mutex->m); } void B2_unlock_mutex(B2_mutex *mutex) { pthread_mutex_unlock(&mutex->m); } void B2_delete_mutex(B2_mutex *mutex) { delete mutex; } #else struct B2_mutex { int dummy; }; B2_mutex *B2_create_mutex(void) { return new B2_mutex; } void B2_lock_mutex(B2_mutex *mutex) { } void B2_unlock_mutex(B2_mutex *mutex) { } void B2_delete_mutex(B2_mutex *mutex) { delete mutex; } #endif /* * Interrupt flags (must be handled atomically!) */ uint32 InterruptFlags = 0; void SetInterruptFlag(uint32 flag) { LOCK_INTFLAGS; InterruptFlags |= flag; UNLOCK_INTFLAGS; } void ClearInterruptFlag(uint32 flag) { LOCK_INTFLAGS; InterruptFlags &= ~flag; UNLOCK_INTFLAGS; } /* * Display error alert */ void ErrorAlert(const char *text) { NSString *title = [NSString stringWithCString: GetString(STR_ERROR_ALERT_TITLE) ]; NSString *error = [NSString stringWithCString: text]; NSString *button = [NSString stringWithCString: GetString(STR_QUIT_BUTTON) ]; NSLog(error); if ( PrefsFindBool("nogui") ) return; VideoQuitFullScreen(); NSRunCriticalAlertPanel(title, error, button, nil, nil); } /* * Display warning alert */ void WarningAlert(const char *text) { NSString *title = [NSString stringWithCString: GetString(STR_WARNING_ALERT_TITLE) ]; NSString *warning = [NSString stringWithCString: text]; NSString *button = [NSString stringWithCString: GetString(STR_OK_BUTTON) ]; NSLog(warning); if ( PrefsFindBool("nogui") ) return; VideoQuitFullScreen(); NSRunAlertPanel(title, warning, button, nil, nil); } /* * Display choice alert */ bool ChoiceAlert(const char *text, const char *pos, const char *neg) { NSString *title = [NSString stringWithCString: GetString(STR_WARNING_ALERT_TITLE) ]; NSString *warning = [NSString stringWithCString: text]; NSString *yes = [NSString stringWithCString: pos]; NSString *no = [NSString stringWithCString: neg]; return NSRunInformationalAlertPanel(title, warning, yes, no, nil); } BasiliskII/src/MacOSX/MacOSX_sound_if.cpp0000644000175000017500000000376510462412105020314 0ustar centriscentris/* * MacOSX_sound_if.h * BasiliskII * * Copyright 2006 Daniel Sumorok. All rights reserved. * * 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 */ #include "AudioBackEnd.h" #include "MacOSX_sound_if.h" OSXsoundOutput::OSXsoundOutput() : player(NULL), callback(NULL) { } void OSXsoundOutput::getMoreSamples(void *arg) { OSXsoundOutput *me; me = (OSXsoundOutput *)arg; if(me == NULL) { return; } if(me->callback == NULL) { return; } me->callback(); } int OSXsoundOutput::start(int bitsPerSample, int numChannels, int sampleRate) { stop(); player = new AudioBackEnd(bitsPerSample, numChannels, sampleRate); if(player != NULL) { player->setCallback(getMoreSamples, (void *)this); player->Start(); } return 0; } int OSXsoundOutput::stop() { if(player != NULL) { player->Stop(); delete player; player = NULL; } return 0; } OSXsoundOutput::~OSXsoundOutput() { stop(); } void OSXsoundOutput::setCallback(audioCallback fn) { callback = fn; } unsigned int OSXsoundOutput::bufferSizeFrames() { if(player != NULL) { return player->BufferSizeFrames(); } return 0; } int OSXsoundOutput::sendAudioBuffer(void *buffer, int numFrames) { if(player != NULL) { return player->sendAudioBuffer(buffer, numFrames); } return 0; } BasiliskII/src/MacOSX/sysdeps.h0000644000175000017500000002426311536451064016501 0ustar centriscentris/* * sysdeps.h - System dependent definitions for Mac OS X. * Based on Unix version * * $Id: sysdeps.h,v 1.11 2011/03/11 16:47:48 asvitkine Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SYSDEPS_H #define SYSDEPS_H #ifndef __STDC__ #error "Your compiler is not ANSI. Get a real one." #endif #include "config.h" #include "user_strings_unix.h" #ifndef STDC_HEADERS #error "You don't have ANSI C header files." #endif #ifdef HAVE_UNISTD_H # include # include #endif #include #include #include #include #include #ifdef HAVE_PTHREADS # include #endif #ifdef HAVE_FCNTL_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #if defined(__MACH__) #include #endif /* Symbol to distinguish Nigel's Aqua port from a normal Darwin X11 build */ /* (this sysdeps.h file is currently specific to the Mac OS X Aqua port) */ #define AQUA 1 /* Header which defines OS X version for selecting APIs */ #ifdef AVAILABILITYMACROS # include #endif #ifdef ENABLE_NATIVE_M68K /* Mac and host address space are the same */ #define REAL_ADDRESSING 1 /* Using 68k natively */ #define EMULATED_68K 0 /* Mac ROM is not write protected */ #define ROM_IS_WRITE_PROTECTED 0 #define USE_SCRATCHMEM_SUBTERFUGE 1 #else /* Mac and host address space are distinct */ #ifndef REAL_ADDRESSING #define REAL_ADDRESSING 0 #endif /* Using 68k emulator */ #define EMULATED_68K 1 /* The m68k emulator uses a prefetch buffer ? */ #define USE_PREFETCH_BUFFER 0 /* Mac ROM is write protected when banked memory is used */ #if REAL_ADDRESSING || DIRECT_ADDRESSING # define ROM_IS_WRITE_PROTECTED 0 # define USE_SCRATCHMEM_SUBTERFUGE 1 #else # define ROM_IS_WRITE_PROTECTED 1 #endif #endif /* Direct Addressing requires Video on SEGV signals */ #if DIRECT_ADDRESSING && !ENABLE_VOSF # undef ENABLE_VOSF # define ENABLE_VOSF 1 #endif /* ExtFS is supported */ #define SUPPORTS_EXTFS 1 /* BSD socket API supported */ #define SUPPORTS_UDP_TUNNEL 1 /* Data types */ typedef unsigned char uint8; typedef signed char int8; #if SIZEOF_SHORT == 2 typedef unsigned short uint16; typedef short int16; #elif SIZEOF_INT == 2 typedef unsigned int uint16; typedef int int16; #else #error "No 2 byte type, you lose." #endif #if SIZEOF_INT == 4 typedef unsigned int uint32; typedef int int32; #elif SIZEOF_LONG == 4 typedef unsigned long uint32; typedef long int32; #else #error "No 4 byte type, you lose." #endif #if SIZEOF_LONG == 8 typedef unsigned long uint64; typedef long int64; #define VAL64(a) (a ## l) #define UVAL64(a) (a ## ul) #elif SIZEOF_LONG_LONG == 8 typedef unsigned long long uint64; typedef long long int64; #define VAL64(a) (a ## LL) #define UVAL64(a) (a ## uLL) #else #error "No 8 byte type, you lose." #endif #if SIZEOF_VOID_P == 4 typedef uint32 uintptr; typedef int32 intptr; #elif SIZEOF_VOID_P == 8 typedef uint64 uintptr; typedef int64 intptr; #else #error "Unsupported size of pointer" #endif #ifndef HAVE_LOFF_T typedef off_t loff_t; #endif #ifndef HAVE_CADDR_T typedef char * caddr_t; #endif /* Time data type for Time Manager emulation */ #ifdef HAVE_CLOCK_GETTIME typedef struct timespec tm_time_t; #elif defined(__MACH__) typedef mach_timespec_t tm_time_t; #else typedef struct timeval tm_time_t; #endif /* Define codes for all the float formats that we know of. * Though we only handle IEEE format. */ #define UNKNOWN_FLOAT_FORMAT 0 #define IEEE_FLOAT_FORMAT 1 #define VAX_FLOAT_FORMAT 2 #define IBM_FLOAT_FORMAT 3 #define C4X_FLOAT_FORMAT 4 /* UAE CPU data types */ #define uae_s8 int8 #define uae_u8 uint8 #define uae_s16 int16 #define uae_u16 uint16 #define uae_s32 int32 #define uae_u32 uint32 #define uae_s64 int64 #define uae_u64 uint64 typedef uae_u32 uaecptr; /* Alignment restrictions */ #if defined(__i386__) || defined(__powerpc__) || defined(__m68k__) || defined(__x86_64__) # define CPU_CAN_ACCESS_UNALIGNED #endif /* Timing functions */ extern uint64 GetTicks_usec(void); extern void Delay_usec(uint32 usec); #ifdef HAVE_PTHREADS /* Centralized pthread attribute setup */ void Set_pthread_attr(pthread_attr_t *attr, int priority); #endif /* UAE CPU defines */ #ifdef WORDS_BIGENDIAN #ifdef CPU_CAN_ACCESS_UNALIGNED /* Big-endian CPUs which can do unaligned accesses */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {return *a;} static inline uae_u32 do_get_mem_word(uae_u16 *a) {return *a;} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {*a = v;} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {*a = v;} #else /* CPU_CAN_ACCESS_UNALIGNED */ #ifdef sgi /* The SGI MIPSPro compilers can do unaligned accesses given enough hints. * They will automatically inline these routines. */ #ifdef __cplusplus extern "C" { /* only the C compiler does unaligned accesses */ #endif extern uae_u32 do_get_mem_long(uae_u32 *a); extern uae_u32 do_get_mem_word(uae_u16 *a); extern void do_put_mem_long(uae_u32 *a, uae_u32 v); extern void do_put_mem_word(uae_u16 *a, uae_u32 v); #ifdef __cplusplus } #endif #else /* sgi */ /* Big-endian CPUs which can not do unaligned accesses (this is not the most efficient way to do this...) */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint8 *b = (uint8 *)a; return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];} static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint8 *b = (uint8 *)a; return (b[0] << 8) | b[1];} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 24; b[1] = v >> 16; b[2] = v >> 8; b[3] = v;} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 8; b[1] = v;} #endif /* sgi */ #endif /* CPU_CAN_ACCESS_UNALIGNED */ #else /* WORDS_BIGENDIAN */ #if defined(__i386__) || defined(__x86_64__) /* Intel x86 */ #define X86_PPRO_OPT static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 retval; __asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc"); return retval;} #ifdef X86_PPRO_OPT static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswapl %k0\n" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #else static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #endif #define HAVE_GET_WORD_UNSWAPPED #define do_get_mem_word_unswapped(a) ((uae_u32)*((uae_u16 *)(a))) static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #ifdef X86_PPRO_OPT static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); *a = v;} #else static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #endif #define HAVE_OPTIMIZED_BYTESWAP_32 /* bswap doesn't affect condition codes */ static inline uae_u32 do_byteswap_32(uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v)); return v;} #define HAVE_OPTIMIZED_BYTESWAP_16 #ifdef X86_PPRO_OPT static inline uae_u32 do_byteswap_16(uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); return v;} #else static inline uae_u32 do_byteswap_16(uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); return v;} #endif #elif defined(CPU_CAN_ACCESS_UNALIGNED) /* Other little-endian CPUs which can do unaligned accesses */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 x = *a; return (x >> 24) | (x >> 8) & 0xff00 | (x << 8) & 0xff0000 | (x << 24);} static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint16 x = *a; return (x >> 8) | (x << 8);} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {*a = (v >> 24) | (v >> 8) & 0xff00 | (v << 8) & 0xff0000 | (v << 24);} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {*a = (v >> 8) | (v << 8);} #else /* CPU_CAN_ACCESS_UNALIGNED */ /* Other little-endian CPUs which can not do unaligned accesses (this needs optimization) */ static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint8 *b = (uint8 *)a; return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];} static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint8 *b = (uint8 *)a; return (b[0] << 8) | b[1];} static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 24; b[1] = v >> 16; b[2] = v >> 8; b[3] = v;} static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 8; b[1] = v;} #endif /* CPU_CAN_ACCESS_UNALIGNED */ #endif /* WORDS_BIGENDIAN */ #ifndef HAVE_OPTIMIZED_BYTESWAP_32 static inline uae_u32 do_byteswap_32(uae_u32 v) { return (((v >> 24) & 0xff) | ((v >> 8) & 0xff00) | ((v & 0xff) << 24) | ((v & 0xff00) << 8)); } #endif #ifndef HAVE_OPTIMIZED_BYTESWAP_16 static inline uae_u32 do_byteswap_16(uae_u32 v) { return (((v >> 8) & 0xff) | ((v & 0xff) << 8)); } #endif #define do_get_mem_byte(a) ((uae_u32)*((uae_u8 *)(a))) #define do_put_mem_byte(a, v) (*(uae_u8 *)(a) = (v)) #define call_mem_get_func(func, addr) ((*func)(addr)) #define call_mem_put_func(func, addr, v) ((*func)(addr, v)) #define __inline__ inline #define CPU_EMU_SIZE 0 #undef NO_INLINE_MEMORY_ACCESS #undef MD_HAVE_MEM_1_FUNCS #define ENUMDECL typedef enum #define ENUMNAME(name) name #define write_log printf #if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY) #define ASM_SYM_FOR_FUNC(a) __asm__(a) #else #define ASM_SYM_FOR_FUNC(a) #endif #ifndef REGPARAM # define REGPARAM #endif #define REGPARAM2 #endif BasiliskII/src/MacOSX/BasiliskII.xcode/0000755000175000017500000000000011735674761017727 5ustar centriscentrisBasiliskII/src/MacOSX/BasiliskII.xcode/project.pbxproj0000644000175000017500000012512210463342321022763 0ustar centriscentris// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 39; objects = { 089C165CFE840E0CC02AAC07 = { children = ( 089C165DFE840E0CC02AAC07, ); isa = PBXVariantGroup; name = InfoPlist.strings; refType = 4; sourceTree = ""; }; 089C165DFE840E0CC02AAC07 = { fileEncoding = 10; isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; refType = 4; sourceTree = ""; }; //080 //081 //082 //083 //084 //100 //101 //102 //103 //104 1058C7A1FEA54F0111CA2CBB = { fallbackIsa = PBXFileReference; isa = PBXFrameworkReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; refType = 0; sourceTree = ""; }; //100 //101 //102 //103 //104 //190 //191 //192 //193 //194 19C28FACFE9D520D11CA2CBB = { children = ( 8D1107320486CEB800E47090, ); isa = PBXGroup; name = Products; refType = 4; sourceTree = ""; }; //190 //191 //192 //193 //194 //290 //291 //292 //293 //294 29B97313FDCFA39411CA2CEA = { buildSettings = { }; buildStyles = ( 4A9504CCFFE6A4B311CA0CBA, 4A9504CDFFE6A4B311CA0CBA, ); hasScannedForEncodings = 1; isa = PBXProject; mainGroup = 29B97314FDCFA39411CA2CEA; projectDirPath = ""; targets = ( 8D1107260486CEB800E47090, ); }; 29B97314FDCFA39411CA2CEA = { children = ( A68501D005C4ED8E00DDBA94, A68501D305C4ED9A00DDBA94, A685FDC205C4E7F600DDBA94, A68501D805C4EDC700DDBA94, A685FDBA05C4E7D700DDBA94, 29B97317FDCFA39411CA2CEA, 29B97323FDCFA39411CA2CEA, 19C28FACFE9D520D11CA2CBB, ); isa = PBXGroup; name = BasiliskII; path = ""; refType = 4; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA = { children = ( A685016A05C4EA0D00DDBA94, A685016E05C4EA2F00DDBA94, A685017205C4EA3F00DDBA94, 8D1107310486CEB800E47090, 089C165CFE840E0CC02AAC07, 29B97318FDCFA39411CA2CEA, A685017605C4EA5A00DDBA94, A685017805C4EA7A00DDBA94, A685017A05C4EA8500DDBA94, A685017C05C4EA8E00DDBA94, ); isa = PBXGroup; name = Resources; path = ""; refType = 4; sourceTree = ""; }; 29B97318FDCFA39411CA2CEA = { children = ( 29B97319FDCFA39411CA2CEA, ); isa = PBXVariantGroup; name = MainMenu.nib; path = ""; refType = 2; sourceTree = SOURCE_ROOT; }; 29B97319FDCFA39411CA2CEA = { isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; refType = 4; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA = { children = ( A60B5F480A174A4900D7F586, A63638A10964120600BE2F74, 29B97324FDCFA39411CA2CEA, A685FF0D05C4E89D00DDBA94, A6F396980A6B67AB0050CF14, A6F396990A6B67AB0050CF14, A685FE6A05C4E87D00DDBA94, 1058C7A1FEA54F0111CA2CBB, A6F3969A0A6B67AB0050CF14, A685FFCD05C4E8CC00DDBA94, 29B97325FDCFA39411CA2CEA, A68500CB05C4E8DE00DDBA94, ); isa = PBXGroup; name = Frameworks; path = ""; refType = 4; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA = { fallbackIsa = PBXFileReference; isa = PBXFrameworkReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; refType = 0; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA = { fallbackIsa = PBXFileReference; isa = PBXFrameworkReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; refType = 0; sourceTree = ""; }; //290 //291 //292 //293 //294 //4A0 //4A1 //4A2 //4A3 //4A4 4A9504CCFFE6A4B311CA0CBA = { buildRules = ( ); buildSettings = { COPY_PHASE_STRIP = NO; DEBUGGING_SYMBOLS = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 0; OPTIMIZATION_CFLAGS = "-O0"; ZERO_LINK = YES; }; isa = PBXBuildStyle; name = Development; }; 4A9504CDFFE6A4B311CA0CBA = { buildRules = ( ); buildSettings = { COPY_PHASE_STRIP = YES; GCC_ENABLE_FIX_AND_CONTINUE = NO; ZERO_LINK = NO; }; isa = PBXBuildStyle; name = Deployment; }; //4A0 //4A1 //4A2 //4A3 //4A4 //8D0 //8D1 //8D2 //8D3 //8D4 8D1107260486CEB800E47090 = { buildPhases = ( 8D1107270486CEB800E47090, 8D1107290486CEB800E47090, 8D11072C0486CEB800E47090, 8D11072E0486CEB800E47090, ); buildRules = ( ); buildSettings = { FRAMEWORK_SEARCH_PATHS = /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks; GCC_ENABLE_TRIGRAPHS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = "AQUA HAVE_CONFIG_H HAVE_SLIRP _REENTRANT DATADIR=\"\""; GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNKNOWN_PRAGMAS = NO; HEADER_SEARCH_PATHS = "../include ../uae_cpu ../Unix ../slirp"; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = .; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; PRODUCT_NAME = BasiliskII; SECTORDER_FLAGS = ""; WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; WRAPPER_EXTENSION = app; }; dependencies = ( ); isa = PBXNativeTarget; name = BasiliskII; productInstallPath = "$(HOME)/Applications"; productName = BasiliskII; productReference = 8D1107320486CEB800E47090; productType = "com.apple.product-type.application"; }; 8D1107270486CEB800E47090 = { buildActionMask = 2147483647; files = ( A685018305C4EAD900DDBA94, A685018405C4EAD900DDBA94, A685018505C4EAD900DDBA94, A685019805C4EB6F00DDBA94, A685019A05C4EB6F00DDBA94, A685019C05C4EB6F00DDBA94, A685019E05C4EB6F00DDBA94, A68501A005C4EB6F00DDBA94, A68501A205C4EB6F00DDBA94, A68501A405C4EB6F00DDBA94, A68501A605C4EB6F00DDBA94, A68501A805C4EB6F00DDBA94, A68501DC05C4EE5100DDBA94, A68501DD05C4EE5100DDBA94, A68501DE05C4EE5100DDBA94, A68501E905C4EEF200DDBA94, A68501EA05C4EEF200DDBA94, A68501EC05C4EEF200DDBA94, A68501F005C4EEF200DDBA94, A685020D05C4EF6700DDBA94, A6F395DF0A6B676C0050CF14, A6F395E10A6B676C0050CF14, A6F396CD0A6B68230050CF14, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 8D1107290486CEB800E47090 = { buildActionMask = 2147483647; files = ( 8D11072A0486CEB800E47090, 8D11072B0486CEB800E47090, A685016B05C4EA0D00DDBA94, A685016F05C4EA2F00DDBA94, A685017305C4EA3F00DDBA94, A685017705C4EA5A00DDBA94, A685017905C4EA7A00DDBA94, A685017B05C4EA8500DDBA94, A685017D05C4EA8E00DDBA94, ); isa = PBXResourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 8D11072A0486CEB800E47090 = { fileRef = 29B97318FDCFA39411CA2CEA; isa = PBXBuildFile; settings = { }; }; 8D11072B0486CEB800E47090 = { fileRef = 089C165CFE840E0CC02AAC07; isa = PBXBuildFile; settings = { }; }; 8D11072C0486CEB800E47090 = { buildActionMask = 2147483647; files = ( A685019905C4EB6F00DDBA94, A685019B05C4EB6F00DDBA94, A685019D05C4EB6F00DDBA94, A685019F05C4EB6F00DDBA94, A68501A105C4EB6F00DDBA94, A68501A305C4EB6F00DDBA94, A68501A505C4EB6F00DDBA94, A68501A705C4EB6F00DDBA94, A68501A905C4EB6F00DDBA94, A68501B105C4EC2100DDBA94, A68501B205C4EC2100DDBA94, A68501B605C4EC9500DDBA94, A68501B705C4EC9500DDBA94, A68501BE05C4ECDB00DDBA94, A68501BF05C4ECDB00DDBA94, A68501C005C4ECDB00DDBA94, A68501C205C4ED0700DDBA94, A68501E805C4EEF200DDBA94, A68501EB05C4EEF200DDBA94, A68501EF05C4EEF200DDBA94, A68501F305C4EF3300DDBA94, A685020305C4EF6700DDBA94, A685020C05C4EF6700DDBA94, A685021605C4EFDC00DDBA94, A685021705C4EFDC00DDBA94, A685022D05C4F04700DDBA94, A685022E05C4F04700DDBA94, A685022F05C4F04700DDBA94, A685023005C4F04700DDBA94, A685023105C4F04700DDBA94, A685023205C4F04700DDBA94, A685023305C4F04700DDBA94, A685023405C4F04700DDBA94, A685023505C4F04700DDBA94, A685023605C4F04700DDBA94, A685023705C4F04700DDBA94, A685023805C4F04700DDBA94, A685023905C4F04700DDBA94, A685023A05C4F04700DDBA94, A685023B05C4F04700DDBA94, A685023C05C4F04700DDBA94, A685023D05C4F04700DDBA94, A685023E05C4F04700DDBA94, A685023F05C4F04700DDBA94, A685024005C4F04700DDBA94, A685024105C4F04700DDBA94, A6C4EFBF09641353006D945B, A622F5580A6B533900E826C8, A6F395DE0A6B676C0050CF14, A6F395E00A6B676C0050CF14, A6F396CC0A6B68230050CF14, A60CFFD60A7DFB7600AE526A, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 8D11072E0486CEB800E47090 = { buildActionMask = 2147483647; files = ( 8D11072F0486CEB800E47090, A685FE6B05C4E87D00DDBA94, A685FF0E05C4E89D00DDBA94, A685FFCE05C4E8CC00DDBA94, A68500CC05C4E8DE00DDBA94, A63638A20964120600BE2F74, A60B5F490A174A4900D7F586, A6F3969B0A6B67AB0050CF14, A6F3969C0A6B67AB0050CF14, A6F3969D0A6B67AB0050CF14, ); isa = PBXFrameworksBuildPhase; runOnlyForDeploymentPostprocessing = 0; }; 8D11072F0486CEB800E47090 = { fileRef = 1058C7A1FEA54F0111CA2CBB; isa = PBXBuildFile; settings = { }; }; 8D1107310486CEB800E47090 = { fileEncoding = 4; isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; refType = 2; sourceTree = SOURCE_ROOT; }; 8D1107320486CEB800E47090 = { explicitFileType = wrapper.application; includeInIndex = 0; isa = PBXFileReference; path = BasiliskII.app; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; //8D0 //8D1 //8D2 //8D3 //8D4 //A60 //A61 //A62 //A63 //A64 A60B5F480A174A4900D7F586 = { isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgenemu.a; refType = 2; sourceTree = SOURCE_ROOT; }; A60B5F490A174A4900D7F586 = { fileRef = A60B5F480A174A4900D7F586; isa = PBXBuildFile; settings = { }; }; A60CFFD50A7DFB7600AE526A = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = clip_macosx.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A60CFFD60A7DFB7600AE526A = { fileRef = A60CFFD50A7DFB7600AE526A; isa = PBXBuildFile; settings = { }; }; A622F5570A6B533900E826C8 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = audio_macosx.cpp; refType = 4; sourceTree = ""; }; A622F5580A6B533900E826C8 = { fileRef = A622F5570A6B533900E826C8; isa = PBXBuildFile; settings = { }; }; A63638A10964120600BE2F74 = { isa = PBXFileReference; lastKnownFileType = archive.ar; path = libslirp.a; refType = 2; sourceTree = SOURCE_ROOT; }; A63638A20964120600BE2F74 = { fileRef = A63638A10964120600BE2F74; isa = PBXBuildFile; settings = { }; }; A68500CB05C4E8DE00DDBA94 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; refType = 0; sourceTree = ""; }; A68500CC05C4E8DE00DDBA94 = { fileRef = A68500CB05C4E8DE00DDBA94; isa = PBXBuildFile; settings = { }; }; A685016A05C4EA0D00DDBA94 = { isa = PBXFileReference; lastKnownFileType = image.icns; path = BasiliskII.icns; refType = 2; sourceTree = SOURCE_ROOT; }; A685016B05C4EA0D00DDBA94 = { fileRef = A685016A05C4EA0D00DDBA94; isa = PBXBuildFile; settings = { }; }; A685016E05C4EA2F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = text.html; path = Credits.html; refType = 2; sourceTree = SOURCE_ROOT; }; A685016F05C4EA2F00DDBA94 = { fileRef = A685016E05C4EA2F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685017205C4EA3F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = text.html; path = HowTo.html; refType = 2; sourceTree = SOURCE_ROOT; }; A685017305C4EA3F00DDBA94 = { fileRef = A685017205C4EA3F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685017605C4EA5A00DDBA94 = { isa = PBXFileReference; lastKnownFileType = image.icns; path = nowrite.icns; refType = 2; sourceTree = SOURCE_ROOT; }; A685017705C4EA5A00DDBA94 = { fileRef = A685017605C4EA5A00DDBA94; isa = PBXBuildFile; settings = { }; }; A685017805C4EA7A00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = text; path = README.txt; refType = 2; sourceTree = SOURCE_ROOT; }; A685017905C4EA7A00DDBA94 = { fileRef = A685017805C4EA7A00DDBA94; isa = PBXBuildFile; settings = { }; }; A685017A05C4EA8500DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = text.html; path = ToDo.html; refType = 2; sourceTree = SOURCE_ROOT; }; A685017B05C4EA8500DDBA94 = { fileRef = A685017A05C4EA8500DDBA94; isa = PBXBuildFile; settings = { }; }; A685017C05C4EA8E00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = text.html; path = Versions.html; refType = 2; sourceTree = SOURCE_ROOT; }; A685017D05C4EA8E00DDBA94 = { fileRef = A685017C05C4EA8E00DDBA94; isa = PBXBuildFile; settings = { }; }; A685018005C4EAD900DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = config.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018105C4EAD900DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = macos_util_macosx.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018205C4EAD900DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sysdeps.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018305C4EAD900DDBA94 = { fileRef = A685018005C4EAD900DDBA94; isa = PBXBuildFile; settings = { }; }; A685018405C4EAD900DDBA94 = { fileRef = A685018105C4EAD900DDBA94; isa = PBXBuildFile; settings = { }; }; A685018505C4EAD900DDBA94 = { fileRef = A685018205C4EAD900DDBA94; isa = PBXBuildFile; settings = { }; }; A685018605C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Controller.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018705C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Controller.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685018805C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Emulator.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018905C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Emulator.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685018A05C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EmulatorView.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018B05C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = EmulatorView.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685018C05C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extfs_macosx.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018D05C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = extfs_macosx.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685018E05C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = main_macosx.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685018F05C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main_macosx.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685019005C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = misc_macosx.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685019105C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = misc_macosx.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685019205C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NNThread.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685019305C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NNThread.m; refType = 2; sourceTree = SOURCE_ROOT; }; A685019405C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PrefsEditor.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685019505C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PrefsEditor.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685019605C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = video_macosx.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685019705C4EB6F00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = video_macosx.mm; refType = 2; sourceTree = SOURCE_ROOT; }; A685019805C4EB6F00DDBA94 = { fileRef = A685018605C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685019905C4EB6F00DDBA94 = { fileRef = A685018705C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685019A05C4EB6F00DDBA94 = { fileRef = A685018805C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685019B05C4EB6F00DDBA94 = { fileRef = A685018905C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685019C05C4EB6F00DDBA94 = { fileRef = A685018A05C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685019D05C4EB6F00DDBA94 = { fileRef = A685018B05C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685019E05C4EB6F00DDBA94 = { fileRef = A685018C05C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A685019F05C4EB6F00DDBA94 = { fileRef = A685018D05C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A005C4EB6F00DDBA94 = { fileRef = A685018E05C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A105C4EB6F00DDBA94 = { fileRef = A685018F05C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A205C4EB6F00DDBA94 = { fileRef = A685019005C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A305C4EB6F00DDBA94 = { fileRef = A685019105C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A405C4EB6F00DDBA94 = { fileRef = A685019205C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A505C4EB6F00DDBA94 = { fileRef = A685019305C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A605C4EB6F00DDBA94 = { fileRef = A685019405C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A705C4EB6F00DDBA94 = { fileRef = A685019505C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A805C4EB6F00DDBA94 = { fileRef = A685019605C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501A905C4EB6F00DDBA94 = { fileRef = A685019705C4EB6F00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501AC05C4EBDC00DDBA94 = { children = ( A685018605C4EB6F00DDBA94, A685018705C4EB6F00DDBA94, A685018805C4EB6F00DDBA94, A685018905C4EB6F00DDBA94, A685018A05C4EB6F00DDBA94, A685018B05C4EB6F00DDBA94, A685019205C4EB6F00DDBA94, A685019305C4EB6F00DDBA94, A685019405C4EB6F00DDBA94, A685019505C4EB6F00DDBA94, ); isa = PBXGroup; name = "Objective-C Classes"; refType = 4; sourceTree = ""; }; A68501AF05C4EC2100DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = prefs_macosx.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501B005C4EC2100DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = sys_darwin.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501B105C4EC2100DDBA94 = { fileRef = A68501AF05C4EC2100DDBA94; isa = PBXBuildFile; settings = { }; }; A68501B205C4EC2100DDBA94 = { fileRef = A68501B005C4EC2100DDBA94; isa = PBXBuildFile; settings = { }; }; A68501B305C4EC9500DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = sys_unix.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501B405C4EC9500DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = timer_unix.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501B605C4EC9500DDBA94 = { fileRef = A68501B305C4EC9500DDBA94; isa = PBXBuildFile; settings = { }; }; A68501B705C4EC9500DDBA94 = { fileRef = A68501B405C4EC9500DDBA94; isa = PBXBuildFile; settings = { }; }; A68501BA05C4ECDB00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sigsegv.cpp; path = ../Unix/sigsegv.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501BB05C4ECDB00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = vm_alloc.cpp; path = ../Unix/vm_alloc.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501BC05C4ECDB00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xpram_unix.cpp; path = ../Unix/xpram_unix.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501BE05C4ECDB00DDBA94 = { fileRef = A68501BA05C4ECDB00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501BF05C4ECDB00DDBA94 = { fileRef = A68501BB05C4ECDB00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501C005C4ECDB00DDBA94 = { fileRef = A68501BC05C4ECDB00DDBA94; isa = PBXBuildFile; settings = { }; }; A68501C105C4ED0700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = user_strings_unix.cpp; path = ../Unix/user_strings_unix.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501C205C4ED0700DDBA94 = { fileRef = A68501C105C4ED0700DDBA94; isa = PBXBuildFile; settings = { }; }; A68501D005C4ED8E00DDBA94 = { children = ( A685021805C4F04700DDBA94, A685021905C4F04700DDBA94, A685021A05C4F04700DDBA94, A685021B05C4F04700DDBA94, A685021C05C4F04700DDBA94, A685021D05C4F04700DDBA94, A685021E05C4F04700DDBA94, A685021F05C4F04700DDBA94, A685022005C4F04700DDBA94, A685022105C4F04700DDBA94, A685022205C4F04700DDBA94, A685022305C4F04700DDBA94, A685022405C4F04700DDBA94, A685022505C4F04700DDBA94, A685022605C4F04700DDBA94, A685022705C4F04700DDBA94, A685022805C4F04700DDBA94, A685022905C4F04700DDBA94, A685022A05C4F04700DDBA94, A685022B05C4F04700DDBA94, A685022C05C4F04700DDBA94, ); isa = PBXGroup; name = "Common Sources"; path = ""; refType = 2; sourceTree = SOURCE_ROOT; }; A68501D305C4ED9A00DDBA94 = { children = ( A685021105C4EFDC00DDBA94, A685021205C4EFDC00DDBA94, ); isa = PBXGroup; name = "Dummy Sources"; path = ""; refType = 2; sourceTree = SOURCE_ROOT; }; A68501D805C4EDC700DDBA94 = { children = ( A68501F705C4EF3F00DDBA94, A68501DF05C4EEF200DDBA94, A68501E005C4EEF200DDBA94, A68501F105C4EF3300DDBA94, A68501E105C4EEF200DDBA94, A68501E205C4EEF200DDBA94, A68501E305C4EEF200DDBA94, A68501E605C4EEF200DDBA94, A68501E705C4EEF200DDBA94, ); isa = PBXGroup; name = "uae_cpu Sources"; path = ""; refType = 2; sourceTree = SOURCE_ROOT; }; A68501D905C4EE5100DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sigsegv.h; path = ../Unix/sigsegv.h; refType = 2; sourceTree = SOURCE_ROOT; }; A68501DA05C4EE5100DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = user_strings_unix.h; path = ../Unix/user_strings_unix.h; refType = 2; sourceTree = SOURCE_ROOT; }; A68501DB05C4EE5100DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vm_alloc.h; path = ../Unix/vm_alloc.h; refType = 2; sourceTree = SOURCE_ROOT; }; A68501DC05C4EE5100DDBA94 = { fileRef = A68501D905C4EE5100DDBA94; isa = PBXBuildFile; settings = { }; }; A68501DD05C4EE5100DDBA94 = { fileRef = A68501DA05C4EE5100DDBA94; isa = PBXBuildFile; settings = { }; }; A68501DE05C4EE5100DDBA94 = { fileRef = A68501DB05C4EE5100DDBA94; isa = PBXBuildFile; settings = { }; }; A68501DF05C4EEF200DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = basilisk_glue.cpp; path = ../uae_cpu/basilisk_glue.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501E005C4EEF200DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = cpu_emulation.h; path = ../uae_cpu/cpu_emulation.h; refType = 2; sourceTree = SOURCE_ROOT; }; A68501E105C4EEF200DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = m68k.h; path = ../uae_cpu/m68k.h; refType = 2; sourceTree = SOURCE_ROOT; }; A68501E205C4EEF200DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = memory.cpp; path = ../uae_cpu/memory.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501E305C4EEF200DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = memory.h; path = ../uae_cpu/memory.h; refType = 2; sourceTree = SOURCE_ROOT; }; A68501E605C4EEF200DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = readcpu.cpp; path = ../uae_cpu/readcpu.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501E705C4EEF200DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = readcpu.h; path = ../uae_cpu/readcpu.h; refType = 2; sourceTree = SOURCE_ROOT; }; A68501E805C4EEF200DDBA94 = { fileRef = A68501DF05C4EEF200DDBA94; isa = PBXBuildFile; settings = { }; }; A68501E905C4EEF200DDBA94 = { fileRef = A68501E005C4EEF200DDBA94; isa = PBXBuildFile; settings = { }; }; A68501EA05C4EEF200DDBA94 = { fileRef = A68501E105C4EEF200DDBA94; isa = PBXBuildFile; settings = { }; }; A68501EB05C4EEF200DDBA94 = { fileRef = A68501E205C4EEF200DDBA94; isa = PBXBuildFile; settings = { }; }; A68501EC05C4EEF200DDBA94 = { fileRef = A68501E305C4EEF200DDBA94; isa = PBXBuildFile; settings = { }; }; A68501EF05C4EEF200DDBA94 = { fileRef = A68501E605C4EEF200DDBA94; isa = PBXBuildFile; settings = { }; }; A68501F005C4EEF200DDBA94 = { fileRef = A68501E705C4EEF200DDBA94; isa = PBXBuildFile; settings = { }; }; A68501F105C4EF3300DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = fpu_ieee.cpp; path = ../uae_cpu/fpu/fpu_ieee.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A68501F305C4EF3300DDBA94 = { fileRef = A68501F105C4EF3300DDBA94; isa = PBXBuildFile; settings = { }; }; A68501F705C4EF3F00DDBA94 = { children = ( A68501F805C4EF6700DDBA94, A685020105C4EF6700DDBA94, A685020205C4EF6700DDBA94, ); isa = PBXGroup; name = Generated; refType = 4; sourceTree = ""; }; A68501F805C4EF6700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cpudefs.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685020105C4EF6700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cpustbl.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685020205C4EF6700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cputbl.h; refType = 2; sourceTree = SOURCE_ROOT; }; A685020305C4EF6700DDBA94 = { fileRef = A68501F805C4EF6700DDBA94; isa = PBXBuildFile; settings = { }; }; A685020C05C4EF6700DDBA94 = { fileRef = A685020105C4EF6700DDBA94; isa = PBXBuildFile; settings = { }; }; A685020D05C4EF6700DDBA94 = { fileRef = A685020205C4EF6700DDBA94; isa = PBXBuildFile; settings = { }; }; A685021105C4EFDC00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scsi_dummy.cpp; path = ../dummy/scsi_dummy.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021205C4EFDC00DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = serial_dummy.cpp; path = ../dummy/serial_dummy.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021605C4EFDC00DDBA94 = { fileRef = A685021105C4EFDC00DDBA94; isa = PBXBuildFile; settings = { }; }; A685021705C4EFDC00DDBA94 = { fileRef = A685021205C4EFDC00DDBA94; isa = PBXBuildFile; settings = { }; }; A685021805C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = adb.cpp; path = ../adb.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021905C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = audio.cpp; path = ../audio.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021A05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = cdrom.cpp; path = ../cdrom.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021B05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = disk.cpp; path = ../disk.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021C05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = emul_op.cpp; path = ../emul_op.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021D05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ether.cpp; path = ../ether.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021E05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = extfs.cpp; path = ../extfs.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685021F05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = macos_util.cpp; path = ../macos_util.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022005C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../main.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022105C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = prefs_items.cpp; path = ../prefs_items.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022205C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = prefs.cpp; path = ../prefs.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022305C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = rom_patches.cpp; path = ../rom_patches.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022405C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = rsrc_patches.cpp; path = ../rsrc_patches.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022505C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scsi.cpp; path = ../scsi.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022605C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = serial.cpp; path = ../serial.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022705C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = slot_rom.cpp; path = ../slot_rom.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022805C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sony.cpp; path = ../sony.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022905C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = timer.cpp; path = ../timer.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022A05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = user_strings.cpp; path = ../user_strings.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022B05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = video.cpp; path = ../video.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022C05C4F04700DDBA94 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = xpram.cpp; path = ../xpram.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A685022D05C4F04700DDBA94 = { fileRef = A685021805C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685022E05C4F04700DDBA94 = { fileRef = A685021905C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685022F05C4F04700DDBA94 = { fileRef = A685021A05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023005C4F04700DDBA94 = { fileRef = A685021B05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023105C4F04700DDBA94 = { fileRef = A685021C05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023205C4F04700DDBA94 = { fileRef = A685021D05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023305C4F04700DDBA94 = { fileRef = A685021E05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023405C4F04700DDBA94 = { fileRef = A685021F05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023505C4F04700DDBA94 = { fileRef = A685022005C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023605C4F04700DDBA94 = { fileRef = A685022105C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023705C4F04700DDBA94 = { fileRef = A685022205C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023805C4F04700DDBA94 = { fileRef = A685022305C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023905C4F04700DDBA94 = { fileRef = A685022405C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023A05C4F04700DDBA94 = { fileRef = A685022505C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023B05C4F04700DDBA94 = { fileRef = A685022605C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023C05C4F04700DDBA94 = { fileRef = A685022705C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023D05C4F04700DDBA94 = { fileRef = A685022805C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023E05C4F04700DDBA94 = { fileRef = A685022905C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685023F05C4F04700DDBA94 = { fileRef = A685022A05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685024005C4F04700DDBA94 = { fileRef = A685022B05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685024105C4F04700DDBA94 = { fileRef = A685022C05C4F04700DDBA94; isa = PBXBuildFile; settings = { }; }; A685FDBA05C4E7D700DDBA94 = { children = ( A6C4EFBE09641353006D945B, A68501BA05C4ECDB00DDBA94, A68501D905C4EE5100DDBA94, A68501B305C4EC9500DDBA94, A68501B405C4EC9500DDBA94, A68501C105C4ED0700DDBA94, A68501DA05C4EE5100DDBA94, A68501BB05C4ECDB00DDBA94, A68501DB05C4EE5100DDBA94, A68501BC05C4ECDB00DDBA94, ); isa = PBXGroup; name = "Unix Sources"; path = ""; refType = 2; sourceTree = SOURCE_ROOT; }; A685FDC205C4E7F600DDBA94 = { children = ( A685018005C4EAD900DDBA94, A685018105C4EAD900DDBA94, A685018205C4EAD900DDBA94, A6F395DA0A6B676C0050CF14, A6F395DB0A6B676C0050CF14, A6F395DC0A6B676C0050CF14, A6F395DD0A6B676C0050CF14, A6F396CA0A6B68230050CF14, A6F396CB0A6B68230050CF14, A622F5570A6B533900E826C8, A60CFFD50A7DFB7600AE526A, A685018C05C4EB6F00DDBA94, A685018D05C4EB6F00DDBA94, A685018E05C4EB6F00DDBA94, A685018F05C4EB6F00DDBA94, A685019005C4EB6F00DDBA94, A685019105C4EB6F00DDBA94, A68501AF05C4EC2100DDBA94, A68501B005C4EC2100DDBA94, A685019605C4EB6F00DDBA94, A685019705C4EB6F00DDBA94, A68501AC05C4EBDC00DDBA94, ); isa = PBXGroup; name = "MacOS X Sources"; path = ""; refType = 2; sourceTree = SOURCE_ROOT; }; A685FE6A05C4E87D00DDBA94 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; refType = 0; sourceTree = ""; }; A685FE6B05C4E87D00DDBA94 = { fileRef = A685FE6A05C4E87D00DDBA94; isa = PBXBuildFile; settings = { }; }; A685FF0D05C4E89D00DDBA94 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; refType = 0; sourceTree = ""; }; A685FF0E05C4E89D00DDBA94 = { fileRef = A685FF0D05C4E89D00DDBA94; isa = PBXBuildFile; settings = { }; }; A685FFCD05C4E8CC00DDBA94 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; refType = 0; sourceTree = ""; }; A685FFCE05C4E8CC00DDBA94 = { fileRef = A685FFCD05C4E8CC00DDBA94; isa = PBXBuildFile; settings = { }; }; A6C4EFBE09641353006D945B = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ether_unix.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A6C4EFBF09641353006D945B = { fileRef = A6C4EFBE09641353006D945B; isa = PBXBuildFile; settings = { }; }; A6F395DA0A6B676C0050CF14 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AudioBackEnd.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A6F395DB0A6B676C0050CF14 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioBackEnd.h; refType = 2; sourceTree = SOURCE_ROOT; }; A6F395DC0A6B676C0050CF14 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AudioDevice.cpp; refType = 2; sourceTree = SOURCE_ROOT; }; A6F395DD0A6B676C0050CF14 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioDevice.h; refType = 2; sourceTree = SOURCE_ROOT; }; A6F395DE0A6B676C0050CF14 = { fileRef = A6F395DA0A6B676C0050CF14; isa = PBXBuildFile; settings = { }; }; A6F395DF0A6B676C0050CF14 = { fileRef = A6F395DB0A6B676C0050CF14; isa = PBXBuildFile; settings = { }; }; A6F395E00A6B676C0050CF14 = { fileRef = A6F395DC0A6B676C0050CF14; isa = PBXBuildFile; settings = { }; }; A6F395E10A6B676C0050CF14 = { fileRef = A6F395DD0A6B676C0050CF14; isa = PBXBuildFile; settings = { }; }; A6F396980A6B67AB0050CF14 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; refType = 0; sourceTree = ""; }; A6F396990A6B67AB0050CF14 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; refType = 0; sourceTree = ""; }; A6F3969A0A6B67AB0050CF14 = { isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; refType = 0; sourceTree = ""; }; A6F3969B0A6B67AB0050CF14 = { fileRef = A6F396980A6B67AB0050CF14; isa = PBXBuildFile; settings = { }; }; A6F3969C0A6B67AB0050CF14 = { fileRef = A6F396990A6B67AB0050CF14; isa = PBXBuildFile; settings = { }; }; A6F3969D0A6B67AB0050CF14 = { fileRef = A6F3969A0A6B67AB0050CF14; isa = PBXBuildFile; settings = { }; }; A6F396CA0A6B68230050CF14 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MacOSX_sound_if.cpp; refType = 4; sourceTree = ""; }; A6F396CB0A6B68230050CF14 = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MacOSX_sound_if.h; refType = 4; sourceTree = ""; }; A6F396CC0A6B68230050CF14 = { fileRef = A6F396CA0A6B68230050CF14; isa = PBXBuildFile; settings = { }; }; A6F396CD0A6B68230050CF14 = { fileRef = A6F396CB0A6B68230050CF14; isa = PBXBuildFile; settings = { }; }; }; rootObject = 29B97313FDCFA39411CA2CEA; } BasiliskII/src/MacOSX/Credits.html0000644000175000017500000000067110324154143017106 0ustar centriscentrisBasilisk II is an open source, 68k Mac. emulator.
It enables you to run 68k MacOS software on your computer, even if you are using a different operating system (however, you do need a copy of the MacOS and a Macintosh ROM image to use it).
The Official Basilisk II Home Page
MacOS X (native windowing) port
by Nigel Pearson <nigel@ind.tansu.com.au>
BasiliskII/src/MacOSX/configure.in0000644000175000017500000006372311536450576017162 0ustar centriscentrisdnl Mac OS X configuration driver dnl $Id: configure.in,v 1.28 2011/03/11 16:44:46 asvitkine Exp $ dnl Process this file with autoconf to produce a configure script. dnl Based on Unix/configure.in dnl Written in 1999 by Christian Bauer et al. dnl Occasionally re-synchronised (merged?) with latest version dnl Written in 2002 by Christian Bauer et al. dnl autoconf on 10.1 doesn't understand these dnl AC_INIT([Basilisk II], 1.0, [Christian.Bauer@uni-mainz.de], BasiliskII) dnl AC_CONFIG_SRCDIR(main_macosx.mm) AC_INIT(main_macosx.mm) AC_CONFIG_AUX_DIR(../Unix) AC_PREREQ(2.12) AC_CONFIG_HEADER(config.h) AH_TOP([ /* Include MacOS X macros determined at compile-time */ #include "config_macosx.h" ]) dnl Aliases for PACKAGE and VERSION macros. AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE_NAME", [Define this program name.]) AC_DEFINE_UNQUOTED(VERSION, "$PACKAGE_VERSION", [Define this program version.]) dnl Some systems do not put corefiles in the currect directory, avoid saving dnl cores for the configure tests since some are intended to dump core. ulimit -c 0 dnl Universal binaries. AC_ARG_ENABLE(universal, [ --enable-universal enable universal binaries for selected arches [default=no]], [ WANT_UNIVERSAL="" for arch in $enableval; do case $arch in yes) WANT_UNIVERSAL="i386 ppc";; ppc|ppc64|i386|x86_64) WANT_UNIVERSAL="$WANT_UNIVERSAL $arch";; esac done ]) AC_ARG_WITH(ppc-sdk, [ --with-ppc-sdk=VERSION use specific SDK VERSION for ppc builds [default=earliest]], [PPC_SDK_VERSION=$withval]) dnl Video options. AC_ARG_ENABLE(multiwin, [ --enable-multiwin allow multiple emulator windows [default=no]], [ENABLE_MULTIPLE=$enableval], [ENABLE_MULTIPLE=no]) dnl JIT compiler options. AC_ARG_ENABLE(jit-compiler, [ --enable-jit-compiler enable JIT compiler [default=no]], [WANT_JIT=$enableval], [WANT_JIT=no]) AC_ARG_ENABLE(jit-debug, [ --enable-jit-debug activate native code disassemblers [default=no]], [WANT_JIT_DEBUG=$enableval], [WANT_JIT_DEBUG=no]) dnl Addressing modes. AC_ARG_ENABLE(addressing, [ --enable-addressing=AM specify the addressing mode to use [default=fastest]], [ case "$enableval" in real) ADDRESSING_TEST_ORDER="real";; direct) ADDRESSING_TEST_ORDER="direct";; banks) ADDRESSING_TEST_ORDER="banks";; fastest)ADDRESSING_TEST_ORDER="direct banks";; *) AC_MSG_ERROR([--enable-addressing takes only one of the following values: fastest, real, direct, banks]);; esac ], [ ADDRESSING_TEST_ORDER="direct banks" ]) dnl External packages. AC_ARG_WITH(mon, [ --with-mon use mon as debugger [default=yes]], [WANT_MON=$withval], [WANT_MON=no]) dnl Canonical system information. AC_CANONICAL_HOST AC_CANONICAL_TARGET dnl Target OS type (target is host if not cross-compiling). case "$target_os" in linux*) OS_TYPE=linux;; netbsd*) OS_TYPE=netbsd;; freebsd*) OS_TYPE=freebsd;; solaris*) OS_TYPE=solaris;; darwin*) OS_TYPE=darwin;; *) OS_TYPE=`echo $target_os | sed -e 's/-/_/g' | sed -e 's/\./_/g'`;; esac DEFINES="$DEFINES -DOS_$OS_TYPE" dnl Target CPU type. HAVE_I386=no HAVE_M68K=no HAVE_SPARC=no HAVE_POWERPC=no HAVE_X86_64=no case "$target_cpu" in i386* | i486* | i586* | i686* | i786* ) HAVE_I386=yes;; m68k* ) HAVE_M68K=yes;; sparc* ) HAVE_SPARC=yes;; powerpc* ) HAVE_POWERPC=yes;; x86_64* ) HAVE_X86_64=yes;; esac dnl Checks for programs. AC_PROG_CC AC_PROG_CC_C_O AC_PROG_CPP AC_PROG_CXX AC_PROG_MAKE_SET AC_PROG_INSTALL AC_PROG_EGREP dnl We use mon if possible. MONSRCS= if [[ "x$WANT_MON" = "xyes" ]]; then AC_MSG_CHECKING(for mon) mon_srcdir=../../../mon/src if grep mon_init $mon_srcdir/mon.h >/dev/null 2>/dev/null; then AC_MSG_RESULT(yes) AC_DEFINE(ENABLE_MON, 1, [Define if using "mon".]) MONSRCS="$mon_srcdir/mon.cpp $mon_srcdir/mon_6502.cpp $mon_srcdir/mon_z80.cpp $mon_srcdir/mon_cmd.cpp $mon_srcdir/mon_disass.cpp $mon_srcdir/mon_ppc.cpp $mon_srcdir/mon_lowmem.cpp $mon_srcdir/disass/floatformat.c $mon_srcdir/disass/i386-dis.c $mon_srcdir/disass/m68k-dis.c $mon_srcdir/disass/m68k-opc.c $mon_srcdir/disass/mips-dis.c $mon_srcdir/disass/mips-opc.c $mon_srcdir/disass/mips16-opc.c" AC_SUBST(MONSRCS) CXXFLAGS="$CXXFLAGS -I$mon_srcdir -I$mon_srcdir/disass" AC_CHECK_LIB(ncurses, tgetent, , [AC_CHECK_LIB(termcap, tgetent, , [AC_CHECK_LIB(termlib, tgetent, , [AC_CHECK_LIB(terminfo, tgetent, , [AC_CHECK_LIB(Hcurses, tgetent, , [AC_CHECK_LIB(curses, tgetent)])])])])]) AC_CHECK_LIB(readline, readline) else AC_MSG_RESULT(no) AC_MSG_WARN([Could not find mon, ignoring --with-mon.]) WANT_MON=no fi fi dnl We want pthreads. Try libpthread first, then libc_r (FreeBSD), then PTL. HAVE_PTHREADS=yes AC_CHECK_LIB(pthread, pthread_create, , [ AC_CHECK_LIB(c_r, pthread_create, , [ AC_CHECK_LIB(PTL, pthread_create, , [ HAVE_PTHREADS=no ]) ]) ]) dnl OS X does have pthreads, but not in any of the above locations: HAVE_PTHREADS=yes if [[ "x$HAVE_PTHREADS" = "xyes" ]]; then AC_DEFINE(HAVE_PTHREADS, 1, [Define if pthreads are available.]) fi AC_CHECK_FUNCS(pthread_cond_init) AC_CHECK_FUNCS(pthread_cancel pthread_testcancel) AC_CHECK_FUNCS(pthread_mutexattr_setprotocol) AC_CHECK_FUNCS(pthread_mutexattr_settype) AC_CHECK_FUNCS(pthread_mutexattr_setpshared) dnl If POSIX.4 semaphores are not available, we emulate them with pthread mutexes. SEMSRC= AC_CHECK_FUNCS(sem_init, , [ if test "x$HAVE_PTHREADS" = "xyes"; then SEMSRC=posix_sem.cpp fi ]) dnl We want to enable multiple window support if possible if [[ "x$WANT_MWIN" = "xyes" ]]; then WANT_MWIN=yes DEFINES="$DEFINES -DENABLE_MULTIPLE" fi dnl We use 64-bit file size support if possible. AC_SYS_LARGEFILE dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(stdlib.h stdint.h) AC_CHECK_HEADERS(unistd.h fcntl.h sys/types.h sys/time.h sys/mman.h mach/mach.h) AC_CHECK_HEADERS(readline.h history.h readline/readline.h readline/history.h) AC_CHECK_HEADERS(sys/socket.h sys/ioctl.h sys/filio.h sys/bitypes.h sys/wait.h) AC_CHECK_HEADERS(sys/poll.h sys/select.h) AC_CHECK_HEADERS(arpa/inet.h) AC_CHECK_HEADERS(linux/if.h linux/if_tun.h net/if.h net/if_tun.h, [], [], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif ]) AC_CHECK_HEADERS(AvailabilityMacros.h) AC_CHECK_HEADERS(IOKit/storage/IOBlockStorageDevice.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_OFF_T dnl These two symbols are not defined in 10.1's autoconf: dnl AC_CHECK_TYPE(loff_t, off_t) dnl AC_CHECK_TYPE(caddr_t, [char *]) dnl We define loff_t as a typedef of off_t in sysdeps.h if we don't have LOFF_T dnl OS X does have caddr_t, but the above check doesn't work, so we have to do: AC_DEFINE(HAVE_CADDR_T, 1, [The type "caddr_t" does exist on MacOS X.]) AC_TYPE_SIZE_T AC_TYPE_SIGNAL AC_HEADER_TIME AC_STRUCT_TM dnl Check whether sys/socket.h defines type socklen_t. dnl (extracted from ac-archive/Miscellaneous) AC_CACHE_CHECK([for socklen_t], ac_cv_type_socklen_t, [ AC_TRY_COMPILE([ #include #include ], [socklen_t len = 42; return 0;], ac_cv_type_socklen_t=yes, ac_cv_type_socklen_t=no, dnl When cross-compiling, do not assume anything. ac_cv_type_socklen_t="guessing no" ) ]) if [[ "x$ac_cv_type_socklen_t" != "xyes" ]]; then AC_DEFINE(socklen_t, int, [Define to 'int' if doesn't define.]) fi dnl Checks for library functions. AC_CHECK_FUNCS(strdup strerror cfmakeraw) AC_CHECK_FUNCS(clock_gettime timer_create) AC_CHECK_FUNCS(sigaction signal) AC_CHECK_FUNCS(poll inet_aton) dnl Darwin seems to define mach_task_self() instead of task_self(). AC_CHECK_FUNCS(mach_task_self task_self) dnl Check for headers and functions related to pty support (sshpty.c) dnl From openssh-3.2.2p1 configure.ac AC_CHECK_HEADERS(strings.h login.h sys/bsdtty.h sys/stat.h util.h pty.h) AC_CHECK_FUNCS(_getpty vhangup strlcpy) if test -z "$no_dev_ptmx" ; then if test "x$disable_ptmx_check" != "xyes" ; then AC_CHECK_FILE([/dev/ptmx], [ AC_DEFINE_UNQUOTED(HAVE_DEV_PTMX, 1, [Define if you have /dev/ptmx.]) have_dev_ptmx=1 ] ) fi fi AC_CHECK_FILE([/dev/ptc], [ AC_DEFINE_UNQUOTED(HAVE_DEV_PTS_AND_PTC, 1, [Define if you have /dev/ptc.]) have_dev_ptc=1 ] ) dnl (end of code from openssh-3.2.2p1 configure.ac) dnl Check for systems where POSIX-style non-blocking I/O (O_NONBLOCK) dnl doesn't work or is unimplemented. On these systems (mostly older dnl ones), use the old BSD-style FIONBIO approach instead. [tcl.m4] AC_CACHE_CHECK([FIONBIO vs. O_NONBLOCK for non-blocking I/O], ac_cv_nonblocking_io, [ case "$host" in *-*-osf*) ac_cv_nonblocking_io=FIONBIO ;; *-*-sunos4*) ac_cv_nonblocking_io=FIONBIO ;; *-*-ultrix*) ac_cv_nonblocking_io=FIONBIO ;; *) ac_cv_nonblocking_io=O_NONBLOCK ;; esac ]) if [[ "$ac_cv_nonblocking_io" = "FIONBIO" ]]; then AC_DEFINE(USE_FIONBIO, 1, [Define if BSD-style non-blocking I/O is to be used]) fi dnl Check whether compiler supports byte bit-fields AC_CACHE_CHECK([whether compiler supports byte bit-fields], ac_cv_have_byte_bitfields, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ struct A { unsigned char b1:4; unsigned char b2:4; unsigned char c; unsigned short s; unsigned char a[4]; }; int main(void) { A a; return ! (sizeof(A) == 8 && &a.c == ((unsigned char *)&a + 1)); }], [ac_cv_have_byte_bitfields=yes], [ac_cv_have_byte_bitfields=no], dnl When cross-compiling, assume only GCC supports this [if [[ "$GCC" = "yes" ]]; then ac_cv_have_byte_bitfields="guessing yes" else ac_cv_have_byte_bitfields="guessing no" fi] ) AC_LANG_RESTORE ]) dnl AC_CHECK_FRAMEWORK($1=NAME, $2=INCLUDES) AC_DEFUN([AC_CHECK_FRAMEWORK], [ AS_VAR_PUSHDEF([ac_Framework], [ac_cv_framework_$1])dnl AC_CACHE_CHECK([whether compiler supports framework $1], ac_Framework, [ saved_LIBS="$LIBS" LIBS="$LIBS -framework $1" AC_TRY_LINK( [$2], [], [AS_VAR_SET(ac_Framework, yes)], [AS_VAR_SET(ac_Framework, no); LIBS="$saved_LIBS"] ) ]) AS_IF([test AS_VAR_GET(ac_Framework) = yes], [AC_DEFINE(AS_TR_CPP(HAVE_FRAMEWORK_$1), 1, [Define if framework $1 is available.])] ) AS_VAR_POPDEF([ac_Framework])dnl ]) dnl Check for some MacOS X frameworks AC_CHECK_FRAMEWORK(AppKit, []) AC_CHECK_FRAMEWORK(Carbon, [#include ]) AC_CHECK_FRAMEWORK(IOKit, [#include ]) AC_CHECK_FRAMEWORK(CoreFoundation, [#include ]) AC_CHECK_FRAMEWORK(CoreAudio, [#include ]) AC_CHECK_FRAMEWORK(AudioUnit, [#include ]) AC_CHECK_FRAMEWORK(AudioToolbox, [#include ]) dnl Select system-dependant source files. ETHERSRC=ether_unix.cpp DEFINES="$DEFINES -DBSD_COMP" CXXFLAGS="$CXXFLAGS -fpermissive" dnl Check for the CAM library AC_CHECK_LIB(cam, cam_open_btl, HAVE_LIBCAM=yes, HAVE_LIBCAM=no) if [[ "x$HAVE_LIBCAM" = "xno" ]]; then AC_MSG_WARN([Cannot find libcam for SCSI management, disabling SCSI support.]) else dnl Check for the sys kernel includes AC_CHECK_HEADER(camlib.h) if [[ "x$ac_cv_header_camlib_h" = "xno" ]]; then dnl In this case I should fix this thing including a "patch" dnl to access directly to the functions in the kernel :) --Orlando AC_MSG_WARN([Cannot find includes for CAM library, disabling SCSI support.]) else SCSISRC=FreeBSD/scsi_freebsd.cpp LIBS="$LIBS -lcam" DEFINES="$DEFINES -DCAM" fi fi dnl Is the slirp library supported? WANT_SLIRP=no case "$ac_cv_have_byte_bitfields" in yes|"guessing yes") WANT_SLIRP=yes ETHERSRC=ether_unix.cpp ;; esac if [[ "x$WANT_SLIRP" = "xyes" ]]; then AC_DEFINE(HAVE_SLIRP, 1, [Define if slirp library is supported]) SLIRP_SRCS="\ ../slirp/bootp.c ../slirp/ip_output.c ../slirp/tcp_input.c \ ../slirp/cksum.c ../slirp/mbuf.c ../slirp/tcp_output.c \ ../slirp/debug.c ../slirp/misc.c ../slirp/tcp_subr.c \ ../slirp/if.c ../slirp/sbuf.c ../slirp/tcp_timer.c \ ../slirp/ip_icmp.c ../slirp/slirp.c ../slirp/tftp.c \ ../slirp/ip_input.c ../slirp/socket.c ../slirp/udp.c" fi AC_SUBST(WANT_SLIRP) AC_SUBST(SLIRP_SRCS) dnl Define a macro that translates a yesno-variable into a C macro definition dnl to be put into the config.h file dnl $1 -- the macro to define dnl $2 -- the value to translate dnl $3 -- template name AC_DEFUN([AC_TRANSLATE_DEFINE], [ if [[ "x$2" = "xyes" -o "x$2" = "xguessing yes" ]]; then AC_DEFINE($1, 1, $3) fi ]) dnl Check that the host supports TUN/TAP devices AC_CACHE_CHECK([whether TUN/TAP is supported], ac_cv_tun_tap_support, [ AC_TRY_COMPILE([ #if defined(HAVE_LINUX_IF_H) && defined(HAVE_LINUX_IF_TUN_H) #include #include #endif #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_IF_TUN_H) #include #include #endif ], [ struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ], ac_cv_tun_tap_support=yes, ac_cv_tun_tap_support=no ) ]) AC_TRANSLATE_DEFINE(ENABLE_TUNTAP, "$ac_cv_tun_tap_support", [Define if your system supports TUN/TAP devices.]) dnl Check signal handlers need to be reinstalled AC_CACHE_CHECK([whether signal handlers need to be reinstalled], ac_cv_signal_need_reinstall, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #include #ifdef HAVE_UNISTD_H #include #endif #include static int handled_signal = 0; RETSIGTYPE sigusr1_handler(int) { handled_signal++; } int main(void) { /* returns 0 if signals need not to be reinstalled */ signal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1); exit(handled_signal == 2); } ], ac_cv_signal_need_reinstall=yes, ac_cv_signal_need_reinstall=no, dnl When cross-compiling, do not assume anything. ac_cv_signal_need_reinstall="guessing yes" ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(SIGNAL_NEED_REINSTALL, "$ac_cv_signal_need_reinstall", [Define if your system requires signals to be reinstalled.]) dnl Check if sigaction handlers need to be reinstalled AC_CACHE_CHECK([whether sigaction handlers need to be reinstalled], ac_cv_sigaction_need_reinstall, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #include #ifdef HAVE_UNISTD_H #include #endif #include static int handled_signal = 0; RETSIGTYPE sigusr1_handler(int) { handled_signal++; } typedef RETSIGTYPE (*signal_handler)(int); static signal_handler mysignal(int sig, signal_handler handler) { struct sigaction old_sa; struct sigaction new_sa; new_sa.sa_handler = handler; return ((sigaction(sig,&new_sa,&old_sa) < 0) ? SIG_IGN : old_sa.sa_handler); } int main(void) { /* returns 0 if signals need not to be reinstalled */ mysignal(SIGUSR1, sigusr1_handler); raise(SIGUSR1); raise(SIGUSR1); exit(handled_signal == 2); } ], ac_cv_sigaction_need_reinstall=yes, ac_cv_sigaction_need_reinstall=no, dnl When cross-compiling, do not assume anything. ac_cv_sigaction_need_reinstall="guessing yes" ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(SIGACTION_NEED_REINSTALL, "$ac_cv_sigaction_need_reinstall", [Define if your system requires sigactions to be reinstalled.]) dnl Check if we can ignore the fault (instruction skipping in SIGSEGV handler) AC_CACHE_CHECK([whether we can skip instruction in SIGSEGV handler], ac_cv_have_skip_instruction, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #include "config_macosx.h" #define HAVE_SIGSEGV_SKIP_INSTRUCTION 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "../Unix/vm_alloc.cpp" #include "../Unix/sigsegv.cpp" ], ac_cv_have_skip_instruction=yes, ac_cv_have_skip_instruction=no, dnl When cross-compiling, do not assume anything. ac_cv_have_skip_instruction=no ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_SIGSEGV_SKIP_INSTRUCTION, "$ac_cv_have_skip_instruction", [Define if we can ignore the fault (instruction skipping in SIGSEGV handler).]) dnl We can do Video on SEGV Signals CAN_VOSF=yes dnl A dummy program that returns always true AC_PATH_PROG([BLESS], "true") dnl Check for linker script support case $target_os:$target_cpu in linux*:i?86) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-i386.ld";; linux*:x86_64) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-x86_64.ld";; linux*:powerpc) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-ppc.ld";; netbsd*:i?86) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/linux-i386.ld";; freebsd*:i?86) LINKER_SCRIPT_FLAGS="-Wl,-T,ldscripts/freebsd-i386.ld";; darwin*:*) LINKER_SCRIPT_FLAGS="-Wl,-seg1addr,0x78048000";; esac if [[ -n "$LINKER_SCRIPT_FLAGS" ]]; then AC_CACHE_CHECK([whether linker script is usable], ac_cv_linker_script_works, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $LINKER_SCRIPT_FLAGS" AC_TRY_RUN( [int main() {if ((char *)&main < (char *)0x70000000) return 1;}], [ac_cv_linker_script_works=yes], [ac_cv_linker_script_works=no], dnl When cross-compiling, assume it works [ac_cv_linker_script_works="guessing yes"] ) AC_LANG_RESTORE if [[ "$ac_cv_linker_script_works" = "no" ]]; then LDFLAGS="$saved_LDFLAGS" LINKER_SCRIPT_FLAGS="" fi ]) fi AC_TRANSLATE_DEFINE(HAVE_LINKER_SCRIPT, "$ac_cv_linker_script_works", [Define if there is a linker script to relocate the executable above 0x70000000.]) dnl Determine the addressing mode to use ADDRESSING_MODE="" AC_MSG_CHECKING([for the addressing mode to use]) for am in $ADDRESSING_TEST_ORDER; do case $am in real) dnl Requires VOSF screen updates if [[ "x$CAN_VOSF" = "xno" ]]; then continue fi dnl Real addressing will probably work. ADDRESSING_MODE="real" WANT_VOSF=yes dnl we can use VOSF and we need it actually DEFINES="$DEFINES -DREAL_ADDRESSING" AC_DEFINE(REAL_ADDRESSING, 1, [Emulated memory is memory mapped to actual address.]) LDFLAGS="$LDFLAGS -pagezero_size 0x2000" break ;; direct) dnl Requires VOSF screen updates if [[ "x$CAN_VOSF" = "xyes" ]]; then ADDRESSING_MODE="direct" WANT_VOSF=yes dnl we can use VOSF and we need it actually DEFINES="$DEFINES -DDIRECT_ADDRESSING" AC_DEFINE(DIRECT_ADDRESSING, 1, [Emulated memory is an offset from actual address.]) break fi ;; banks) dnl Default addressing mode ADDRESSING_MODE="memory banks" break ;; *) AC_MSG_ERROR([Internal configure.in script error for $am addressing mode]) esac done AC_MSG_RESULT($ADDRESSING_MODE) if [[ "x$ADDRESSING_MODE" = "x" ]]; then AC_MSG_WARN([Sorry, no suitable addressing mode in $ADDRESSING_TEST_ORDER]) ADDRESSING_MODE="memory banks" fi dnl Banked Memory Addressing mode is not supported by the JIT compiler if [[ "x$WANT_JIT" = "xyes" -a "x$ADDRESSING_MODE" = "xmemory banks" ]]; then AC_MSG_ERROR([Sorry, the JIT Compiler requires Direct Addressing, at least]) fi dnl Enable VOSF screen updates with this feature is requested and feasible if [[ "x$WANT_VOSF" = "xyes" -a "x$CAN_VOSF" = "xyes" ]]; then AC_DEFINE(ENABLE_VOSF, 1, [Define if using video enabled on SEGV signals.]) else WANT_VOSF=no fi dnl Check for GAS. HAVE_GAS=no AC_MSG_CHECKING(for GAS .p2align feature) cat >conftest.S << EOF .text .p2align 5 EOF if $CC conftest.S -c -o conftest.o >/dev/null 2>&1 ; then HAVE_GAS=yes; fi AC_MSG_RESULT($HAVE_GAS) dnl Check for GCC 2.7 or higher. HAVE_GCC27=no AC_MSG_CHECKING(for GCC 2.7 or higher) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if ! (__GNUC__ - 1 > 1 || __GNUC_MINOR__ - 1 > 5) # error gcc < 2.7 #endif ]])], [AC_MSG_RESULT(yes); HAVE_GCC27=yes], [AC_MSG_RESULT(no)]) dnl Check for GCC 3.0 or higher. HAVE_GCC30=no AC_MSG_CHECKING(for GCC 3.0 or higher) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#if ! (__GNUC__ >= 3) # error gcc < 3 #endif ]])], [AC_MSG_RESULT(yes); HAVE_GCC30=yes], [AC_MSG_RESULT(no)]) dnl Check for ICC. AC_MSG_CHECKING(for ICC) HAVE_ICC=no if $CXX -V -v 2>&1 | grep -q "Intel(R) C++ Compiler"; then HAVE_ICC=yes fi AC_MSG_RESULT($HAVE_ICC) dnl Set "-fomit-frame-pointer" on i386 GCC 2.7 or higher. dnl Also set "-fno-exceptions" for C++ because exception handling requires dnl the frame pointer. if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_I386" = "xyes" ]]; then CFLAGS="$CFLAGS -fomit-frame-pointer" CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -fno-exceptions" fi dnl (gb) Do not merge constants since it breaks fpu/fpu_x86.cpp. dnl As of 2001/08/02, this affects the following compilers: dnl Official: probably gcc-3.1 (mainline CVS) dnl Mandrake: gcc-2.96 >= 0.59mdk, gcc-3.0.1 >= 0.1mdk dnl Red Hat : gcc-2.96 >= 89, gcc-3.0 >= 1 if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_ICC" = "xno" ]]; then SAVED_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -fno-merge-constants" AC_CACHE_CHECK([whether GCC supports constants merging], ac_cv_gcc_constants_merging, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_COMPILE([],[],[ac_cv_gcc_constants_merging=yes],[ac_cv_gcc_constants_merging=no]) AC_LANG_RESTORE ]) if [[ "x$ac_cv_gcc_constants_merging" != "xyes" ]]; then CXXFLAGS="$SAVED_CXXFLAGS" fi fi dnl Store motion was introduced in 3.3-hammer branch and any gcc >= 3.4 dnl However, there are some corner cases exposed on x86-64 if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_ICC" = "xno" ]]; then SAVED_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS -fno-gcse-sm" AC_CACHE_CHECK([whether GCC supports store motion], ac_cv_gcc_store_motion, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_COMPILE([],[],[ac_cv_gcc_store_motion=yes],[ac_cv_gcc_store_motion=no]) AC_LANG_RESTORE ]) if [[ "x$ac_cv_gcc_store_motion" != "xyes" ]]; then CXXFLAGS="$SAVED_CXXFLAGS" fi fi dnl Add -fno-strict-aliasing for slirp sources if [[ "x$HAVE_GCC30" = "xyes" ]]; then SAVED_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-strict-aliasing" AC_CACHE_CHECK([whether the compiler supports -fno-strict-aliasing], ac_cv_gcc_no_strict_aliasing, [ AC_TRY_COMPILE([],[],[ac_cv_gcc_no_strict_aliasing=yes],[ac_cv_gcc_no_strict_aliasing=no]) ]) if [[ "x$ac_cv_gcc_no_strict_aliasing" = "xyes" ]]; then AC_SUBST(SLIRP_CFLAGS, "-fno-strict-aliasing") fi CFLAGS="$SAVED_CFLAGS" fi dnl Add -mdynamic-no-pic for MacOS X (XXX icc10 will support MacOS X) if [[ "x$HAVE_GCC30" = "xyes" -a "x$HAVE_ICC" = "xno" ]]; then SAVED_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -mdynamic-no-pic" AC_CACHE_CHECK([whether the compiler supports -mdynamic-no-pic], ac_cv_gcc_mdynamic_no_pic, [ AC_TRY_COMPILE([],[],[ac_cv_gcc_mdynamic_no_pic=yes],[ac_cv_gcc_mdynamic_no_pic=no]) ]) if [[ "x$ac_cv_gcc_mdynamic_no_pic" = "xyes" ]]; then CXXFLAGS="$CXXFLAGS -mdynamic-no-pic" else CFLAGS="$SAVED_CFLAGS" fi fi dnl Make sure we can enable JIT debug mode. if [[ "x$WANT_JIT_DEBUG" = "xyes" ]]; then if [[ ":$WANT_JIT:$WANT_MON:" != ":yes:yes:" ]]; then AC_MSG_WARN([cxmon not found, ignoring --enable-jit-debug]) WANT_JIT_DEBUG=no fi fi dnl Additionnal checks for the IEEE FPU emulation code. AC_CHECK_HEADERS(ieee754.h ieeefp.h floatingpoint.h nan.h) AC_CHECK_FUNCS(atanh) AC_CHECK_FUNCS(isnan isinf finite isnormal signbit) dnl Math functions not mandated by C99 standard AC_CHECK_FUNCS(isnanl isinfl) dnl Math functions required by C99 standard, but probably not dnl implemented everywhere. In that case, we fall back to the dnl regular variant for doubles. AC_CHECK_FUNCS(logl log10l expl powl fabsl sqrtl) AC_CHECK_FUNCS(sinl cosl tanl sinhl coshl tanhl) AC_CHECK_FUNCS(asinl acosl atanl asinhl acoshl atanhl) AC_CHECK_FUNCS(floorl ceill) dnl Remove the "-g" option if set for GCC. if [[ "x$HAVE_GCC27" = "xyes" ]]; then CFLAGS=`echo $CFLAGS | sed -e 's/-g\b//g'` CXXFLAGS=`echo $CXXFLAGS | sed -e 's/-g\b//g'` fi dnl dnl Some Mac OS X specific stuff: dnl dnl MacOS 10.2 (and later?) have a particular header for defining the OS version if [[ "x$ac_cv_header_AvailabilityMacros_h" = "xyes" ]]; then AC_DEFINE(AVAILABILITYMACROS, 1, [Header specific to 10.2 and later.]) fi dnl Which IDE do we use? if test -d "/Developer/Applications/Xcode.app"; then IDE=xcodebuild PROJECT=BasiliskII.xcode IDEARGS="-project BasiliskII.xcode" else IDE=pbxbuild PROJECT=BasiliskII.pbproj IDEARGS="" fi dnl Universal binaries if [[ -z "$WANT_UNIVERSAL" ]]; then WANT_UNIVERSAL=`echo $target_cpu | sed -e 's/i.86/i386/'` fi AC_SUBST(TARGET_ARCHES, [$WANT_UNIVERSAL]) AC_MSG_CHECKING(for PowerPC SDK) for version in $PPC_SDK_VERSION 10.2.8 10.3.9 10.4; do sdk=`echo /Developer/SDKs/MacOSX$version*.sdk` if [[ -d "$sdk" ]]; then PPC_SDK_VERSION="$version" break fi done AC_MSG_RESULT($PPC_SDK_VERSION) AC_SUBST(PPC_SDK_VERSION) AC_DEFINE(DATADIR, "~", [unix_ether needs this!]) dnl Generate Makefile. AC_SUBST(DEFINES) AC_SUBST(MONSRCS) AC_SUBST(CPUINCLUDES) AC_SUBST(BLESS) AC_SUBST(IDE) AC_SUBST(PROJECT) AC_SUBST(IDEARGS) AC_SUBST(SLIRP_SRCS) AC_SUBST(KEYCODES) AC_SUBST(WANT_JIT) AC_SUBST(WANT_JIT_DEBUG) dnl autoconf on 10.1 doesn't understand these dnl AC_CONFIG_FILES([Makefile]) dnl AC_OUTPUT AC_OUTPUT(Makefile) dnl Print summary. echo echo Basilisk II configuration summary: echo echo Build binaries for ..................... : $WANT_UNIVERSAL echo Multiple emulator windows .............. : $ENABLE_MULTIPLE echo Enable video on SEGV signals ........... : $WANT_VOSF echo mon debugger support ................... : $WANT_MON echo Build JIT compiler ..................... : $WANT_JIT echo Build JIT with debug code .............. : $WANT_JIT_DEBUG echo Addressing mode ........................ : $ADDRESSING_MODE echo Mac OS X development environment ....... : $IDE echo echo "Configuration done. Now type \"make\" (or \"make ide\")." BasiliskII/src/MacOSX/Controller.h0000644000175000017500000000352310736405220017120 0ustar centriscentris/* * Controller.h - Simple application window management. * * $Id: Controller.h,v 1.9 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import #import "PrefsEditor.h" // If the application supports multiple windows, // ENABLE_MULTIPLE can be defined in config.h @interface Controller : NSApplication { #ifdef ENABLE_MULTIPLE NSMutableArray *emulators; // Array of created Emulators #endif IBOutlet Emulator *theEmulator; IBOutlet PrefsEditor *thePrefsEditor; } - (void) dispatchKeyEvent: (NSEvent *)event type: (NSEventType)type; - (void) dispatchEvent: (NSEvent *)event type: (NSEventType)type; - (IBAction) HelpHowTo: (id)sender; - (IBAction) HelpToDo: (id)sender; - (IBAction) HelpVersions: (id)sender; #ifdef ENABLE_MULTIPLE - (IBAction) NewEmulator: (id)sender; - (IBAction) PauseAll: (id)sender; - (IBAction) RunAll: (id)sender; - (IBAction) TerminateAll: (id)sender; #endif - (BOOL) isAnyEmulatorDisplayingSheets; - (BOOL) isAnyEmulatorRunning; - (short) emulatorCreatedCount; // If any emulator environments have been setup, count how many @end BasiliskII/src/MacOSX/video_macosx.mm0000644000175000017500000006555410736405220017653 0ustar centriscentris/* * $Id: video_macosx.mm,v 1.16 2008/01/01 09:40:32 gbeauche Exp $ * * video_macosx.mm - Interface between Basilisk II and Cocoa windowing. * Based on video_amiga.cpp and video_x.cpp * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #ifdef HAVE_PTHREADS # include #endif #include #include #include #include "macos_util_macosx.h" #include #include #include "video_macosx.h" #define DEBUG 0 #define VERBOSE 0 #include "debug.h" #ifdef NSBITMAP #import #endif #import // Needed for NSLog(@"") #import "misc_macosx.h" // WarningSheet() prototype // Global variables uint8 display_type = DISPLAY_WINDOW, // These are used by PrefsEditor frame_skip; uint16 init_width = MIN_WIDTH, // as well as this code init_height = MIN_HEIGHT, init_depth = 32; EmulatorView *output = nil; // Set by [EmulatorView init] NSWindow *the_win = nil; // Set by [Emulator awakeFromNib] static BOOL singleDisplay = YES; /* * Utility functions */ static uint8 bits_from_depth(const video_depth depth) { int bits = 1 << depth; // if (bits == 16) // bits = 15; // else if (bits == 32) // bits = 24; return bits; } static char * colours_from_depth(const video_depth depth) { switch ( depth ) { case VDEPTH_1BIT : return "Monochrome"; case VDEPTH_2BIT : return "4 colours"; case VDEPTH_4BIT : return "16 colours"; case VDEPTH_8BIT : return "256 colours"; case VDEPTH_16BIT: return "Thousands of colours"; case VDEPTH_32BIT: return "Millions of colours"; } return "illegal colour depth"; } static char * colours_from_depth(const uint16 depth) { return colours_from_depth(DepthModeForPixelDepth(depth) ); } bool parse_screen_prefs(const char *mode_str) { if ( ! mode_str ) { // No screen pref was found. Supply a default: mode_str = "win/512/384"; } if (sscanf(mode_str, "win/%hd/%hd/%hd", &init_width, &init_height, &init_depth) == 3) display_type = DISPLAY_WINDOW; else if (sscanf(mode_str, "win/%hd/%hd", &init_width, &init_height) == 2) display_type = DISPLAY_WINDOW; else if (strcmp(mode_str, "full") == 0) display_type = DISPLAY_SCREEN; else if (sscanf(mode_str, "full/%hd/%hd/%hd", &init_width, &init_height, &init_depth) == 3) display_type = DISPLAY_SCREEN; else if (sscanf(mode_str, "full/%hd/%hd", &init_width, &init_height) == 2) display_type = DISPLAY_SCREEN; else if (sscanf(mode_str, "opengl/%hd/%hd/%hd", &init_width, &init_height, &init_depth) == 3) display_type = DISPLAY_OPENGL; else if (sscanf(mode_str, "opengl/%hd/%hd", &init_width, &init_height) == 2) display_type = DISPLAY_OPENGL; else return false; return true; } // Supported video modes static vector VideoModes; // Add mode to list of supported modes static void add_mode(const uint16 width, const uint16 height, const uint32 resolution_id, const uint32 bytes_per_row, const uint32 user_data, const video_depth depth) { vector::const_iterator i, end = VideoModes.end(); for (i = VideoModes.begin(); i != end; ++i) if ( i->x == width && i->y == height && i->bytes_per_row == bytes_per_row && i->depth == depth ) { D(NSLog(@"Duplicate mode (%hdx%hdx%ld, ID %02x, new ID %02x)\n", width, height, depth, i->resolution_id, resolution_id)); return; } video_mode mode; mode.x = width; mode.y = height; mode.resolution_id = resolution_id; mode.bytes_per_row = bytes_per_row; mode.user_data = user_data; mode.depth = depth; D(bug("Added video mode: w=%d h=%d d=%d(%d bits)\n", width, height, depth, bits_from_depth(depth) )); VideoModes.push_back(mode); } // Add standard list of windowed modes for given color depth static void add_standard_modes(const video_depth depth) { D(bug("add_standard_modes: depth=%d(%d bits)\n", depth, bits_from_depth(depth) )); add_mode(512, 384, 0x80, TrivialBytesPerRow(512, depth), 0, depth); add_mode(640, 480, 0x81, TrivialBytesPerRow(640, depth), 0, depth); add_mode(800, 600, 0x82, TrivialBytesPerRow(800, depth), 0, depth); add_mode(832, 624, 0x83, TrivialBytesPerRow(832, depth), 0, depth); add_mode(1024, 768, 0x84, TrivialBytesPerRow(1024, depth), 0, depth); add_mode(1152, 768, 0x85, TrivialBytesPerRow(1152, depth), 0, depth); add_mode(1152, 870, 0x86, TrivialBytesPerRow(1152, depth), 0, depth); add_mode(1280, 1024, 0x87, TrivialBytesPerRow(1280, depth), 0, depth); add_mode(1600, 1200, 0x88, TrivialBytesPerRow(1600, depth), 0, depth); } // Helper function to get a 32bit int from a dictionary static int32 getCFint32 (CFDictionaryRef dict, CFStringRef key) { CFNumberRef ref = (CFNumberRef) CFDictionaryGetValue(dict, key); if ( ref ) { int32 val; if ( CFNumberGetValue(ref, kCFNumberSInt32Type, &val) ) return val; else NSLog(@"getCFint32() - Failed to get the value %@", key); } else NSLog(@"getCFint32() - Failed to get a 32bit int for %@", key); return 0; } // Nasty hack. Under 10.1, CGDisplayAvailableModes() does not provide bytes per row, // and the emulator doesn't like setting the bytes per row after the screen, // so we use a lot of magic numbers here. // This will probably fail on some video hardware. // I have tested on my G4 PowerBook 400 and G3 PowerBook Series 292 static int CGBytesPerRow(const uint16 width, const video_depth depth) { if ( depth == VDEPTH_8BIT ) switch ( width ) { case 640: case 720: return 768; case 800: case 896: return 1024; case 1152: return 1280; } if ( width == 720 && depth == VDEPTH_16BIT) return 1536; if ( width == 720 && depth == VDEPTH_32BIT) return 3072; if ( width == 800 && depth == VDEPTH_16BIT) return 1792; if ( width == 800 && depth == VDEPTH_32BIT) return 3328; return TrivialBytesPerRow(width, depth); } static bool add_CGDirectDisplay_modes() { #define kMaxDisplays 8 CGDirectDisplayID displays[kMaxDisplays]; CGDisplayErr err; CGDisplayCount n; int32 oldRes = 0, res_id = 0x80; err = CGGetActiveDisplayList(kMaxDisplays, displays, &n); if ( err != CGDisplayNoErr ) n = 1, displays[n] = kCGDirectMainDisplay; if ( n > 1 ) singleDisplay = NO; for ( CGDisplayCount dc = 0; dc < n; ++dc ) { CGDirectDisplayID d = displays[dc]; CFArrayRef m = CGDisplayAvailableModes(d); if ( ! m ) // Store the current display mode add_mode(CGDisplayPixelsWide(d), CGDisplayPixelsHigh(d), res_id++, CGDisplayBytesPerRow(d), (const uint32) d, DepthModeForPixelDepth(CGDisplayBitsPerPixel(d))); else { CFIndex nModes = CFArrayGetCount(m); for ( CFIndex mc = 0; mc < nModes; ++mc ) { CFDictionaryRef modeSpec = (CFDictionaryRef) CFArrayGetValueAtIndex(m, mc); int32 bpp = getCFint32(modeSpec, kCGDisplayBitsPerPixel); int32 height = getCFint32(modeSpec, kCGDisplayHeight); int32 width = getCFint32(modeSpec, kCGDisplayWidth); #ifdef MAC_OS_X_VERSION_10_2 int32 bytes = getCFint32(modeSpec, kCGDisplayBytesPerRow); #else int32 bytes = 0; #endif video_depth depth = DepthModeForPixelDepth(bpp); if ( ! bpp || ! height || ! width ) { NSLog(@"Could not get details of mode %d, display %d", mc, dc); return false; } #if VERBOSE else NSLog(@"Display %ld, spec = %@", d, modeSpec); #endif if ( ! bytes ) { NSLog(@"Could not get bytes per row, guessing"); bytes = CGBytesPerRow(width, depth); } if ( ! oldRes ) oldRes = width * height; else if ( oldRes != width * height ) { oldRes = width * height; ++res_id; } add_mode(width, height, res_id, bytes, (const uint32) d, depth); } } } return true; } #ifdef CG_USE_ALPHA // memset() by long instead of byte static void memsetl (long *buffer, long pattern, size_t length) { long *buf = (long *) buffer, *end = buf + length/4; while ( ++buf < end ) *buf = pattern; } // Sets the alpha channel in a image to full on, except for the corners static void mask_buffer (void *buffer, size_t width, size_t size) { long *bufl = (long *) buffer; char *bufc = (char *) buffer; memsetl(bufl, 0xFF000000, size); // Round upper-left corner *bufl = 0, *bufc+4 = 0; // XXXXX bufc += width, *bufc++ = 0, *bufc++ = 0, *bufc++ = 0; // XXX bufc += width, *bufc++ = 0, *bufc = 0; // XX bufc += width, *bufc = 0; // X bufc += width, *bufc = 0; // X NSLog(@"Masked buffer"); } #endif // monitor_desc subclass for Mac OS X displays class OSX_monitor : public monitor_desc { public: OSX_monitor(const vector &available_modes, video_depth default_depth, uint32 default_id); virtual void set_palette(uint8 *pal, int num); virtual void switch_to_current_mode(void); void set_mac_frame_buffer(const video_mode mode); void video_close(void); bool video_open (const video_mode &mode); private: bool init_opengl(const video_mode &mode); bool init_screen( video_mode &mode); bool init_window(const video_mode &mode); #ifdef CGIMAGEREF CGColorSpaceRef colourSpace; uint8 *colourTable; CGImageRef imageRef; CGDataProviderRef provider; short x, y, bpp, depth, bpr; #endif #ifdef NSBITMAP NSBitmapImageRep *bitmap; #endif void *the_buffer; // These record changes we made in setting full screen mode, // so that we can set the display back as it was again. CGDirectDisplayID theDisplay; CFDictionaryRef originalMode, newMode; }; OSX_monitor :: OSX_monitor (const vector &available_modes, video_depth default_depth, uint32 default_id) : monitor_desc (available_modes, default_depth, default_id) { #ifdef CGIMAGEREF colourSpace = nil; colourTable = (uint8 *) malloc(256 * 3); imageRef = nil; provider = nil; #endif #ifdef NSBITMAP bitmap = nil; #endif newMode = originalMode = nil; the_buffer = NULL; theDisplay = nil; }; // Should also have a destructor which does //#ifdef CGIMAGEREF // free(colourTable); //#endif // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac) void OSX_monitor::set_mac_frame_buffer(const video_mode mode) { #if !REAL_ADDRESSING && !DIRECT_ADDRESSING switch ( mode.depth ) { // case VDEPTH_15BIT: case VDEPTH_16BIT: MacFrameLayout = FLAYOUT_HOST_555; break; // case VDEPTH_24BIT: case VDEPTH_32BIT: MacFrameLayout = FLAYOUT_HOST_888; break; default : MacFrameLayout = FLAYOUT_DIRECT; } set_mac_frame_base(MacFrameBaseMac); // Set variables used by UAE memory banking MacFrameBaseHost = (uint8 *) the_buffer; MacFrameSize = mode.bytes_per_row * mode.y; InitFrameBufferMapping(); #else set_mac_frame_base((unsigned int)Host2MacAddr((uint8 *)the_buffer)); #endif D(bug("mac_frame_base = %08x\n", get_mac_frame_base())); } static void resizeWinBy(const short deltaX, const short deltaY) { NSRect rect = [the_win frame]; D(bug("resizeWinBy(%d,%d) - ", deltaX, deltaY)); D(bug("old x=%g, y=%g", rect.size.width, rect.size.height)); rect.size.width += deltaX; rect.size.height += deltaY; D(bug(", new x=%g, y=%g\n", rect.size.width, rect.size.height)); [the_win setFrame: rect display: YES animate: YES]; [the_win center]; rect = [the_win frame]; } void resizeWinTo(const uint16 newWidth, const uint16 newHeight) { int deltaX = newWidth - [output width], deltaY = newHeight - [output height]; D(bug("resizeWinTo(%d,%d)\n", newWidth, newHeight)); if ( deltaX || deltaY ) resizeWinBy(deltaX, deltaY); } // Open window bool OSX_monitor::init_window(const video_mode &mode) { D(bug("init_window: depth=%d(%d bits)\n", mode.depth, bits_from_depth(mode.depth) )); // Set absolute mouse mode ADBSetRelMouseMode(false); // Is the window open? if ( ! the_win ) { ErrorAlert(STR_OPEN_WINDOW_ERR); return false; } resizeWinTo(mode.x, mode.y); // Create frame buffer ("height + 2" for safety) int the_buffer_size = mode.bytes_per_row * (mode.y + 2); the_buffer = calloc(the_buffer_size, 1); if ( ! the_buffer ) { NSLog(@"calloc(%d) failed", the_buffer_size); ErrorAlert(STR_NO_MEM_ERR); return false; } D(bug("the_buffer = %p\n", the_buffer)); unsigned char *offsetBuffer = (unsigned char *) the_buffer; offsetBuffer += 1; // OS X NSBitmaps are RGBA, but Basilisk generates ARGB #ifdef CGIMAGEREF switch ( mode.depth ) { case VDEPTH_1BIT: bpp = 1; break; case VDEPTH_2BIT: bpp = 2; break; case VDEPTH_4BIT: bpp = 4; break; case VDEPTH_8BIT: bpp = 8; break; case VDEPTH_16BIT: bpp = 5; break; case VDEPTH_32BIT: bpp = 8; break; } x = mode.x, y = mode.y, depth = bits_from_depth(mode.depth), bpr = mode.bytes_per_row; colourSpace = CGColorSpaceCreateDeviceRGB(); if ( mode.depth < VDEPTH_16BIT ) { CGColorSpaceRef oldColourSpace = colourSpace; colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, colourTable); CGColorSpaceRelease(oldColourSpace); } if ( ! colourSpace ) { ErrorAlert("No valid colour space"); return false; } provider = CGDataProviderCreateWithData(NULL, the_buffer, the_buffer_size, NULL); if ( ! provider ) { ErrorAlert("Could not create CGDataProvider from buffer data"); return false; } imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace, #ifdef CG_USE_ALPHA kCGImageAlphaPremultipliedFirst, #else kCGImageAlphaNoneSkipFirst, #endif provider, NULL, // colourMap translation table NO, // shouldInterpolate colours? kCGRenderingIntentDefault); if ( ! imageRef ) { ErrorAlert("Could not create CGImage from CGDataProvider"); return false; } [output readyToDraw: imageRef bitmap: offsetBuffer imageWidth: x imageHeight: y]; #ifdef CG_USE_ALPHA mask_buffer(the_buffer, x, the_buffer_size); /* Create an image mask with this call? */ //CG_EXTERN CGImageRef //CGImageMaskCreate(size_t width, size_t height, size_t bitsPerComponent, // size_t bitsPerPixel, size_t bytesPerRow, // CGDataProviderRef provider, const float decode[], bool shouldInterpolate); #endif return true; #endif #ifndef CGIMAGEREF short bitsPer, samplesPer; // How big is each Pixel? if ( mode.depth == VDEPTH_1BIT ) bitsPer = 1; else bitsPer = 8; if ( mode.depth == VDEPTH_32BIT ) samplesPer = 3; else samplesPer = 1; #endif #ifdef NSBITMAP bitmap = [NSBitmapImageRep alloc]; bitmap = [bitmap initWithBitmapDataPlanes: (unsigned char **) &offsetBuffer pixelsWide: mode.x pixelsHigh: mode.y bitsPerSample: bitsPer samplesPerPixel: samplesPer hasAlpha: NO isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: mode.bytes_per_row bitsPerPixel: bits_from_depth(mode.depth)]; if ( ! bitmap ) { ErrorAlert("Could not allocate an NSBitmapImageRep"); return false; } [output readyToDraw: bitmap imageWidth: mode.x imageHeight: mode.y]; #endif #ifdef CGDRAWBITMAP [output readyToDraw: offsetBuffer width: mode.x height: mode.y bps: bitsPer spp: samplesPer bpp: bits_from_depth(mode.depth) bpr: mode.bytes_per_row isPlanar: NO hasAlpha: NO]; #endif return true; } #import #import #import "NNThread.h" bool OSX_monitor::init_screen(video_mode &mode) { // Set absolute mouse mode ADBSetRelMouseMode(false); // Display stored by add_CGDirectDisplay_modes() theDisplay = (CGDirectDisplayID) mode.user_data; originalMode = CGDisplayCurrentMode(theDisplay); if ( ! originalMode ) { ErrorSheet(@"Could not get current mode of display", the_win); return false; } D(NSLog(@"About to call CGDisplayBestModeForParameters()")); newMode = CGDisplayBestModeForParameters(theDisplay, bits_from_depth(mode.depth), mode.x, mode.y, NULL); if ( ! newMode ) { ErrorSheet(@"Could not find a matching screen mode", the_win); return false; } // This sometimes takes ages to return after the window is genied, // so for now we leave it onscreen // [the_win miniaturize: nil]; D(NSLog(@"About to call CGDisplayCapture()")); if ( CGDisplayCapture(theDisplay) != CGDisplayNoErr ) { // [the_win deminiaturize: nil]; ErrorSheet(@"Could not capture display", the_win); return false; } D(NSLog(@"About to call CGDisplaySwitchToMode()")); if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr ) { CGDisplayRelease(theDisplay); // [the_win deminiaturize: nil]; ErrorSheet(@"Could not switch to matching screen mode", the_win); return false; } the_buffer = CGDisplayBaseAddress(theDisplay); if ( ! the_buffer ) { CGDisplaySwitchToMode(theDisplay, originalMode); CGDisplayRelease(theDisplay); // [the_win deminiaturize: nil]; ErrorSheet(@"Could not get base address of screen", the_win); return false; } if ( mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) ) { D(bug("Bytes per row (%d) doesn't match current (%ld)\n", mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay))); mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay); } HideMenuBar(); if ( singleDisplay ) { CGDisplayHideCursor(theDisplay); [output startedFullScreen: theDisplay]; // Send emulated mouse to current location [output fullscreenMouseMove]; } else { // Should set up something to hide the cursor when it enters theDisplay? } return true; } bool OSX_monitor::init_opengl(const video_mode &mode) { ErrorAlert("Sorry. OpenGL mode is not implemented yet"); return false; } /* * Initialization */ static bool monitor_init(const video_mode &init_mode) { OSX_monitor *monitor; BOOL success; monitor = new OSX_monitor(VideoModes, init_mode.depth, init_mode.resolution_id); success = monitor->video_open(init_mode); if ( success ) { monitor->set_mac_frame_buffer(init_mode); VideoMonitors.push_back(monitor); return YES; } return NO; } bool VideoInit(bool classic) { // Read frame skip prefs frame_skip = PrefsFindInt32("frameskip"); if (frame_skip == 0) frame_skip = 1; // Get screen mode from preferences const char *mode_str; if (classic) mode_str = "win/512/342"; else mode_str = PrefsFindString("screen"); // Determine display_type and init_width, height & depth parse_screen_prefs(mode_str); // Construct list of supported modes if (classic) add_mode(512, 342, 0x80, 64, 0, VDEPTH_1BIT); else switch ( display_type ) { case DISPLAY_SCREEN: if ( ! add_CGDirectDisplay_modes() ) { ErrorAlert("Unable to get list of displays for full screen mode"); return false; } break; case DISPLAY_OPENGL: // Same as window depths and sizes? case DISPLAY_WINDOW: #ifdef CGIMAGEREF add_standard_modes(VDEPTH_1BIT); add_standard_modes(VDEPTH_2BIT); add_standard_modes(VDEPTH_4BIT); add_standard_modes(VDEPTH_8BIT); add_standard_modes(VDEPTH_16BIT); #endif add_standard_modes(VDEPTH_32BIT); break; } // video_init_depth_list(); Now done in monitor_desc constructor? #if DEBUG bug("Available video modes:\n"); vector::const_iterator i, end = VideoModes.end(); for (i = VideoModes.begin(); i != end; ++i) bug(" %dx%d (ID %02x), %s\n", i->x, i->y, i->resolution_id, colours_from_depth(i->depth)); #endif D(bug("VideoInit: width=%hd height=%hd depth=%d\n", init_width, init_height, init_depth)); // Find requested default mode and open display if (VideoModes.size() > 0) { // Find mode with specified dimensions std::vector::const_iterator i, end = VideoModes.end(); for (i = VideoModes.begin(); i != end; ++i) { D(bug("VideoInit: w=%d h=%d d=%d\n", i->x, i->y, bits_from_depth(i->depth))); if (i->x == init_width && i->y == init_height && bits_from_depth(i->depth) == init_depth) return monitor_init(*i); } } char str[150]; sprintf(str, "Cannot open selected video mode\r(%hd x %hd, %s).\r%s", init_width, init_height, colours_from_depth(init_depth), "Using lowest resolution"); WarningAlert(str); return monitor_init(VideoModes[0]); } // Open display for specified mode bool OSX_monitor::video_open(const video_mode &mode) { D(bug("video_open: width=%d height=%d depth=%d bytes_per_row=%d\n", mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row)); // Open display switch ( display_type ) { case DISPLAY_WINDOW: return init_window(mode); case DISPLAY_SCREEN: return init_screen((video_mode &)mode); case DISPLAY_OPENGL: return init_opengl(mode); } return false; } void OSX_monitor::video_close() { D(bug("video_close()\n")); switch ( display_type ) { case DISPLAY_WINDOW: // Stop redraw thread [output disableDrawing]; // Free frame buffer stuff #ifdef CGIMAGEREF CGImageRelease(imageRef); CGColorSpaceRelease(colourSpace); CGDataProviderRelease(provider); #endif #ifdef NSBITMAP [bitmap release]; #endif free(the_buffer); break; case DISPLAY_SCREEN: if ( theDisplay && originalMode ) { if ( singleDisplay ) CGDisplayShowCursor(theDisplay); ShowMenuBar(); CGDisplaySwitchToMode(theDisplay, originalMode); CGDisplayRelease(theDisplay); //[the_win deminiaturize: nil]; } break; case DISPLAY_OPENGL: break; } } /* * Deinitialization */ void VideoExit(void) { // Close displays vector::iterator i, end; end = VideoMonitors.end(); for (i = VideoMonitors.begin(); i != end; ++i) dynamic_cast(*i)->video_close(); VideoMonitors.clear(); VideoModes.clear(); } /* * Set palette */ void OSX_monitor::set_palette(uint8 *pal, int num) { if ( [output isFullScreen] && CGDisplayCanSetPalette(theDisplay) && ! IsDirectMode(get_current_mode()) ) { CGDirectPaletteRef CGpal; CGDisplayErr err; CGpal = CGPaletteCreateWithByteSamples((CGDeviceByteColor *)pal, num); err = CGDisplaySetPalette(theDisplay, CGpal); if ( err != noErr ) NSLog(@"Failed to set palette, error = %d", err); CGPaletteRelease(CGpal); } #ifdef CGIMAGEREF if ( display_type != DISPLAY_WINDOW ) return; // To change the palette, we have to regenerate // the CGImageRef with the new colour space. CGImageRef oldImageRef = imageRef; CGColorSpaceRef oldColourSpace = colourSpace; colourSpace = CGColorSpaceCreateDeviceRGB(); if ( depth < 16 ) { CGColorSpaceRef tempColourSpace = colourSpace; colourSpace = CGColorSpaceCreateIndexed(colourSpace, 255, pal); CGColorSpaceRelease(tempColourSpace); } if ( ! colourSpace ) { ErrorAlert("No valid colour space"); return; } imageRef = CGImageCreate(x, y, bpp, depth, bpr, colourSpace, #ifdef CG_USE_ALPHA kCGImageAlphaPremultipliedFirst, #else kCGImageAlphaNoneSkipFirst, #endif provider, NULL, // colourMap translation table NO, // shouldInterpolate colours? kCGRenderingIntentDefault); if ( ! imageRef ) { ErrorAlert("Could not create CGImage from CGDataProvider"); return; } unsigned char *offsetBuffer = (unsigned char *) the_buffer; offsetBuffer += 1; // OS X NSBitmaps are RGBA, but Basilisk generates ARGB [output readyToDraw: imageRef bitmap: offsetBuffer imageWidth: x imageHeight: y]; CGColorSpaceRelease(oldColourSpace); CGImageRelease(oldImageRef); #endif } /* * Switch video mode */ void OSX_monitor::switch_to_current_mode(void) { video_mode mode = get_current_mode(); char *failure = NULL; D(bug("switch_to_current_mode(): width=%d height=%d depth=%d bytes_per_row=%d\n", mode.x, mode.y, bits_from_depth(mode.depth), mode.bytes_per_row)); if ( display_type == DISPLAY_SCREEN && originalMode ) { D(NSLog(@"About to call CGDisplayBestModeForParameters()")); newMode = CGDisplayBestModeForParameters(theDisplay, bits_from_depth(mode.depth), mode.x, mode.y, NULL); if ( ! newMode ) failure = "Could not find a matching screen mode"; else { D(NSLog(@"About to call CGDisplaySwitchToMode()")); if ( CGDisplaySwitchToMode(theDisplay, newMode) != CGDisplayNoErr ) failure = "Could not switch to matching screen mode"; } // For mouse event processing: update screen height [output startedFullScreen: theDisplay]; if ( ! failure && mode.bytes_per_row != CGDisplayBytesPerRow(theDisplay) ) { D(bug("Bytes per row (%d) doesn't match current (%ld)\n", mode.bytes_per_row, CGDisplayBytesPerRow(theDisplay))); mode.bytes_per_row = CGDisplayBytesPerRow(theDisplay); } if ( ! failure && ! ( the_buffer = CGDisplayBaseAddress(theDisplay) ) ) failure = "Could not get base address of screen"; } #ifdef CGIMAGEREF // Clean up the old CGImageRef stuff else if ( display_type == DISPLAY_WINDOW && imageRef ) { CGImageRef oldImageRef = imageRef; CGColorSpaceRef oldColourSpace = colourSpace; CGDataProviderRef oldProvider = provider; void *oldBuffer = the_buffer; if ( video_open(mode) ) { CGImageRelease(oldImageRef); CGColorSpaceRelease(oldColourSpace); CGDataProviderRelease(oldProvider); free(oldBuffer); } else failure = "Could not video_open() requested mode"; } #endif else if ( ! video_open(mode) ) failure = "Could not video_open() requested mode"; if ( ! failure && display_type == DISPLAY_SCREEN ) { // Whenever we change screen resolution, the MacOS mouse starts // up in the top left corner. Send real mouse to that location // if ( CGDisplayMoveCursorToPoint(theDisplay, CGPointMake(15,15)) // == CGDisplayNoErr ) // { // [output fullscreenMouseMove]; // } // else // failure = "Could move (jump) cursor on screen"; } if ( failure ) { NSLog(@"In switch_to_current_mode():"); NSLog(@"%s.", failure); video_close(); if ( display_type == DISPLAY_SCREEN ) ErrorAlert("Cannot switch screen to selected video mode"); else ErrorAlert(STR_OPEN_WINDOW_ERR); QuitEmulator(); } else set_mac_frame_buffer(mode); } /* * Close down full-screen mode * (if bringing up error alerts is unsafe while in full-screen mode) */ void VideoQuitFullScreen(void) { } /* * Mac VBL interrupt */ void VideoInterrupt(void) { } // This function is called on non-threaded platforms from a timer interrupt void VideoRefresh(void) { } // Deal with a memory access signal referring to the screen. // For now, just ignore bool Screen_fault_handler(char *a, char *b) { // NSLog(@"Got a screen fault %lx %lx", a, b); // [output setNeedsDisplay: YES]; return YES; } BasiliskII/src/MacOSX/main_macosx.h0000644000175000017500000000214510736405220017272 0ustar centriscentris/* * main_macosx.h - Prototypes for Mac OS X general definitions * * $Id: main_macosx.h,v 1.4 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ bool InitEmulator (); void QuitEmuNoExit(); extern void ErrorAlert (const char *text); extern void WarningAlert(const char *text); extern bool ChoiceAlert (const char *text, const char *pos, const char *neg); BasiliskII/src/MacOSX/audio_macosx.cpp0000644000175000017500000001324310736405220020003 0ustar centriscentris/* * audio_macosx.cpp - Audio support, implementation Mac OS X * Copyright (C) 2006, Daniel Sumorok * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "audio.h" #include "audio_defs.h" #include "MacOSX_sound_if.h" #define DEBUG 0 #include "debug.h" // The currently selected audio parameters (indices in // audio_sample_rates[] etc. vectors) static int audio_sample_rate_index = 0; static int audio_sample_size_index = 0; static int audio_channel_count_index = 0; // Prototypes static OSXsoundOutput *soundOutput = NULL; static bool main_mute = false; static bool speaker_mute = false; /* * Initialization */ static int audioInt(void); static bool open_audio(void) { AudioStatus.sample_rate = audio_sample_rates[audio_sample_rate_index]; AudioStatus.sample_size = audio_sample_sizes[audio_sample_size_index]; AudioStatus.channels = audio_channel_counts[audio_channel_count_index]; if (soundOutput) delete soundOutput; soundOutput = new OSXsoundOutput(); soundOutput->start(AudioStatus.sample_size, AudioStatus.channels, AudioStatus.sample_rate >> 16); soundOutput->setCallback(audioInt); audio_frames_per_block = soundOutput->bufferSizeFrames(); audio_open = true; return true; } void AudioInit(void) { // Sound disabled in prefs? Then do nothing if (PrefsFindBool("nosound")) return; //audio_sample_sizes.push_back(8); audio_sample_sizes.push_back(16); audio_channel_counts.push_back(1); audio_channel_counts.push_back(2); audio_sample_rates.push_back(11025 << 16); audio_sample_rates.push_back(22050 << 16); audio_sample_rates.push_back(44100 << 16); // Default to highest supported values audio_sample_rate_index = audio_sample_rates.size() - 1; audio_sample_size_index = audio_sample_sizes.size() - 1; audio_channel_count_index = audio_channel_counts.size() - 1; AudioStatus.mixer = 0; AudioStatus.num_sources = 0; audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut; audio_component_flags = 0; open_audio(); } /* * Deinitialization */ static void close_audio(void) { D(bug("Closing Audio\n")); if (soundOutput) { delete soundOutput; soundOutput = NULL; } audio_open = false; } void AudioExit(void) { // Close audio device close_audio(); } /* * First source added, start audio stream */ void audio_enter_stream() { // Streaming thread is always running to avoid clicking noises } /* * Last source removed, stop audio stream */ void audio_exit_stream() { // Streaming thread is always running to avoid clicking noises } /* * MacOS audio interrupt, read next data block */ void AudioInterrupt(void) { D(bug("AudioInterrupt\n")); uint32 apple_stream_info; uint32 numSamples; int16 *p; M68kRegisters r; if (!AudioStatus.mixer) { numSamples = 0; soundOutput->sendAudioBuffer((void *)p, (int)numSamples); D(bug("AudioInterrupt done\n")); return; } // Get data from apple mixer r.a[0] = audio_data + adatStreamInfo; r.a[1] = AudioStatus.mixer; Execute68k(audio_data + adatGetSourceData, &r); D(bug(" GetSourceData() returns %08lx\n", r.d[0])); apple_stream_info = ReadMacInt32(audio_data + adatStreamInfo); if (apple_stream_info && (main_mute == false) && (speaker_mute == false)) { numSamples = ReadMacInt32(apple_stream_info + scd_sampleCount); p = (int16 *)Mac2HostAddr(ReadMacInt32(apple_stream_info + scd_buffer)); } else { numSamples = 0; p = NULL; } soundOutput->sendAudioBuffer((void *)p, (int)numSamples); D(bug("AudioInterrupt done\n")); } /* * Set sampling parameters * "index" is an index into the audio_sample_rates[] etc. vectors * It is guaranteed that AudioStatus.num_sources == 0 */ bool audio_set_sample_rate(int index) { close_audio(); audio_sample_rate_index = index; return open_audio(); } bool audio_set_sample_size(int index) { close_audio(); audio_sample_size_index = index; return open_audio(); } bool audio_set_channels(int index) { close_audio(); audio_channel_count_index = index; return open_audio(); } /* * Get/set volume controls (volume values received/returned have the * left channel volume in the upper 16 bits and the right channel * volume in the lower 16 bits; both volumes are 8.8 fixed point * values with 0x0100 meaning "maximum volume")) */ bool audio_get_main_mute(void) { return main_mute; } uint32 audio_get_main_volume(void) { return 0x01000100; } bool audio_get_speaker_mute(void) { return speaker_mute; } uint32 audio_get_speaker_volume(void) { return 0x01000100; } void audio_set_main_mute(bool mute) { main_mute = mute; } void audio_set_main_volume(uint32 vol) { } void audio_set_speaker_mute(bool mute) { speaker_mute = mute; } void audio_set_speaker_volume(uint32 vol) { } static int audioInt(void) { SetInterruptFlag(INTFLAG_AUDIO); TriggerInterrupt(); return 0; } BasiliskII/src/MacOSX/BasiliskII.icns0000644000175000017500000012755511117525276017511 0ustar centriscentrisicns¯mICN#ÿÿÿÿÿÿÿÿÿûÿÿÿç³ÿŸþ=à8àpåàá€ááãÃÃBÇ†ŽŒ À Ãà ` @ @‡áÜðŒÀŒÀ„`Ä ãÇ÷ÿñË÷ÿø?ÿÿþÿÿÿÿÿÿÿ?ÿÿÿÿÿ?ÿÿÿ?ÿÿÿ?ÿÿÿ?ÿÿÿ?ÿÿÿ?ÿÿþ?ÿÿþÿÿþÿÿüÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿÿüÿÿüÿÿüÿÿü?ÿ¿€ÿ¿€ÿ?þüil32 £ÉqÿqJ’hÿî %îͳ¥ƒzzƒzƒzzƒ´,‡ÿÿ%Abj‹ÿ,,jjaj‹ÿÿbjzzƒz‹ÿzrjœœ¥ïÿ÷”{csŒœœŠÿÆ{rbœ¥÷ÿÿŒkZ{”œ¥”­ÆŒk„s÷ÿ{ƒXj¥ïÿÿ”cZ{œ¥¥œRsÆ‚Œ”ŒŒ”ÿï„z6aÆÿÿÎcRJ{œ¥œ”RÞÞÎΔR‚Öÿƃjj€ÿ cRkc„¥¥œZcç ”RçÞçç÷ÿ½ƒI€îÿÿœRZŒc„œœ¥RÖçÞçÞœJ€çÞÿ眃€€ÿ RRs”œ¥¥œŒJ€çÞ‚çÞçÿÎŒƒ€ÝÿÿÎJZ„œ¥¥œ¥ckçÞ€ç ÞÞçÞçÿ÷µŒz€€ÿZR{ÿï¥R­çÞçÞƒçÿÞœ¥y€ÿRZÿÎÎÿRÖÞ€ç ÞçÞçÞïÿÆŒ½yŠ€ÿRc”œ{c€ÿç΀çÞ‚çÿï­”ÖzÝÿÿÞRk”„k{µ€ÿ1JRJR€ç ÞçÿÖœ­Þy€ÿ½J{‚œ€ÿµs”kZÞÞçç÷ÿÆŒÆÞƒ€ÿ½R{œ¥œ¥œ€ÿïc”RŒ€ç Þÿç­œÖçz€ÿÎR„”k{œ¥ç€ÿR„JµçÞçÞÿJŒµÞçzæÿÿçZ„¥Œ€k½€ÿJsRŒsZJ½Þ­”ÎÞçz£€ÿR„œ¥œ¥œÆÿÿ÷1RRZs”ÖÿÞ¥¥Þççz%€ÿR{œ¥œ¥œÖÿÿÆRsJµÞççÿΔ½ÞçÞz€€ÿkkœ¥œ¥¥çÿÿcZ{R”çç÷÷½”΀çy€ ´ÿÿïk”¥œ¥œ€ÿ RZ„ccÞçÿÖ¥¥€Þçz€ÿk¥µ½µµÿÿœck¥¥RïïÿÖœÖïï÷ïzHÿÿ÷XŠÿÝzzbRÿWQj‡yÿÿ÷6PÿæQƒz6I7ÿrQˆYîÿa%rzQR7r$‰ YzƒrIIjzQƒIXŠAbrzjb6…†É'sJ’(Œb %bYIBI‡ {„Abj”Œ””Œ…”s(,jjaj8”kbjzzƒz”„ss{€s{sczrjœœ¥c”c”{csŒœœ”{skksksksZ{rbœ¥s„kŒkZ{”œ¥”9”kk„sRk{ƒXj¥c„s„cZ{œ¥¥œRsÆ‚Œ”ŒŒ”cR„z6as”{RcRJ{œ¥œ”RÞÞÎΔRÖÆk½ƒjb”{kcRkc„¥¥œZcç ”RçÞççkc½ƒI€j„sRRZŒc„œœ¥RÖçÞçÞœJ€çÞk”œƒ€ ”{kRRs”œ¥¥œŒJ€çÞ‚çÞ½sÎŒƒ€YŒsBJZ„œ¥¥œ¥ckçÞ€ç ÞÞçÞçccµŒz€”{kRRkZ€sR¥R­çÞçÞƒçkΜ¥y”skRRkccŒsscRÖÞ€çÞçÞçÞ¥cÆŒ½y(”kRRc”œ{cŒssB΀çÞ‚çR„­”ÖzbŒsJRk”„k{ZŒss1JRJR€çÞçkÖœ­ÞyZ„kBJ{‚œ'”{sBs”kZÞÞçç”ZÆŒÆÞƒc„sBR{œ¥œ¥œcŒkJc”RŒ€ç1ÞZ¥­œÖçzc„sJR„”k{œ¥c”sRR„JµçÞçÞkJŒµÞçzbŒkJZ„¥Œ€kRJ”sZJsRŒsZJBJ­”ÎÞçz7ŒsZR„œ¥œ¥œZ”sJ1RRZs”ÖcÖ¥¥ÞççzŒskR{œ¥œ¥œkŒsJRsJµÞçÖcΔ½ÞçÞz€”„sJkœ¥œ¥¥cŒsJZ{R”ççc„½”΀çy€@ŒsJk”¥œ¥œc„cRZ„ccÞçsÖ¥¥€Þçz”„kk¥µ½µµ”sZck¥¥Rï­RÖœÖïï÷ïz%Œ{ZX8{QzzbRZQj‡A”{Z.{YQƒz6I7srQˆ YYkksc&%rzQR7r$‰ YzƒrIIjzQƒIXŠAbrzjb6…†ÉJ’  % )† ‰Abj‹(,jjaj bjzzƒz‹zrjœœ¥”{csŒœœŠ9{rbœ¥ŒkZ{”œ¥”!„kk„s{ƒXj¥„cZ{œ¥¥œRsÆ‚Œ”ŒŒ”„z6aR1cRJ{œ¥œ”RÞÞÎΔRÖƵƒjb€ cRkc„¥¥œZcç ”RçÞçç9½ƒI€9RZŒc„œœ¥RÖçÞçÞœJ€çÞ„œƒƒ RRs”œ¥¥œŒJ€çÞ‚ç޵Όƒ€JZ„œ¥¥œ¥ckçÞ€ç ÞÞçÞç!)µŒzƒRRk€¥R­çÞçÞƒçΜ¥y€RRJJRÖÞ€ç ÞçÞçޔƌ½y€Rc”œ{c€΀çÞ‚çc­”ÖzRk”„k{J€1JRJR€çÞçÖœ­Þy‚J{‚œ€)s”kZÞÞçç{ÆŒÆÞƒ‚!R{œ¥œ¥œ€c”RŒ€çÞœ­œÖçz‚R„”k{œ¥)€R„JµçÞçÞJŒµÞçzZ„¥Œ€k1€JsRŒsZJ!­”ÎÞçz€R„œ¥œ¥œB€1RRZs”ÖÎ¥¥Þççz€R{œ¥œ¥œJ!RsJµÞçÖΔ½ÞçÞzƒJkœ¥œ¥¥)BZ{R”çç)c½”΀çy€ k”¥œ¥œ€ RZ„ccÞçÖ¥¥€Þçz„c¥µ½µµRck¥¥RïœÖœÖïï÷ïz€XzzbRQj‡0.Qƒz6I7rQˆY%rzQR7r$‰ YzƒrIIjzQƒIXŠAbrzjb6…†l8mksÿsÿ!kÿï!)ïÎÖÿ„{{„{„{{„µ9ÿÿ)!R””ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ9)9„„{„”ÿÿ„œÆÖÎ¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿƵ„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷„„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÖB{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿçZïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÖ!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿµÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ”ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„Œÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{Þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{çÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„µÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{Jÿÿÿ„ŒÿÞÖ÷”ÿÿZkœ!„ÿÿÿBRÿïkïÎBÞœÿ!¥k{÷ÿÿÿÿc)µÖkÿJµ1{Þï­ZZ¥ÎkZsJ”½½­ŒBit32`ªÿÿÿÿÿÿÿ½¿ã‚ÿßPÊß…ÿâ€P¥Ü‡ÿ\PjÙˆÿùª€¿ª†j‚PÊ׉ÿ ª¿Ôßâççåß̪„¥‚P¥ÖˆÿüñÌßçîñèëëñùýÿý‚ÿâ||[PPj „ÿ«ˆÿ üªÔâëñëçæäááñ·ÿª‡ÿûªÔâìòíåáÞÖÔÐÒõ·ÿªª€¿ª¢‡ÿüªÌâìòîæß×ÐÊÃÀ¿Âð¶ÿüâå€ç⡇ÿñÌßìòîçàÙÏǾ¶±¯°·ï¶ÿõèêëìêóŸ‡ÿû¿ßéòíæßÖÎļ´¬©§§¬·ï¶ÿåäáâÞá瞇ÿñÔçðìåÞØÍÄ»²¬¦¤¤¦¬´¿ñµÿîÒÑÏÎÎÐÖœ‡ÿýÌâîééáÚÑÅ»²«¦££¥©°¹ÃÍõµÿÍ»»·¶¸½È›‡ÿüÚéòçãÛÒȽ³«¥££¥©°¹ÂËÕÝø´ÿ󦥤¡¡¤¬¸‡Îê…ÿýÕÊÇľ·®¦œ”Œ†ƒƒ†Š— ¦®µ»Àâ´ÿÉ““‘’“—¡±‡Î¡§ç…ÿú°š–‘‹„|unifefjou|‚ˆŽ’–™œÏ´ÿˆˆ‡ˆ‰‘¯‡ÎŒ¡³ô…ÿ˜”އ€wpjfddhlrzˆ’—™œžžÊ³ÿÏ‚„‡ž±‡Î‹¡¾ú…ÿô£›—‘‹ƒ{slfcbdhnv~†Œ’–™œžŸ  ¸³ÿ Ÿ~~€€ƒˆ‘£·‡ÎСĆÿú¯™”ˆ€wohcaadiqy‰•™œžŸ ­²ÿï€~€„‹—ª¿‡Î‰¡Ð†ÿú®˜’Œ…|skea_adks|…Œ’˜›Ÿ €¡õ±ÿ·€~†ž±È‡Îˆ¡Ü‡ÿ®–‘Šyphb_^`elu~‡•™ž€ ‚¡†È°ÿ÷…€€ƒ‰”¥»Ï‡Î‡¡Ü‡ÿÀ•‡~ume`]]`emw€‰‘–›Ÿ€ ‚¡ “P’ÿÿÝÔÙÕ¾¤›˜œr{žùƒÿÊ}€…™¬ÁևΆ¡Ü‡ÿÒ”…|rjc^\\_fnwŠ’˜›žŸ  „¡ kP[qOM Á­˜‡|vsžr܃ÿ „}~‚‡‘¡µË݇΅¡Ö‡ÿ哌ƒypha\Z[_enx‚Œ“˜œž€ „¡“P OgÓ~xttst˜uƒÿ Üs~€„‹—¨¿Óã‡Î„¡Ä‡ÿù™Šwnf_[YZ^enyƒŒ”™ž€ …¡kPO¶ÕƳŸ‚zxwxxyy˜z“ƒÿ ªu€€†ž±ÈÜé‡Îƒ¡Äˆÿ­‰€vld]ZXY]dmxƒŒ”™Ÿ  †¡“‚P…ß×ʸ¥”ˆ‚€€‚ƒƒ„•…»‚ÿ ï}z‚ƒ‰•¦»Ñâì‡Î‚¡³ú‡ÿȈ~tkb\XWX\cmw‚Œ”™Ÿ  ‡¡k‚P»àÙξ­ž“‹‹Ž‘“””•”–ë‚ÿ Ɔ€‡„ƒ†›®ÃÙæñ‡Î¡§ù‡ÿê‡~tia\XV:DIMNO…P¼äðÿôÜÓÆ³¡“Ž”¡´ÆÔÜàãääûˆŠÿ}PQQTXan|Š•›š–’‘’–™œžž›™¼Šÿ ôQW`kw‚ŠŽ‘’“†P]ÉäúÿêÙÏ¿­œ˜¨»Ë×ßâãääûˆŠÿ}PQQTZcp–œžž›™˜˜™œž žŸ‹ÿ u[cn|ˆ’šž  †PkÖŽäçÿûÞ×ʸ¥–Ž‘¯ÁÐÚàâãääûˆŠÿ|PQRU[er˜Ÿ Ÿž€žž„ ŸåŠÿ ŸW^hu‚Ž—Ÿ kP†äóÿñÜÒIJ “Ž•¤¶ÇÕÝáã€äûˆŠÿ |PQRU\ftƒ™ €Ÿ ¡  ŸÎŠÿ ¾UZbn|‰”›ž kP¡äüÿäÙξ«›š«½ÍØßâã€äûˆŠÿ |PQSV]hv…‘™ž† „¡  ¶Šÿ ÓSW^iv„˜’]P¼ŽäéÿùÞÖÈ·¥•“Ÿ±ÄÒÛàâã€äûˆŠÿ |PQSV^iw†’šž  Œ¡  Šÿ ôRU[dpŒ–œ‘‚PÉŽäóÿìÛÑ📖¦¸É×ÞáãäûˆŠÿ|PQSW_ky‡“›ž  †“Š¡  íŠÿ QSX`lzˆ“š„P]ÖŽäýÿÔ™©½ªš‘œ­¿ÏÙàâãäûˆŠÿ |QQSW_kzˆ”›ž †€k†“ˆ¡ áŠÿ \SV]hu„™ƒO€PkŽäìÿÖZKQ ¤•”¢´ÆÔÜàã‚äûˆŠÿ ’QQSX`m{‰”›ž’ƒk†“†¡ ÐŠÿ }RUZdr€—‚O€P†Žäõÿ†MIDR”’˜¨»Ë×ßâã‚äûˆŠÿ ¨QQSXam|Š•›‘‡k†“„¡ÊŠÿ }QTXan|Š•gO€P†ŒäÖ¼ø€ÿôNLHB;c’¯ÁÐÚàâã‚äûˆŠÿ ¨QQSXam|Š•œ‘Šk†“¡¸Šÿ }QSW_ky‡“gO€P“ˆäÖÉ®†]’ÿ²MJF?9`•¤¶ÇÕÝáãƒäûˆŠÿ ¨QQSXam|Š•œŸ †‹k††“­Šÿ|QSV]hw…‘fNOPP“ƒäÖɼ¡†k]€PÈÿoMICf‚’‘š«½ÍØßâãƒäûˆŠÿÓQQSXam|Š•œŸ ¡¡†Œk‡Šÿ|QRU\ftƒfNOPP¡Öɼ¡“†k]„P[ÿÞNXƒ¤¨˜‘” ±ÄÒÛàâãƒäûˆŠÿ ÓQQSXam|Š•œŸ ¡“†ŠkŠÿrCDFKT_lwXNOPP]]‹P’ÿº¨ÇÆ´¢”‘—¦¸É×Þáã„äûˆ‹ÿ QQSX`m{Š”›Ÿ ƒ¡““†‡kŠÿ [668f“’Œ|M`ȪÔâìòíåáÞÖÔÐÒWt’ƒ”§“ ’Ž…|uqp,ªª€¿ª¢Ô`S’Œˆ]I­ªÌâìòîæß×ÐÊÃÀ¿ÂSwœ”•…”•†”‘‰~vr[kâå€çâ¡“@z“‰yA‡äÌßìòîçàÙÏǾ¶±¯°·Qx‚”“”“¥”““‡}urF¦èêëìêóŸ#ÔS`“‘މ„eIÈ¿ßéòíæßÖÎļ´¬©§§¬·Qy””“’‘€¥‘Š‚ztq0ØäáâÞáçž'“@€“Œ†TläÔçðìåÞØÍÄ»²¬¦¤¤¦¬´¿Ty””“Œ‰ˆˆ€‰„ЉƒŠ‰Š‰ŒŠ‰Š€‰ˆ†{vrVjÒÑÏÎÎÐÖœ'ß``”’ŠƒxI’ÌâîééáÚÑÅ»²«¦££¥©°¹ÃÍWy””’†€~¤~|yurp=˜»»·¶¸½È›*¼Dz”’މ‚vD«ÚéòçãÛÒȽ³«¥££¥©°¹ÂËÕÝZy””’‹‚{vu‚vww€vwvwvwvwvwv€wƒv€wvvwvvuusrpg;¦¥¤¡¡¤¬¸‡Î,sM”’އ€uB®ÊÇľ·®¦œ”Œ†ƒƒ†Š— ¦®µ»Àx`””‘Š€xsrq€rqrq…rq‚r€q€p N_““‘’“—¡±‡Î¡,šIg””’‡k;‰š–‘‹„|unifefjou|‚ˆŽ’–™œe`””‘Š€wr¨p€o 0‚ˆˆ‡ˆ‰‘¯‡ÎŒ¡.‹Az””’†~jEœ˜”އ€wpjfddhlrzˆ’—™œžžmY””‘‰wrpŸo„p€oVK‚„‡ž±‡Î‹¡/|E‡”“‘Œ…~n>–›—‘‹ƒ{slfcbdhnv~†Œ’–™œžŸ  ƒF””‘‰vrpžopqrssrqppoo=j~~€€ƒˆ‘£·‡ÎŠ¡"uM“‘މƒ|r?ˆ™”ˆ€wohcaadiqy‰•™œžŸ  ’9””‘‰~vqp¨og7€~€„‹—ª¿‡Î‰¡!fS”’Š…zp?†˜’Œ…|skea_adks|…Œ’˜›Ÿ €¡/“‡}uqp¨oIZ€~†ž±È‡Îˆ¡ X`”’Žˆ‚|wt9†–‘Šyphb_^`elu~‡•™ž€ ‚¡†7s“|nTPF€=9œ,0Ak‚ok4x€€ƒ‰”¥»Ï‡Î‡¡ Xm”’އ€zvsFq•‡~ume`]]`emw€‰‘–›Ÿ€ ‚¡ “PB?,26oknofceœrn\DkoVF}€…™¬ÁևΆ¡"Xm”’އytqR\”…|rjc^\\_fnwŠ’˜›žŸ  „¡ kPNIOM Á­˜‡|vsžr>^o 4i}~‚‡‘¡µË݇΅¡_f”“ˆ€ytq_G“Œƒypha\Z[_enx‚Œ“˜œž€ „¡“P OgÓ~xttst˜u,o ^>s~€„‹—¨¿Óã‡Î„¡uS”“‰ytql7ŒŠwnf_[YZ^enyƒŒ”™ž€ …¡kPO¶ÕƳŸ‚zxwxxyy˜zk9o E[u€€†ž±ÈÜé‡Îƒ¡!uS”“‘Šƒzurp=x‰€vld]ZXY]dmxƒŒ”™Ÿ  †¡“‚P…ß×ʸ¥”ˆ‚€€‚ƒƒ„•…^I€og7}z‚ƒ‰•¦»Ñâì‡Î‚¡!‹E”‘Œ„|urpN^ˆ~tkb\XWX\cmw‚Œ”™Ÿ  ‡¡k‚P»àÙξ­ž“‹‹Ž‘“””•”–@b€oN\†€‡„ƒ†›®ÃÙæñ‡Î¡!š9”’†}wrpb?‡~tia\XV:VS€Q SV]hu‚Ž—œŸ  Ž¡†PkÖ¦äqVoogCÛѯœŠŽœ­Ôãó⪈Eˆ”“Ž…zsp€o9QURQQRUZbm{ˆ’šž  ¡kP“§ä8kooIØÌ¼¨—Œ‹“¢µÛéïÔ‡Ô@””’Œxrpoog2VS€Q SV]ft–œ˜|fQ€IQf|š†¡“]P®¦äŸE€o0ÒÕÆµ¢“‹Œ˜ª½áë翈ym””ˆ}uq€oR@TQTXalz‡ŒpA0AN[_^^ZNA0Bušƒ¡†‚PɦäfZooZdÚÐÁ®œ‹‘ž±Äçñߪˆ8”’„zsp€o9NS€Q RU\er€\7Ebppqpp€obE7f€ ¡¡†Pk¦äØ0€oA§×˺§–Œ‹•¥¹Êìë̇Ô?””‘Š€wrpook/TR€QSW_jd7NkppqstuutrqpokN;Š€ kP†¦ä“IoogCÝÔÆ´¡’‹œ­ÀÏð⪈‡f”“‡|uqpooVjˆ{vrpp‚oN[MMNO\Èã¤äˆNoobNÜÓŲŸ’‹‘ž°ÃÑÛ÷ªˆ¯S”“ˆ~vrpoog1R€QRUW4kok=VŸŸžœ„T?‰‚{vrpƒoE>KLMiÓâã£äCgooEœÙϾ¬šŽŒ•¥·ÉÖÞøˆ‡f”“†|uq€oZ9QSVQ=o^6}žžš—’wBlŠƒ|vsq‚o k9AIKßáâã¡äÁ9€o0ÓÖÉ·¥”Œ›¬¾ÏÙàù‰ S€”“Ž„ztppooN?QSX]4ECŒšžœ™”ˆ{pFlŠ„|wsqpo b0DG{ØÞàâã ä}RooVpÛÒ𞑌“¡³ÅÓÜàú‰,””’‚ysp€o!=HQPQRUZcc_Œ•››˜’Œ„|uoif:y‹„}vsp‚o N4BŒÏ×ÝàâãŸä8kooA§ØÍ½ª™ŽŽ—§ºË×ßáúˆ Ô?””’‹xrp€o"4LQPQRV\ft‚—››˜’Šyrkgca[8†‘‹„|urp‚o 4:‹ÃÏ×ÝàâãäªAoogCÝÕǶ¤”œ®ÁÐÚàâúˆ ¯S””‘Šwrp€o,QSW_jx†’˜›™“‹xpkgdcbaRF“Š‚{uqpo V0‰ª¶ÁÉÏÓÔÕ‰ÖäqVooR{Ûѯ‘”¤¶ÇÕÝáãûˆ “`”“ˆ~uqpoo^6QPQQTXam|Š”™š–…zqk€i€k iBm“‰ytqpo4QPQRU\ftƒ˜›™“Š€wstw|…††„€Im”’ކ}vrp€o k,15;AFJMOO†PkäfZooEœÚÐÀ®œŽ–¥¸É×Þáãäûˆ8”’ƒzsp€o'N>PPQSV]iw…‘™›™”Œ„~|~ƒˆ’’|9””’Œƒztpp€o A-17=CHKNO†P“äÍ4€o0Ô×˺§—Žœ­¿ÏÙàâãäûˆ,””’Œ‚ysp€oN>PQQSX_kzˆ“š›—‘‹††‰’–˜€™ –’Dz”“ˆ~vrp€o V,.38>DIMNO…P¼ä“IooVpÜÓÆ³¡“Ž”¡´ÆÔÜàãääûˆ,””’‹xrp€o'=HPQQTXan|Š•›š–’‘’–™œžž›™mS””’Œƒysp€o k.QW`kw‚ŠŽ‘’“†P]ÉäObooA¨ÙÏ¿­œ˜¨»Ë×ßâãääûˆ,””’‹€wrp€o=HPQQTZcp–œžž›™˜˜™œž  ž’2””“†|uqo 9M[cn|ˆ’šž  †PkÖŽäÍ4oogCÞ×ʸ¥–Ž‘¯ÁÐÚàâãääûˆ,””‘Š€wrp€o=GPQRU[er˜Ÿ Ÿž€žž„  ŸGy””‘‰wrp€o IBW^hu‚Ž—Ÿ kP†ä}RooR{ÜÒIJ “Ž•¤¶ÇÕÝáã€äûˆ,””‘Šwrp€o =GPQRU\ftƒ™ €Ÿ ¡   Ÿd_””’Œ‚xsp€o V:UZbn|‰”›ž kP¡äCgoo4ÉÙξ«›š«½ÍØßâã€äûˆ,””‘Švrp€o =GPQSV]hv…‘™ž† „¡   E””“Ž…{tq€o ^5SW^iv„˜’]P¼ŽäÁ9oobNÞÖÈ·¥•“Ÿ±ÄÒÛàâã€äûˆ,””‘‰vrp€o=GPQSV^iw†’šž  Œ¡  ,“”“‡}uqpook.RU[dpŒ–œ‘‚PÉŽä}RooEœÛÑ📖¦¸É×Þáãäûˆ,””‘‰vqp€o=GPQSW_ky‡“›ž  †“Š¡   A€””‘Š€wrp€o ,QSX`lzˆ“š„P]ÖŽä8koo0Ç™©½ªš‘œ­¿ÏÙàâãäûˆ,””‘‰vrp€o=GQQSW_kzˆ”›ž †€k†“ˆ¡  Pr””’Œ‚xsp€o 0OSV]hu„™ƒO€PkŽäªAooVRZKQ ¤•”¢´ÆÔÜàã‚äûˆ,””‘‰wrp€o EBQQSX`m{‰”›ž’ƒk†“†¡  f_””“„ysp€o =HRUZdr€—‚O€P†ŽäqVooADMIDR”’˜¨»Ë×ßâã‚äûˆ,””‘Švrp€o N>QQSXam|Š•›‘‡k†“„¡ mX””“Ž„zsp€o =HQTXan|Š•gO€P†ŒäÖ¼2kok.NLHB;c’¯ÁÐÚàâã‚äûˆ,””‘Š€wrp€o N>QQSXam|Š•œ‘Šk†“¡ ƒE””“Ž…{sp€o =HQSW_ky‡“gO€P“ˆäÖÉ®†]BEooR;MJF?9`•¤¶ÇÕÝáãƒäûˆ,””‘Š€wrp€oN>QQSXam|Š•œŸ †‹k ††“xE””“†{tq€o=GQSV]hw…‘fNOPP“ƒäÖɼ¡†k]€P7Zoo9HMICf‚’‘š«½ÍØßâãƒäûˆ8”‘Š€wrp€o^5QQSXam|Š•œŸ ¡¡†Œk _?“”“‡|tq€o=GQRU\ftƒfNOPP¡Öɼ¡“†k]„PN0oob3NXƒ¤¨˜‘” ±ÄÒÛàâãƒäûˆ`z”‘‹wrp€o ^5QQSXam|Š•œŸ ¡“†Šk,“”“‡}uq€o==CDFKT_lwXNOPP]]‹PBEooI]¨ÇÆ´¢”‘—¦¸É×Þáã„äûˆms”’‹xspo ,QQSX`m{Š”›Ÿ ƒ¡““†‡k,“””‘ˆ~uqpoo93668PQQSXan}‹cMOPP“Šä}Roo9¾ÜÒIJ ”“›«½ÍØßâã†äû‰ “`”’Œ‚yspp€o ,QRU\fuƒ™ž  ¡,“”“‡|uqooECPQQSXan}‹cMOPP“Šä8kobNàÙξ¬œ“” ±ÃÑÛàâã†äû‰ Ô@”“‡}uqp€o =HRU[es˜  Ž¡’9””“†|tpoo9JPQQTYbo~ŒdNOPP†‰äªAooI’ÞÖÈ·¥—“˜¦¸ÉÖÞáã‡äûŠ8”‘‹‚xsppooRŠ‹ƒ|urVpѹ¤“ˆƒ‚„‰–¦»ÍßîëÌjPÚEgoo4ÞòæÙı¥¤®ÀÓäè媡Ôîç½F”“‘‹„|vrpVV¬ÃÕãé翃ïVzˆƒ|vsVtÞɳŸ†ƒƒ‡ž±ÆØæò⪂ÚPj¼AooZléìâѼ¬£¦´ÈÚêðÚ¢¿åóç¶F”“Šƒ{urpVI¦ÌÞéðߪïUqzvsVuæÖ왌…ƒ†˜¨¼ÑâíëÌ‚¿‚Pâ`^ooE­ðéÜǵ¦£©ºÍßíéÌ£8ÔìîÞ°:z”“‰‚zurp^;tÉáììÔ¯m’ކ}urpookVI==ARgo€plNSÏîîßÏ»¦—Œ‡‰›©½ÏàçïÚª†\€PI5,,lèòæÙı¤¡«¼Ñáì翦ÔîîâÒÁŸW9kŠ€xrp‰ogN;’Úëëã×ðž‘‰Š˜¦¸ÉÜäò⿇ʂP¿éìâѼ«¡£°ÄÙæòߪ§ªßðéÝϾ­ŽQ2L[jp†ogRAE“çâîêçÚȶ¥—ŽŒ˜¥¶ÈØâêé̈‚PºÔïéÛɶ¦¢¨·ËÝçì̧¿åòäÛμ¬ŒfL55=ENA=0D‚¶ìëîòîâÙÍ»ªœ‘Ž—¤µÆ×äììÔ‰¹PºßòæÖ𦤯ÀÓäéå¿©0ÌéèæÜͼ¬ž“‹†xnd[`fl‘£ÌßçéîîèæÞÙ̼¬Ÿ–‘“š¥´ÄÒáîïÚªŠ¿PP¹¿ªâèãÒÁ°©«¶ÉÜêðÚª.ÔëéæÜ̽®¡–Žˆ……‡• ¬¸ÄÎ×ÙÞÝÛÖÑÅ»¬¡˜•–œ¦¶ÆÒâçðߪŒî¿€ªåèãÕÄ·°µÁÔáì鿬,ªÔëéæÛÍÀ±¤š‘Œˆ‡‰“œ¦±¹ÁÇÈÊÈü´©¡›˜™¡«¸ÈÕâçðâ¿’ªâòæÚÍ¿ÄÑÞéðߪ­+ªÔëèäÝÒĶª —‘‹‹Ž‘— §­±µµ´°«¥ œŸ¦±½ÉÙåîðâ¿’ ÚïîáØÐÑÕÞæè翯)Ôéòéâ×ɾ²¨Ÿ—““–™ž¢¤¥¤£¡  ¢¦­·ÃÏÜãíðâ¿“ ÌçòèãÞßäêéëÔ°ÌåñîãÛÒȼ²©£žš˜€—™œž ¡¡¤¦©°·ÁÌ×ßäêîß¿• ªÔçðêííêñéÔª²¿âîééáÚÐÇ¿·±¬¨¥€£¤¦§©¬°¶¼ÃËÒÞãçòéÔª˜ ªÌßçëëçß̪´"ªÔçðìêáÜÕÎȽ»·µ¶µ·¹¼ÀÄÊÑÖÝãééîâÌšª¿ÌÌ¿ª¡ÿÿÿÿÿÿÿ½¿ã¬}>>¬ßPÊß×nâ€P¥Ü»>„\PjÙ»>….ʪ€¿ª†j‚PÊ×»>… ~ª¿Ôßâççåß̪„¥‚P¥Ö×N…‹äÌßçîñèëëÝj.>>N}}œ¤<^ß«ßn… >ªÔâëñëçæäáံ>ªœ„>¼ªÔâìòíåáÞÖÔÐÒ6·ªª€¿ª¢É>„ªÌâìòîæß×ÐÊÃÀ¿Â2¶Mâå€çâ¡}…näÌßìòîçàÙÏǾ¶±¯°·0¶–èêëìêóŸÉ.„¼¿ßéòíæßÖÎļ´¬©§§¬·0¶ØäáâÞáçž}…OäÔçðìåÞØÍÄ»²¬¦¤¤¦¬´¿3µNÒÑÏÎÎÐÖœ×>…|ÌâîééáÚÑÅ»²«¦££¥©°¹ÃÍ6µŒ»»·¶¸½È›¬ „ œÚéòçãÛÒȽ³«¥££¥©°¹ÂËÕÝ8´¦¥¤¡¡¤¬¸‡Î[… ¦ÊÇľ·®¦œ”Œ†ƒƒ†Š— ¦®µ»Àa´I““‘’“—¡±‡Î¡—(… €š–‘‹„|unifefjou|‚ˆŽ’–™œO´ˆˆ‡ˆ‰‘¯‡ÎŒ¡ƒ…Šœ˜”އ€wpjfddhlrzˆ’—™œžžZ³0‚„‡ž±‡Î‹¡n…“›—‘‹ƒ{slfcbdhnv~†Œ’–™œžŸ  x³ _~~€€ƒˆ‘£·‡ÎŠ¡d†™”ˆ€wohcaadiqy‰•™œžŸ ²€~€„‹—ª¿‡Î‰¡P†~˜’Œ…|skea_adks|…Œ’˜›Ÿ €¡±G€~†ž±È‡Îˆ¡=‡~–‘Šyphb_^`elu~‡•™ž€ ‚¡†°u€€ƒ‰”¥»Ï‡Î‡¡=‡`•‡~ume`]]`emw€‰‘–›Ÿ€ ‚¡ “P2YU^d[X]œrkNƒ+}€…™¬ÁևΆ¡=‡C”…|rjc^\\_fnwŠ’˜›žŸ  „¡ kPKAOM Á­˜‡|vsžrƒ d}~‚‡‘¡µË݇΅¡G‡&“Œƒypha\Z[_enx‚Œ“˜œž€ „¡“P OgÓ~xttst˜uƒ s~€„‹—¨¿Óã‡Î„¡d‡ ‰Šwnf_[YZ^enyƒŒ”™ž€ …¡kPO¶ÕƳŸ‚zxwxxyy˜zcƒ Ju€€†ž±ÈÜé‡Îƒ¡dˆm‰€vld]ZXY]dmxƒŒ”™Ÿ  †¡“‚P…ß×ʸ¥”ˆ‚€€‚ƒƒ„•…K‚ }z‚ƒ‰•¦»Ñâì‡Î‚¡ƒ‡Hˆ~tkb\XWX\cmw‚Œ”™Ÿ  ‡¡k‚P»àÙξ­ž“‹‹Ž‘“””•”–‚ F†€‡„ƒ†›®ÃÙæñ‡Î¡— ‡‡~tia\XV:ˆb_XURRSV\do|ˆ’fhj€kŠ¡“‚P®‘äƒPä+ ÌÏ¿­šŒ†™§»Ñâì鿈»‰5aZUSQRTX`kw„—hjkŠ¡†P]Ö‘äƒPŒäÇ‚T×ʹ¥”‰‡¯ÃÙæñߪˆ>‰W\VSQQSV\fr‹”›ijkŠ¡]P†’äƒPŒä€‚³ÓŲŸˆŠ£·Íàîì̇»‰'^XSRQRUZamy†‘˜Ÿ  Œ¡“‚P®§ä*ÙϾ¬™‹ˆªÀÒãè⪈>‰OYURQQSV]gtŒ–›ž  ¡†P]֦乂ŠÖÉ·¥”Љ’²ÉÛéïԇɉ\VSQQRUZbnzˆ’™  Ž¡kP†§äd ÍÒñž‰‹˜ºÐáë翈^‰;XS€Q SW^ht‚–œŸ  ¡“‚P®§äTØÎ½ª˜‹‰žÃØåñߪ‡ß‰ZURQQRUZbn{ˆ’™ž  Ž¡†‚Pɦ䜂´Õȶ£“Š‹•¥Ìàîë̇}‰#VS€Q SV]hu‚Ž—œŸ  Ž¡†PkÖ¦äVÛѯœŠŽœ­Ôãó⪈‰HURQQRUZbm{ˆ’šž  ¡kP“§ä}ØÌ¼¨—Œ‹“¢µÛéïԇɉ VS€Q SV]ft–œ•nP3€(3Pn—†¡“]P®¦äŽ‚ÏÕÆµ¢“‹Œ˜ª½áë翈^‰'TQTXalz‡‰_ˆd—ƒ¡†‚PɦäHFÚÐÁ®œ‹‘ž±Äçñߪˆ‰FS€QRU\er€FŒ P€ ¡¡†Pk¦äÖ‚™×˺§–Œ‹•¥¹Êìë̇ɉTR€QSW_jY‚€ kP†¦ä€ÝÔÆ´¡’‹œ­ÀÏð⪈n‰ S€QRUZb7”cžŸ\P¡¦ä+bÚÏ¿­›Ž‹“¢µÆÔóÔˆ.‰5R€QSV]'–DNOOPP»¥äÇ‚Â×ʹ¦•Œ˜©¼Í×õ¿ˆ×ŠIQSX0ƒ(( ŽEMMNO\Èã¤är*ÜÓŲŸ’‹‘ž°ÃÑÛ÷ªˆœ‰ R€QRUT:ŠŸŸžœ|8.KLMiÓâã£äŒÙϾ¬šŽŒ•¥·ÉÖÞøˆn‰QSVF€ ržžš—’n‹9IKßáâã¡ä¹‚ÐÖÉ·¥”Œ›¬¾ÏÙàù‰.‰)QSXZ"‰šžœ™”ˆ{n*‹ DG{ØÞàâã ädTÛÒ𞑌“¡³ÅÓÜàú–=QPQRUZc[OŒ•››˜’Œ„|uoif‹BŒÏ×ÝàâãŸä™ØÍ½ª™ŽŽ—§ºË×ßáúˆÉŠGQPQRV\ft‚—››˜’ŠyrkgcaX ‹4‹ÃÏ×ÝàâãäœÝÕǶ¤”œ®ÁÐÚàâúˆœŠQSW_jx†’˜›™“‹xpkgdcbaG‹ ‰ª¶ÁÉÏÓÔÕ‰ÖäVbÛѯ‘”¤¶ÇÕÝáãûˆ}‰QPQQTXam|Š”™š–…zqk€i€ki&‹6CIPTXZ\‰]¼äÖ‚Ã×̼©˜Ž™ª½ÍØßâãûˆN‰QPQRUZdq€Œ–š™”‹€vomnptwyxvd‹5:@EIMNOˆPÉäŽ*ÝÔÆµ¢”’Ÿ±ÄÒÛàâãûˆ>‰(QPQRU\ftƒ˜›™“Š€wstw|…††„€.Š 15;AFJMOO†PkäHŒÚÐÀ®œŽ–¥¸É×Þáãäûˆ‰(PPQSV]iw…‘™›™”Œ„~|~ƒˆ’’v‹17=CHKNO†P“äÇ‚Ñ×˺§—Žœ­¿ÏÙàâãäû•(PQQSX_kzˆ“š›—‘‹††‰’–˜€™–’#Š .38>DIMNO…P¼ä€UÜÓÆ³¡“Ž”¡´ÆÔÜàãääû•=PQQTXan|Š•›š–’‘’–™œžž›™\Š QW`kw‚ŠŽ‘’“†P]Éä+šÙÏ¿­œ˜¨»Ë×ßâãääû•=PQQTZcp–œžž›™˜˜™œž ž‹ E[cn|ˆ’šž  †PkÖŽäÇÞ×ʸ¥–Ž‘¯ÁÐÚàâãääû•‰ QQSXam|Š•œŸ ¡“†ŠkŠ2CDFKT_lwXNOPP]]‹P2J¨ÇÆ´¢”‘—¦¸É×Þáã„äûˆNŠ QQSX`m{Š”›Ÿ ƒ¡““†‡kŠ +668‰ QSV]hv…‘™ž  ¡‰(PQQSXan}‹cMOPP“Šäd¶ÜÒIJ ”“›«½ÍØßâã†äû‰}Š QRU\fuƒ™ž  ¡‰3PQQSXan}‹cMOPP“Šä€+àÙξ¬œ“” ±ÃÑÛàâã†äû‰ÉŠ =RU[es˜  Ž¡‰BPQQTYbo~ŒdNOPP†‰äœ~ÞÖÈ·¥—“˜¦¸ÉÖÞáã‡äûЉ $QTZcp€—Ÿ Ž¡yˆQPQQTZbp~NOPPk‰äHÒÛѰŸ””œ­¾ÏÙàâã‡äûŠ^‰ QTYbn}‹–œŸ Ž¡yˆQPQQUZdr€Ž~NOPPkˆäÖGßØÍ¼ª›“•¢´ÅÓÜàãã‡äûЬРGSX`lz‰”›ž Ž¡Zˆ3QPQRU[et‚NOPP]և䀚ÝÔÆ¶¤—“š¨ºË×ßáãˆäû‹‰ -SV^jx†’šž  ¡Pˆ LQPQRV\gu„‘ŒNO€Pɇä+€àÚÐÁ®ž””ž¯ÁÐÚàâãˆäû‹}‰ RV\huƒ™ž  ¡3‡QQPQSV]iw†’š[O€P¼†ä¹cß×˺¨š“—¥¶ÇÕÝáã‰äû‹×Š CU[drŽ—Ÿ ¡‡:QSW_kzˆ”›iP¡†äd¶ÜÓÅ´¢–”œ«½ÍØßâã‰äûŒ\‰ TYbn}‹•œŸ ¡‡ TQTYan|Š•œjP††ä€+àÙϾ­œ”• ±ÃÑÛàâã‰äûŒÛ‰ NX_kyˆ“šž  ‹¡y‡,S€Q RUZdr€—„PkÖ„äœ~ÞÖɸ¦˜”˜¦¸ÉÖÞáãŠäûŒ¿]‰ )V]hu„™  ‹¡P†RS€Q SV]guƒ™’‚PÉ„äHÒÛÒñ •”œ­¾ÏÙàâãŠäûŒª×‰ P[dq€–œŸ ‹¡(†/WS€Q SX_ky‡’šž’]P¼ƒäÇGßØÍ½«œ”–¢´ÅÓÜàããŠäûŒÔy‰ *Xam{ˆ”›ž  ‰¡—† ^VSQQRUZbo~‹•›Ÿ kP“ƒä€šÝÕǶ¥—”š¨»Ë×ßáã‹äû¿âˆ hx†—©¸ÃÊ̊Ά\wnjhhjnw„•¦·ÂÉÌΧPkƒû€öðåÕÁ®££®ÁÕåðöùúŒûªß·‰ )ž±ÈÜéðÚ‰.…9¡†€€„‹—¨¾Óãó⪿‚P¿»]éíßÏ»ª¤¨·ÈÛèïÔÌìg‰h—ª¿Óãè忈»… ¨žŽ…€†ž±ÈÜéðÚjPß^ËðêÚÈ´§¤­½Ðáë翟ªåè+ˆ ˆ¢µÌÝçîÔ‡>…“®™Œ„ƒŠ”¦»Ñâìé¿€ÊP¥€ßåéäÓÀ®£¦±ÄØåñߪŸÔîÞ ˆ#™­Ã×âó忆œ…x¿¨–Šƒ‚†°ÄØæñߪ€¿‚P€‹ìçÝ˸¨£¨¸ÍÝîìÌ ¿åèº ˆ7¤·ÍÝçîÔ„ß„Uѹ¤“ˆƒ‚„‰–¦»ÍßîëÌjPÚ×òæÙı¥¤®ÀÓäè媡Ôîçµ ˆ:¬ÃÕãé翃ß,„YÞɳŸ†ƒƒ‡ž±ÆØæò⪂ÚPj¬NéìâѼ¬£¦´ÈÚêðÚ¢¿åóç¯ ˆ'ŸÌÞéðߪß,„[æÖ왌…ƒ†˜¨¼ÑâíëÌ‚¿‚Pâ>›ðéÜǵ¦£©ºÍßíéÌ£ÔìîÞª ˆ _ÄáììÔœ„[íÞϹ¤“‰……‰“£µÉÙêñߪ„jP™åèãÒÀ¯¤¤¯ÃÕâó⪤ªßñêܼ-‰ P³¸¬o…›òå×űˆ†‰‘ž¯ÂÕäëéÌ…ßP<]ìîÝ͸©¡§¶ÉÛéïÔ¤ÌçêãÖÄc•/ËîîßÏ»¦—Œ‡‰›©½ÏàçïÚª†\€PA NèòæÙı¤¡«¼Ñáì翦ÔîîâÒÁ™;’|Úëëã×ðž‘‰Š˜¦¸ÉÜäò⿇ʂP¿éìâѼ«¡£°ÄÙæòߪ§ ªßðéÝϾ­Š6Ž}çâîêçÚȶ¥—ŽŒ˜¥¶ÈØâêé̈‚PºÔïéÛɶ¦¢¨·ËÝçì̧ ¿åòäÛμ¬ˆV1‡i¨ìëîòîâÙÍ»ªœ‘Ž—¤µÆ×äììÔ‰¹PºßòæÖ𦤯ÀÓäéå¿©0ÌéèæÜͼ¬ž“‹†scSEJOW‚˜ÉßçéîîèæÞÙ̼¬Ÿ–‘“š¥´ÄÒáîïÚªŠ¿PP¹¿ªâèãÒÁ°©«¶ÉÜêðÚª.ÔëéæÜ̽®¡–Žˆ……‡• ¬¸ÄÎ×ÙÞÝÛÖÑÅ»¬¡˜•–œ¦¶ÆÒâçðߪŒî¿€ªåèãÕÄ·°µÁÔáì鿬,ªÔëéæÛÍÀ±¤š‘Œˆ‡‰“œ¦±¹ÁÇÈÊÈü´©¡›˜™¡«¸ÈÕâçðâ¿’ªâòæÚÍ¿ÄÑÞéðߪ­+ªÔëèäÝÒĶª —‘‹‹Ž‘— §­±µµ´°«¥ œŸ¦±½ÉÙåîðâ¿’ ÚïîáØÐÑÕÞæè翯)Ôéòéâ×ɾ²¨Ÿ—““–™ž¢¤¥¤£¡  ¢¦­·ÃÏÜãíðâ¿“ ÌçòèãÞßäêéëÔ°ÌåñîãÛÒȼ²©£žš˜€—™œž ¡¡¤¦©°·ÁÌ×ßäêîß¿• ªÔçðêííêñéÔª²¿âîééáÚÐÇ¿·±¬¨¥€£¤¦§©¬°¶¼ÃËÒÞãçòéÔª˜ ªÌßçëëçß̪´"ªÔçðìêáÜÕÎȽ»·µ¶µ·¹¼ÀÄÊÑÖÝãééîâÌšª¿ÌÌ¿ª¡t8mk@P€¿¿Pÿ1 ïÿÿÿÿï ÿÿÿX@¿ÿÿÿÿÿÿÿߢÿÿÿÿ”@¿ÿÿÿÿÿÿÿÿÏ1”ÿÿÿÿÿ1@¿ÿÿÿÿÿÿÿÿï XÿÿÿÿÿX ¯ÿÿÿÿÿÿÿÿßq &—ÑïÀ¿¯€€`Zÿÿÿÿÿ”@`€¿Ÿÿÿÿÿÿÿÿÿ¿a !)043‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿`ïÿÿÿÿÿÿÿ¿A (3?KTXUÒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ0¿ÿÿÿÿÿÿÿßa *8GWfs{}vØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ² €ÿÿÿÿÿÿÿÿ+:J\n˜™ŒÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿn0ÏÿÿÿÿÿÿÿßA *9K^qƒ”¡ª®¬¡ŽÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ<14674,€ÿÿÿÿÿÿÿÿ° (7I]q„–¤¯´´¯¤“|×ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿VY\_^XK ¿ÿÿÿÿÿÿÿÿ $3EZo„–¥°µ¶±§™ˆt]Ñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡„‡‹Š€lPïÿÿÿÿÿÿÿïb  .@Uk•¥±¶¶±§™ˆvcP=Êÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõ¯±´··²£‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéÔÕרÖͺšÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìëìíìçÚžÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü÷÷÷÷ôíÜÀ˜ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýýüûöë×¶ŒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýûôæÍ¨}ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýùðÞÀ˜lÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþüöêÓ±‡[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþúòâÇ¡uKÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýøíÙ¹c<ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþûôæÍ©}R/ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüùðÝ¿˜kC$ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùúõéÒ°…Z5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôöðáÅŸsJ)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîñêÖ¶a;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿçëâʦzP- ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâ娻”h@"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÌ«V2 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÖ¿šoF&ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØÍ±ˆ]7 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔ vL+ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿεd= ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŧ}S0  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿº–kC$¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬…Z5 @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsJ)¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒa;@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{Q. ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿiA#0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿX4 ŸÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿI(ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ: €ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ. ßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ#0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿPÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿPÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ£ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ'ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿOÿÿÿÿÿÿÿÿÿÿÿÿúÞÀ˜kC$ÏÿÿÿÿÿÿÿÿÛ¹ÛïùüûôæÍ©~R. ÿÿÿÿÿ@ÿÿÿÿ¡ 8\…¦´«Žg@"ÿÿÿÿÿÿÿÿÿÿÿÿìͨ}R/ @ÿÿÿÿÿÿÿÿöÀßñúüùïÝÀ˜lC$”ÿÿÿÿŸÿÿÿÿ6%El“®´¢€W3  ØÿÿÿÿÿÿÿÿÿÿÿþÚ¸d=!¿ÿÿÿÿÿÿÿÿ•ŸÇäóúúõèѯ…Z5 1ÿÿÿÿXÿÿÿÿß 0S{Ÿ³°—qI(/óÿÿÿÿÿÿÿÿÿÿÿøÇ¢wN- `ÿÿÿÿÿÿÿÿœ|©ÏèõúøïÞœqI)ÿÿÿÿÿpÿÿÿÿs =AKZo‡¡¹ÊÒÐípQ5  /OrŽ™uT3  )A]{˜²ÈÙäëíêáÔxngfkt‚”§¹ÆÌǺ¥ŠlO5   )Eav|qZ>$ '=Vr¦¼ÍÚâæåà×˼®¢˜’‘”›¥±»Âý¯šeJ2 4HWYP>)  $6Me~–«½ËÕÛÝÛÖÏÇ¿¸´±²µ¹¼¼¸¯ Œt[C.  ".781%  .AVl‚–§µÀÈÌÎÍËÇÿ¼º·´°§œŒydN9'   $4EXj|‹˜£«±µ¶¶´°¬§¡™ƒtcQ?.    &4BP^kv€‡ŒŒˆ‚zqfYL=/# BasiliskII/src/MacOSX/HowTo.html0000644000175000017500000002144610363023452016555 0ustar centriscentris Basilisk II, Mac OS X port, HowTos

Index


Minimum Requirements

To run Basilisk II, you need both:
  • A Mac ROM image. Even though there is a ROM in your OS X Mac, it is too new for a 68k Mac to make use of. Any Mac II ROM, and most of the Quadra ROMS, will work.
    (Quadra 660av and 840av ROMs are currently unusable. I don't know about Mac LC ROMs. In the near future, Mac Plus, SE or Classic ROMS may also be usable, though only for emulating a monochrome Mac).
  • A copy of the MacOS, which at the moment has to either be on a CD-ROM, or on a disk image

Macintosh ROM image

To run Basilisk II, you need a ROM image, which is a data file containing a copy of the ROM chips from a real 68k Macintosh.

The best way (i.e. most legally acceptable) to get a ROM image is to produce it from your old Mac. Take a program like CopyROM, download it onto your old Mac, and use it to produce the image file, which you then copy or upload to your OS X Mac. A good page which describes this process is here.

The easiest way to get a ROM image is to get one from someone else (e.g. another Basilisk II user, or an emulation web site). Note that this probably contravenes several copyright laws.

Once you have your ROM image, you need to tell Basilisk II to use it:

  1. Open the Basilisk II application
  2. Go to the 'BasiliskII' menu, then the Preferences...' menu item
  3. On the Emulation tab, there is a field 'ROM file:'. Either type in the path to the ROM file, or click the Browse button and Open the ROM file
  4. Click the Save button, so that Basilisk II will be able to find the ROM each time you boot it

If you want to test this, press the Run or Power button (in the top right corner of the 'BasiliskII Emulator' window). After a few moments you should see a Mac screen, with a picture of a floppy disk with a flashing question mark. That is the Mac telling you that it needs a disk to boot from.


Finding a boot disk

Basilisk II needs a copy of the MacOS to boot from. Anything from System 7 through to MacOS 8.1 should be usable.
(Felix Eng and I have only tested System 7.0.1, 7.1, 7.5.3 and 7.6, although Felix also got System 6.0.8 to work with SE/30 Roms)

Basilisk II can currently boot from:
CD-ROM Most (not all) MacOS Install CDs will also boot your Mac. I also think that some old Norton Utilities install CDs might have booted 68k Macs
Floppy disk image Jonathan C. Silverstein reports that this Apple floppy disk image will boot Basilisk II
Preinstalled Basilisk II disk image Another Basilisk II user might be willing to loan you the disk image that they are using

It is possible to use Basilisk II with a CD-ROM or floppy image, but because most bootable CDs have a minimal System Folder, it is better if you use a disk image with a more complete MacOS installed on it. The next section tells you how to do this.

Note that there is currently no Install CD image on Apple's Web site, but they do seem to have MacOS 7.5.3 floppy disk images (all 19 of them). Burning those images onto a CD (not in the extended format) should allow you to install.
Thanks to Attilio Farina for this tip!

Installing the MacOS

Create a new BasiliskII disk

Before you can install the MacOS onto a disk volume, you need to create a disk to install onto:

  1. Start up the Basilisk application.
    (If it is already running, skip this step)
  2. Open the preferences.
  3. Go to the Disk Volumes tab.
  4. Press the 'Create...' button (go with the defaults, unless you think you will need a huge disk).

If you want to have more than one hard disk available to Basilisk II, you could create additional volumes here.

Installing the MacOS

Insert your MacOS install CD-ROM, and wait a few moments for the OS X Finder to mount the disk. While still in your preferences:

  1. Go to the Emulation tab and check that your emulation is appropriate for your install image
    (e.g. I had to change from Quadra900 to IIci, because my generic 7.1 install CD didn't support the Quadra), and that you have the RAM size set appropriately
    (e.g. 8MB RAM may not be enough for a 7.5.3 install).
  2. Click the save button.
  3. In the BasiliskII Emulator window, click Run.
    (If it is already running, but showing the floppy with the question mark, press the restart button - the triangle in the bottom right hand corner)
    You should get a HappyMac, and the emulator will start to boot from the CD. You should then a dialog asking you to format a disk.
  4. Click Initialize, then Erase, give the disk an appropriate name (e.g. Hard Disk), then click OK.
  5. Find the OS installer (in my case the CD booted into At Ease, and one of the first buttons was 'Install System'), and go with the defaults.

After the installer finishes it may try to reboot (or you may need to force a reboot). When it reboots, BasiliskII may exit. Start it again, and you should boot into your installed OS.


Mounting Unix Files

If Basilisk II is running MacOS 7.5.3 or newer, you can easily access some of the files from your OS X disks. Just set the 'Unix directory to mount' in the Volumes tab of the Preferences. Next time the Emulator starts up, a new disk will appear on its Desktop (called Unix).

To prevent clashes with the OS X desktop files, I suggest that the directory you select is not a whole disk (e.g. '/' or '/Volumes/disk'). Mount a sub-folder instead (like '/Applications (Mac OS 9)').


Importing Mac Files

If you are not running MacOS 7.5.3 or newer, the above trick won't work. This makes getting files into Basilisk II harder. Luckily, Apple's 'Disk Copy' or 'Disk Utility' can create a disk image file that is compatible with Basilisk II (i.e. you can add it as a disk volume).

  1. Open 10.1's 'Disk Copy' program, and create a 'Mac Standard' image,
    or 10.3's 'Disk Utility', and create a 'read/write disk image',
    or Disk Copy 6.??? in Classic, and create new image
  2. If the image is not mounted, mount it
  3. Copy any files that you want to access in the emulator to the mounted image
  4. Unmount the image
  5. In Basilisk II's preferences, go to the 'Disk Volumes' tab, add your new image, and start the emulation
A new disk should appear on the emulation's desktop which contains the files that you wanted to access. If the emulator complains about a disk needing to be formatted, you may have chosen the wrong type of image type in 'Disk Copy' or 'Disk Utility.'

Networking

If your Mac is networked, then your emulated MacOS can also access that network:

  1. Open Basilisk II, go to the Preferences, then the Hardware tab, and set the emulator's EtherNet interface to slirp
  2. Start the Emulator
  3. In the emulated MacOS, open the TCP/IP Control Panel and set:
    • 'Connect via:' to EtherNet, and
    • 'Configure:' to 'Using DHCP Server'
  4. Restart the emulation.
You should now be able to surf the web, or FTP download software, in the emulated Mac. Not sure about AppleTalk networking, though.

Note that this does not require the OS X Mac to be using EtherNet, any working TCP/IP networking should be fine. I have tested it over DHCP EtherNet (ADSL modem/router at home), and with a static IP address at work (which also has an external web proxy/firewall).


$Id: HowTo.html,v 1.6 2006/01/16 23:07:22 nigel Exp $
Written by Nigel Pearson on 26th March, 2003. BasiliskII/src/MacOSX/Multiple-Windows/0000755000175000017500000000000011735674761020066 5ustar centriscentrisBasiliskII/src/MacOSX/Multiple-Windows/README0000644000175000017500000000053107444541571020737 0ustar centriscentrisThis is a version of the interface that would allow multiple emulations to run side-by-side, in different windows. Currently, the uae_cpu engine is not re-entrant, and some of the Basilisk glue would not allow this, so this will probably never be used. I will save it here for educational purposes, and just in case this feature is ever needed. BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/0000755000175000017500000000000011735675027022600 5ustar centriscentrisBasiliskII/src/MacOSX/Multiple-Windows/English.lproj/InfoPlist.strings0000755000175000017500000000031007444541571026115 0ustar centriscentris/* Localized versions of Info.plist keys */ CFBundleName = "BasiliskII"; NSHumanReadableCopyright = "Copyright 1997-2001 Christian Bauer et al., Freely distributable under the terms of the GNU GPL"; BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/0000755000175000017500000000000011735675027024755 5ustar centriscentrisBasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/Collapsed.tiff0000644000175000017500000000154607444541575027545 0ustar centriscentrisMM*¬=”Ž"¿¿ªn¿¿¿¿®O¿¿¿¿¿¿Ÿ3 ¿¿¿¿¿¿¿¹…¿¿¿¿¿¿Ÿ3 ¿¿¿¿®O¿¿ªn”Ž"=   N¤V^(R ü€' ü€'BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/Expanded.tiff0000644000175000017500000000154607444541575027367 0ustar centriscentrisMM*¬=”¿¿¿¿¿¿¿”=Ž¿¿¿¿¿¿¿Ž"ª¿¿¿¿¿ª"n¿¿¿¿¿n®¿¿¿®O¿¿¿OŸ¿Ÿ3¹3 …   N¤V^(R ü€' ü€'BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/resetH.tiff0000644000175000017500000002310607444541600027052 0ustar centriscentrisMM*%Œ6k *™HÀ&iÝ)5ˆó/<˜þ*7Šó )lÝJÀ +™k6"n :µ#1õ>R­ÿ[oÇÿuŠÛÿ‹åÿ—¨ëÿœ¯íÿ˜ªìÿŽ¢çÿ{ÞÿbvÎÿEYµÿ(8Œõ >µn"tLÊ.CœÿNiÁÿu‘ãÿ›µõÿ»ÑÿÿÐâÿÿÜìÿÿãñÿÿæòÿÿäñÿÿàîÿÿÔæÿÿÂ×ÿÿ¥¾ùÿœëÿVsÍÿ4L§ÿPÊtO 5²!9ÿ@_¹ÿgŠÞÿ°øÿ¬Ìÿÿ¿ÛÿÿËåÿÿÒéÿÿÔëÿÿÖëÿÿÖëÿÿ×ëÿÿ×ëÿÿÖëÿÿÑéÿÿÆáÿÿ³Óÿÿ”¹ÿÿo”éÿGjÆÿ&B›ÿ 9²O r YÞ&F›ÿBj¿ÿcŽÝÿ}¨ïÿ¹ùÿœÅûÿ¡Éûÿ¢Ëùÿ¢É÷ÿ¡Èõÿ Çõÿ Çôÿ Èôÿ£Éõÿ¥Ë÷ÿ¦Ìùÿ¥Íûÿ¡Éýÿ”Àýÿƒ°öÿi—æÿHsËÿ,P¨ÿ$aÞr   …/vö&L¡ÿ>k¼ÿS„Ðÿd—Þÿn¢åÿs¨æÿuªæÿuªãÿs¨ßÿq¦Ýÿr¥Üÿq¤Úÿq¤Úÿq¤Úÿr¥Üÿt§Þÿv¨àÿx¬ãÿx¬èÿv¬éÿr§éÿhäÿWŒ×ÿCsÄÿ,Uªÿ5ö …   †1}þ!Kžÿ3c³ÿCxÃÿO‡ÍÿW‘Ôÿ[–Õÿ]™Õÿ_˜Óÿa˜Òÿc™Ñÿe™ÑÿfšÑÿg›Ñÿg›Ñÿg›ÑÿfšÑÿf›ÑÿešÒÿcšÓÿb™Ôÿ`™Öÿ^™ØÿZ•×ÿSÒÿGÈÿ7k¹ÿ&T§ÿ8ˆþ †  v1uöJ›ÿ)_¬ÿ5o·ÿ?}ÂÿF†ÈÿO‹ËÿVÍÿ[”Îÿ^–Ïÿc™ÑÿgœÒÿjžÔÿmŸÔÿn Õÿn Õÿn ÕÿmŸÔÿkŸÔÿiœÔÿešÒÿa—Ðÿ\”ÏÿX’ÎÿRŽÌÿJŠÊÿB‚Æÿ8u¼ÿ-e±ÿQ¢ÿ7€öv   U #XßH—ÿZ§ÿ*i²ÿ4u»ÿA€ÂÿJˆÇÿSŽËÿZ“Îÿa˜Ñÿg›ÓÿlŸÕÿp¢×ÿr¥Ùÿu§Úÿv§Ûÿv§Ûÿv§Ûÿv§Úÿs¦Ùÿq¤×ÿm¡ÖÿhÓÿc™Òÿ\•ÐÿUÌÿN‰ÈÿEƒÅÿ9z¾ÿ-nµÿ#_ªÿOžÿ )aß U  #5·BÿV£ÿ"d­ÿ/q·ÿ<|ÀÿH…ÆÿRËÿ\”ÐÿcšÔÿjŸÖÿn¢Øÿs¦Úÿw©Ûÿy«Ýÿ|¬Þÿ}¬Þÿ}­Þÿ}­Þÿ}¬Þÿz«Ýÿx©Üÿu¨Ûÿk’¸ÿ]p„ÿeœÔÿ^—ÒÿWÍÿLˆÉÿA€Ãÿ4v»ÿ%h±ÿZ¨ÿJšÿ;·# ~ <„ÿQ ÿ`¬ÿ)mµÿ9z½ÿF…ÆÿQŽÌÿ[•ÑÿdœÕÿk¡Øÿq¥Ûÿu¨Üÿz«Þÿ}­Þÿ¯àÿ°àÿ‚°àÿ‚±àÿ‚±àÿ°àÿ€¯àÿz¢ÌÿhuƒÿXXXÿLU_ÿl¡×ÿhÕÿ_—ÓÿU‘ÏÿJˆÉÿ>Áÿ.q¹ÿ d°ÿW§ÿD’ÿ ~ 1 JÐ K™ÿ]ªÿ&kµÿ5w¾ÿDƒÇÿPÍÿZ•Òÿcœ×ÿk£Úÿq§ÜÿwªÞÿ{«ßÿ®àÿ‚±áÿ„²áÿ…³áÿ†´áÿ†´áÿ†´áÿ‚®×ÿpƒ–ÿ[\]ÿLLLÿ>>>ÿDLUÿq¤Øÿm£ÙÿfžØÿ^˜ÔÿSÏÿH‡Èÿ:|Áÿ,p¸ÿa­ÿR¢ÿ%SÐ1 | @‰ÿW§ÿf±ÿ1u¼ÿ?€ÅÿLŒÍÿW”Óÿb›Øÿj¢Ûÿq§ÝÿwªÞÿ|­ßÿ¯áÿ‚±áÿ…²áÿˆ´âÿ‰µâÿеâÿˆ³Ýÿv¤ÿ^acÿPPPÿBBBÿ:::ÿ999ÿCKSÿs£Ôÿq¥Ùÿl£ÜÿeØÿ[–ÔÿQÏÿD…Èÿ6yÀÿ%kµÿ]«ÿ I—ÿ | ;¿ O›ÿa¯ÿ*o¹ÿ:}ÄÿGˆÍÿU“Óÿ_›Øÿh¡Üÿo¦Þÿv«ßÿ|­àÿ€¯áÿƒ±áÿ†´áÿˆµâÿжãÿ‹·ãÿ{–±ÿchlÿRRRÿBBBÿ999ÿ999ÿ999ÿ999ÿCJQÿs Îÿu¨Úÿr¨ßÿk¢ÝÿbœÚÿY–ÕÿLŒÐÿ?Èÿ0t¾ÿ f³ÿV¦ÿ D¿ M;y÷Z§ÿ#j¶ÿ3xÁÿC…ÌÿPÓÿ\™ÙÿeŸÝÿm¦ßÿtªáÿ{­áÿ¯áÿƒ²áÿ†´âÿ‰¶ãÿ‹·ãÿ ÀÿgowÿUUUÿEEEÿ999ÿ999ÿBGLÿc€œÿ999ÿ999ÿBIPÿt Îÿx©Úÿw«áÿo§ßÿh¡Ýÿ_›ÚÿS“ÕÿG‰Ïÿ9}Åÿ)o»ÿ`¯ÿD‰÷M  € K“ÿc°ÿ,r¾ÿ;€ÈÿJŒÒÿV•ØÿažÝÿj¤àÿrªáÿy­âÿ¯ãÿƒ²ãÿ…¶äÿ‰·åÿ„§Íÿmy…ÿWWWÿIIIÿ999ÿ999ÿ>@Cÿd{”ÿlŒ­ÿeƒ¢ÿ999ÿ999ÿBIPÿw¢Íÿ|ªÝÿ{®ãÿt«âÿl¦àÿd Þÿ[™ÚÿOÔÿ@…Ìÿ1wÂÿ!h¶ÿV¢ÿ €  /«U ÿ#k¹ÿ3yÄÿA‡ÏÿP’Øÿ\›Ýÿg£àÿo¨âÿv¬äÿ|°åÿ³åÿ…µæÿƒ®Øÿq‚“ÿZZZÿLLLÿ999ÿ999ÿ999ÿ_rˆÿp°ÿnŒ¬ÿl‹ªÿg†¤ÿ999ÿ999ÿCIPÿz¤Ïÿ®ßÿ~±äÿx­äÿqªãÿj¥àÿ`žßÿV–ÚÿH‹Óÿ:€Éÿ)p½ÿ_¬ÿ5« &'LÍ_ªÿ+s¿ÿ;ÌÿIÕÿV˜Üÿa áÿk§ãÿs«åÿz¯çÿ€²èÿ‚±àÿsŠ¡ÿ^_aÿOOOÿ:::ÿ999ÿ999ÿWgwÿq®ÿp®ÿp®ÿt”³ÿu•¶ÿpޝÿ999ÿ999ÿCJPÿ|¦Òÿ‚±áÿ‚´èÿ|°çÿu­æÿn©ãÿe£âÿZ›ßÿN’Ùÿ@†Ïÿ0xÄÿ hµÿ -VÍ& , 9lå g³ÿ2zÇÿA‡ÒÿO“Ûÿ\žáÿg¥äÿpªçÿv®èÿ|°æÿt‘±ÿ`dgÿQQQÿ>>>ÿ999ÿ999ÿNZfÿpŽ­ÿq¯ÿr®ÿu”³ÿ{œ¼ÿ‚¤Çÿƒ¦Êÿ{Àÿ999ÿ999ÿCJPÿ¨Óÿ„³ãÿ…·ëÿ³êÿy°éÿr¬çÿj§åÿ`¡ãÿT—ÞÿFŒÖÿ8Ëÿ'n½ÿBwå,  1J‡ö&m¹ÿ7ÌÿFŒØÿT˜ßÿa£åÿk©èÿt®êÿq—½ÿdksÿSSSÿCCCÿ999ÿ999ÿGNVÿl‰¦ÿr’²ÿr’±ÿu•´ÿ{›½ÿ‚¥Èÿ‰®Óÿ¶Ýÿ޵Ûÿ¥Éÿ999ÿ999ÿDJQÿ«×ÿ‡µæÿ‡ºíÿƒ·íÿ|³ìÿv®ëÿn«éÿe¦çÿZ›âÿL‘Ûÿ=„Ðÿ,tÃÿS•ö1 5T˜þ+rÀÿ<„ÒÿK’ÝÿYäÿf¦êÿn¬íÿTm†ÿ999ÿ999ÿ999ÿ999ÿ@DHÿh„ ÿr”¶ÿr’´ÿu•¶ÿy›¾ÿ‚¥ÉÿНÕÿ‘·Þÿ–½çÿ™Áìÿ”½æÿ†«Ñÿ999ÿ999ÿDKRÿ…®Ùÿ‹¸éÿмñÿ†ºðÿ€·ðÿz³ïÿq®íÿi©ëÿ^¡çÿP–áÿAŠ×ÿ1{Èÿ`©þ5!8QŽö0wÄÿ@‰ÖÿP–áÿ\¡èÿh¨ëÿp®íÿv¯êÿc‡¬ÿBIPÿ999ÿ999ÿGGGÿWWWÿelsÿu’°ÿ€¤Éÿ‰¯Õÿ¸àÿ—¿éÿ›ÃîÿžÆòÿÇóÿ—¿êÿˆ­Óÿ999ÿ999ÿEKRÿ…±ÜÿŒ»ìÿÀõÿˆ½ôÿ„ºóÿ}·òÿu²ñÿm¬îÿa¤êÿTšäÿEŽÛÿ7Íÿ \žö8!":Eyç2zÆÿDÚÿR›åÿ`¥ìÿk¬ïÿr°îÿu¬çÿt¥ØÿošÆÿWn…ÿ=?Bÿ999ÿ999ÿJJJÿYYYÿq~Œÿ”ºàÿÅðÿ Éõÿ Ëöÿ¡Ë÷ÿ¡Ë÷ÿ™ÃíÿНÖÿ999ÿ999ÿELRÿˆ³àÿ¿ïÿÄ÷ÿ‹Á÷ÿ†½öÿºöÿx¶õÿo¯òÿe¨îÿWžçÿI’Þÿ:ƒÑÿP‡ç:"":6[Ó5|ÈÿGÞÿUéÿc¨ðÿm°óÿt±ðÿu­åÿr£Õÿl™Åÿi¸ÿfˆ¬ÿRbtÿ;<>ÿ999ÿ999ÿNNNÿ[[[ÿ•«ÿ£Îúÿ¤Ðýÿ¤Ðýÿ¤ÐýÿžÈóÿ³Ûÿ999ÿ999ÿELSÿ‹·åÿ’Ãõÿ“ÇýÿŽÅýÿˆÁüÿ‚¾ûÿ{¹ùÿr´÷ÿh¬óÿ\¢ìÿL–ãÿ=†Ôÿ>hÓ:"": $=¹7|ÆÿI“áÿX¢íÿf¬ôÿq³øÿx¶÷ÿ{³ïÿw¬àÿu¢ÐÿqšÂÿo”¹ÿq•¸ÿo‘¯ÿTbpÿ999ÿ999ÿ===ÿQQQÿ`bcÿ­Éÿ¨Ôþÿ§Ôÿÿ Ìõÿ¸Ýÿ999ÿ999ÿFMTÿ޽æÿ•Ç÷ÿ–Ëÿÿ’Èÿÿ‹Åÿÿ…Âÿÿ~¼þÿv·úÿj¯öÿ^¦ðÿO™æÿ@ˆÖÿ*F¹:"!8!˜6x¿ÿL•ãÿZ¤ïÿh¯÷ÿt·ýÿ}»üÿ‚½÷ÿ‚»ïÿ‚´ãÿ€¯×ÿ|¦Ëÿy¡Âÿyž¾ÿ| Àÿu”­ÿPZcÿ999ÿ999ÿCCCÿTTTÿhmqÿš¾Ûÿ£Ðõÿ“»Ýÿ999ÿ999ÿFMTÿ¿æÿ—Ë÷ÿ™Ðÿÿ•ÍÿÿŽÉÿÿ‡Åÿÿ€Àÿÿyºþÿm²úÿ`¨óÿRœéÿ?‡Óÿ &˜8!5 r/h§øL•âÿ]¦ðÿi±ûÿvºÿÿÀÿÿ†ÄýÿŒÇúÿŽÆôÿÃìÿ‹¼áÿ‡´Õÿƒ«Éÿ¥Áÿ¤¾ÿ§Áÿr¡ÿFLPÿ999ÿ999ÿGGGÿWWWÿoy€ÿ³ÎÿGGGÿ999ÿGNTÿ”Äæÿ›Ï÷ÿ›Ôÿÿ—Ñÿÿ‘ÌÿÿŠÈÿÿƒÄÿÿz½ÿÿo´üÿb©õÿSêÿ9y½ø r5 1L:\ÐK‘Üÿ]§óÿj²üÿw¼ÿÿ€Ãÿÿ‰ÉÿÿÏÿÿ–Ñýÿ˜ÑùÿšÏóÿ˜Ëêÿ”Âßÿ¹Óÿˆ°Çÿ„©Àÿ„©¾ÿ…ª¿ÿj€Žÿ@CEÿ999ÿ999ÿJJJÿLLLÿHHHÿ999ÿGOTÿ˜ÇæÿŸÔ÷ÿžØÿÿ™Õÿÿ“ÐÿÿËÿÿ„Çÿÿ|Àÿÿo¶þÿb¬øÿTéÿ DjÐL1  ,F &¡F‰Îÿ]§õÿj³þÿw¾ÿÿ‚Æÿÿ‹Íÿÿ’Óÿÿ™×ÿÿžÚþÿ¤Üýÿ¥Ûøÿ£×òÿžÏèÿ™ÈÝÿ’¼Ðÿ´Æÿ‰®¿ÿˆ®¿ÿ‡«¼ÿdw€ÿ<>?ÿ999ÿ999ÿ999ÿ999ÿHPTÿ™Êæÿ¡×÷ÿ¡Üÿÿ›Ùÿÿ•ÔÿÿŽÏÿÿ…Èÿÿ|Âÿÿp·ÿÿc­úÿP˜âÿ +¡F, &?k)R{ÝZ£îÿk´ÿÿw¿ÿÿ‚ÇÿÿŒÏÿÿ”Öÿÿ›Ûÿÿ¡ßÿÿ§âÿÿ«äþÿ­äüÿ«â÷ÿªÝðÿ¥ÖæÿžËÚÿ•ÀÎÿ·Äÿ‹²¿ÿ‹²¿ÿ†«·ÿZkpÿ999ÿ999ÿ999ÿHPTÿœÏæÿ¤Û÷ÿ£àÿÿÝÿÿ–×ÿÿÒÿÿ†Ëÿÿ|Ãÿÿp¸ÿÿb­úÿ0[‰Ýk?& 6Q-§Q”Øÿi³þÿxÀÿÿ‚ÉÿÿŒÐÿÿ•×ÿÿœÞÿÿ¢âÿÿ©æÿÿ­éÿÿ±ìÿÿ´îþÿµíûÿ²éöÿ¯äîÿ©ÚäÿŸÎ×ÿ–ÂËÿºÂÿŒ¶¾ÿ‹´¼ÿy›¢ÿMX[ÿ999ÿIQTÿÔæÿ¥á÷ÿ¤ãÿÿžßÿÿ˜ÛÿÿÓÿÿ†Íÿÿ|Äÿÿo¹ÿÿ\¤îÿ"3§Q6  -Fk$CcÍb©ðÿu¿ÿÿ€ÉÿÿŒÒÿÿ•Ùÿÿàÿÿ¤åÿÿªëÿÿ¯îÿÿ³ñÿÿ·óÿÿºöÿÿ»õþÿºóúÿ¹ïõÿ³çìÿªÝáÿ¡ÑÕÿ˜ÅÉÿŽº¿ÿˆ²¸ÿƒ­³ÿq‘—ÿYkoÿ Øæÿ§ä÷ÿ¦çÿÿ ãÿÿ˜ÝÿÿÕÿÿ†Íÿÿ{Äÿÿk´ûÿ*MpÍkF- $;T@q¢ép¹úÿ~ÈÿÿŠÑÿÿ“Ùÿÿœáÿÿ£èÿÿªìÿÿ°ñÿÿ¶ôÿÿ¹öÿÿ½úÿÿ¿üÿÿÁýÿÿÁüýÿ¿ùùÿ»óóÿ´êêÿ«ßßÿŸÑÒÿ”ÄÆÿº½ÿŒºÀÿ•ÈÐÿ¢Üèÿ¨ç÷ÿ¦éÿÿŸãÿÿ—ÝÿÿŽÕÿÿ„ÌÿÿwÁÿÿI~²é T;$ /G_ /¥X˜ÐùzÂýÿ‡Ðÿÿ‘Øÿÿšàÿÿ£çÿÿªíÿÿ°òÿÿ¶÷ÿÿºúÿÿ½þÿÿÀÿÿÿÃÿÿÿÆÿÿÿÄþþÿÄýýÿÁøøÿ»òòÿ²èèÿ§ÝÝÿœÐÑÿ™ÎÐÿÔÙÿ¤âëÿ¨êùÿ¥êÿÿžãÿÿ•ÜÿÿŒÔÿÿ€Éÿÿe¥àù%5¥_G/ #8Pf+>°f¦ßþÉýÿŽ×ÿÿ—àÿÿ¡çÿÿ¨îÿÿ®óÿÿ´øÿÿ¹ýÿÿ½ÿÿÿÀÿÿÿÃÿÿÿÅÿÿÿÅÿÿÿÆÿÿÿÅþþÿÃüüÿ¾÷÷ÿ·ððÿ­èèÿ§ãäÿ¥âçÿ¨éòÿ§ëúÿ£êÿÿœãÿÿ’Ûÿÿ‡Ðÿÿq¶íþ1C°fP8# +@Wf->°f¢Òù…Îýÿ”Ýÿÿžæÿÿ¦íÿÿ®óÿÿ³ùÿÿ¸ýÿÿ¼ÿÿÿÀÿÿÿÃÿÿÿÄÿÿÿÆÿÿÿÆÿÿÿÆÿÿÿÆÿÿÿÃþþÿ¾ûûÿ¸÷÷ÿ²ôôÿ®ïôÿ«ðùÿ¨îýÿ¡éÿÿ˜áÿÿÖÿÿq°ßù2C°fW@+ 0F\f%2¥Tƒ§é‡Îöÿ—áÿÿ¡êÿÿ¨ñÿÿ¯öÿÿµüÿÿºÿÿÿ¾ÿÿÿÀÿÿÿÃÿÿÿÄÿÿÿÅÿÿÿÄÿÿÿÄÿÿÿÁÿÿÿ¿ÿÿÿºþþÿµüýÿ°öüÿ«ñýÿ¤ìþÿœæÿÿŽÖûÿ]²é)6¥f\F0 "4H]f 8WlÍ‚Æêÿ—áýÿ¢íÿÿªóÿÿ°ùÿÿµþÿÿºÿÿÿ¼ÿÿÿ¾ÿÿÿÀÿÿÿÀÿÿÿÀÿÿÿ¿ÿÿÿ½ÿÿÿºÿÿÿ¶ÿÿÿ²üÿÿ¬öÿÿ¦ïÿÿœæÿÿŠÑóÿ=^rÍf]H4"  $5H\fp,7§NuŒÝ‹Ïëÿœäúÿ§ñÿÿ®øÿÿ²ýÿÿ¶ÿÿÿ¸ÿÿÿºÿÿÿ¹ÿÿÿ¹ÿÿÿ¹ÿÿÿ¶ÿÿÿ³þÿÿ¯ûÿÿªôÿÿ¢ëüÿ“ÙòÿT}’Ý0:§pf\H5$  $4FWffv)1¤BdsÐ¼Ðø˜Ýïÿ¢ëøÿ¨ôüÿ®øþÿ°ûþÿ±üÿÿ±ûÿÿ®ùþÿ«õýÿ¥îúÿœãòÿ†ÄÕøGjwÐ-4¤ vffWF4$  "0@P_fff ƒ*/£5NW¿Px‚×mž«éƒ¿Î÷Ñßþ„ÁÏ÷o¡­éTz…×7QY¿,1£ ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/resetN.tiff0000644000175000017500000002310607444541601027061 0ustar centriscentrisMM*%Œ6k$$$™===ÀZZZÝttt󃃃þvvvó\\\Ý@@@À%%%™k6"n666µzzzõ   ÿ½½½ÿÑÑÑÿÜÜÜÿäääÿæææÿåååÿßßßÿÕÕÕÿÄÄÄÿ¨¨¨ÿƒƒƒõ:::µn"tDDDÊŽŽŽÿºººÿÝÝÝÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿæææÿÅÅÅÿšššÿKKKÊtO...²ÿ¨¨¨ÿÊÊÊÿéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿÔÔÔÿ´´´ÿŽŽŽÿ222²O rSSSÞÿµµµÿÑÑÑÿãããÿïïïÿôôôÿôôôÿóóóÿñññÿïïïÿíííÿíííÿíííÿîîîÿñññÿóóóÿöööÿ÷÷÷ÿôôôÿêêêÿÚÚÚÿ¿¿¿ÿšššÿ\\\Þr  …mmmö–––ÿ¯¯¯ÿÅÅÅÿÓÓÓÿÚÚÚÿÝÝÝÿÜÜÜÿÚÚÚÿ×××ÿÔÔÔÿÓÓÓÿÒÒÒÿÑÑÑÿÒÒÒÿÓÓÓÿÔÔÔÿ×××ÿÚÚÚÿÝÝÝÿàààÿßßßÿÙÙÙÿÌÌÌÿ¶¶¶ÿ   ÿwwwö…  †pppþ‘‘‘ÿ§§§ÿ¶¶¶ÿÃÃÃÿÊÊÊÿÍÍÍÿÌÌÌÿËËËÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÉÉÉÿÊÊÊÿÊÊÊÿËËËÿÌÌÌÿÎÎÎÿÏÏÏÿÎÎÎÿÈÈÈÿ¼¼¼ÿ­­­ÿšššÿ{{{þ†  vmmmöŽŽŽÿ¡¡¡ÿ®®®ÿ¶¶¶ÿ¾¾¾ÿÁÁÁÿÄÄÄÿÆÆÆÿÇÇÇÿÈÈÈÿËËËÿÌÌÌÿÍÍÍÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿÍÍÍÿËËËÿÉÉÉÿÈÈÈÿÆÆÆÿÅÅÅÿÃÃÃÿÁÁÁÿ»»»ÿ²²²ÿ¦¦¦ÿ•••ÿvvvöv  USSSßÿ›››ÿ¨¨¨ÿ±±±ÿ···ÿ¼¼¼ÿÁÁÁÿÅÅÅÿÈÈÈÿËËËÿÎÎÎÿÐÐÐÿÒÒÒÿÒÒÒÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿÒÒÒÿÑÑÑÿÏÏÏÿÌÌÌÿÊÊÊÿÆÆÆÿÃÃÃÿ¿¿¿ÿºººÿ´´´ÿ«««ÿŸŸŸÿ”””ÿ[[[ßU  "///·„„„ÿ˜˜˜ÿ¡¡¡ÿ­­­ÿµµµÿ¼¼¼ÿÁÁÁÿÇÇÇÿÊÊÊÿÎÎÎÿÑÑÑÿÓÓÓÿÔÔÔÿÕÕÕÿÕÕÕÿÖÖÖÿ×××ÿ×××ÿÖÖÖÿÕÕÕÿÔÔÔÿÓÓÓÿ²²²ÿÿËËËÿÈÈÈÿÄÄÄÿ½½½ÿ¸¸¸ÿ°°°ÿ¥¥¥ÿ›››ÿŽŽŽÿ555·# ~yyyÿ–––ÿ¢¢¢ÿªªªÿµµµÿ½½½ÿÃÃÃÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÕÕÕÿÖÖÖÿ×××ÿØØØÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿØØØÿÆÆÆÿÿXXXÿ^^^ÿÏÏÏÿÍÍÍÿÊÊÊÿÅÅÅÿ¿¿¿ÿ¸¸¸ÿ­­­ÿ¥¥¥ÿšššÿ†††ÿ~ 1FFFÐŒŒŒÿŸŸŸÿ©©©ÿ³³³ÿ¼¼¼ÿÄÄÄÿÉÉÉÿÎÎÎÿÒÒÒÿÓÓÓÿÕÕÕÿ×××ÿØØØÿÚÚÚÿÚÚÚÿÚÚÚÿÛÛÛÿÛÛÛÿÛÛÛÿÑÑÑÿ“““ÿ\\\ÿLLLÿ>>>ÿTTTÿÏÏÏÿÐÐÐÿÐÐÐÿËËËÿÆÆÆÿ¿¿¿ÿ¶¶¶ÿ®®®ÿ¢¢¢ÿ”””ÿOOOÐ1 |ÿ˜˜˜ÿ¥¥¥ÿ°°°ÿ¹¹¹ÿÃÃÃÿÉÉÉÿÎÎÎÿÒÒÒÿÕÕÕÿÖÖÖÿØØØÿÙÙÙÿÚÚÚÿÛÛÛÿÜÜÜÿÜÜÜÿÜÜÜÿ×××ÿ¡¡¡ÿcccÿPPPÿBBBÿ:::ÿ999ÿRRRÿËËËÿÑÑÑÿÓÓÓÿÐÐÐÿËËËÿÅÅÅÿ¾¾¾ÿµµµÿ©©©ÿœœœÿŒŒŒÿ| 888¿’’’ÿ¡¡¡ÿ®®®ÿ¹¹¹ÿÁÁÁÿÉÉÉÿÐÐÐÿÓÓÓÿÖÖÖÿ×××ÿØØØÿÚÚÚÿÛÛÛÿÜÜÜÿÜÜÜÿÝÝÝÿÝÝÝÿ­­­ÿlllÿRRRÿBBBÿ999ÿ999ÿ999ÿ999ÿPPPÿÈÈÈÿÓÓÓÿÖÖÖÿÔÔÔÿÑÑÑÿÌÌÌÿÅÅÅÿ½½½ÿ³³³ÿ¦¦¦ÿšššÿ???¿ Msss÷ÿ©©©ÿ···ÿÁÁÁÿÈÈÈÿÏÏÏÿÓÓÓÿÖÖÖÿÙÙÙÿÚÚÚÿÛÛÛÿÜÜÜÿÜÜÜÿÝÝÝÿÝÝÝÿ»»»ÿvvvÿUUUÿEEEÿ999ÿ999ÿKKKÿ˜˜˜ÿ999ÿ999ÿOOOÿÇÇÇÿÓÓÓÿÙÙÙÿ×××ÿÔÔÔÿÑÑÑÿËËËÿÅÅÅÿºººÿ®®®ÿ£££ÿ÷M €‰‰‰ÿ¥¥¥ÿ±±±ÿ½½½ÿÇÇÇÿÎÎÎÿÓÓÓÿÖÖÖÿØØØÿÛÛÛÿÜÜÜÿÝÝÝÿÞÞÞÿÞÞÞÿÇÇÇÿƒƒƒÿWWWÿIIIÿ999ÿ999ÿBBBÿÿ¨¨¨ÿÿ999ÿ999ÿOOOÿÇÇÇÿÖÖÖÿÛÛÛÿÙÙÙÿ×××ÿÕÕÕÿÐÐÐÿËËËÿÂÂÂÿµµµÿ«««ÿ–––ÿ€  ***«———ÿ®®®ÿ¹¹¹ÿÅÅÅÿÎÎÎÿÓÓÓÿ×××ÿÚÚÚÿÜÜÜÿÝÝÝÿÞÞÞÿÞÞÞÿÒÒÒÿ‘‘‘ÿZZZÿLLLÿ999ÿ999ÿ999ÿ„„„ÿªªªÿ§§§ÿ¦¦¦ÿ   ÿ999ÿ999ÿOOOÿÉÉÉÿØØØÿÞÞÞÿÜÜÜÿÛÛÛÿÙÙÙÿÕÕÕÿÑÑÑÿÉÉÉÿ½½½ÿ³³³ÿ¢¢¢ÿ///« &EEEÍ¡¡¡ÿµµµÿ¿¿¿ÿÊÊÊÿÒÒÒÿÖÖÖÿÜÜÜÿÝÝÝÿÞÞÞÿàààÿÙÙÙÿÿaaaÿOOOÿ:::ÿ999ÿ999ÿuuuÿªªªÿ©©©ÿ©©©ÿ¯¯¯ÿ±±±ÿ«««ÿ999ÿ999ÿOOOÿËËËÿÙÙÙÿßßßÿÞÞÞÿÞÞÞÿÜÜÜÿÙÙÙÿÕÕÕÿÎÎÎÿÄÄÄÿºººÿ«««ÿOOOÍ& ,aaa娨¨ÿºººÿÅÅÅÿÐÐÐÿÖÖÖÿÚÚÚÿÞÞÞÿàààÿÝÝÝÿ«««ÿgggÿQQQÿ>>>ÿ999ÿ999ÿcccÿ¨¨¨ÿ«««ÿªªªÿ®®®ÿ···ÿÂÂÂÿÅÅÅÿºººÿ999ÿ999ÿPPPÿÍÍÍÿÛÛÛÿâââÿáááÿàààÿßßßÿÜÜÜÿØØØÿÓÓÓÿÊÊÊÿÀÀÀÿ±±±ÿnnnå,  1{{{ö¯¯¯ÿÁÁÁÿÌÌÌÿÕÕÕÿÛÛÛÿßßßÿâââÿ¸¸¸ÿrrrÿSSSÿCCCÿ999ÿ999ÿUUUÿ£££ÿ¯¯¯ÿ­­­ÿ±±±ÿ¹¹¹ÿÄÄÄÿÏÏÏÿÙÙÙÿ×××ÿÅÅÅÿ999ÿ999ÿPPPÿÏÏÏÿßßßÿæææÿåååÿãããÿãããÿàààÿÝÝÝÿØØØÿÏÏÏÿÆÆÆÿ¸¸¸ÿ‰‰‰ö1 5‰‰‰þ´´´ÿÆÆÆÿÐÐÐÿÚÚÚÿàààÿâââÿƒƒƒÿ999ÿ999ÿ999ÿ999ÿHHHÿœœœÿ±±±ÿ¯¯¯ÿ²²²ÿ¹¹¹ÿÄÄÄÿÎÎÎÿÙÙÙÿàààÿæææÿàààÿËËËÿ999ÿ999ÿPPPÿÒÒÒÿâââÿéééÿèèèÿçççÿæææÿäääÿàààÿÝÝÝÿÔÔÔÿËËËÿ½½½ÿšššþ5!8‚‚‚ö¹¹¹ÿËËËÿÕÕÕÿÞÞÞÿáááÿãããÿâââÿ¦¦¦ÿOOOÿ999ÿ999ÿGGGÿWWWÿrrrÿ­­­ÿÄÄÄÿÐÐÐÿÙÙÙÿâââÿçççÿëëëÿìììÿåååÿÎÎÎÿ999ÿ999ÿQQQÿÕÕÕÿåååÿìììÿëëëÿëëëÿêêêÿèèèÿäääÿàààÿØØØÿÐÐÐÿÂÂÂÿ‘‘‘ö8!":nnnç¼¼¼ÿÐÐÐÿÚÚÚÿâââÿæææÿåååÿÞÞÞÿÑÑÑÿÀÀÀÿ‚‚‚ÿBBBÿ999ÿ999ÿJJJÿYYYÿŠŠŠÿÜÜÜÿëëëÿðððÿñññÿòòòÿòòòÿéééÿÑÑÑÿ999ÿ999ÿRRRÿÚÚÚÿéééÿñññÿïïïÿïïïÿîîîÿìììÿéééÿäääÿÝÝÝÿÔÔÔÿÆÆÆÿ}}}ç:"":TTTÓ½½½ÿÓÓÓÿÝÝÝÿåååÿéééÿçççÿÝÝÝÿÍÍÍÿ¾¾¾ÿ²²²ÿ§§§ÿqqqÿ>>>ÿ999ÿ999ÿNNNÿ[[[ÿ§§§ÿóóóÿöööÿöööÿöööÿìììÿÕÕÕÿ999ÿ999ÿRRRÿÝÝÝÿíííÿõõõÿôôôÿòòòÿñññÿïïïÿìììÿèèèÿàààÿ×××ÿÉÉÉÿ```Ó:"":777¹¼¼¼ÿÖÖÖÿàààÿéééÿîîîÿìììÿçççÿÙÙÙÿÊÊÊÿ½½½ÿµµµÿµµµÿ­­­ÿoooÿ999ÿ999ÿ===ÿQQQÿcccÿÇÇÇÿúúúÿûûûÿñññÿÚÚÚÿ999ÿ999ÿSSSÿâââÿòòòÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿóóóÿñññÿìììÿäääÿÜÜÜÿÊÊÊÿ@@@¹:"!8˜¶¶¶ÿÙÙÙÿãããÿíííÿòòòÿôôôÿñññÿëëëÿâââÿÖÖÖÿËËËÿÂÂÂÿ¾¾¾ÿÀÀÀÿ­­­ÿcccÿ999ÿ999ÿCCCÿTTTÿqqqÿÛÛÛÿõõõÿÝÝÝÿ999ÿ999ÿTTTÿæææÿ÷÷÷ÿþþþÿýýýÿüüüÿúúúÿøøøÿõõõÿðððÿçççÿßßßÿÈÈÈÿ###˜8!5 r¡¡¡øÙÙÙÿåååÿðððÿöööÿùùùÿüüüÿúúúÿôôôÿìììÿáááÿÕÕÕÿÉÉÉÿÁÁÁÿ¾¾¾ÿÁÁÁÿ¡¡¡ÿPPPÿ999ÿ999ÿGGGÿWWWÿ€€€ÿÎÎÎÿGGGÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿøøøÿòòòÿéééÿàààÿ³³³ø r5 1LYYYÐÕÕÕÿæææÿòòòÿúúúÿþþþÿÿÿÿÿÿÿÿÿýýýÿùùùÿóóóÿêêêÿßßßÿÓÓÓÿÇÇÇÿÀÀÀÿ¾¾¾ÿ¿¿¿ÿŽŽŽÿEEEÿ999ÿ999ÿJJJÿLLLÿHHHÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿõõõÿëëëÿßßßÿfffÐL1  ,F$$$¡ÆÆÆÿåååÿôôôÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿøøøÿòòòÿèèèÿÝÝÝÿÐÐÐÿÆÆÆÿ¿¿¿ÿ¿¿¿ÿ¼¼¼ÿ€€€ÿ???ÿ999ÿ999ÿ999ÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿëëëÿØØØÿ***¡F, &?kwwwÝàààÿôôôÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿ÷÷÷ÿðððÿæææÿÚÚÚÿÎÎÎÿÄÄÄÿ¿¿¿ÿ¿¿¿ÿ···ÿpppÿ999ÿ999ÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿêêêÿ‡‡‡Ýk?& 6Q+++§ÌÌÌÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿöööÿîîîÿäääÿ×××ÿËËËÿÂÂÂÿ¾¾¾ÿ¼¼¼ÿ¢¢¢ÿ[[[ÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿàààÿ111§Q6  -Fk\\\ÍçççÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿúúúÿõõõÿìììÿáááÿÕÕÕÿÉÉÉÿ¿¿¿ÿ¸¸¸ÿ³³³ÿ———ÿoooÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿiiiÍkF- $;TžžžéúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿóóóÿêêêÿßßßÿÒÒÒÿÆÆÆÿ½½½ÿÀÀÀÿÐÐÐÿèèèÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°éT;$ /G_,,,¥ÏÏÏùüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿøøøÿòòòÿèèèÿÝÝÝÿÑÑÑÿÐÐÐÿÙÙÙÿëëëÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááù222¥_G/ #8Pf;;;°ÜÜÜþüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿ÷÷÷ÿðððÿèèèÿäääÿçççÿòòòÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëþBBB°fP8# +@Wf>>>°ÕÕÕùýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿ÷÷÷ÿôôôÿôôôÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿáááùCCC°fW@+ 0F\f111¥«««éõõõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿýýýÿþþþÿÿÿÿÿüüüÿ¶¶¶é555¥f\F0 "4H]fjjjÍéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿòòòÿrrrÍf]H4"  $5H\fp333§Ýîîîÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿôôôÿ———Ý777§pf\H5$  $4FWffv000¤uuuÐÒÒÒøïïïÿøøøÿüüüÿþþþÿþþþÿÿÿÿÿÿÿÿÿþþþÿýýýÿúúúÿóóóÿ×××øzzzÐ222¤vffWF4$  "0@P_fffƒ...£VVV¿€€€×§§§éÊÊÊ÷ÜÜÜþÌÌÌ÷©©©é‚‚‚×XXX¿000£ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/objects.nib0000644000175000017500000000577507444541576027121 0ustar centriscentris typedstreamè„@„„„NSIBObjectDataà„„NSObject…’„„„NSCustomObject)”„@@„„„NSString”„+ Controller†…†„i–„„„NSView)„„ NSResponder”’…™„ @@@@ffffffff„„„NSMutableArray„„NSArray”™ ’„„„ NSCustomView)š’™™‚œ„™†……… =XX’™’…’…’…–„˜˜ EmulatorView†„˜˜NSView††’„„„NSProgressIndicatorÜš’™™‚Bœ…„„„ NSPSMatrix”„[12f]„c££†…… ²šš’™’…’…’…„ccddcdd†’„„„NSButton„„ NSControl)š’™™œ…………Û—1111’™’…’…’…„icc@„„„ NSButtonCell?„„ NSActionCell„„NSCellA”„ii‚þ‚„@@@@„˜˜Power†„„„NSFont”™$„[36c]þÿLucidaGrande„f ££££†……„i:…’…’¨„ ssii@@@@@È‚T@ÿ„˜˜†„„„NSMutableString˜˜†„„„NSCustomResource)”–„˜˜NSImage†„˜˜ shutdownN††„¶–·„˜˜ shutdownH††…††’„©’™™œ…………h T!T!’™’…’…’…§„¬«‚þ‚¬„˜˜Run†°……°…’…’»±È‚È„@ÿ„˜˜Pause†²………††’„©’™™œ…………Û1111’™’…’…’…§„¬«‚þ‚¬„˜˜Restart†°……°…’…’¿±È‚D@ÿ²„´˜†„¶–·„˜˜resetN††„¶–·„˜˜resetH††…††’„©’™™œ…………… T!T!’™’…’…’…§„¬«‚þ‚8¬„˜˜ Interrupt†°……°…’…’DZÈ‚†‚@ÿ²„´˜†…„±™„[28c]þÿHelvetica¯ ££££†…††’„©’™™œ………… f!f!’™’…’…’…§„¬«‚þ‚8¬„˜˜Zap PRAM†°……°…’…’̱È‚†‚@ÿ²„´˜†…Ë…††’„©’™™œ………… ž ’™’…’…’…§„¬«‚þ‚¬²°……°…’…’бÈ‚ÈD@ÿ²„´˜†„¶–·„˜˜Expanded††„¶–·„˜˜ Collapsed††…††’„©’™™œ…………‰ `!`!’™’…’…’…§„¬«‚þ‚¬„˜˜Snapshot†°……°…’…’ױȂ†”@ÿ²„´˜†………††’„„„NSSliderª’™™œ…………tt’™’…’…’…§„„„ NSSliderCellâ­«‚þ¬„´˜†„±™,„[44c]$þÿHelvetica-Oblique¯ ££££†……°…’…’Û„ddddiii< ††’„„„ NSTextFieldª’™™œ………… ’™’…’…’…§„„„NSTextFieldCell=­«‚1þA‚@¬„˜˜0†°……°…’…’á„c@@„„„NSColor”£„@@@„˜˜System†„˜˜ controlColor†„磄ffƒ?*ª«††„磽脘˜controlTextColor†„磾†††’…„:…†’„â’™™œ…………f ’™’…’…’…§„ä«‚1þA‚@¬„˜˜60†°……°…’…’î»æë†’…¿…†’„â’™™œ………… JJ’™’…’…’…§„ä«‚1þA‚@¬„˜˜ Frames/sec.†„±™$®þÿLucidaGrande¯ ££££ †……°…’…’ñ»æë†’…¿…††……… ÑÑ’…’…’…’…†„„„NSWindowTemplateø”„ iiffffi@@@@@cÑ‚0x„˜˜BasiliskII Emulator†„˜˜NSWindow†„´˜View†™…„ffff*€À£¾â’„˜˜Window†£¾2¨†–Ì™–Ç™–Й–ñ™–á™–Û™–Ÿ™–»™–õ•–¤™–î™–×™–¿™–„––„˜˜Emulator†…†•–¨™™–™„˜˜NSView†–Ì„˜˜ NSButton5†–Ç„˜˜ NSButton2†–Є˜˜ NSButton6†–ñ„˜˜ NSTextField2†–ᄘ˜ NSTextField†–Û„˜˜NSSlider†–Ÿ„˜˜ NSCustomView†–•„´˜ File's Owner†–»„˜˜NSButton†–õ„˜˜Window†–¤„˜˜1†–˜ NSTextField1†–ׄ˜˜ NSButton4†–¿„˜˜ NSButton1†–û„˜˜Emulator†–¨„˜˜ NSButton3†’„„„ NSMutableSet„„NSSet”„I’õ†’„™ ’„„„NSNibOutletConnectorÏ„„NSNibConnector”½û¤„˜˜ barberPole††’„½ûõ„˜˜win††’„½ûŸ„˜˜screen††’„„„NSNibControlConnectorϽÛû„˜˜ SpeedChange:††’„½ûÛ„˜˜speed††’„½¨û„˜˜ PowerKey:††’„½×û„˜˜ Snapshot:††’„½»û„˜˜ ToggleState:††’„½¿û„˜˜Restart:††’„½Çû„˜˜ Interrupt:††’„½Ìû„˜˜ZapPRAM:††’„½û»„˜˜ runOrPause††’„½•û„˜˜ myEmulator†††’…™„@i»öÉÐ)ɨpÉÛþÉÇüÉ) ÉîÉñÉßÉŸÇÉ¿ûÉõËÉ'ÉÌýÉ+%É%É×É-0É#ÉûšÉ!†ÉÖÉáɤÈÉ…ÉÉ•ÉÿÉ×səř5™’„´˜IBCocoaFramework††BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/info.nib0000644000175000017500000000075407444541575026412 0ustar centriscentris IBDocumentLocation 18 42 473 240 0 41 1024 705 IBMainMenuLocation 0 702 365 44 0 41 1024 705 IBUserGuides Window guideLocations guidesLocked NO BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/classes.nib0000644000175000017500000000201307444541575027102 0ustar centriscentris{ IBClasses = ( { ACTIONS = {NewEmulator = id; ShowAbout = id; pauseAll = id; terminateAll = id; }; CLASS = Controller; LANGUAGE = ObjC; OUTLETS = {myEmulator = id; }; SUPERCLASS = NSObject; }, { ACTIONS = { Interrupt = id; PowerKey = id; Restart = id; Resume = id; Snapshot = id; SpeedChange = id; Suspend = id; Terminate = id; ToggleState = id; ZapPRAM = id; }; CLASS = Emulator; LANGUAGE = ObjC; OUTLETS = {barberPole = id; runOrPause = id; screen = id; speed = id; win = id; }; SUPERCLASS = NSObject; }, {CLASS = EmulatorView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; } ); IBVersion = 1; }BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/shutdownH.tiff0000644000175000017500000002310607444541603027606 0ustar centriscentrisMM*%Œ6k *™HÀ&iÝ)5ˆó/<˜þ*7Šó )lÝJÀ +™k6"n :µ#1õ>R­ÿ[oÇÿuŠÛÿ‹åÿ—¨ëÿœ¯íÿ˜ªìÿŽ¢çÿ{ÞÿbvÎÿEYµÿ(8Œõ >µn"tLÊ.CœÿNiÁÿu‘ãÿ›µõÿ»ÑÿÿÐâÿÿÜìÿÿãñÿÿæòÿÿäñÿÿàîÿÿÔæÿÿÂ×ÿÿ¥¾ùÿœëÿVsÍÿ4L§ÿPÊtO 5²!9ÿ@_¹ÿgŠÞÿ°øÿ¬Ìÿÿ¿ÛÿÿËåÿÿÒéÿÿÔëÿÿÖëÿÿÖëÿÿ×ëÿÿ×ëÿÿÖëÿÿÑéÿÿÆáÿÿ³Óÿÿ”¹ÿÿo”éÿGjÆÿ&B›ÿ 9²O r YÞ&F›ÿBj¿ÿcŽÝÿ}¨ïÿ¹ùÿœÅûÿ¡Éûÿ¢Ëùÿ¢É÷ÿ¡Èõÿ Çõÿ Çôÿ Èôÿ£Éõÿ¥Ë÷ÿ¦Ìùÿ¥Íûÿ¡Éýÿ”Àýÿƒ°öÿi—æÿHsËÿ,P¨ÿ$aÞr   …/vö&L¡ÿ>k¼ÿS„Ðÿd—Þÿn¢åÿs¨æÿuªæÿuªãÿs¨ßÿq¦Ýÿr¥Üÿq¤Úÿq¤Úÿq¤Úÿr¥Üÿt§Þÿv¨àÿx¬ãÿx¬èÿv¬éÿr§éÿhäÿWŒ×ÿCsÄÿ,Uªÿ5ö …   †1}þ!Kžÿ3c³ÿCxÃÿO‡ÍÿW‘Ôÿ[–Õÿ]™Õÿ_˜Óÿa˜Òÿc™Ñÿe™ÑÿfšÑÿg›Ñÿg›Ñÿg›ÑÿfšÑÿf›ÑÿešÒÿcšÓÿb™Ôÿ`™Öÿ^™ØÿZ•×ÿSÒÿGÈÿ7k¹ÿ&T§ÿ8ˆþ †  v1uöJ›ÿ)_¬ÿ5o·ÿ?}ÂÿF†ÈÿO‹ËÿVÍÿ[”Îÿ^–Ïÿc™ÑÿgœÒÿjžÔÿmŸÔÿHbÿ?N^ÿIdÿmŸÔÿkŸÔÿiœÔÿešÒÿa—Ðÿ\”ÏÿX’ÎÿRŽÌÿJŠÊÿB‚Æÿ8u¼ÿ-e±ÿQ¢ÿ7€öv   U #XßH—ÿZ§ÿ*i²ÿ4u»ÿA€ÂÿJˆÇÿSŽËÿZ“Îÿa˜Ñÿg›ÓÿlŸÕÿp¢×ÿr¥Ùÿt¦Øÿ$2Aÿ+9Iÿ$2Aÿu¦Øÿs¦Ùÿq¤×ÿm¡ÖÿhÓÿc™Òÿ\•ÐÿUÌÿN‰ÈÿEƒÅÿ9z¾ÿ-nµÿ#_ªÿOžÿ )aß U  #5·BÿV£ÿ"d­ÿ/q·ÿ<|ÀÿH…ÆÿRËÿ\”ÐÿcšÔÿjŸÖÿn¢Øÿs¦Úÿw©ÛÿxªÛÿy¨Ùÿ$1?ÿ#1?ÿ$1?ÿz¨ÙÿyªÛÿx©Üÿu¨Ûÿp¥Ùÿk ×ÿeœÔÿ^—ÒÿWÍÿLˆÉÿA€Ãÿ4v»ÿ%h±ÿZ¨ÿJšÿ;·# ~ <„ÿQ ÿ`¬ÿ)mµÿ9z½ÿF…ÆÿQŽÌÿ[•ÑÿdœÕÿk¡Øÿq¥Ûÿu¨Üÿv¦×ÿgŒ²ÿ}¬Üÿ{¨Õÿ#0=ÿ#/;ÿ#0=ÿ{¨Õÿ~¬Üÿi޶ÿy©Úÿx©Ýÿs¦Üÿm¢ÙÿhžÖÿ_—ÓÿU‘ÏÿJˆÉÿ>Áÿ.q¹ÿ d°ÿW§ÿD’ÿ ~ 1 JÐ K™ÿ]ªÿ&kµÿ5w¾ÿDƒÇÿPÍÿZ•Òÿcœ×ÿk£Úÿq§ÜÿwªÞÿe‰¯ÿSjƒÿ7ETÿ®Üÿ|§Òÿ#/:ÿ"-9ÿ#/:ÿ|¨Òÿ‚®Üÿ8ESÿUm†ÿh´ÿy«ßÿt¨Ýÿn¤ÛÿfžØÿ^˜ÔÿSÏÿH‡Èÿ:|Áÿ,p¸ÿa­ÿR¢ÿ%SÐ1 | @‰ÿW§ÿf±ÿ1u¼ÿ?€ÅÿLŒÍÿW”Óÿb›Øÿj¢Ûÿq§ÝÿpŸÏÿYv•ÿ:HWÿ.Mÿ$1?ÿ#0<ÿWu’ÿwœÃÿ|¢Êÿ„ªÑÿ„©Ïÿ%/:ÿ$.8ÿ%/:ÿ„©Ïÿ„ªÒÿ}£ÊÿwÂÿSoŠÿ#0=ÿ%3@ÿ1?Oÿg»ÿt«âÿl¦àÿd Þÿ[™ÚÿOÔÿ@…Ìÿ1wÂÿ!h¶ÿV¢ÿ €  /«U ÿ#k¹ÿ3yÄÿA‡ÏÿP’Øÿ\›Ýÿg£àÿo¨âÿq¥ÚÿB[uÿ)6Dÿ#/<ÿMh„ÿs˜¾ÿxžÃÿ‚§Îÿ‡®×ÿ†«Òÿ%/:ÿ$.8ÿ%/:ÿ…ªÑÿˆ®Öÿ‚§ÎÿyžÄÿt™¿ÿJb{ÿ$0=ÿ+8FÿHc~ÿw¬âÿqªãÿj¥àÿ`žßÿV–ÚÿH‹Óÿ:€Éÿ)p½ÿ_¬ÿ5« &'LÍ_ªÿ+s¿ÿ;ÌÿIÕÿV˜Üÿa áÿk§ãÿsªäÿ^‡±ÿ+:Iÿ#0=ÿ3DWÿtšÁÿxžÄÿ¦Ïÿˆ¯ÙÿŒ´Ûÿ‰®Õÿ&0;ÿ%/9ÿ&0;ÿ‰¯Ôÿ´Ûÿ‰¯Ùÿ§ÏÿyžÄÿi‹®ÿ2BTÿ#1>ÿ,:Hÿl˜Çÿu¬åÿn©ãÿe£âÿZ›ßÿN’Ùÿ@†Ïÿ0xÄÿ hµÿ -VÍ& , 9lå g³ÿ2zÇÿA‡ÒÿO“Ûÿ\žáÿg¥äÿpªçÿu¬åÿJi‰ÿ(5Dÿ"/;ÿRmŠÿyŸÆÿ¨Ñÿ‹²Üÿ¹åÿ‘¹ãÿ‹±Øÿ'1;ÿ%/9ÿ'1;ÿ²Øÿ“¹âÿ‘¹äÿбÚÿ¨ÏÿxŸÄÿLd~ÿ#/<ÿ)6EÿUxÿx®æÿr¬çÿj§åÿ`¡ãÿT—ÞÿFŒÖÿ8Ëÿ'n½ÿBwå,  1J‡ö&m¹ÿ7ÌÿFŒØÿT˜ßÿa£åÿk©èÿt­éÿw®åÿ9Qhÿ'4Bÿ".;ÿo“¹ÿ¨Ñÿ‹³Þÿ’¼æÿ–Àëÿ•¿æÿ޵Úÿ'1<ÿ&0:ÿ'1<ÿŽ´Úÿ•¿æÿ–Àëÿ’¼æÿвÜÿ§Ðÿ`€ ÿ#.;ÿ(5CÿAZtÿz¯çÿv­êÿn«éÿe¦çÿZ›âÿL‘Ûÿ=„Ðÿ,tÃÿS•ö1 5T˜þ+rÀÿ<„ÒÿK’ÝÿYäÿf¦êÿn¬íÿv°ëÿx¯æÿ+=Oÿ&3@ÿ#/;ÿ|¥Ïÿˆ³Þÿ‘½éÿ˜ÂïÿšÅñÿ–Àêÿ¶Þÿ'2=ÿ&0;ÿ(2=ÿ¶Þÿ—Áêÿ™Åñÿ—Âïÿ‘¼èÿˆ±Üÿu™¿ÿ#/;ÿ&3Aÿ.ASÿ{±èÿy²íÿq®íÿi©ëÿ^¡çÿP–áÿAŠ×ÿ1{Èÿ`©þ5!8QŽö0wÄÿ@‰ÖÿP–áÿ\¡èÿh©ìÿq°ðÿy³ïÿy°çÿ$2Aÿ#0=ÿ$0=ÿ‚­ØÿŽºçÿ–Âðÿ›ÆôÿœÇôÿ™Ãíÿ‘¸áÿI\qÿ'1<ÿRf}ÿ’¸áÿ™ÂíÿÈôÿšÆóÿ–Áïÿ޹æÿ‚¬Öÿ$0=ÿ#0=ÿ%3Bÿ~±èÿ|µïÿu²ñÿm¬îÿa¤êÿTšäÿEŽÛÿ7Íÿ \žö8!":Eyç2zÆÿDÚÿR›åÿ`¥ìÿk­ðÿu´ôÿ{´ñÿ|°çÿ,=Oÿ#0=ÿ%2>ÿ‰´áÿ”ÀïÿšÈ÷ÿÊøÿžÊøÿœÆñÿ•¼åÿ‰­Òÿ…¨Ëÿ‰­Òÿ•¼åÿ›ÆñÿŸÊ÷ÿžÊøÿšÇõÿ’¿íÿ}¥Îÿ&2>ÿ$1=ÿ.@Rÿ~²èÿ}·òÿx¶õÿo¯òÿe¨îÿWžçÿI’Þÿ:ƒÑÿP‡ç:"":6[Ó5|ÈÿGÞÿUéÿc¨ðÿn±õÿx·øÿ}¸ôÿ}²éÿ9Pgÿ$1>ÿ(5CÿªÖÿ—ÆöÿžÍþÿ Îþÿ¡Ïýÿ ÌøÿšÃíÿµÜÿ‹°ÖÿµÜÿšÃíÿ¡Ìøÿ¢Ïýÿ¡ÎþÿžÌüÿ–Åõÿp“¸ÿ)6Cÿ$1>ÿ@Xqÿ´ëÿºöÿ{¹ùÿr´÷ÿh¬óÿ\¢ìÿL–ãÿ=†Ôÿ>hÓ:"": $=¹7|ÆÿI“áÿX¢íÿf¬ôÿq´ùÿ{ºýÿ€»ùÿ~¶íÿLi‡ÿ%1?ÿ.;Gÿgˆ§ÿšËøÿ¡Ñÿÿ¤Òÿÿ¥Óÿÿ¤Ñûÿ Êóÿ˜Áèÿ–¾äÿšÂéÿ Ëôÿ¥Òüÿ¦Ôÿÿ¤Òÿÿ¢Ðþÿ›É÷ÿ\y“ÿ-:Fÿ%2?ÿXx™ÿ·íÿ‚½ùÿ~¼þÿv·úÿj¯öÿ^¦ðÿO™æÿ@ˆÖÿ*F¹:"!8!˜6x¿ÿL•ãÿZ¤ïÿh¯÷ÿt¸þÿ~½ÿÿƒ¾ùÿ¹íÿc‰­ÿ&3?ÿ+8DÿH^oÿ™Èñÿ¥Õÿÿ§×ÿÿ©×ÿÿ©×ýÿ§Ôùÿ¤Ñôÿ£Ïòÿ¤Ñôÿ¨Öúÿ©×ýÿ©×ÿÿ¨×ÿÿ¥Õþÿ‹´×ÿDXhÿ)6Aÿ&3?ÿu¢Éÿ…¼îÿ„Áúÿ€Àÿÿyºþÿm²úÿ`¨óÿRœéÿ?‡Óÿ &˜8!5 r/h§øL•âÿ]¦ðÿi±ûÿvºÿÿÀÿÿ„Âúÿ†¾ïÿ}¯ØÿBZmÿ(6@ÿ8GQÿp¨ÿ§ØýÿªÜÿÿ«Üÿÿ­Þÿÿ­Üýÿ¬Ûüÿ«Ûûÿ¬Ûüÿ­Ýýÿ®Þÿÿ¬Üÿÿ«Üÿÿ§Øüÿfƒ˜ÿ6DNÿ(5?ÿGauÿ„·ßÿˆÀðÿˆÅûÿƒÄÿÿz½ÿÿo´üÿb©õÿSêÿ9y½ø r5 1L:\ÐK‘Üÿ]§óÿj²üÿw¼ÿÿ€Ãÿÿ‡Çüÿ‰Äòÿ†»âÿdŠ¥ÿ)7@ÿ-;Dÿ?NWÿ€¥»ÿ®áÿÿ¯áÿÿ±ãÿÿ²âÿÿ²âÿÿ²âÿÿ²âÿÿ±ãÿÿ±ãÿÿ¯âÿÿ¬ßýÿw˜¬ÿ>MVÿ,:Bÿ*8AÿuŸ¼ÿ‰¾äÿŒÆóÿ‹Éüÿ„Çÿÿ|Àÿÿo¶þÿb¬øÿTéÿ DjÐL1  ,F &¡F‰Îÿ]§õÿj³þÿw¾ÿÿ‚ÆÿÿŠËýÿŒËõÿ‹Ãçÿ‡ºØÿYxŠÿ,:Aÿ1@HÿCRZÿ}ž­ÿ¥Ôéÿµèÿÿ·èÿÿ¶èÿÿ¶èÿÿ¶èÿÿ¶èÿÿµèÿÿ¡Íâÿv”¢ÿBQXÿ/>Eÿ+9Aÿaƒ–ÿмÚÿŽÇêÿÍ÷ÿÎþÿ…Èÿÿ|Âÿÿp·ÿÿc­úÿP˜âÿ +¡F, &?k)R{ÝZ£îÿk´ÿÿw¿ÿÿ‚Çÿÿ‹Îþÿ‘Ñùÿ‘ÌîÿŒÂÞÿ„³ÊÿYvƒÿ.=Cÿ1AGÿCSYÿbx€ÿ†¨³ÿÈÕÿ°áñÿºîÿÿ³åõÿŸÉ×ÿ‚£®ÿ_t|ÿBRWÿ1AFÿ.°f¦ßþÉýÿŽ×ÿÿ—àÿÿ æþÿ§ìýÿ©ìøÿªêñÿ¨æèÿ¦ààÿ£ÙÙÿ¤ÖÖÿ¤ÔÔÿ£ÓÓÿ£ÒÒÿ¤ÓÓÿ¤ÔÔÿ¤ÖÖÿ¦ÚÚÿ§ààÿ«èéÿ­íòÿ­ðùÿ©îýÿ£êÿÿœãÿÿ’Ûÿÿ‡Ðÿÿq¶íþ1C°fP8# +@Wf->°f¢Òù…Îýÿ”Ýÿÿžæÿÿ¦íÿÿ­ñýÿ¯ôúÿ±óõÿ°ïïÿ¯ééÿ®ããÿ«ÞÞÿªÛÛÿ©ÚÚÿªÛÛÿ­ßßÿ¯ääÿ±êêÿ³ððÿ³ööÿ²õúÿ®ôýÿ©ðÿÿ¡éÿÿ˜áÿÿÖÿÿq°ßù2C°fW@+ 0F\f%2¥Tƒ§é‡Îöÿ—áÿÿ¡êÿÿ¨ñÿÿ®õþÿ³ùüÿ¶úúÿ·ööÿ·óóÿ¸ððÿ·îîÿ·ííÿ·îîÿ¸ððÿ¸óóÿ¹÷÷ÿ·úúÿµüýÿ±øþÿ¬óÿÿ¥íÿÿœæÿÿŽÖûÿ]²é)6¥f\F0 "4H]f 8WlÍ‚Æêÿ—áýÿ¢íÿÿªóÿÿ°ùÿÿ´ýþÿ¹ýýÿºüüÿ»ûûÿ¼úúÿ»ùùÿ¼úúÿ¼ûûÿ»üüÿ¹þþÿ¶ÿÿÿ²üÿÿ¬öÿÿ¦ïÿÿœæÿÿŠÑóÿ=^rÍf]H4"  $5H\fp,7§NuŒÝ‹Ïëÿœäúÿ§ñÿÿ®øÿÿ²ýÿÿ¶ÿÿÿ¸ÿÿÿºÿÿÿ¹ÿÿÿ¹ÿÿÿ¹ÿÿÿ¶ÿÿÿ³þÿÿ¯ûÿÿªôÿÿ¢ëüÿ“ÙòÿT}’Ý0:§pf\H5$  $4FWffv)1¤BdsÐ¼Ðø˜Ýïÿ¢ëøÿ¨ôüÿ®øþÿ°ûþÿ±üÿÿ±ûÿÿ®ùþÿ«õýÿ¥îúÿœãòÿ†ÄÕøGjwÐ-4¤ vffWF4$  "0@P_fff ƒ*/£5NW¿Px‚×mž«éƒ¿Î÷Ñßþ„ÁÏ÷o¡­éTz…×7QY¿,1£ ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/Win512x342.nib/shutdownN.tiff0000644000175000017500000002310607444541605027616 0ustar centriscentrisMM*%Œ6k$$$™===ÀZZZÝttt󃃃þvvvó\\\Ý@@@À%%%™k6"n666µzzzõ   ÿ½½½ÿÑÑÑÿÜÜÜÿäääÿæææÿåååÿßßßÿÕÕÕÿÄÄÄÿ¨¨¨ÿƒƒƒõ:::µn"tDDDÊŽŽŽÿºººÿÝÝÝÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿæææÿÅÅÅÿšššÿKKKÊtO...²ÿ¨¨¨ÿÊÊÊÿéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿÔÔÔÿ´´´ÿŽŽŽÿ222²O rSSSÞÿµµµÿÑÑÑÿãããÿïïïÿôôôÿôôôÿóóóÿñññÿïïïÿíííÿíííÿíííÿîîîÿñññÿóóóÿöööÿ÷÷÷ÿôôôÿêêêÿÚÚÚÿ¿¿¿ÿšššÿ\\\Þr  …mmmö–––ÿ¯¯¯ÿÅÅÅÿÓÓÓÿÚÚÚÿÝÝÝÿÜÜÜÿÚÚÚÿ×××ÿÔÔÔÿÓÓÓÿÒÒÒÿÑÑÑÿÒÒÒÿÓÓÓÿÔÔÔÿ×××ÿÚÚÚÿÝÝÝÿàààÿßßßÿÙÙÙÿÌÌÌÿ¶¶¶ÿ   ÿwwwö…  †pppþ‘‘‘ÿ§§§ÿ¶¶¶ÿÃÃÃÿÊÊÊÿÍÍÍÿÌÌÌÿËËËÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÉÉÉÿÊÊÊÿÊÊÊÿËËËÿÌÌÌÿÎÎÎÿÏÏÏÿÎÎÎÿÈÈÈÿ¼¼¼ÿ­­­ÿšššÿ{{{þ†  vmmmöŽŽŽÿ¡¡¡ÿ®®®ÿ¶¶¶ÿ¾¾¾ÿÁÁÁÿÄÄÄÿÆÆÆÿÇÇÇÿÈÈÈÿËËËÿÌÌÌÿÍÍÍÿ{{{ÿ\\\ÿ}}}ÿÎÎÎÿÍÍÍÿËËËÿÉÉÉÿÈÈÈÿÆÆÆÿÅÅÅÿÃÃÃÿÁÁÁÿ»»»ÿ²²²ÿ¦¦¦ÿ•••ÿvvvöv  USSSßÿ›››ÿ¨¨¨ÿ±±±ÿ···ÿ¼¼¼ÿÁÁÁÿÅÅÅÿÈÈÈÿËËËÿÎÎÎÿÐÐÐÿÒÒÒÿÐÐÐÿ???ÿFFFÿ???ÿÑÑÑÿÒÒÒÿÑÑÑÿÏÏÏÿÌÌÌÿÊÊÊÿÆÆÆÿÃÃÃÿ¿¿¿ÿºººÿ´´´ÿ«««ÿŸŸŸÿ”””ÿ[[[ßU  "///·„„„ÿ˜˜˜ÿ¡¡¡ÿ­­­ÿµµµÿ¼¼¼ÿÁÁÁÿÇÇÇÿÊÊÊÿÎÎÎÿÑÑÑÿÓÓÓÿÔÔÔÿÓÓÓÿÐÐÐÿ===ÿ===ÿ===ÿÑÑÑÿÓÓÓÿÔÔÔÿÓÓÓÿÑÑÑÿÏÏÏÿËËËÿÈÈÈÿÄÄÄÿ½½½ÿ¸¸¸ÿ°°°ÿ¥¥¥ÿ›››ÿŽŽŽÿ555·# ~yyyÿ–––ÿ¢¢¢ÿªªªÿµµµÿ½½½ÿÃÃÃÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÕÕÕÿÏÏÏÿ­­­ÿÕÕÕÿÏÏÏÿ;;;ÿ:::ÿ;;;ÿÏÏÏÿÕÕÕÿ°°°ÿÒÒÒÿÕÕÕÿÔÔÔÿÑÑÑÿÎÎÎÿÊÊÊÿÅÅÅÿ¿¿¿ÿ¸¸¸ÿ­­­ÿ¥¥¥ÿšššÿ†††ÿ~ 1FFFÐŒŒŒÿŸŸŸÿ©©©ÿ³³³ÿ¼¼¼ÿÄÄÄÿÉÉÉÿÎÎÎÿÒÒÒÿÓÓÓÿÕÕÕÿ©©©ÿÿRRRÿÕÕÕÿËËËÿ999ÿ777ÿ999ÿËËËÿÕÕÕÿRRRÿ‚‚‚ÿ¯¯¯ÿÖÖÖÿÔÔÔÿÒÒÒÿÐÐÐÿËËËÿÆÆÆÿ¿¿¿ÿ¶¶¶ÿ®®®ÿ¢¢¢ÿ”””ÿOOOÐ1 |ÿ˜˜˜ÿ¥¥¥ÿ°°°ÿ¹¹¹ÿÃÃÃÿÉÉÉÿÎÎÎÿÒÒÒÿÕÕÕÿÇÇÇÿ‘‘‘ÿUUUÿHHHÿ@@@ÿÔÔÔÿËËËÿ888ÿ666ÿ888ÿËËËÿÔÔÔÿ@@@ÿIIIÿVVVÿ–––ÿÍÍÍÿÕÕÕÿÓÓÓÿÐÐÐÿËËËÿÅÅÅÿ¾¾¾ÿµµµÿ©©©ÿœœœÿŒŒŒÿ| 888¿’’’ÿ¡¡¡ÿ®®®ÿ¹¹¹ÿÁÁÁÿÉÉÉÿÐÐÐÿÓÓÓÿÖÖÖÿÇÇÇÿ†††ÿNNNÿ???ÿ>>>ÿ\\\ÿÑÑÑÿÊÊÊÿ888ÿ666ÿ888ÿÊÊÊÿÑÑÑÿ]]]ÿ>>>ÿ???ÿOOOÿÿÒÒÒÿÖÖÖÿÔÔÔÿÑÑÑÿÌÌÌÿÅÅÅÿ½½½ÿ³³³ÿ¦¦¦ÿšššÿ???¿ Msss÷ÿ©©©ÿ···ÿÁÁÁÿÈÈÈÿÏÏÏÿÓÓÓÿÖÖÖÿØØØÿÿMMMÿ>>>ÿ;;;ÿ†††ÿÇÇÇÿÌÌÌÿÉÉÉÿ888ÿ666ÿ888ÿÉÉÉÿÍÍÍÿÃÃÃÿÿ<<<ÿ>>>ÿNNNÿ˜˜˜ÿØØØÿ×××ÿÔÔÔÿÑÑÑÿËËËÿÅÅÅÿºººÿ®®®ÿ£££ÿ÷M €‰‰‰ÿ¥¥¥ÿ±±±ÿ½½½ÿÇÇÇÿÎÎÎÿÓÓÓÿÖÖÖÿ×××ÿ¥¥¥ÿKKKÿ===ÿ;;;ÿŽŽŽÿ½½½ÿÄÄÄÿÌÌÌÿÉÉÉÿ888ÿ777ÿ888ÿÉÉÉÿÌÌÌÿÄÄÄÿ½½½ÿ†††ÿ;;;ÿ>>>ÿMMMÿµµµÿÙÙÙÿ×××ÿÕÕÕÿÐÐÐÿËËËÿÂÂÂÿµµµÿ«««ÿ–––ÿ€  ***«———ÿ®®®ÿ¹¹¹ÿÅÅÅÿÎÎÎÿÓÓÓÿ×××ÿÚÚÚÿÒÒÒÿqqqÿBBBÿ:::ÿ€€€ÿ¹¹¹ÿ¾¾¾ÿÈÈÈÿÐÐÐÿÌÌÌÿ999ÿ777ÿ999ÿËËËÿÐÐÐÿÉÉÉÿ¾¾¾ÿ¹¹¹ÿxxxÿ;;;ÿDDDÿ{{{ÿÚÚÚÿÛÛÛÿÙÙÙÿÕÕÕÿÑÑÑÿÉÉÉÿ½½½ÿ³³³ÿ¢¢¢ÿ///« &EEEÍ¡¡¡ÿµµµÿ¿¿¿ÿÊÊÊÿÒÒÒÿÖÖÖÿÜÜÜÿÜÜÜÿ«««ÿGGGÿ;;;ÿTTTÿºººÿ¾¾¾ÿÇÇÇÿÓÓÓÿÖÖÖÿÏÏÏÿ999ÿ777ÿ999ÿÏÏÏÿÖÖÖÿÓÓÓÿÇÇÇÿ¾¾¾ÿ¨¨¨ÿQQQÿ;;;ÿFFFÿÀÀÀÿÝÝÝÿÜÜÜÿÙÙÙÿÕÕÕÿÎÎÎÿÄÄÄÿºººÿ«««ÿOOOÍ& ,aaa娨¨ÿºººÿÅÅÅÿÐÐÐÿÖÖÖÿÚÚÚÿÞÞÞÿÝÝÝÿƒƒƒÿAAAÿ999ÿ………ÿÀÀÀÿËËËÿÖÖÖÿÝÝÝÿÜÜÜÿÒÒÒÿ:::ÿ888ÿ:::ÿÒÒÒÿÜÜÜÿÝÝÝÿÕÕÕÿÊÊÊÿ¿¿¿ÿzzzÿ:::ÿBBBÿ–––ÿÝÝÝÿßßßÿÜÜÜÿØØØÿÓÓÓÿÊÊÊÿÀÀÀÿ±±±ÿnnnå,  1{{{ö¯¯¯ÿÁÁÁÿÌÌÌÿÕÕÕÿÛÛÛÿßßßÿáááÿÞÞÞÿeeeÿ@@@ÿ999ÿ²²²ÿËËËÿÙÙÙÿâââÿæææÿâââÿÖÖÖÿ;;;ÿ999ÿ;;;ÿÖÖÖÿâââÿæææÿâââÿØØØÿÊÊÊÿšššÿ999ÿAAAÿpppÿßßßÿâââÿàààÿÝÝÝÿØØØÿÏÏÏÿÆÆÆÿ¸¸¸ÿ‰‰‰ö1 5‰‰‰þ´´´ÿÆÆÆÿÐÐÐÿÚÚÚÿàààÿâââÿãããÿÞÞÞÿMMMÿ>>>ÿ:::ÿÈÈÈÿØØØÿãããÿéééÿëëëÿåååÿÙÙÙÿ;;;ÿ999ÿ;;;ÿÙÙÙÿåååÿëëëÿéééÿâââÿÖÖÖÿ¹¹¹ÿ:::ÿ???ÿQQQÿßßßÿäääÿäääÿàààÿÝÝÝÿÔÔÔÿËËËÿ½½½ÿšššþ5!8‚‚‚ö¹¹¹ÿËËËÿÕÕÕÿÞÞÞÿâââÿæææÿæææÿÞÞÞÿ???ÿ;;;ÿ;;;ÿÑÑÑÿàààÿéééÿîîîÿîîîÿçççÿÚÚÚÿnnnÿ:::ÿyyyÿÚÚÚÿçççÿîîîÿíííÿèèèÿßßßÿÏÏÏÿ:::ÿ;;;ÿ@@@ÿàààÿçççÿèèèÿäääÿàààÿØØØÿÐÐÐÿÂÂÂÿ‘‘‘ö8!":nnnç¼¼¼ÿÐÐÐÿÚÚÚÿâââÿçççÿëëëÿèèèÿßßßÿLLLÿ<<<ÿ===ÿÛÛÛÿéééÿñññÿòòòÿòòòÿìììÿàààÿÎÎÎÿÇÇÇÿÎÎÎÿàààÿìììÿòòòÿòòòÿðððÿèèèÿÈÈÈÿ===ÿ<<<ÿOOOÿáááÿêêêÿìììÿéééÿäääÿÝÝÝÿÔÔÔÿÆÆÆÿ}}}ç:"":TTTÓ½½½ÿÓÓÓÿÝÝÝÿåååÿëëëÿîîîÿëëëÿáááÿdddÿ===ÿAAAÿÐÐÐÿîîîÿöööÿöööÿöööÿñññÿçççÿÖÖÖÿÐÐÐÿÖÖÖÿçççÿñññÿöööÿöööÿõõõÿíííÿ±±±ÿAAAÿ===ÿnnnÿâââÿìììÿïïïÿìììÿèèèÿàààÿ×××ÿÉÉÉÿ```Ó:"":777¹¼¼¼ÿÖÖÖÿàààÿéééÿïïïÿòòòÿðððÿæææÿƒƒƒÿ===ÿFFFÿ¤¤¤ÿôôôÿûûûÿûûûÿûûûÿ÷÷÷ÿïïïÿäääÿàààÿåååÿðððÿøøøÿüüüÿüüüÿúúúÿóóóÿ‘‘‘ÿEEEÿ===ÿ•••ÿæææÿñññÿóóóÿñññÿìììÿäääÿÜÜÜÿÊÊÊÿ@@@¹:"!8˜¶¶¶ÿÙÙÙÿãããÿíííÿóóóÿ÷÷÷ÿóóóÿéééÿ­­­ÿ???ÿDDDÿoooÿñññÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿôôôÿòòòÿôôôÿúúúÿýýýÿÿÿÿÿÿÿÿÿþþþÿ×××ÿhhhÿAAAÿ???ÿÇÇÇÿëëëÿõõõÿøøøÿõõõÿðððÿçççÿßßßÿÈÈÈÿ###˜8!5 r¡¡¡øÙÙÙÿåååÿðððÿöööÿùùùÿùùùÿïïïÿØØØÿmmmÿ@@@ÿQQQÿ¨¨¨ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿüüüÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ˜˜˜ÿNNNÿ???ÿuuuÿßßßÿðððÿûûûÿûûûÿøøøÿòòòÿéééÿàààÿ³³³ø r5 1LYYYÐÕÕÕÿæææÿòòòÿúúúÿþþþÿüüüÿòòòÿâââÿ¥¥¥ÿ@@@ÿDDDÿWWWÿ»»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ¬¬¬ÿVVVÿBBBÿAAAÿ¼¼¼ÿäääÿóóóÿüüüÿÿÿÿÿüüüÿõõõÿëëëÿßßßÿfffÐL1  ,F$$$¡ÆÆÆÿåååÿôôôÿýýýÿÿÿÿÿýýýÿõõõÿçççÿØØØÿŠŠŠÿAAAÿHHHÿZZZÿ­­­ÿéééÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâââÿ¢¢¢ÿXXXÿEEEÿAAAÿ–––ÿÚÚÚÿêêêÿ÷÷÷ÿþþþÿÿÿÿÿÿÿÿÿøøøÿëëëÿØØØÿ***¡F, &?kwwwÝàààÿôôôÿþþþÿÿÿÿÿþþþÿùùùÿîîîÿÞÞÞÿÊÊÊÿƒƒƒÿCCCÿGGGÿYYYÿ€€€ÿ³³³ÿÕÕÕÿñññÿÿÿÿÿõõõÿ×××ÿ®®®ÿ|||ÿWWWÿFFFÿBBBÿŠŠŠÿÕÕÕÿàààÿðððÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿêêêÿ‡‡‡Ýk?& 6Q+++§ÌÌÌÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿôôôÿçççÿÙÙÙÿÌÌÌÿÿEEEÿGGGÿNNNÿZZZÿcccÿhhhÿiiiÿhhhÿcccÿZZZÿMMMÿFFFÿEEEÿ˜˜˜ÿÓÓÓÿÚÚÚÿéééÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿàààÿ111§Q6  -Fk\\\Íçççÿþþþÿÿÿÿÿÿÿÿÿþþþÿúúúÿðððÿãããÿ×××ÿÓÓÓÿ¯¯¯ÿzzzÿEEEÿHHHÿIIIÿIIIÿJJJÿIIIÿIIIÿGGGÿEEEÿ{{{ÿ¾¾¾ÿÓÓÓÿØØØÿäääÿñññÿúúúÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿiiiÍkF- $;Tžžžéúúúÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿøøøÿîîîÿâââÿ×××ÿÓÓÓÿÕÕÕÿ¿¿¿ÿ›››ÿvvvÿXXXÿHHHÿXXXÿwwwÿÿÇÇÇÿÔÔÔÿÓÓÓÿØØØÿãããÿïïïÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°éT;$ /G_,,,¥ÏÏÏùüüüÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ÷÷÷ÿîîîÿãããÿÚÚÚÿÕÕÕÿÓÓÓÿÔÔÔÿÖÖÖÿ×××ÿ×××ÿ×××ÿÖÖÖÿÔÔÔÿÓÓÓÿÕÕÕÿÚÚÚÿäääÿïïïÿøøøÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááù222¥_G/ #8Pf;;;°ÜÜÜþüüüÿÿÿÿÿÿÿÿÿþþþÿýýýÿøøøÿñññÿèèèÿàààÿÙÙÙÿÖÖÖÿÔÔÔÿÓÓÓÿÒÒÒÿÓÓÓÿÔÔÔÿÖÖÖÿÚÚÚÿàààÿéééÿòòòÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëþBBB°fP8# +@Wf>>>°ÕÕÕùýýýÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿúúúÿõõõÿïïïÿéééÿãããÿÞÞÞÿÛÛÛÿÚÚÚÿÛÛÛÿßßßÿäääÿêêêÿðððÿöööÿúúúÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááùCCC°fW@+ 0F\f111¥«««éõõõÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿúúúÿöööÿóóóÿðððÿîîîÿíííÿîîîÿðððÿóóóÿ÷÷÷ÿúúúÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ¶¶¶é555¥f\F0 "4H]fjjjÍéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿúúúÿûûûÿüüüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿòòòÿrrrÍf]H4"  $5H\fp333§Ýîîîÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿôôôÿ———Ý777§pf\H5$  $4FWffv000¤uuuÐÒÒÒøïïïÿøøøÿüüüÿþþþÿþþþÿÿÿÿÿÿÿÿÿþþþÿýýýÿúúúÿóóóÿ×××øzzzÐ222¤vffWF4$  "0@P_fffƒ...£VVV¿€€€×§§§éÊÊÊ÷ÜÜÜþÌÌÌ÷©©©é‚‚‚×XXX¿000£ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/MainMenu.nib/0000755000175000017500000000000011735675027025060 5ustar centriscentrisBasiliskII/src/MacOSX/Multiple-Windows/English.lproj/MainMenu.nib/objects.nib0000644000175000017500000004561007444541575027213 0ustar centriscentris typedstreamè„@„„„NSIBObjectDataà„„NSObject…’„„„NSCustomObject)”„@@„„„NSMutableString„„NSString”„+ NSApplication†…†„i˜–„„„ NSTextField„„ NSControl)„„NSView)„„ NSResponder”’„’„„„NSBox*’„’„„„ NSTabView’„’…š„ @@@@ffffffff„„„NSMutableArray„„NSArray”𒣆……… ¢ ¢’…’…’…’…†š¡„§š’¢†………ÿŸšŸš’¥’…’…’…„@@@icc„§š’„„„ NSTabViewItem”„@@@@@@@„™™1†„’…š¡„§š’„¡’®š¡„§š’„’°š¡„§š’„„„NSButtonœ’²š¡…………T!T!’²’…’…’…„icc@„„„ NSButtonCell?„„ NSActionCell„„NSCellA”„ii‚þ‚8„@@@@„™™Add…†„„„NSFont”š$„[36c]þÿLucidaGrande„f „c±±±†……„i:…’…’´„ ssii@@@@@È‚†‚@ÿ„˜™†„˜™†…„¼š„[28c]þÿHelvetica° ±±±±†…††’„µ’²š¡…………Z!Z!’²’…’…’…¨„·¬‚þ‚8­„™™Remove†»……²…’…’À³È‚†‚@ÿ„˜™†„˜™†…¿…††’„µ’²š¡…………[`!`!’²’…’…’…¨„·¬‚þ‚8­„™™ Create…†»……²…’…’ųÈ‚†‚@ÿ„˜™†„˜™†…¿…††’„µ’²š¡…………½T!T!’²’…’…’…¨„·¬‚þ‚8­„™™Delete†»……²…’…’ʳÈ‚†‚@ÿ„˜™†„˜™†…¿…††’„„„ NSScrollViewâ’²š‚€¡„§š’„„„ NSClipView:’Ïš‚À¡„§š’„„„ NSTableView=œ’Òš¡„§š†………OO’Ò’…’…’…¨…„ @@@ff@@f::i„„„NSTableHeaderView’„Ó’Ïš‚À¡„§š’؆………OO’Ï’…’Ø’…’Ø„@@ccc„„„NSColor”±„@@@„™™System†„™™controlBackgroundColor†„ݱ„ffƒ?*ª«††…†š‚€¡…………OO’Ú’…’…’…’Õ†„„„ _NSCornerView’Ïš‚€¡„§š†………P’Ï’…’…’…†„§š’„„„ NSTableColumn)”„@fff@@cc„™™locked†  „„„NSTableHeaderCell„„NSTextFieldCell=¸¬‚þ­„™™†„¼š$¯þÿLucidaGrande° ±±±±†……²…’…’…„c@@„ݱ½ƒ>ªª«†„ݱ¼Þ„™™headerTextColor†„ݱ½†††„ꬂ1þ@‚­„˜™Field†»……²…’…’…Äݱ½†„ݱ¼Þ„™™controlTextColor†ð††’Õ†’„æÀ„™™path†)))„鬂þ­„™™File containing image†ì……²…’…’…Ãíꬂ1þ@­ò»……²…’…’…Ãóô†’Õ††܄ݱ¼Þ„™™ gridColor†„ݱ½ƒ?††……‚¨@’…’…’…††………O¡O¡’Ï’…’Õ’…’պ܅†’„„„ NSScrollerÓœ’Ïš‚€¡„§š†………P¡¡’Ï’…’…’…¨…’Ï„ff:ƒ?Hò=„ _doScroller:±±†’„ÿ’Ïš‚€¡„§š†………œœQQ’Ï’…’…’…¨…’ÏŃ?}ÙÆ±±†’ڒᆅ…… *`³`³’²’…’Ò’…’þ’’Ò’Ú’á„ffffi ‚„††………säsä’°’…’…’…††……… owøwø’®’…’…’…„ff@@ccc„¹¬‚þ­„™™Disk Images to mount†»……†²’…†’„¡’®š¡„§š’„’š¡„§š’„›’š¡………… *__’’…’…’…¨„ꬂ”qþA‚@­ë»……²…’…’ Äݱ¼Þ„™™textBackgroundColor†ó†„ݱ¼Þ„™™ textColor†ð††’…„:…†’„µ’š¡…………‰`!`!’’…’…’…¨„·¬‚þ‚8­„™™ Browse…†»……²…’…’³È‚†‚@ÿ„˜™†„˜™†…¿…†††………sHsH’’…’…’…††……… w\w\’®’…’…’…È„¹¬‚þ­„™™1Unix directories to mount (via ExtFS & MacOS 7.6)†»……†’…††……… !‹l‹l’…’…’…’…†„™™ Disk Volumes†„ݱ¼Þ„™™ controlColor†à†……£†’„¬¦„™™1†„’…š¡„§š’„¡’š¡„§š’„’š¡„§š’„Ð’š‚€¡„§š’„Ó’!š‚À¡„§š’„Ö’#š¡„§š†………OO’#’…’…’…¨…¸„Ù’„Ó’!š‚À¡„§š’'†………OO’!’…’'’…’'ºÜ…†š‚€¡…………OO’(’…’…’…’%†„â’!š‚€¡„§š†………P’!’…’…’…†„§š’„æÀ…ƒA£ è„鬂þ­„™™ID†ì……²…’…’…Ãíꬂ1þ@­„˜™Field†»……²…’…’…Ãóô†’%†’„æÀ„™™path†ƒCšG è„鬂þ­„™™ Unix Device†ì……²…’…’…Äݱ¼Þ„™™ headerColor†ó†î†„ꬂ1þ@­„™™Field†„¼š$¯þÿLucidaGrande° ±±±±†……²…’…’…ÃÜô†’%††Üû……‚¨@’…’…’…††………OjOj’!’…’%’…’%ºÜ…†’„ÿ’!š‚€¡„§š†………Pjj’!’…’…’…¨…’!Ń?Hò=Ʊ±†’„ÿ’!š‚€¡„§š†………œœuu’!’…’…’…¨…’!Ń?}ÙÆ±±†’(’*†……… *`|`|’’…’#’…’;’=’#’(’*Ç ‚„†’„µ’š¡…………»Z!Z!’’…’…’…¨„·¬‚þ‚8­„™™Add…†»……²…’…’?³È‚†‚@ÿ„˜™†„˜™†…¿…††’„µ’š¡…………Z!Z!’’…’…’…¨„·¬‚þ‚8­„™™Remove†»……²…’…’D³È‚†‚@ÿ„˜™†„˜™†…¿…†††………s­s­’’…’…’…††……… ¥wÁwÁ’’…’…’…È„¹¬‚þ­„™™SCSI disks to mount†»……†’…†’„¡’š¡„§š’„’Kš¡„§š ’„›’Mš¡…………K‚‚’M’…’…’…¨„ꬂ1þA‚@­„™™Modem port device:†»……²…’…’OÃô†’…É…†’„›’Mš¡…………+}}’M’…’…’…¨„ꬂ1þA‚@­„™™Printer port device:†»……²…’…’RÃô†’…É…†’„›’Mš¡………… ~~’M’…’…’…¨„ꬂ1þA‚@­„™™EtherNet interface:†»……²…’…’UÃô†’…É…†’„›’Mš¡…………ŒH€€’M’…’…’…¨„ꬂ”qþA‚@­ë»……²…’…’Xà †’…É…†’„›’Mš¡…………Œ(€€’M’…’…’…¨„ꬂ”qþA‚@­ë»……²…’…’Zà †’…É…†’„›’Mš¡…………Œ €€’M’…’…’…¨„ꬂ”qþA‚@­ë»……²…’…’\à †’…É…†’„µ’Mš¡…………A`!`!’M’…’…’…¨„·¬‚þ‚8­„™™ Browse…†»……²…’…’^³È‚†‚@ÿ„˜™†„˜™†…¿…††’„µ’Mš¡…………!`!`!’M’…’…’…¨„·¬‚þ‚8­„™™ Browse…†»……²…’…’c³È‚†‚@ÿ„˜™†„˜™†…¿…††’„µ’Mš¡…………`!`!’M’…’…’…¨„·¬‚þ‚8­„™™ Browse…†»……²…’…’h³È‚†‚@ÿ„˜™†„˜™†…¿…†††………sdsd’K’…’…’…††……… wxwx’’…’…’…È„¹¬‚þ­„™™Serial/Network†»……†M’…††……… !‹l‹l’…’…’…’…†„™™Hardware†……£†’„¬¦„™™2†¢„™™ Emulation†……£††p»’…†š¡„§š’„¡’¢š¡„§š’„’tš¡„§š ’„µ’vš¡…………¤¡¡’v’…’…’…¨„·¬‚þ­„™™Disable sound output†»……²…’…’x³È‚Hœ’vš¡…………X/X/’v’…’…’…¨…„#iiii:::ffffi@@@@@¸ÿÿ………X‚„§š’„„„ NSFormCell)¸¬‚qþ@‚ @­„˜™†»……²…’…’ƒ„f@2„¹¬‚þ­„™™Width:†»……††’„ˆ¬‚qþ@‚ @­„˜™†»……²…’…’ƒÐ2„¹¬‚þ­„™™Height:†»……†††󅄈¬‚qþ@‚ @­„˜™†»……²…’…’…Ð2„¹¬‚þ­„˜™Field:†»……††’…’…’…†’„›’vš¡…………ÏScc’v’…’…’…¨„ꬂ1þA‚@­„™™Display refresh†»……²…’…’”Ãô†’…É…†’„„’vš¡…………Ïp/p/’v’…’…’…¨…θÿÿ………p‚„§š’„ˆ¬‚qþ@‚ @­„˜™†»……²…’…’—ÐI„¹¬‚þ­„™™Delay:†»……††’„ˆ¬‚qþ@‚ @­„˜™†»……²…’…’—ÐI„¹¬‚þ­„™™ Frequency:†»……†††󅄈¬‚qþ@‚ @­„˜™†»……²…’…’…ÐI„¹¬‚þ­„˜™Field:†»……††’…’…’…†’„›’vš¡…………D8""’v’…’…’…¨„ꬂ1þA‚@­„™™ticks†»……²…’…’¥Ãô†’…É…†’„›’vš¡…………D ''’v’…’…’…¨„ꬂ1þA‚@­„™™Hertz†»……²…’…’¨Ãô†’…É…†’„…’vš¡…………Q’v’…’…’…¨…θ………H‚D¨„§š’„·¬‚$þ­„™™Screen†»……²…’…’«³È‚È""’v’…’…’…¨„ꬂ”qþA‚@­ë»……²…’…’¶Ã †’…É…†’„›’vš¡………… 33’v’…’…’…¨„ꬂ1þA‚@­„™™Depth:†»……²…’…’¸Ãô†’…É…†’„›’vš¡…………e8**’v’…’…’…¨„ꬂ1þA‚@­„™™pixels†»……²…’…’»Ãô†’…É…†’„›’vš¡…………e**’v’…’…’…¨„ꬂ1þA‚@­„™™pixels†»……²…’…’¾Ãô†’…É…†’„›’vš¡…………e""’v’…’…’…¨„ꬂ1þA‚@­„™™bits†»……²…’…’ÁÃô†’…É…††………sese’t’…’…’…††……… îwywy’¢’…’…’…È„¹¬‚þ­„™™Graphics/Sound†»……†v’…†’ ’„µ’¢š¡…………׫«’¢’…’…’…¨„·¬‚þ­„™™Disable CD-ROM Driver†»……²…’…’ƳÈ‚H>’Ÿ’…’…’…¨„ꬂ1þA‚@­„™™ ROM file:†»……²…’…’èÃô†’…É…†’„›’Ÿš¡…………N¾¾’Ÿ’…’…’…¨„ꬂ”qþA‚@­ë»……²…’…’ëà †’…É…†’„µ’Ÿš¡…………`!`!’Ÿ’…’…’…¨„·¬‚þ‚8­„™™ Browse…†»……²…’…’í³È‚†‚@ÿ넘™†…¿…††’„µ’Ÿš¡…………“;NN’Ÿ’…’…’…¨„·¬‚þ­„™™With FPU†»……²…’…’ñ³È‚H IBDocumentLocation 5 42 473 240 0 41 1024 705 IBMainMenuLocation 0 702 365 44 0 42 1152 704 IBUserGuides About guideLocations guidesLocked NO BasiliskII/src/MacOSX/Multiple-Windows/English.lproj/MainMenu.nib/classes.nib0000644000175000017500000000700307444541571027205 0ustar centriscentris{ IBClasses = ( { ACTIONS = { NewEmulator = id; PauseAll = id; RunAll = id; ShowAbout = id; TerminateAll = id; }; CLASS = Controller; LANGUAGE = ObjC; OUTLETS = {myEmulator = id; }; SUPERCLASS = NSObject; }, { ACTIONS = { Interrupt = id; PowerKey = id; Restart = id; Resume = id; Snapshot = id; SpeedChange = id; Suspend = id; Terminate = id; ToggleState = id; ZapPRAM = id; }; CLASS = Emulator; LANGUAGE = ObjC; OUTLETS = {barberPole = id; runOrPause = id; screen = id; speed = id; win = id; }; SUPERCLASS = NSObject; }, {CLASS = EmulatorView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { ACTIONS = { Interrupt = id; PowerKey = id; Restart = id; Resume = id; Snapshot = id; Suspend = id; Terminate = id; ZapPRAM = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { ACTIONS = { AddSCSI = id; AddVolume = id; BrowseEtherNet = id; BrowseExtFS = id; BrowseModem = id; BrowsePrinter = id; BrowseROM = id; ChangeBootFrom = id; ChangeCPU = id; ChangeDisableCD = id; ChangeDisableSound = id; ChangeFPU = id; ChangeModel = id; CreateVolume = id; DeleteVolume = id; EditBytes = id; EditDelay = id; EditDepth = id; EditEtherNetDevice = id; EditExtFS = id; EditFrequency = id; EditHeight = id; EditMB = id; EditModemDevice = id; EditPrinterDevice = id; EditROMpath = id; EditWidth = id; RemoveSCSI = id; RemoveVolume = id; ShowPrefs = id; }; CLASS = PrefsEditor; LANGUAGE = ObjC; OUTLETS = { CPU68000 = id; CPU68020 = id; CPU68030 = id; CPU68040 = id; FPU = id; IIci = id; MB = id; Quadra900 = id; ROMfile = id; SCSIdisks = id; bootFromAny = id; bootFromCD = id; bytes = id; classic = id; delay = id; depth = id; disableCD = id; disableSound = id; diskImages = id; etherNet = id; extFS = id; frequency = id; height = id; modem = id; panel = id; printer = id; width = id; }; SUPERCLASS = NSObject; } ); IBVersion = 1; }BasiliskII/src/MacOSX/prefs_macosx.cpp0000644000175000017500000000705311275113017020022 0ustar centriscentris/* * $Id: prefs_macosx.cpp,v 1.12 2009/11/06 21:33:03 nigel Exp $ * * prefs_macosx.cpp - Preferences handling, Mac OS X specific. * Based on prefs_unix.cpp * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include using std::string; #include "prefs.h" // Platform-specific preferences items prefs_desc platform_prefs_items[] = { #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION {"ignoresegv", TYPE_BOOLEAN, false, "ignore illegal memory accesses"}, #endif {"idlewait", TYPE_BOOLEAN, false, "sleep when idle"}, {NULL, TYPE_END, false, NULL} // End of list }; // Prefs file name and path const char PREFS_FILE_NAME[] = ".basilisk_ii_prefs"; string UserPrefsPath; static string prefs_path; /* * Load preferences from settings file */ void LoadPrefs(const char *vmdir) { if (vmdir) { prefs_path = string(vmdir) + '/' + string("prefs"); FILE *prefs = fopen(prefs_path.c_str(), "r"); if (!prefs) { printf("No file at %s found.\n", prefs_path.c_str()); exit(1); } LoadPrefsFromStream(prefs); fclose(prefs); return; } // Construct prefs path if (UserPrefsPath.empty()) { char *home = getenv("HOME"); if (home) prefs_path = string(home) + '/'; prefs_path += PREFS_FILE_NAME; UserPrefsPath = prefs_path; } else prefs_path = UserPrefsPath; // Read preferences from settings file FILE *f = fopen(prefs_path.c_str(), "r"); if (f != NULL) { // Prefs file found, load settings LoadPrefsFromStream(f); fclose(f); } else { // No prefs file, save defaults SavePrefs(); } // Remove Nigel's bad old serial prefs const char *str; int tmp = 0; if ( (str = PrefsFindString("seriala") ) != NULL && strcmp(str, "/dev/ttys0") == 0 ) { puts("Deleting invalid prefs item 'seriala /dev/ttys0'"); PrefsRemoveItem("seriala", 1); } if ( (str = PrefsFindString("serialb") ) != NULL && strcmp(str, "/dev/ttys1") == 0 ) { puts("Deleting invalid prefs item 'serialb /dev/ttys1'"); PrefsRemoveItem("serialb", 1); } // Floppy & cdrom prefs are always removed - // we search for them each time the emulator is started while ( (str = PrefsFindString("floppy", tmp) ) != NULL ) PrefsRemoveItem("floppy", tmp); while ( (str = PrefsFindString("cdrom", tmp) ) != NULL ) PrefsRemoveItem("cdrom", tmp); } /* * Save preferences to settings file */ void SavePrefs(void) { FILE *f; if ((f = fopen(prefs_path.c_str(), "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit() */ void AddPlatformPrefsDefaults(void) { PrefsReplaceString("extfs", getenv("HOME")); PrefsReplaceString("screen", "win/512/384/16"); #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION PrefsAddBool("ignoresegv", false); #endif PrefsAddBool("idlewait", true); } BasiliskII/src/MacOSX/sys_darwin.cpp0000644000175000017500000003014311040565563017516 0ustar centriscentris/* * $Id: sys_darwin.cpp,v 1.15 2008/07/20 07:38:27 asvitkine Exp $ * * sys_darwin.cpp - Extra Darwin system dependant routines. Called by: * * sys_unix.cpp - System dependent routines, Unix implementation * * Based on Apple's CDROMSample.c and Evan Jones' cd-discid.c patches * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import #import #import #import #import #import #import #ifdef HAVE_IOKIT_STORAGE_IOBLOCKSTORAGEDEVICE_H #import #endif #import #import #import #include "sysdeps.h" #include "sys.h" #include "prefs.h" #define DEBUG 0 #import "debug.h" // Global variables static volatile CFRunLoopRef media_poll_loop = NULL; static bool media_thread_active = false; static pthread_t media_thread; // Prototypes static void *media_poll_func(void *); // From sys_unix.cpp extern void SysMediaArrived(const char *path, int type); extern void SysMediaRemoved(const char *path, int type); /* * Initialization */ void DarwinSysInit(void) { media_thread_active = (pthread_create(&media_thread, NULL, media_poll_func, NULL) == 0); D(bug("Media poll thread installed (%ld)\n", media_thread)); } /* * Deinitialization */ void DarwinSysExit(void) { // Stop media poll thread if (media_thread_active) { while (media_poll_loop == NULL || !CFRunLoopIsWaiting(media_poll_loop)) usleep(0); CFRunLoopStop(media_poll_loop); pthread_join(media_thread, NULL); media_poll_loop = NULL; media_thread_active = false; } } /* * Get the BSD-style path of specified object */ static kern_return_t get_device_path(io_object_t obj, char *path, size_t maxPathLength) { kern_return_t kernResult = KERN_FAILURE; CFTypeRef pathAsCFString = IORegistryEntryCreateCFProperty(obj, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); if (pathAsCFString) { strcpy(path, "/dev/"); size_t pathLength = strlen(path); if (CFStringGetCString((const __CFString *)pathAsCFString, path + pathLength, maxPathLength - pathLength, kCFStringEncodingASCII)) kernResult = KERN_SUCCESS; CFRelease(pathAsCFString); } return kernResult; } /* * kIOMatchedNotification handler */ static void media_arrived(int type, io_iterator_t iterator) { io_object_t obj; while ((obj = IOIteratorNext(iterator))) { char path[MAXPATHLEN]; kern_return_t kernResult = get_device_path(obj, path, sizeof(path)); if (kernResult == KERN_SUCCESS) { D(bug("Media Arrived: %s\n", path)); SysMediaArrived(path, type); } kernResult = IOObjectRelease(obj); if (kernResult != KERN_SUCCESS) { fprintf(stderr, "IOObjectRelease() returned %d\n", kernResult); } } } /* * kIOTerminatedNotification handler */ static void media_removed(int type, io_iterator_t iterator) { io_object_t obj; while ((obj = IOIteratorNext(iterator))) { char path[MAXPATHLEN]; kern_return_t kernResult = get_device_path(obj, path, sizeof(path)); if (kernResult == KERN_SUCCESS) { D(bug("Media Removed: %s\n", path)); SysMediaRemoved(path, type); } kernResult = IOObjectRelease(obj); if (kernResult != KERN_SUCCESS) { fprintf(stderr, "IOObjectRelease() returned %d\n", kernResult); } } } /* * Media poll function * * NOTE: to facilitate orderly thread termination, media_poll_func MUST end up waiting in CFRunLoopRun. * Early returns must be avoided, even if there is nothing useful to be done here. See DarwinSysExit. */ static void dummy(void *) { }; // stub for dummy runloop source static void *media_poll_func(void *) { media_poll_loop = CFRunLoopGetCurrent(); mach_port_t masterPort; kern_return_t kernResult; CFMutableDictionaryRef matchingDictionary; CFRunLoopSourceRef loopSource = NULL; CFRunLoopSourceRef dummySource = NULL; if ((kernResult = IOMasterPort(bootstrap_port, &masterPort)) != KERN_SUCCESS) fprintf(stderr, "IOMasterPort() returned %d\n", kernResult); else if ((matchingDictionary = IOServiceMatching(kIOCDMediaClass)) == NULL) fprintf(stderr, "IOServiceMatching() returned a NULL dictionary\n"); else { matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary); IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault); loopSource = IONotificationPortGetRunLoopSource(notificationPort); CFRunLoopAddSource(media_poll_loop, loopSource, kCFRunLoopDefaultMode); io_iterator_t mediaArrivedIterator; kernResult = IOServiceAddMatchingNotification(notificationPort, kIOMatchedNotification, matchingDictionary, (IOServiceMatchingCallback)media_arrived, (void *)MEDIA_CD, &mediaArrivedIterator); if (kernResult != KERN_SUCCESS) fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult); media_arrived(MEDIA_CD, mediaArrivedIterator); io_iterator_t mediaRemovedIterator; kernResult = IOServiceAddMatchingNotification(notificationPort, kIOTerminatedNotification, matchingDictionary, (IOServiceMatchingCallback)media_removed, (void *)MEDIA_CD, &mediaRemovedIterator); if (kernResult != KERN_SUCCESS) fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult); media_removed(MEDIA_CD, mediaRemovedIterator); } if (loopSource == NULL) { // add a dummy runloop source to prevent premature return from CFRunLoopRun CFRunLoopSourceContext context = { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dummy }; dummySource = CFRunLoopSourceCreate(NULL, 0, &context); CFRunLoopAddSource(media_poll_loop, dummySource, kCFRunLoopDefaultMode); } CFRunLoopRun(); if (dummySource != NULL) CFRelease(dummySource); return NULL; } void DarwinAddFloppyPrefs(void) { mach_port_t masterPort; // The way to talk to the kernel io_iterator_t allFloppies; // List of possible floppys CFMutableDictionaryRef classesToMatch; io_object_t nextFloppy; if ( IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS ) bug("IOMasterPort failed. Won't be able to do anything with floppy drives\n"); // This selects all partitions of all disks classesToMatch = IOServiceMatching(kIOMediaClass); if ( classesToMatch ) { // Skip drivers and partitions CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaWholeKey), kCFBooleanTrue); // Skip fixed drives (hard disks?) CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue); } if ( IOServiceGetMatchingServices(masterPort, classesToMatch, &allFloppies) != KERN_SUCCESS ) { D(bug("IOServiceGetMatchingServices failed. No removable drives found?\n")); return; } // Iterate through each floppy while ( nextFloppy = IOIteratorNext(allFloppies)) { char bsdPath[MAXPATHLEN]; long size; CFTypeRef sizeAsCFNumber = IORegistryEntryCreateCFProperty(nextFloppy, CFSTR(kIOMediaSizeKey), kCFAllocatorDefault, 0); if ( CFNumberGetValue((CFNumberRef)sizeAsCFNumber, kCFNumberSInt32Type, &size) ) { D(bug("Got size of %ld\n", size)); if ( size < 800 * 1024 || size > 1440 * 1024 ) { D(puts("Device does not appear to be 800k or 1440k")); continue; } } else { D(puts("Couldn't get kIOMediaSizeKey of device")); continue; // if kIOMediaSizeKey is unavailable, we shouldn't use it anyway } if (get_device_path(nextFloppy, bsdPath, sizeof(bsdPath)) == KERN_SUCCESS) { PrefsAddString("floppy", bsdPath); } else { D(bug("Could not get BSD device path for floppy\n")); } } IOObjectRelease(nextFloppy); IOObjectRelease(allFloppies); } void DarwinAddSerialPrefs(void) { mach_port_t masterPort; // The way to talk to the kernel io_iterator_t allModems; // List of modems on the system CFMutableDictionaryRef classesToMatch; io_object_t nextModem; if ( IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS ) bug("IOMasterPort failed. Won't be able to do anything with modems\n"); // Serial devices are instances of class IOSerialBSDClient classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); if ( classesToMatch ) { // Narrow the search a little further. Each serial device object has // a property with key kIOSerialBSDTypeKey and a value that is one of // kIOSerialBSDAllTypes, kIOSerialBSDModemType, or kIOSerialBSDRS232Type. CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDModemType)); // This will find built-in and USB modems, but not serial modems. } if ( IOServiceGetMatchingServices(masterPort, classesToMatch, &allModems) != KERN_SUCCESS ) { D(bug("IOServiceGetMatchingServices failed. No modems found?\n")); return; } // Iterate through each modem while ( nextModem = IOIteratorNext(allModems)) { char bsdPath[MAXPATHLEN]; CFTypeRef bsdPathAsCFString = IORegistryEntryCreateCFProperty(nextModem, CFSTR(kIOCalloutDeviceKey), // kIODialinDeviceKey? kCFAllocatorDefault, 0); *bsdPath = '\0'; if ( bsdPathAsCFString ) { if ( CFStringGetCString((const __CFString *)bsdPathAsCFString, bsdPath, MAXPATHLEN, kCFStringEncodingASCII) ) { D(bug("Modem BSD path: %s\n", bsdPath)); // Note that if there are multiple modems, we only get the last PrefsAddString("seriala", bsdPath); } else D(bug("Could not get BSD device path for modem\n")); CFRelease(bsdPathAsCFString); } else D(puts("Cannot determine bsdPath for modem\n")); } IOObjectRelease(nextModem); IOObjectRelease(allModems); // Getting a printer device is a bit harder. Creating a fake device // that emulates a simple printer (e.g. a HP DeskJet) is one possibility, // but for now I will just create a fake, safe, device entry: PrefsAddString("serialb", "/dev/null"); } #ifdef MAC_OS_X_VERSION_10_2 /* * Read CD-ROM TOC (binary MSF format, 804 bytes max.) */ bool DarwinCDReadTOC(char *name, uint8 *toc) { char *c, *devname; int fd; // The open filehandle is something like /dev/disk5s1 // The DKIOCCDREADTOC ioctl needs the original cd file, // so we strip the s1 suffix off it, and open the file just for this ioctl devname = strdup(name); if ( ! devname ) return false; for ( c = devname; *c; ++c ) ; // Go to the end of the name, --c, --c; // point to the 's1' on the end, *c = '\0'; // and truncate the string fd = open(devname, O_RDONLY); if ( ! fd ) { printf("Failed to open CD device %s for ioctl\n", devname); free(devname); return false; } D(bug("Opened %s for ioctl()\n", devname)); dk_cd_read_toc_t TOCrequest; // Setup the ioctl request structure: memset(&TOCrequest, 0, sizeof(TOCrequest)); TOCrequest.buffer = toc; TOCrequest.bufferLength = 804; TOCrequest.formatAsTime = kCDTrackInfoAddressTypeTrackNumber; if ( ioctl(fd, DKIOCCDREADTOC, &TOCrequest) < 0 ) { printf("ioctl(DKIOCCDREADTOC) failed: %s\n", strerror(errno)); close(fd); free(devname); return false; } if ( TOCrequest.bufferLength < sizeof(CDTOC) ) { printf("ioctl(DKIOCCDREADTOC): only read %d bytes (a CDTOC is at least %d)\n", TOCrequest.bufferLength, (int)sizeof(CDTOC)); close(fd); free(devname); return false; } D(bug("ioctl(DKIOCCDREADTOC) read %d bytes\n", TOCrequest.bufferLength)); close(fd); free(devname); return true; } #endif BasiliskII/src/MacOSX/Makefile.in0000644000175000017500000002551711275225126016704 0ustar centriscentris# Unix makefile for Basilisk II ## System specific configuration SHELL = /bin/sh HOST_CC = @CC@ HOST_CXX = @CXX@ CC_PROG = @CC@ CXX_PROG = @CXX@ CFLAGS = @CFLAGS@ CXXFLAGS = @CXXFLAGS@ CPPFLAGS = @CPPFLAGS@ -I../include -I. @CPUINCLUDES@ -I../slirp DEFS = @DEFS@ @DEFINES@ -D_REENTRANT -DAQUA -DFPU_IEEE LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ CFLAGS += -g CPPFLAGS += -I../uae_cpu CXXFLAGS += -g LN_S = ln -s ## Compilers selection (XXX hackery for 10.2 cross-compilation...) SDK_VERSION.ppc = @PPC_SDK_VERSION@ SDK_VERSION = $(SDK_VERSION.$(ARCH)) ifeq ($(SDK_VERSION), 10.2.8) CC_PROG = gcc-3.3 CXX_PROG = g++-3.3 SDK_ROOT = /Developer/SDKs/MacOSX10.2.8.sdk CC_ROOT = -F$(SDK_ROOT)/System/Library/Frameworks LDFLAGS += -Wl,-syslibroot,$(SDK_ROOT) endif ifeq ($(SDK_VERSION), 10.3.9) CC_ROOT = -isysroot /Developer/SDKs/MacOSX10.3.9.sdk -mmacosx-version-min=10.3 endif ifeq ($(SDK_VERSION), 10.4) CC_ROOT = -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 endif CC = $(CC_PROG) $(CC_ROOT) -arch $(ARCH) CXX = $(CXX_PROG) $(CC_ROOT) -arch $(ARCH) SLIRP_CFLAGS = @SLIRP_CFLAGS@ SLIRP_SRCS = @SLIRP_SRCS@ SLIRP_OBJS = $(SLIRP_SRCS:../slirp/%.c=obj/%.o) ## CPU emulation code WANT_JIT = @WANT_JIT@ WANT_JIT_DEBUG = @WANT_JIT_DEBUG@ USE_JIT = no CPUSRCS = \ ../uae_cpu/basilisk_glue.cpp ../uae_cpu/readcpu.cpp \ ../uae_cpu/memory.cpp ../uae_cpu/newcpu.cpp ../uae_cpu/fpu/fpu_ieee.cpp GEN_CPUSRCS = \ cpustbl.cpp cpudefs.cpp \ cpuemu1.cpp cpuemu2.cpp cpuemu3.cpp cpuemu4.cpp \ cpuemu5.cpp cpuemu6.cpp cpuemu7.cpp cpuemu8.cpp ifeq ($(ARCH), i386) USE_JIT = $(WANT_JIT) DEFS += -DUNALIGNED_PROFITABLE -DREGPARAM="__attribute__((regparm(3)))" DEFS += -DX86_ASSEMBLY -DOPTIMIZED_FLAGS -DSAHF_SETO_PROFITABLE endif ifeq ($(ARCH), x86_64) USE_JIT = $(WANT_JIT) DEFS += -DUNALIGNED_PROFITABLE DEFS += -DX86_64_ASSEMBLY -DOPTIMIZED_FLAGS endif ifeq ($(USE_JIT), yes) DEFS += -DUSE_JIT -DUSE_JIT_FPU ifeq ($(WANT_JIT_DEBUG), yes) DEFS += -DJIT_DEBUG endif CPUSRCS += \ ../uae_cpu/compiler/compemu_support.cpp \ ../uae_cpu/compiler/compemu_fpp.cpp GEN_CPUSRCS += \ cpuemu1_nf.cpp cpuemu2_nf.cpp cpuemu3_nf.cpp cpuemu4_nf.cpp \ cpuemu5_nf.cpp cpuemu6_nf.cpp cpuemu7_nf.cpp cpuemu8_nf.cpp \ compemu1.cpp compemu2.cpp compemu3.cpp compemu4.cpp \ compemu5.cpp compemu6.cpp compemu7.cpp compemu8.cpp \ cpustbl_nf.cpp compstbl.cpp endif GEN_DIR = gen ifneq ($(ARCH),) GEN_DIR = gen.$(ARCH) endif CPUSRCS += $(foreach file, $(GEN_CPUSRCS), $(GEN_DIR)/$(file)) CPPFLAGS += -I$(GEN_DIR) ## Source files thst replace/augment the ones from the Unix directory SYSSRCS = serial_unix.cpp ../dummy/scsi_dummy.cpp \ audio_macosx.cpp AudioBackEnd.cpp AudioDevice.cpp MacOSX_sound_if.cpp \ clip_macosx.cpp Controller.mm Emulator.mm EmulatorView.mm \ ether_unix.cpp extfs_macosx.cpp main_macosx.mm misc_macosx.mm \ NNThread.m prefs_macosx.cpp PrefsEditor.mm sys_darwin.cpp video_macosx.mm ## Files SRCS = ../main.cpp ../prefs.cpp ../prefs_items.cpp \ sys_unix.cpp ../rom_patches.cpp ../slot_rom.cpp ../rsrc_patches.cpp \ ../emul_op.cpp ../macos_util.cpp ../xpram.cpp xpram_unix.cpp ../timer.cpp \ timer_unix.cpp ../adb.cpp ../serial.cpp ../ether.cpp \ ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp ../video.cpp \ vm_alloc.cpp sigsegv.cpp ../audio.cpp ../extfs.cpp \ ../user_strings.cpp user_strings_unix.cpp sshpty.c strlcpy.c \ $(SYSSRCS) $(CPUSRCS) $(SLIRP_SRCS) ## Source files from Unix source directory that we link to UNIXSRCS = ether_unix.cpp semaphore.h serial_unix.cpp sigsegv.cpp sigsegv.h \ sshpty.c sshpty.h strlcpy.c strlcpy.h sys_unix.cpp timer_unix.cpp \ user_strings_unix.cpp user_strings_unix.h \ vm_alloc.cpp vm_alloc.h xpram_unix.cpp ## Documentation files DOCS = README.txt Credits.html ToDo.html HowTo.html Versions.html ## Binaries to build APP = BasiliskII APP_APP = $(APP).app TARGET_ARCHES = @TARGET_ARCHES@ PROGS = $(foreach arch, $(TARGET_ARCHES), $(APP).$(arch)) BLESS = $(OBJ_DIR)/lowmem ## Rules .PHONY: modules install installdirs uninstall mostlyclean clean distclean depend dep .SUFFIXES: .SUFFIXES: .c .cpp .s .o .h all: $(APP)_app README.txt: ../../README $(LN_S) $< $@ $(UNIXSRCS): %: ../Unix/% $(LN_S) $< $@ OBJ_DIR = obj ifneq ($(ARCH),) OBJ_DIR = obj.$(ARCH) endif $(OBJ_DIR):: @[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1 define SRCS_LIST_TO_OBJS $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(SRCS), \ $(basename $(notdir $(file)))))) endef OBJS = $(SRCS_LIST_TO_OBJS) SRC_PATHS += $(sort $(foreach file, $(SRCS), $(dir $(file)))) VPATH := VPATH += $(addprefix :, $(subst ,:, $(filter-out $($(subst, :, ,$(VPATH))), $(SRC_PATHS)))) define PROGS_template $(APP).$(1): links +$(MAKE) $(OBJ_DIR).$(1)/$(APP) ARCH=$(1) $(LN_S) -f $(OBJ_DIR).$(1)/$(APP) $(APP).$(1) endef $(APP): $(PROGS) lipo $(foreach arch, $(TARGET_ARCHES), -arch $(arch) $(APP).$(arch)) \ -create -output $@ $(foreach arch,$(TARGET_ARCHES),$(eval $(call PROGS_template,$(arch)))) links: $(UNIXSRCS) $(BLESS): $(OBJ_DIR) $(OBJ_DIR)/lowmem.o $(HOST_CC) -o $@ $(OBJ_DIR)/lowmem.o $(OBJ_DIR)/lowmem.o: ../Unix/Darwin/lowmem.c $(HOST_CC) -o $@ -c $< $(OBJ_DIR)/$(APP): $(OBJ_DIR) $(GEN_DIR) $(OBJS) $(BLESS) $(CXX) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) $(BLESS) $@ $(APP)_app: $(APP) $(DOCS) Info.plist $(APP).icns rm -rf $(APP_APP)/Contents mkdir -p $(APP_APP)/Contents cp -f ../MacOSX/Info.plist $(APP_APP)/Contents/ echo -n 'APPL????' > $(APP_APP)/Contents/PkgInfo mkdir -p $(APP_APP)/Contents/MacOS cp -f $(APP) $(APP_APP)/Contents/MacOS/ strip -x $(APP_APP)/Contents/MacOS/$(APP) mkdir -p $(APP_APP)/Contents/Resources cp -Rp English.lproj $(APP_APP)/Contents/Resources/ cp -f $(APP).icns $(APP_APP)/Contents/Resources/ cp -f $(DOCS) $(APP_APP)/Contents/Resources/ find $(APP_APP) -type d -name CVS | xargs rm -rf mostlyclean: rm -f $(PROGS) $(OBJ_DIR)/* core* *.core *~ *.bak rm -f $(foreach arch, $(TARGET_ARCHES), $(GEN_DIR).$(arch)/*) rm -f $(foreach arch, $(TARGET_ARCHES), $(OBJ_DIR).$(arch)/*) clean: mostlyclean rm -f $(UNIXSRCS) rm -f README.txt distclean: clean rm -rf $(foreach arch, $(TARGET_ARCHES), $(GEN_DIR).$(arch)) rm -rf $(foreach arch, $(TARGET_ARCHES), $(OBJ_DIR).$(arch)) rm -rf autom4te.cache rm -f Makefile rm -f config.cache config.log config.status config.h configure depend dep: makedepend $(CPPFLAGS) -Y. $(SRCS) 2>/dev/null $(OBJ_DIR)/%.o : ../slirp/%.c $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) $(SLIRP_CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.c $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.m $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.mm $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.s $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.ho : %.c $(HOST_CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.ho : %.cpp $(HOST_CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/build68k: $(OBJ_DIR)/build68k.ho $(HOST_CC) -o $@ $(OBJ_DIR)/build68k.ho $(OBJ_DIR)/gencpu: $(OBJ_DIR)/gencpu.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho $(HOST_CXX) -o $@ $(OBJ_DIR)/gencpu.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho $(OBJ_DIR)/gencomp: $(OBJ_DIR)/gencomp.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho $(HOST_CXX) -o $@ $(OBJ_DIR)/gencomp.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho $(GEN_DIR):: @[ -d $(GEN_DIR) ] || mkdir $(GEN_DIR) > /dev/null 2>&1 $(GEN_DIR)/cpudefs.cpp: $(OBJ_DIR)/build68k ../uae_cpu/table68k $(OBJ_DIR)/build68k <../uae_cpu/table68k > $@ $(GEN_DIR)/cpustbl.cpp: $(GEN_DIR)/cpuemu.cpp $(GEN_DIR)/cpustbl_nf.cpp: $(GEN_DIR)/cpustbl.cpp $(GEN_DIR)/compstbl.cpp: $(GEN_DIR)/compemu.cpp $(GEN_DIR)/cputbl.h: $(GEN_DIR)/cpuemu.cpp $(GEN_DIR)/comptbl.h: $(GEN_DIR)/compemu.cpp $(GEN_DIR)/cpuemu.cpp: $(OBJ_DIR)/gencpu cd $(GEN_DIR) && ../$(OBJ_DIR)/gencpu $(GEN_DIR)/compemu.cpp: $(OBJ_DIR)/gencomp cd $(GEN_DIR) && ../$(OBJ_DIR)/gencomp $(OBJ_DIR)/cpustbl_nf.o: $(GEN_DIR)/cpustbl.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -DNOFLAGS -c $< -o $@ $(OBJ_DIR)/compemu_support.o: compemu_support.cpp $(GEN_DIR)/comptbl.h $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu1.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu2.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu3.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu4.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu5.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu6.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu7.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu8.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu1_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu2_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu3_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu4_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu5_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu6_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu7_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu8_nf.o: $(GEN_DIR)/cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu1.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu2.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu3.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu4.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu5.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu6.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu7.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu8.o: $(GEN_DIR)/compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 $(CXXFLAGS) -c $< -o $@ #------------------------------------------------------------------------- # DO NOT DELETE THIS LINE -- make depend depends on it. BasiliskII/src/MacOSX/ToDo.html0000644000175000017500000000606410740061712016361 0ustar centriscentris Bugs:
  • In window mode, if the framerate is low (e.g. if you leave it at the default of 10fps) or if the emulated screen is too large, really fast mouse clicks are sometimes not picked up by the Emulator. For now, click more slowly
  • In full screen mode after a restart, when the mouse is first moved, the emulated pointer jumps to the location that it was before the restart. Disturbing, but not damaging.
  • Ejecting a CD only works in 10.2 or higher, and it freezes the emulation for about 5 seconds.
  • Status of 'dd' command is not always correct. (If it runs out of space, an error about file not found is printed?)
  • The Snapshot function is currently broken in some situations (if the emulation changes its own screen settings, and the program is compiled with the default window drawing mode of CGIMAGEREF). Setting the depth to millions (in the emulator) is a workaround for now
  • Cut and paste between emulator and OS X only half works
Untested:
  • Mac Classic emulation. I don't have a ROM, but I suspect it will crash
  • Serial port code
Unimplemented:
  • CD audio stuff. I am still trying to get this to work
  • CD insert detection. At the moment, if a CD isn't there when the emulator boots, or if you change CDs, it will never know. I don't know how to register with the OS for disk insertion and mount events. (Gwenolé rewrote the CD code, and it should poll for new disks, but it don't work for me. I must be doing something wrong!)
  • Floppy stuff. If a floppy is mounted by the OS X Finder, it is busy and cannot be opened by the emulator
  • Interrupt function for emulator
  • 'nogui' to disable GUI alerts (and maybe preferences, but I need to split MainMenu.nib to do that)
Possible Enhancements:
  • Use NSFileManager's movePath:toPath:handler to rename all a file's forks in extfs_macosx.mm
  • Emulator snapshot - save the current emulator state (memory + registers) to a file for fast startup next time
  • Multiple emulators. The window stuff is mostly there, but the uae_cpu code has lots of globals, and is not re-entrant
  • Real addressing mode for the emulator. Mike Sliczniak had done most of the work, but with real addressing the emulator just crashes for me
  • Improve Objective-C object allocation. e.g. http://www.mulle-kybernetik.com/artikel/Optimisation/opti-5.html
  • Use automake instead of the current 1_prepare_files.sh ?
  • Add JIT options to preferences?
  • Use internal windows to display Help doco?
  • Provide feedback during external commands (e.g. ejecting a CD or creating a disk volume)
  • Widescreen window layout (suggestion by Michael Franz), so that users with widescreen displays can squeeze a bigger emulated screen in. I have a mock up of this that can be pasted in (MainMenu.nib). Ideally, this would be via a generalised "theme" facility, but who has time for that :-)
BasiliskII/src/MacOSX/PrefsEditor.mm0000644000175000017500000004554311275113017017414 0ustar centriscentris/* * PrefsEditor.m - GUI stuff for Basilisk II preferences * (which is a text file in the user's home directory) * * $Id: PrefsEditor.mm,v 1.21 2009/11/06 21:33:03 nigel Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import "PrefsEditor.h" @implementation TableDS - (TableDS *) init { self = [super init]; numItems = 0; col1 = [NSMutableArray new]; col2 = [NSMutableArray new]; return self; } - (void) dealloc { [col1 dealloc]; [col2 dealloc]; [super dealloc]; } - (void) addInt: (int)target withPath: (NSString *)path { [col1 addObject: [NSNumber numberWithInt: target]]; [col2 addObject: path]; ++numItems; } - (void) addObject: (NSObject *)obj withPath: (NSString *)path { [col1 addObject: obj]; [col2 addObject: path]; ++numItems; } - (void) deleteAll { numItems = 0; [col1 removeAllObjects]; [col2 removeAllObjects]; } - (BOOL) deleteRow: (int)row { if ( row > numItems ) return NO; [col1 removeObjectAtIndex: row]; [col2 removeObjectAtIndex: row]; -- numItems; return YES; } - (int)intAtRow: (int)row { return [[col1 objectAtIndex: row] intValue]; } - (int) numberOfRowsInTableView: (NSTableView *)tView { return numItems; } - (NSString *)pathAtRow: (int)row { return (NSString *) [col2 objectAtIndex: row]; } - (id) tableView: (NSTableView *)tView objectValueForTableColumn: (NSTableColumn *)tColumn row: (int)row { if ( [[tColumn identifier] isEqualToString:@"path"] ) return [col2 objectAtIndex: row]; else return [col1 objectAtIndex: row]; } @end #import // For [NSBundle pathForImageResource:] proto #include using std::string; extern string UserPrefsPath; // from prefs_unix.cpp #import "sysdeps.h" // Types used in Basilisk C++ code #import "video_macosx.h" // some items that we edit here #import "misc_macosx.h" // WarningSheet() prototype #import "main_macosx.h" // ChoiceAlert() prototype #import #define DEBUG 0 #import @implementation PrefsEditor - (PrefsEditor *) init { self = [super init]; edited = NO; devs = @"/dev"; home = [NSHomeDirectory() retain]; volsDS = [TableDS new]; SCSIds = [TableDS new]; lockCell = [NSImageCell new]; if ( lockCell == nil ) NSLog (@"%s - Can't create NSImageCell?", __PRETTY_FUNCTION__); blank = [NSImage new]; locked = [[NSImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForImageResource: @"nowrite.icns"]]; if (locked == nil ) NSLog(@"%s - Couldn't open write protection image", __PRETTY_FUNCTION__); return self; } - (void) dealloc { [home release]; [volsDS release]; [SCSIds release]; [lockCell release]; [blank release]; [locked release]; [super dealloc]; } - (void) awakeFromNib { emuFreq = [theEmulator speed]; #if DEBUG [self ShowPrefs: self]; // For testing #endif } - (BOOL) hasEdited { return edited; } - (NSWindow *) window { return panel; } - (IBAction) AddSCSI: (id)sender { NSOpenPanel *oP = [NSOpenPanel openPanel]; if ( [oP runModalForDirectory:home file:nil types:nil] == NSOKButton ) { [SCSIds addInt: -1 withPath: [oP filename] ]; [SCSIdisks reloadData]; edited = YES; } } - (IBAction) AddVolume: (id)sender { NSOpenPanel *oP = [NSOpenPanel openPanel]; if ( [oP runModalForDirectory:home file:nil types:nil] == NSOKButton ) { [volsDS addObject: (NSObject *) locked withPath: [oP filename] ]; PrefsAddString("disk", [[oP filename] UTF8String]); [diskImages reloadData]; edited = YES; } } - (IBAction) BrowseExtFS: (id)sender { NSOpenPanel *oP = [NSOpenPanel openPanel]; [oP setCanChooseDirectories: YES]; [oP setCanChooseFiles: NO]; [oP setPrompt: @"Select"]; [oP setTitle: @"Select a directory to mount"]; D(NSLog(@"%s - home = %@, [extFS stringValue] = %@", __PRETTY_FUNCTION__, home, [extFS stringValue])); if ( [oP runModalForDirectory: ([extFS stringValue] ? [extFS stringValue] : home) file:nil types:nil] == NSOKButton ) { [extFS setStringValue: [oP directory] ]; PrefsReplaceString("extfs", [[oP directory] UTF8String]); edited = YES; } } - (IBAction) BrowsePrefs: (id)sender { NSOpenPanel *oP = [NSOpenPanel openPanel]; [oP setCanChooseFiles: YES]; [oP setTitle: @"Select a Preferences file"]; D(NSLog(@"%s - home = %@", __PRETTY_FUNCTION__, home)); if ( [oP runModalForDirectory: ([prefsFile stringValue] ? [prefsFile stringValue] : home) file:nil types:nil] == NSOKButton ) { [prefsFile setStringValue: [oP filename] ]; UserPrefsPath = [[oP filename] UTF8String]; } } - (IBAction) BrowseROM: (id)sender { NSOpenPanel *oP = [NSOpenPanel openPanel]; [oP setCanChooseFiles: YES]; [oP setTitle: @"Open a ROM file"]; D(NSLog(@"%s - home = %@", __PRETTY_FUNCTION__, home)); if ( [oP runModalForDirectory: ([ROMfile stringValue] ? [ROMfile stringValue] : home) file:nil types:nil] == NSOKButton ) { [ROMfile setStringValue: [oP filename] ]; PrefsReplaceString("rom", [[oP filename] UTF8String]); edited = YES; } } #include // for CDROMRefNum - (IBAction) ChangeBootFrom: (NSMatrix *)sender { if ( [sender selectedCell] == (id)bootFromCD ) { [disableCD setState: NSOffState]; PrefsReplaceInt32("bootdriver", CDROMRefNum); } else PrefsReplaceInt32("bootdriver", 0); edited = YES; } - (IBAction) ChangeCPU: (NSMatrix *)sender { PrefsReplaceInt32("cpu", [[sender selectedCell] tag]); edited = YES; } - (IBAction) ChangeDisableCD: (NSButton *)sender { int disabled = [disableCD state]; PrefsReplaceBool("nocdrom", disabled); if ( disabled ) { [bootFromAny setState: NSOnState]; [bootFromCD setState: ![disableCD state]]; } edited = YES; } - (IBAction) ChangeDisableSound: (NSButton *)sender { BOOL noSound = [disableSound state]; if ( ! noSound ) WarningSheet(@"Sound is currently unimplemented", panel); PrefsReplaceBool("nosound", noSound); edited = YES; } - (IBAction) ChangeFPU: (NSButton *)sender { PrefsReplaceBool("fpu", [FPU state]); edited = YES; } - (IBAction) ChangeKeyboard: (NSPopUpButton *)sender { // Deselest current item int current = [keyboard indexOfItemWithTag: PrefsFindInt32("keyboardtype")]; if ( current != -1 ) [[keyboard itemAtIndex: current] setState: FALSE]; PrefsReplaceInt32("keyboardtype", [[sender selectedItem] tag]); edited = YES; } - (IBAction) ChangeModel: (NSMatrix *)sender { PrefsReplaceInt32("modelid", [[sender selectedCell] tag]); edited = YES; } // If we are not using the CGIMAGEREF drawing strategy, // then source bitmaps must be 32bits deep. - (short) testWinDepth: (int) newbpp { #ifdef CGIMAGEREF return newbpp; #else if ( newbpp != 32 ) WarningSheet(@"Sorry - In windowed mode, depth must be 32", panel); return 32; #endif } // This is called when the screen/window, // width, height or depth is clicked. // // Note that sender may not actually be an NSMatrix. - (IBAction) ChangeScreen: (NSMatrix *)sender { NSButton *cell = [sender selectedCell]; short newx = [width intValue]; short newy = [height intValue]; short newbpp = [depth intValue]; short newtype; char str[20]; if ( cell == screen ) newtype = DISPLAY_SCREEN; else if ( cell == window ) newtype = DISPLAY_WINDOW; else newtype = display_type; // Check that a field actually changed if ( newbpp == init_depth && newx == init_width && newy == init_height && newtype == display_type ) { D(NSLog(@"No changed GUI items in ChangeScreen")); return; } // If we are changing type, supply some sensible defaults short screenx = CGDisplayPixelsWide(kCGDirectMainDisplay), screeny = CGDisplayPixelsHigh(kCGDirectMainDisplay), screenb = CGDisplayBitsPerPixel(kCGDirectMainDisplay); if ( newtype != display_type ) { D(NSLog(@"Changing display type in ChangeScreen")); // If changing to full screen, supply main screen dimensions as a default if ( newtype == DISPLAY_SCREEN ) newx = screenx, newy = screeny, newbpp = screenb; // If changing from full screen, use minimum screen resolutions if ( display_type == DISPLAY_SCREEN ) { newx = MIN_WIDTH, newy = MIN_HEIGHT; newbpp = [self testWinDepth: newbpp]; } } else { newbpp = [self testWinDepth: newbpp]; // Check size is within ranges of MIN_WIDTH ... MAX_WIDTH // and MIN_HEIGHT ... MAX_HEIGHT // ??? } [width setIntValue: newx]; [height setIntValue: newy]; [depth setIntValue: newbpp]; // Store new prefs *str = '\0'; switch ( newtype ) { case DISPLAY_WINDOW: if ( newbpp ) sprintf(str, "win/%hd/%hd/%hd", newx, newy, newbpp); else sprintf(str, "win/%hd/%hd", newx, newy); break; case DISPLAY_SCREEN: if ( newbpp ) sprintf(str, "full/%hd/%hd/%hd", newx, newy, newbpp); else sprintf(str, "full/%hd/%hd", newx, newy); break; }; PrefsReplaceString("screen", str); parse_screen_prefs(str); edited = YES; if ( display_type != DISPLAY_SCREEN ) { D(NSLog(@"Display type is not SCREEN (%d), resizing window", display_type)); resizeWinTo(newx, newy); } } - (IBAction) CreateVolume: (id)sender { NSSavePanel *sP = [NSSavePanel savePanel]; [sP setAccessoryView: newVolumeView]; [sP setPrompt: @"Create"]; [sP setTitle: @"Create new volume as"]; if ( [sP runModalForDirectory:NSHomeDirectory() file:@"basilisk-II.vol"] == NSOKButton ) { char cmd[1024]; const char *filename = [[sP filename] UTF8String]; int retVal, size = [newVolumeSize intValue]; sprintf(cmd, "dd if=/dev/zero \"of=%s\" bs=1024k count=%d", filename, size); retVal = system(cmd); if (retVal != 0) { NSString *details = [NSString stringWithFormat: @"The dd command failed.\nReturn status %d (%s)", retVal, strerror(errno)]; WarningSheet(@"Unable to create volume", details, nil, panel); } else { [volsDS addObject: (NSObject *) blank withPath: [sP filename] ]; PrefsAddString("disk", filename); [diskImages reloadData]; } } } - (BOOL) fileManager: (NSFileManager *) manager shouldProceedAfterError: (NSDictionary *) errorDict { NSRunAlertPanel(@"File operation error", @"%@ %@, toPath %@", @"Bugger!", nil, nil, [errorDict objectForKey:@"Error"], [errorDict objectForKey:@"Path"], [errorDict objectForKey:@"ToPath"]); return NO; } - (IBAction) DeleteVolume: (id)sender { NSString *Path = [self RemoveVolumeEntry]; if ( ! Path ) return; if ( ! [[NSFileManager defaultManager] removeFileAtPath: Path handler: self] ) { WarningSheet(@"Unable to delete volume", panel); NSLog(@"%s unlink(%s) failed - %s", __PRETTY_FUNCTION__, [Path cString], strerror(errno)); } } - (IBAction) EditDelay: (NSTextField *)sender { int ticks = [delay intValue]; float freq; if ( ticks ) freq = 60.0 / ticks; else freq = 60.0; [frequency setFloatValue: freq]; [emuFreq setFloatValue: freq]; PrefsReplaceInt32("frameskip", ticks); edited = YES; } - (IBAction) EditBytes: (NSTextField *)sender { int B = (int) [bytes floatValue]; float M = B / 1024 / 1024; D(NSLog(@"%s = %f %d", __PRETTY_FUNCTION__, M, B)); PrefsReplaceInt32("ramsize", B); [MB setFloatValue: M]; edited = YES; } - (IBAction) EditEtherNetDevice: (NSTextField *)sender { NSString *path = [etherNet stringValue]; PrefsReplaceString("ether", [path UTF8String]); edited = YES; } - (IBAction) EditExtFS: (NSTextField *)sender { NSString *path = [extFS stringValue]; PrefsReplaceString("extfs", [path UTF8String]); edited = YES; } - (IBAction) EditFrequency: (NSTextField *)sender { float freq = [frequency floatValue]; [delay setIntValue: frequencyToTickDelay(freq)]; [emuFreq setFloatValue: freq]; edited = YES; } - (IBAction) EditModemDevice: (NSTextField *)sender { NSString *path = [modem stringValue]; PrefsReplaceString("seriala", [path UTF8String]); edited = YES; } - (IBAction) EditMB: (NSTextField *)sender { float M = [MB floatValue]; int B = (int) (M * 1024 * 1024); D(NSLog(@"%s = %f %d", __PRETTY_FUNCTION__, M, B)); PrefsReplaceInt32("ramsize", B); [bytes setIntValue: B]; edited = YES; } - (IBAction) EditPrinterDevice: (NSTextField *)sender { NSString *path = [printer stringValue]; PrefsReplaceString("serialb", [path UTF8String]); edited = YES; } - (IBAction) EditROMpath: (NSTextField *)sender { NSString *path = [ROMfile stringValue]; PrefsReplaceString("rom", [path UTF8String]); } - (IBAction) RemoveSCSI: (id)sender { char pref[6]; int row = [SCSIdisks selectedRow], SCSIid = [SCSIds intAtRow: row]; if ( ! [SCSIds deleteRow: row] ) NSLog (@"%s - [SCSIds deleteRow: %d] failed", __PRETTY_FUNCTION__, row); [SCSIdisks reloadData]; sprintf(pref, "scsi%d", SCSIid); //PrefsRemoveItem(pref,0); PrefsRemoveItem(pref, 1); } - (NSString *) RemoveVolumeEntry { int row = [diskImages selectedRow]; if ( row != -1 ) { NSString *Path = [volsDS pathAtRow: row]; const char *path = [Path UTF8String], *str; int tmp = 0; NSString *prompt = [NSString stringWithFormat: @"%s\n%s", "Are you sure you want to delete the file", path]; if ( ! ChoiceAlert([prompt cString], "Delete", "Cancel") ) return NULL; while ( (str = PrefsFindString("disk", tmp) ) != NULL ) { if ( strcmp(str, path) == 0 ) { PrefsRemoveItem("disk", tmp); D(NSLog(@"%s - Deleted prefs entry \"disk\", %d", __PRETTY_FUNCTION__, tmp)); edited = YES; break; } ++tmp; } if ( str == NULL ) { NSLog(@"%s - Couldn't find any disk preference to match %s", __PRETTY_FUNCTION__, path); return NULL; } if ( ! [volsDS deleteRow: row] ) NSLog (@"%s - RemoveVolume %d failed", __PRETTY_FUNCTION__, tmp); [diskImages reloadData]; // return path; return Path; } else { WarningSheet(@"Please select a volume first", panel); return NULL; } } - (IBAction) RemoveVolume: (id)sender { [self RemoveVolumeEntry]; } - (void) loadPrefs: (int) argc args: (char **) argv { [panel close]; // Temporarily hide preferences panel PrefsExit(); // Purge all the old pref values PrefsInit(NULL, argc, argv); AddPrefsDefaults(); AddPlatformPrefsDefaults(); // and only create basic ones [SCSIds deleteAll]; // Clear out datasources for the tables [volsDS deleteAll]; [self ShowPrefs: self]; // Reset items in panel, and redisplay edited = NO; } - (IBAction) LoadPrefs: (id)sender { int argc = 2; char *argv[2]; argv[0] = "--prefs", argv[1] = (char *) [[prefsFile stringValue] UTF8String]; [self loadPrefs: argc args: argv]; } - (IBAction) ResetPrefs: (id)sender { [self loadPrefs: 0 args: NULL]; } - (void) setStringOf: (NSTextField *) field fromPref: (const char *) prefName { const char *value = PrefsFindString(prefName, 0); if ( value ) [field setStringValue: [NSString stringWithUTF8String: value] ]; } - (IBAction) SavePrefs: (id)sender { SavePrefs(); edited = NO; } - (IBAction) ShowPrefs: (id)sender { NSTableColumn *locks; const char *str; int cpu, tmp, val; // Set simple single field items val = PrefsFindInt32("frameskip"); [delay setIntValue: val]; if ( val ) [frequency setFloatValue: 60.0 / val]; else [frequency setFloatValue: 60.0]; val = PrefsFindInt32("ramsize"); [bytes setIntValue: val]; [MB setFloatValue: val / (1024.0 * 1024.0)]; [disableCD setState: PrefsFindBool("nocdrom")]; [disableSound setState: PrefsFindBool("nosound")]; [FPU setState: PrefsFindBool("fpu") ]; [self setStringOf: etherNet fromPref: "ether" ]; [self setStringOf: extFS fromPref: "extfs" ]; [self setStringOf: modem fromPref: "seriala"]; [self setStringOf: printer fromPref: "serialb"]; [self setStringOf: ROMfile fromPref: "rom"]; [prefsFile setStringValue: [NSString stringWithUTF8String: UserPrefsPath.c_str()] ]; parse_screen_prefs(PrefsFindString("screen")); [width setIntValue: init_width]; [height setIntValue: init_height]; [depth setIntValue: init_depth]; [screen setState: NO]; switch ( display_type ) { case DISPLAY_WINDOW: [window setState: YES]; break; case DISPLAY_SCREEN: [screen setState: YES]; break; } [newVolumeSize setIntValue: 10]; // Radio button groups: val = PrefsFindInt32("bootdriver"); [bootFromAny setState: val != CDROMRefNum]; [bootFromCD setState: val == CDROMRefNum]; cpu = PrefsFindInt32("cpu"); val = PrefsFindInt32("modelid"); #if REAL_ADDRESSING || DIRECT_ADDRESSING puts("Current memory model does not support 24bit addressing"); if ( val == [classic tag] ) { // Window already created by NIB file, just display [panel makeKeyAndOrderFront:self]; WarningSheet(@"Compiled-in memory model does not support 24bit", @"Disabling Mac Classic emulation", nil, panel); cpu = [CPU68030 tag]; PrefsReplaceInt32("cpu", cpu); val = [IIci tag]; PrefsReplaceInt32("modelid", val); } puts("Disabling 68000 & Mac Classic buttons"); [CPU68000 setEnabled:FALSE]; [classic setEnabled:FALSE]; #endif [CPU68000 setState: [CPU68000 tag] == cpu]; [CPU68020 setState: [CPU68020 tag] == cpu]; [CPU68030 setState: [CPU68030 tag] == cpu]; [CPU68040 setState: [CPU68040 tag] == cpu]; [classic setState: [classic tag] == val]; [IIci setState: [IIci tag] == val]; [quadra900 setState: [quadra900 tag] == val]; // Lists of thingies: val = PrefsFindInt32("keyboardtype"); tmp = [keyboard indexOfItemWithTag: val]; if ( tmp != -1 ) [keyboard selectItemAtIndex: tmp]; for ( tmp = 0; tmp < [keyboard numberOfItems]; ++tmp ) { NSMenuItem *type = [keyboard itemAtIndex: tmp]; [type setState: [type tag] == val]; } for ( tmp = 0; tmp < 7; ++tmp) { char pref[6]; pref[0] = '\0'; sprintf (pref, "scsi%d", tmp); if ( (str = PrefsFindString(pref, 0) ) ) [SCSIds addInt: tmp withPath: [NSString stringWithCString: str] ]; } [SCSIdisks setDataSource: SCSIds]; locks = [diskImages tableColumnWithIdentifier: @"locked"]; if ( locks == nil ) NSLog (@"%s - Can't find column for lock images", __PRETTY_FUNCTION__); [locks setDataCell: lockCell]; tmp = 0; while ( (str = PrefsFindString("disk", tmp++) ) != NULL ) { if ( *str == '*' ) [volsDS addObject: (NSObject *) locked withPath: [NSString stringWithUTF8String: str+1]]; else [volsDS addObject: (NSObject *) blank withPath: [NSString stringWithUTF8String: str]]; } [diskImages setDataSource: volsDS]; [panel makeKeyAndOrderFront:self]; // Window already created by NIB file, just display } @end BasiliskII/src/MacOSX/EmulatorView.mm0000644000175000017500000003020610736405220017600 0ustar centriscentris/* * EmulatorView.mm - Custom NSView for Basilisk II windowed graphics output * * $Id: EmulatorView.mm,v 1.16 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import "sysdeps.h" // Types used in Basilisk C++ code, #define DEBUG 0 #import #import #import "main_macosx.h" // For WarningAlert() et al prototypes #import "misc_macosx.h" // For InfoSheet() prototype #import "video_macosx.h" // For init_* globals, and bitmap drawing strategy #import "EmulatorView.h" @implementation EmulatorView // // Standard NSView methods that we override // - (id) initWithFrame: (NSRect) frameRect { self = [super initWithFrame: frameRect]; output = self; // Set global for access by Basilisk C++ code // bitmap = nil; // Set by readyToDraw: drawView = NO; // Disable drawing until later fullScreen = NO; return self; } - (void) awakeFromNib { // Here we store the height of the screen which the app was opened on. // NSApplication's sendEvent: always uses that screen for its mouse co-ords screen_height = (int) [[NSScreen mainScreen] frame].size.height; } // Mouse click in this window. If window is not active, // should the click be passed to this view? - (BOOL) acceptsFirstMouse: (NSEvent *) event { return [self mouseInView]; } // // Key event processing. // OS X doesn't send us separate events for the modifier keys // (shift/control/command), so we need to monitor them separately // #include static int prevFlags; - (void) flagsChanged: (NSEvent *) event { int flags = [event modifierFlags]; if ( (flags & NSAlphaShiftKeyMask) != (prevFlags & NSAlphaShiftKeyMask) ) if ( flags & NSAlphaShiftKeyMask ) ADBKeyDown(0x39); // CAPS_LOCK else ADBKeyUp(0x39); if ( (flags & NSShiftKeyMask) != (prevFlags & NSShiftKeyMask) ) if ( flags & NSShiftKeyMask ) ADBKeyDown(0x38); // SHIFT_LEFT else ADBKeyUp(0x38); if ( (flags & NSControlKeyMask) != (prevFlags & NSControlKeyMask) ) if ( flags & NSControlKeyMask ) ADBKeyDown(0x36); // CTL_LEFT else ADBKeyUp(0x36); if ( (flags & NSAlternateKeyMask) != (prevFlags & NSAlternateKeyMask) ) if ( flags & NSAlternateKeyMask ) ADBKeyDown(0x3a); // OPTION_LEFT else ADBKeyUp(0x3a); if ( (flags & NSCommandKeyMask) != (prevFlags & NSCommandKeyMask) ) if ( flags & NSCommandKeyMask ) ADBKeyDown(0x37); // APPLE_LEFT else ADBKeyUp(0x37); prevFlags = flags; } // // Windowed mode. We only send mouse/key events // if the OS X mouse is within the little screen // - (BOOL) mouseInView: (NSEvent *) event { NSRect box; NSPoint loc; if ( fullScreen ) { box = displayBox; loc = [NSEvent mouseLocation]; } else { box = [self frame]; loc = [event locationInWindow]; } D(NSLog (@"%s - loc.x=%f, loc.y=%f, box.origin.x=%f, box.origin.y=%f, box.size.width=%f, box.size.height=%f", __PRETTY_FUNCTION__, loc.x, loc.y, box.origin.x, box.origin.y, box.size.width, box.size.height)); return [self mouse: loc inRect: box]; } - (BOOL) mouseInView { NSPoint loc = [[self window] mouseLocationOutsideOfEventStream]; NSRect box = [self frame]; D(NSLog (@"%s - loc.x=%f, loc.y=%f, box.origin.x=%f, box.origin.y=%f", __PRETTY_FUNCTION__, loc.x, loc.y, box.origin.x, box.origin.y)); return [self mouse: loc inRect: box]; } // // Custom methods // - (void) benchmark { int i; float seconds; NSDate *startDate; char *method; if ( ! drawView ) { WarningSheet (@"The emulator has not been setup yet.", @"Try to run, then pause the emulator, first.", nil, [self window]); return; } drawView = NO; [self lockFocus]; startDate = [NSDate date]; for (i = 1; i < 300; ++i ) #ifdef NSBITMAP [bitmap draw]; #endif #ifdef CGIMAGEREF cgDrawInto([self bounds], cgImgRep); #endif #ifdef CGDRAWBITMAP [self CGDrawBitmap]; #endif seconds = -[startDate timeIntervalSinceNow]; [self unlockFocus]; drawView = YES; #ifdef NSBITMAP method = "NSBITMAP"; #endif #ifdef CGIMAGEREF method = "CGIMAGEREF"; #endif #ifdef CGDRAWBITMAP method = "CGDRAWBITMAP"; #endif InfoSheet(@"Ran benchmark (300 screen redraws)", [NSString stringWithFormat: @"%.2f seconds, %.3f frames per second (using %s implementation)", seconds, i/seconds, method], @"Thanks", [self window]); } // Return a TIFF for a snapshot of the screen image - (NSData *) TIFFrep { #ifdef NSBITMAP return [bitmap TIFFRepresentation]; #else NSBitmapImageRep *b = [NSBitmapImageRep alloc]; b = [b initWithBitmapDataPlanes: (unsigned char **) &bitmap pixelsWide: x pixelsHigh: y #ifdef CGIMAGEREF bitsPerSample: CGImageGetBitsPerComponent(cgImgRep) samplesPerPixel: 3 hasAlpha: NO isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: CGImageGetBytesPerRow(cgImgRep) bitsPerPixel: CGImageGetBitsPerPixel(cgImgRep)]; #endif #ifdef CGDRAWBITMAP bitsPerSample: bps samplesPerPixel: spp hasAlpha: hasAlpha isPlanar: isPlanar colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: bytesPerRow bitsPerPixel: bpp]; #endif if ( ! b ) { ErrorAlert("Could not allocate an NSBitmapImageRep for the TIFF\nTry setting the emulation to millions of colours?"); return nil; } return [b TIFFRepresentation]; #endif } // Enable display of, and drawing into, the view #ifdef NSBITMAP - (void) readyToDraw: (NSBitmapImageRep *) theBitmap imageWidth: (short) width imageHeight: (short) height { numBytes = [theBitmap bytesPerRow] * height; #endif #ifdef CGIMAGEREF - (void) readyToDraw: (CGImageRef) image bitmap: (void *) theBitmap imageWidth: (short) width imageHeight: (short) height { cgImgRep = image; numBytes = CGImageGetBytesPerRow(image) * height; #endif #ifdef CGDRAWBITMAP - (void) readyToDraw: (void *) theBitmap width: (short) width height: (short) height bps: (short) bitsPerSample spp: (short) samplesPerPixel bpp: (short) bitsPerPixel bpr: (int) bpr isPlanar: (BOOL) planar hasAlpha: (BOOL) alpha { bps = bitsPerSample; spp = samplesPerPixel; bpp = bitsPerPixel; bytesPerRow = bpr; isPlanar = planar; hasAlpha = alpha; numBytes = bpr * height; #endif D(NSLog(@"readyToDraw: theBitmap=%lx\n", theBitmap)); bitmap = theBitmap; x = width, y = height; drawView = YES; [[self window] setAcceptsMouseMovedEvents: YES]; // [[self window] setInitialFirstResponder: self]; [[self window] makeFirstResponder: self]; } - (void) disableDrawing { drawView = NO; } - (void) startedFullScreen: (CGDirectDisplayID) display { CGRect displayBounds = CGDisplayBounds(display); fullScreen = YES; memcpy(&displayBox, &displayBounds, sizeof(displayBox)); } - (short) width { return (short)[self bounds].size.width; } - (short) height { return (short)[self bounds].size.height; } - (BOOL) isFullScreen { return fullScreen; } - (BOOL) isOpaque { return drawView; } - (BOOL) processKeyEvent: (NSEvent *) event { if ( fullScreen || [self acceptsFirstMouse: event] ) if ( [event isARepeat] ) return NO; else return YES; [self interpretKeyEvents:[NSArray arrayWithObject:event]]; return NO; } - (void) keyDown: (NSEvent *) event { if ( [self processKeyEvent: event] ) { int code = [event keyCode]; if ( code == 126 ) code = 0x3e; // CURS_UP if ( code == 125 ) code = 0x3d; // CURS_DOWN if ( code == 124 ) code = 0x3c; // CURS_RIGHT if ( code == 123 ) code = 0x3b; // CURS_LEFT ADBKeyDown(code); } } - (void) keyUp: (NSEvent *) event { if ( [self processKeyEvent: event] ) { int code = [event keyCode]; if ( code == 126 ) code = 0x3e; // CURS_UP if ( code == 125 ) code = 0x3d; // CURS_DOWN if ( code == 124 ) code = 0x3c; // CURS_RIGHT if ( code == 123 ) code = 0x3b; // CURS_LEFT ADBKeyUp(code); } } - (void) fullscreenMouseMove { NSPoint location = [NSEvent mouseLocation]; D(NSLog (@"%s - loc.x=%f, loc.y=%f", __PRETTY_FUNCTION__, location.x, location.y)); D(NSLog (@"%s - Sending ADBMouseMoved(%d,%d). (%d-%d)", __PRETTY_FUNCTION__, (int)location.x, screen_height - (int)location.y, screen_height, (int)location.y)); ADBMouseMoved((int)location.x, screen_height - (int)location.y); } static NSPoint mouse; // Previous/current mouse location - (BOOL) processMouseMove: (NSEvent *) event { if ( ! drawView ) { D(NSLog(@"Unable to process event - Emulator has not started yet")); return NO; } if ( fullScreen ) { [self fullscreenMouseMove]; return YES; } NSPoint location = [self convertPoint: [event locationInWindow] fromView:nil]; D(NSLog (@"%s - loc.x=%f, loc.y=%f", __PRETTY_FUNCTION__, location.x, location.y)); if ( NSEqualPoints(location, mouse) ) return NO; mouse = location; int mouseY = y - (int) (y * mouse.y / [self height]); int mouseX = (int) (x * mouse.x / [self width]); // If the view was not resizable, then this would be simpler: // int mouseY = y - (int) mouse.y; // int mouseX = (int) mouse.x; ADBMouseMoved(mouseX, mouseY); return YES; } - (void) mouseDown: (NSEvent *) event { [self processMouseMove: event]; ADBMouseDown(0); } - (void) mouseDragged: (NSEvent *) event { [self processMouseMove: event]; } - (void) mouseMoved: (NSEvent *) event { #if DEBUG if ( ! [self mouseInView] ) { NSLog (@"%s - Received event while outside of view", __PRETTY_FUNCTION__); return; } #endif [self processMouseMove: event]; } - (void) mouseUp: (NSEvent *) event { [self processMouseMove: event]; ADBMouseUp(0); } #if DEBUG - (void) randomise // Draw some coloured snow in the bitmap { unsigned char *data, *pixel; #ifdef NSBITMAP data = [bitmap bitmapData]; #else data = bitmap; #endif for ( int i = 0; i < 1000; ++i ) { pixel = data + (int) (numBytes * rand() / RAND_MAX); *pixel = (unsigned char) (256.0 * rand() / RAND_MAX); } } #endif - (void) drawRect: (NSRect) rect { if ( ! drawView ) // If the emulator is still being setup, return; // we do not want to draw #if DEBUG NSLog(@"In drawRect"); [self randomise]; #endif #ifdef NSBITMAP NSRectClip(rect); [bitmap draw]; #endif #ifdef CGIMAGEREF cgDrawInto(rect, cgImgRep); #endif #ifdef CGDRAWBITMAP [self CGDrawBitmap]; #endif } - (void) setTo: (int) val // Set all of bitmap to val { unsigned char *data #ifdef NSBITMAP = [bitmap bitmapData]; #else = (unsigned char *) bitmap; #endif memset(data, val, (long unsigned)numBytes); } - (void) blacken // Set bitmap black { [self setTo: 0]; } - (void) clear // Set bitmap white { [self setTo: 0xFF]; } // // Extra drawing stuff // #ifdef CGDRAWBITMAP extern "C" void CGDrawBitmap(...); - (void) CGDrawBitmap { CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; NSRect rect = [self bounds]; CGRect cgRect = { {rect.origin.x, rect.origin.y}, {rect.size.width, rect.size.height} }; CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect? CGDrawBitmap(cgContext, cgRect, x, y, bps, spp, bpp, bytesPerRow, isPlanar, hasAlpha, colourSpace, &bitmap); } #endif #ifdef CGIMAGEREF void cgDrawInto(NSRect rect, CGImageRef cgImgRep) { CGContextRef cgContext = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; CGRect cgRect = { {rect.origin.x, rect.origin.y}, {rect.size.width, rect.size.height} }; // CGContextSetShouldAntialias(cgContext, NO); // Seems to have no effect? CGContextDrawImage(cgContext, cgRect, cgImgRep); } #endif @end BasiliskII/src/MacOSX/misc_macosx.mm0000644000175000017500000000616110736405220017465 0ustar centriscentris/* * $Id: misc_macosx.mm,v 1.6 2008/01/01 09:40:32 gbeauche Exp $ * * misc_macosx.m - Miscellaneous Mac OS X routines. * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import #import "sysdeps.h" // Types used in Basilisk C++ code #import #define DEBUG 0 #import /************************************************************************/ /* Display Errors and Warnings in a sliding thingy attached to a */ /* particular window, instead of as a separate window (Panel or Dialog) */ /************************************************************************/ void ErrorSheet (NSString * message, NSWindow * window) { NSLog(message); NSBeginCriticalAlertSheet(message, nil, nil, nil, window, nil, nil, nil, NULL, @""); while ( [window attachedSheet] ) sleep(1); //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow: 1.0]]; } void ErrorSheet (NSString * message1, NSString * message2, NSString * button, NSWindow * window) { NSLog(message1); NSLog(message2); NSBeginCriticalAlertSheet(message1, button, nil, nil, window, nil, nil, nil, NULL, message2); while ( [window attachedSheet] ) sleep(1); //[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow: 1.0]]; } void WarningSheet (NSString * message, NSWindow * window) { NSLog(message); NSBeginAlertSheet(message, nil, nil, nil, window, nil, nil, nil, NULL, @""); } void WarningSheet (NSString * message1, NSString * message2, NSString * button, NSWindow * window) { NSLog(message1); NSLog(message2); NSBeginAlertSheet(message1, button, nil, nil, window, nil, nil, nil, NULL, message2); } void InfoSheet (NSString * message, NSWindow * window) { NSLog(message); NSBeginInformationalAlertSheet(message, nil, nil, nil, window, nil, nil, nil, NULL, @""); } void InfoSheet (NSString * message1, NSString * message2, NSString * button, NSWindow * window) { NSLog(message1); NSLog(message2); NSBeginInformationalAlertSheet(message1, nil, nil, nil, window, nil, nil, nil, NULL, message2); } void EndSheet (NSWindow * window) { [[window attachedSheet] close]; } // Convert a frequency (i.e. updates per second) to a 60hz tick delay, and update prefs int frequencyToTickDelay (float freq) { if ( freq == 0.0 ) return 0; else { int delay = (int) (60.0 / freq); PrefsReplaceInt32("frameskip", delay); return delay; } } BasiliskII/src/MacOSX/PrefsEditor.h0000644000175000017500000001017410736405220017223 0ustar centriscentris/* * PrefsEditor.h - GUI stuff for Basilisk II preferences * (which is a text file in the user's home directory) * * $Id: PrefsEditor.h,v 1.7 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import @interface TableDS : NSObject { int numItems; NSMutableArray *col1, *col2; } - (void) addInt: (int)target withPath: (NSString *)path; - (void) addObject: (NSObject *)obj withPath: (NSString *)path; - (void) deleteAll; - (BOOL) deleteRow: (int)row; - (int) intAtRow: (int)row; - (int) numberOfRowsInTableView: (NSTableView *)tView; - (NSString *) pathAtRow: (int)row; - (id) tableView: (NSTableView *)tView objectValueForTableColumn: (NSTableColumn *)tColumn row: (int)rowIndex; @end #include "Emulator.h" @interface PrefsEditor : NSObject { IBOutlet NSSlider *emuFreq; IBOutlet NSView *newVolumeView; IBOutlet NSTextField *newVolumeSize; IBOutlet NSWindow *panel; IBOutlet Emulator *theEmulator; IBOutlet NSButton *bootFromAny, *bootFromCD; IBOutlet NSTextField *bytes; IBOutlet NSButton *classic, *CPU68000, *CPU68020, *CPU68030, *CPU68040; IBOutlet NSTextField *delay, *depth; IBOutlet NSButton *disableCD, *disableSound; IBOutlet NSTableView *diskImages; IBOutlet NSTextField *etherNet, *extFS; IBOutlet NSButton *FPU; IBOutlet NSTextField *frequency, *height; IBOutlet NSButton *IIci; IBOutlet NSPopUpButton *keyboard; IBOutlet NSTextField *MB, *modem; IBOutlet NSButton *openGL; IBOutlet NSTextField *prefsFile, *printer; IBOutlet NSButton *quadra900; IBOutlet NSTextField *ROMfile; IBOutlet NSButton *screen; IBOutlet NSTableView *SCSIdisks; IBOutlet NSTextField *width; IBOutlet NSButton *window; NSString *devs, *home; TableDS *volsDS, // Object managing tha data in the Volumes, *SCSIds; // and SCSI devices, tables NSImage *locked, *blank; NSImageCell *lockCell; BOOL edited; // Set if the user changes anything, reset on save } - (BOOL) hasEdited; - (NSWindow *) window; - (IBAction) AddSCSI: (id)sender; - (IBAction) AddVolume: (id)sender; - (IBAction) BrowseExtFS: (id)sender; - (IBAction) BrowsePrefs: (id)sender; - (IBAction) BrowseROM: (id)sender; - (IBAction) ChangeBootFrom: (NSMatrix *)sender; - (IBAction) ChangeCPU: (NSMatrix *)sender; - (IBAction) ChangeDisableCD: (NSButton *)sender; - (IBAction) ChangeDisableSound:(NSButton *)sender; - (IBAction) ChangeFPU: (NSButton *)sender; - (IBAction) ChangeKeyboard: (NSPopUpButton *)sender; - (IBAction) ChangeModel: (NSMatrix *)sender; - (IBAction) ChangeScreen: (id)sender; - (IBAction) CreateVolume: (id)sender; - (IBAction) DeleteVolume: (id)sender; - (IBAction) EditBytes: (NSTextField *)sender; - (IBAction) EditDelay: (NSTextField *)sender; - (IBAction) EditEtherNetDevice:(NSTextField *)sender; - (IBAction) EditExtFS: (NSTextField *)sender; - (IBAction) EditFrequency: (NSTextField *)sender; - (IBAction) EditMB: (NSTextField *)sender; - (IBAction) EditModemDevice: (NSTextField *)sender; - (IBAction) EditPrinterDevice: (NSTextField *)sender; - (IBAction) EditROMpath: (NSTextField *)sender; - (IBAction) LoadPrefs: (id)sender; - (IBAction) RemoveSCSI: (id)sender; - (IBAction) RemoveVolume: (id)sender; - (NSString *) RemoveVolumeEntry; - (IBAction) ResetPrefs: (id)sender; - (IBAction) ShowPrefs: (id)sender; - (IBAction) SavePrefs: (id)sender; @endBasiliskII/src/MacOSX/extfs_macosx.cpp0000644000175000017500000004442611026577035020051 0ustar centriscentris/* * extfs_macosx.cpp - MacOS file system for access native file system access, MacOS X specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include #include #include #include "sysdeps.h" #include "prefs.h" #include "extfs.h" #include "extfs_defs.h" // XXX: don't clobber with native definitions #define noErr native_noErr #define Point native_Point #define Rect native_Rect #define ProcPtr native_ProcPtr # include #undef ProcPtr #undef Rect #undef Point #undef noErr #define DEBUG 0 #include "debug.h" // Default Finder flags const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; /* * Extended attributes (Tiger+) */ #define USE_XATTRS g_use_xattrs static bool g_use_xattrs = false; #define XATTR_TEST "org.BasiliskII.TestAttr" #define XATTR_FINFO "org.BasiliskII.FinderInfo" #define XATTR_FXINFO "org.BasiliskII.ExtendedFinderInfo" static bool get_xattr(const char *path, const char *name, void *value, uint32 size) { return syscall(SYS_getxattr, path, name, value, size, 0, 0) == size; } static bool set_xattr(const char *path, const char *name, const void *value, uint32 size) { return syscall(SYS_setxattr, path, name, value, size, 0, 0) == 0; } static bool remove_xattr(const char *path, const char *name) { return syscall(SYS_removexattr, path, name, 0) == 0; } static bool check_xattr(void) { const char *path = PrefsFindString("extfs"); if (path == NULL) return false; const uint32 sentinel = 0xdeadbeef; if (!set_xattr(path, XATTR_TEST, &sentinel, sizeof(sentinel))) return false; uint32 v; if (!get_xattr(path, XATTR_TEST, &v, sizeof(v))) return false; if (!remove_xattr(path, XATTR_TEST)) return false; return v == sentinel; } /* * Initialization */ void extfs_init(void) { g_use_xattrs = check_xattr(); } /* * Deinitialization */ void extfs_exit(void) { } /* * Add component to path name */ void add_path_component(char *path, const char *component) { int l = strlen(path); if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') { path[l] = '/'; path[l+1] = 0; } strncat(path, component, MAX_PATH_LENGTH-1); } /* * Finder info manipulation helpers */ typedef uint8 FinderInfo[SIZEOF_FInfo]; struct FinderInfoAttrBuf { uint32 length; FinderInfo finderInfo; FinderInfo extendedFinderInfo; }; static const FinderInfo kNativeFInfoMask = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; static const FinderInfo kNativeFXInfoMask = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; static const FinderInfo kNativeDInfoMask = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; static const FinderInfo kNativeDXInfoMask = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00}; /* XXX: keep frScroll? */ static void finfo_merge(FinderInfo dst, const FinderInfo emu, const FinderInfo nat, const FinderInfo mask) { for (int i = 0; i < SIZEOF_FInfo; i++) dst[i] = (emu[i] & ~mask[i]) | (nat[i] & mask[i]); } static void finfo_split(FinderInfo dst, const FinderInfo emu, const FinderInfo mask) { for (int i = 0; i < SIZEOF_FInfo; i++) dst[i] = emu[i] & mask[i]; } /* * Finder info are kept in helper files (on anything below Tiger) * * Finder info: * /path/.finf/file * * The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo * (16+16 bytes) */ static void make_finf_path(const char *src, char *dest, bool only_dir = false) { dest[0] = 0; // Get pointer to last component of path const char *last_part = strrchr(src, '/'); if (last_part) last_part++; else last_part = src; // Copy everything before strncpy(dest, src, last_part-src); dest[last_part-src] = 0; // Add additional component strncat(dest, ".finf/", MAX_PATH_LENGTH-1); // Add last component if (!only_dir) strncat(dest, last_part, MAX_PATH_LENGTH-1); } static int create_finf_dir(const char *path) { char finf_dir[MAX_PATH_LENGTH]; make_finf_path(path, finf_dir, true); if (finf_dir[strlen(finf_dir) - 1] == '/') // Remove trailing "/" finf_dir[strlen(finf_dir) - 1] = 0; return mkdir(finf_dir, 0777); } static int open_finf(const char *path, int flag) { char finf_path[MAX_PATH_LENGTH]; make_finf_path(path, finf_path); if ((flag & O_ACCMODE) == O_RDWR || (flag & O_ACCMODE) == O_WRONLY) flag |= O_CREAT; int fd = open(finf_path, flag, 0666); if (fd < 0) { if (errno == ENOENT && (flag & O_CREAT)) { // One path component was missing, probably the finf // directory. Try to create it and re-open the file. int ret = create_finf_dir(path); if (ret < 0) return ret; fd = open(finf_path, flag, 0666); } } return fd; } /* * Resource forks are kept into their native location * * Resource fork: * /path/file/..namedfork/rsrc */ static void make_rsrc_path(const char *src, char *dest) { int l = strlen(src); if (l + 1 + 16 + 1 <= MAX_PATH_LENGTH) memcpy(dest, src, l + 1); else { // The rsrc component is copied as is, if there is not enough // space to add it. In that case, open() will fail gracefully // and this is what we want. dest[0] = '.'; dest[1] = '\0'; } add_path_component(dest, "..namedfork/rsrc"); } static int open_rsrc(const char *path, int flag) { char rsrc_path[MAX_PATH_LENGTH]; make_rsrc_path(path, rsrc_path); return open(rsrc_path, flag); } /* * Get/set finder info for file/directory specified by full path */ struct ext2type { const char *ext; uint32 type; uint32 creator; }; static const ext2type e2t_translation[] = { {".Z", FOURCC('Z','I','V','M'), FOURCC('L','Z','I','V')}, {".gz", FOURCC('G','z','i','p'), FOURCC('G','z','i','p')}, {".hqx", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".bin", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".pdf", FOURCC('P','D','F',' '), FOURCC('C','A','R','O')}, {".ps", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".sit", FOURCC('S','I','T','!'), FOURCC('S','I','T','x')}, {".tar", FOURCC('T','A','R','F'), FOURCC('T','A','R',' ')}, {".uu", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".uue", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".zip", FOURCC('Z','I','P',' '), FOURCC('Z','I','P',' ')}, {".8svx", FOURCC('8','S','V','X'), FOURCC('S','N','D','M')}, {".aifc", FOURCC('A','I','F','C'), FOURCC('T','V','O','D')}, {".aiff", FOURCC('A','I','F','F'), FOURCC('T','V','O','D')}, {".au", FOURCC('U','L','A','W'), FOURCC('T','V','O','D')}, {".mid", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".midi", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".mp2", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".mp3", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".wav", FOURCC('W','A','V','E'), FOURCC('T','V','O','D')}, {".bmp", FOURCC('B','M','P','f'), FOURCC('o','g','l','e')}, {".gif", FOURCC('G','I','F','f'), FOURCC('o','g','l','e')}, {".lbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".ilbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".jpg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".jpeg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".pict", FOURCC('P','I','C','T'), FOURCC('o','g','l','e')}, {".png", FOURCC('P','N','G','f'), FOURCC('o','g','l','e')}, {".sgi", FOURCC('.','S','G','I'), FOURCC('o','g','l','e')}, {".tga", FOURCC('T','P','I','C'), FOURCC('o','g','l','e')}, {".tif", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".tiff", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".htm", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".html", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".txt", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".rtf", FOURCC('T','E','X','T'), FOURCC('M','S','W','D')}, {".c", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".C", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cc", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".h", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hh", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".s", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".S", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".i", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".mpg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mpeg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mov", FOURCC('M','o','o','V'), FOURCC('T','V','O','D')}, {".fli", FOURCC('F','L','I',' '), FOURCC('T','V','O','D')}, {".avi", FOURCC('V','f','W',' '), FOURCC('T','V','O','D')}, {".qxd", FOURCC('X','D','O','C'), FOURCC('X','P','R','3')}, {".hfv", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".dsk", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".img", FOURCC('r','o','h','d'), FOURCC('d','d','s','k')}, {NULL, 0, 0} // End marker }; // Get emulated Finder info from metadata (Tiger+) static bool get_finfo_from_xattr(const char *path, uint8 *finfo, uint8 *fxinfo) { if (!get_xattr(path, XATTR_FINFO, finfo, SIZEOF_FInfo)) return false; if (fxinfo && !get_xattr(path, XATTR_FXINFO, fxinfo, SIZEOF_FXInfo)) return false; return true; } // Get emulated Finder info from helper file static bool get_finfo_from_helper(const char *path, uint8 *finfo, uint8 *fxinfo) { int fd = open_finf(path, O_RDONLY); if (fd < 0) return false; ssize_t actual = read(fd, finfo, SIZEOF_FInfo); if (fxinfo) actual += read(fd, fxinfo, SIZEOF_FXInfo); close(fd); return actual == (SIZEOF_FInfo + (fxinfo ? SIZEOF_FXInfo : 0)); } // Get native Finder info static bool get_finfo_from_native(const char *path, uint8 *finfo, uint8 *fxinfo) { struct attrlist attrList; memset(&attrList, 0, sizeof(attrList)); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_FNDRINFO; FinderInfoAttrBuf attrBuf; if (getattrlist(path, &attrList, &attrBuf, sizeof(attrBuf), 0) < 0) return false; memcpy(finfo, attrBuf.finderInfo, SIZEOF_FInfo); if (fxinfo) memcpy(fxinfo, attrBuf.extendedFinderInfo, SIZEOF_FXInfo); return true; } static bool do_get_finfo(const char *path, bool has_fxinfo, FinderInfo emu_finfo, FinderInfo emu_fxinfo, FinderInfo nat_finfo, FinderInfo nat_fxinfo) { memset(emu_finfo, 0, SIZEOF_FInfo); if (has_fxinfo) memset(emu_fxinfo, 0, SIZEOF_FXInfo); *((uint16 *)(emu_finfo + fdFlags)) = htonl(DEFAULT_FINDER_FLAGS); *((uint32 *)(emu_finfo + fdLocation)) = htonl((uint32)-1); if (USE_XATTRS) get_finfo_from_xattr(path, emu_finfo, has_fxinfo ? emu_fxinfo : NULL); else get_finfo_from_helper(path, emu_finfo, has_fxinfo ? emu_fxinfo : NULL); if (!get_finfo_from_native(path, nat_finfo, has_fxinfo ? nat_fxinfo : NULL)) return false; return true; } void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Merge emulated and native Finder info FinderInfo emu_finfo, emu_fxinfo; FinderInfo nat_finfo, nat_fxinfo; if (do_get_finfo(path, fxinfo, emu_finfo, emu_fxinfo, nat_finfo, nat_fxinfo)) { if (!is_dir) { finfo_merge(Mac2HostAddr(finfo), emu_finfo, nat_finfo, kNativeFInfoMask); if (fxinfo) finfo_merge(Mac2HostAddr(fxinfo), emu_fxinfo, nat_fxinfo, kNativeFXInfoMask); if (ReadMacInt32(finfo + fdType) != 0 && ReadMacInt32(finfo + fdCreator) != 0) return; } else { finfo_merge(Mac2HostAddr(finfo), emu_finfo, nat_finfo, kNativeDInfoMask); if (fxinfo) finfo_merge(Mac2HostAddr(fxinfo), emu_fxinfo, nat_fxinfo, kNativeDXInfoMask); return; } } // No native Finder info, translate file name extension to MacOS type/creator if (!is_dir) { int path_len = strlen(path); for (int i=0; e2t_translation[i].ext; i++) { int ext_len = strlen(e2t_translation[i].ext); if (path_len < ext_len) continue; if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) { WriteMacInt32(finfo + fdType, e2t_translation[i].type); WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator); break; } } } } // Set emulated Finder info into metada (Tiger+) static bool set_finfo_to_xattr(const char *path, const uint8 *finfo, const uint8 *fxinfo) { if (!set_xattr(path, XATTR_FINFO, finfo, SIZEOF_FInfo)) return false; if (fxinfo && !set_xattr(path, XATTR_FXINFO, fxinfo, SIZEOF_FXInfo)) return false; return true; } // Set emulated Finder info into helper file static bool set_finfo_to_helper(const char *path, const uint8 *finfo, const uint8 *fxinfo) { int fd = open_finf(path, O_RDWR); if (fd < 0) return false; ssize_t actual = write(fd, finfo, SIZEOF_FInfo); if (fxinfo) actual += write(fd, fxinfo, SIZEOF_FXInfo); close(fd); return actual == (SIZEOF_FInfo + (fxinfo ? SIZEOF_FXInfo : 0)); } // Set native Finder info static bool set_finfo_to_native(const char *path, const uint8 *finfo, const uint8 *fxinfo, bool is_dir) { struct attrlist attrList; memset(&attrList, 0, sizeof(attrList)); attrList.bitmapcount = ATTR_BIT_MAP_COUNT; attrList.commonattr = ATTR_CMN_FNDRINFO; FinderInfoAttrBuf attrBuf; if (getattrlist(path, &attrList, &attrBuf, sizeof(attrBuf), 0) < 0) return false; finfo_merge(attrBuf.finderInfo, attrBuf.finderInfo, finfo, is_dir ? kNativeDInfoMask : kNativeFInfoMask); if (fxinfo) finfo_merge(attrBuf.extendedFinderInfo, attrBuf.extendedFinderInfo, fxinfo, is_dir ? kNativeDXInfoMask : kNativeFXInfoMask); attrList.commonattr = ATTR_CMN_FNDRINFO; if (setattrlist(path, &attrList, attrBuf.finderInfo, 2 * SIZEOF_FInfo, 0) < 0) return false; return true; } void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Extract native Finder info flags FinderInfo nat_finfo, nat_fxinfo; const uint8 *emu_finfo = Mac2HostAddr(finfo); const uint8 *emu_fxinfo = fxinfo ? Mac2HostAddr(fxinfo) : NULL; finfo_split(nat_finfo, emu_finfo, is_dir ? kNativeDInfoMask : kNativeFInfoMask); if (fxinfo) finfo_split(nat_fxinfo, emu_fxinfo, is_dir ? kNativeDXInfoMask : kNativeFXInfoMask); // Update Finder info file (all flags) if (USE_XATTRS) set_finfo_to_xattr(path, emu_finfo, emu_fxinfo); else set_finfo_to_helper(path, emu_finfo, emu_fxinfo); // Update native Finder info flags set_finfo_to_native(path, nat_finfo, nat_fxinfo, is_dir); } /* * Resource fork emulation functions */ uint32 get_rfork_size(const char *path) { // Open resource file int fd = open_rsrc(path, O_RDONLY); if (fd < 0) return 0; // Get size off_t size = lseek(fd, 0, SEEK_END); // Close file and return size close(fd); return size < 0 ? 0 : size; } int open_rfork(const char *path, int flag) { return open_rsrc(path, flag); } void close_rfork(const char *path, int fd) { close(fd); } /* * Read "length" bytes from file to "buffer", * returns number of bytes read (or -1 on error) */ ssize_t extfs_read(int fd, void *buffer, size_t length) { return read(fd, buffer, length); } /* * Write "length" bytes from "buffer" to file, * returns number of bytes written (or -1 on error) */ ssize_t extfs_write(int fd, void *buffer, size_t length) { return write(fd, buffer, length); } /* * Remove file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_remove(const char *path) { // Remove helpers first, don't complain if this fails char helper_path[MAX_PATH_LENGTH]; make_finf_path(path, helper_path, false); remove(helper_path); make_rsrc_path(path, helper_path); remove(helper_path); // Now remove file or directory (and helper directories in the directory) if (remove(path) < 0) { if (errno == EISDIR || errno == ENOTEMPTY) { helper_path[0] = 0; strncpy(helper_path, path, MAX_PATH_LENGTH-1); add_path_component(helper_path, ".finf"); rmdir(helper_path); return rmdir(path) == 0; } else return false; } return true; } /* * Rename/move file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_rename(const char *old_path, const char *new_path) { // Rename helpers first, don't complain if this fails char old_helper_path[MAX_PATH_LENGTH], new_helper_path[MAX_PATH_LENGTH]; make_finf_path(old_path, old_helper_path, false); make_finf_path(new_path, new_helper_path, false); create_finf_dir(new_path); rename(old_helper_path, new_helper_path); make_rsrc_path(old_path, old_helper_path); make_rsrc_path(new_path, new_helper_path); rename(old_helper_path, new_helper_path); // Now rename file return rename(old_path, new_path) == 0; } /* * Strings (filenames) conversion */ // Convert string in the specified source and target encodings const char *convert_string(const char *str, CFStringEncoding from, CFStringEncoding to) { const char *ostr = str; CFStringRef cfstr = CFStringCreateWithCString(NULL, str, from); if (cfstr) { static char buffer[MAX_PATH_LENGTH]; memset(buffer, 0, sizeof(buffer)); if (CFStringGetCString(cfstr, buffer, sizeof(buffer), to)) ostr = buffer; CFRelease(cfstr); } return ostr; } // Convert from the host OS filename encoding to MacRoman const char *host_encoding_to_macroman(const char *filename) { return convert_string(filename, kCFStringEncodingUTF8, kCFStringEncodingMacRoman); } // Convert from MacRoman to host OS filename encoding const char *macroman_to_host_encoding(const char *filename) { return convert_string(filename, kCFStringEncodingMacRoman, kCFStringEncodingUTF8); } BasiliskII/src/MacOSX/Emulator.h0000644000175000017500000000532111117531367016571 0ustar centriscentris/* * Emulator.h - Class whose actions are attached GUI widgets in a window, * used to control a single Basilisk II emulated Macintosh. * * $Id: Emulator.h,v 1.7 2008/12/09 18:03:35 asvitkine Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import #import #import "EmulatorView.h" #import "NNThread.h" @interface Emulator : NSObject { NNThread *emul; // Run emulThread NNTimer *RTC, // Invoke RTCinterrupt *redraw, // Invoke redrawScreen *tick, // Invoke tickInterrupt *xPRAM; // Invoke xPRAMbackup BOOL uaeCreated, // Has thread created the emulator environment? running; // Is the emulator currently grinding away? float redrawDelay; // Seconds until next screen update // UI elements that this class changes the state of IBOutlet NSProgressIndicator *barberPole; IBOutlet NSButton *runOrPause; IBOutlet EmulatorView *screen; IBOutlet NSSlider *speed; IBOutlet NSWindow *win; } // The following allow the Controller and PrefsEditor classes to access our internal data - (BOOL) isRunning; - (BOOL) uaeCreated; - (EmulatorView *) screen; - (NSSlider *) speed; - (NSWindow *) window; - (void) runUpdate; // Update some UI elements - (IBAction) Benchmark: (id)sender; - (IBAction) Interrupt: (id)sender; - (IBAction) PowerKey: (id)sender; - (IBAction) Restart: (id)sender; - (IBAction) Resume: (id)sender; - (IBAction) ScreenHideShow:(NSButton *)sender; - (IBAction) Snapshot: (id)sender; - (IBAction) SpeedChange: (NSSlider *)sender; - (IBAction) Suspend: (id)sender; - (IBAction) Terminate: (id)sender; - (IBAction) ToggleState: (NSButton *)sender; - (IBAction) ZapPRAM: (id)sender; - (void) createThreads; - (void) exitThreads; - (void) emulThread; // Thread for processor emulator - (void) RTCinterrupt; // Emulator real time clock update - (void) redrawScreen; // Draw emulator screen in window - (void) tickInterrupt; // Draw emulator screen in window - (void) xPRAMbackup; // PRAM watchdog @end BasiliskII/src/MacOSX/AudioDevice.h0000644000175000017500000000636410462406746017176 0ustar centriscentris/* Copyright: © Copyright 2004 Apple Computer, Inc. All rights reserved. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*============================================================================= AudioDevice.h =============================================================================*/ #ifndef __AudioDevice_h__ #define __AudioDevice_h__ #include #include class AudioDevice { public: AudioDevice() : mID(kAudioDeviceUnknown) { } AudioDevice(AudioDeviceID devid, bool isInput) { Init(devid, isInput); } void Init(AudioDeviceID devid, bool isInput); bool Valid() { return mID != kAudioDeviceUnknown; } void SetBufferSize(UInt32 size); int CountChannels(); char * GetName(char *buf, UInt32 maxlen); public: AudioDeviceID mID; bool mIsInput; UInt32 mSafetyOffset; UInt32 mBufferSizeFrames; AudioStreamBasicDescription mFormat; }; #endif // __AudioDevice_h__ BasiliskII/src/MacOSX/audio_defs_macosx.h0000644000175000017500000000434010736405220020447 0ustar centriscentris/* * $Id: audio_defs_macosx.h,v 1.5 2008/01/01 09:40:32 gbeauche Exp $ * * audio_defs_macosx.h - Work around clashes with the enums in * Based on: * * audio_defs.h - Definitions for MacOS audio components * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef AUDIO_DEFS_H #define AUDIO_DEFS_H #include "macos_util_macosx.h" enum { // ComponentResource struct componentType = 0, componentSubType = 4, componentManufacturer = 8, componentFlags = 12, componentFlagsMask = 16, componentResType = 20, componentResID = 24, componentNameType = 26, componentNameID = 30, componentInfoType = 32, componentInfoID = 36, componentIconType = 38, componentIconID = 42, componentVersion = 44, componentRegisterFlags = 48, componentIconFamily = 52, componentPFCount = 54, componentPFFlags = 58, componentPFResType = 62, componentPFResID = 66, componentPFPlatform = 68 }; enum { // ComponentParameters struct cp_flags = 0, // call modifiers: sync/async, deferred, immed, etc cp_paramSize = 1, // size in bytes of actual parameters passed to this call cp_what = 2, // routine selector, negative for Component management calls cp_params = 4 // actual parameters for the indicated routine }; enum { // SoundComponentData struct scd_flags = 0, scd_format = 4, scd_numChannels = 8, scd_sampleSize = 10, scd_sampleRate = 12, scd_sampleCount = 16, scd_buffer = 20, scd_reserved = 24, SIZEOF_scd = 28 }; enum { // SoundInfoList struct sil_count = 0, sil_infoHandle = 2 }; #endif BasiliskII/src/MacOSX/AudioDevice.cpp0000644000175000017500000001044310462406746017522 0ustar centriscentris/* Copyright: © Copyright 2004 Apple Computer, Inc. All rights reserved. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*============================================================================= AudioDevice.cpp =============================================================================*/ #include "AudioDevice.h" void AudioDevice::Init(AudioDeviceID devid, bool isInput) { mID = devid; mIsInput = isInput; if (mID == kAudioDeviceUnknown) return; UInt32 propsize; propsize = sizeof(UInt32); verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertySafetyOffset, &propsize, &mSafetyOffset)); propsize = sizeof(UInt32); verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyBufferFrameSize, &propsize, &mBufferSizeFrames)); propsize = sizeof(AudioStreamBasicDescription); verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyStreamFormat, &propsize, &mFormat)); } void AudioDevice::SetBufferSize(UInt32 size) { UInt32 propsize = sizeof(UInt32); verify_noerr(AudioDeviceSetProperty(mID, NULL, 0, mIsInput, kAudioDevicePropertyBufferFrameSize, propsize, &size)); propsize = sizeof(UInt32); verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyBufferFrameSize, &propsize, &mBufferSizeFrames)); } int AudioDevice::CountChannels() { OSStatus err; UInt32 propSize; int result = 0; err = AudioDeviceGetPropertyInfo(mID, 0, mIsInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL); if (err) return 0; AudioBufferList *buflist = (AudioBufferList *)malloc(propSize); err = AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist); if (!err) { for (UInt32 i = 0; i < buflist->mNumberBuffers; ++i) { result += buflist->mBuffers[i].mNumberChannels; } } free(buflist); return result; } char * AudioDevice::GetName(char *buf, UInt32 maxlen) { verify_noerr(AudioDeviceGetProperty(mID, 0, mIsInput, kAudioDevicePropertyDeviceName, &maxlen, buf)); return buf; } BasiliskII/src/MacOSX/0_HOW_TO_BUILD.txt0000644000175000017500000000334010737016032017557 0ustar centriscentris How to build this source ------------------------ 1) Install the OS X Development tools Source now only builds on 10.2 and 10.3. On 10.1, there are a few compile and link errors that I just can't be bothered to fix. On 10.4 when doing Xcode builds, there are problems with the way that I have built libslirp.a. For now, do "make" instead of "make ide". 2) Open a Terminal, and cd to BasiliskII-1.0/src/MacOSX 3) autoconf autoheader ./configure This creates some symlinks to files in the Unix source and /usr/libexec directories, generates ./configure, and runs it. The end result is a Makefile and some header files 4) make This should generate the uae_cpu emulator core's source, compile the SLIRP sources and then the application. * It is also possible to use the OS X integrated development environment (i.e. "Project Builder" or Xcode) to build the application, instead of make. Instead of step 4) above, do these steps: 4) make ide This should generate the uae_cpu emulator core's source, and then open the project in the Project Builder or Xcode IDE. 5) From the Build menu, choose 'Build' or 'Build & Run' This should build everything Notes: 1) Compiling cpuemu.cpp takes 58 seconds on my 384MB G4 400. Compiling it as separate files (cpuemu1.cpp thru cpuemu8.cpp) takes 68 seconds on the same machine. If you have less RAM, it may be faster to compile it as separate files. 2) If you want to change the addressing default (which is currently direct), you have to reconfigure. (i.e. make clean; ./configure --enable-addressing=banks) 3) To emulate a Mac Classic, or any Mac with 24bit addressing, the app needs to be built with the above (bank) style addressing. BasiliskII/src/MacOSX/misc_macosx.h0000644000175000017500000000277310736405220017310 0ustar centriscentris/* * $Id: misc_macosx.h,v 1.6 2008/01/01 09:40:32 gbeauche Exp $ * * misc_macosx.h - Some prototypes of functions defined in misc_macosx.mm * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #if defined(__APPLE__) && defined(__MACH__) // This means we are on Mac OS X of some sort #endif extern void ErrorSheet (NSString *msg, NSWindow *win), ErrorSheet (NSString *msg1, NSString *msg2, NSString *button, NSWindow *win), WarningSheet (NSString *message,NSWindow *win), WarningSheet (NSString *msg1, NSString *msg2, NSString *button, NSWindow *win), InfoSheet (NSString *msg, NSWindow *win), InfoSheet (NSString *msg1, NSString *msg2, NSString *button, NSWindow *win), EndSheet (NSWindow * window); extern int frequencyToTickDelay (float frequency); BasiliskII/src/MacOSX/clip_macosx.cpp0000644000175000017500000001224411700165452017633 0ustar centriscentris/* * clip_macosx.cpp - Clipboard handling, MacOS X (Carbon) implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #define _UINT64 #include #include "clip.h" #include "main.h" #include "cpu_emulation.h" #include "emul_op.h" #define DEBUG 0 #include "debug.h" // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the MacOS X side static bool we_put_this_data = false; static void SwapScrapData(uint32 type, void *data, int32 length, int from_host) { #if BYTE_ORDER != BIG_ENDIAN if (type == kScrapFlavorTypeTextStyle) { uint16 *sdata = (uint16 *) data; // the first short stores the number of runs uint16 runs = sdata[0]; sdata[0] = htons(sdata[0]); if (from_host) runs = sdata[0]; sdata++; // loop through each run for (int i = 0; i < runs; i++) { struct style_data { uint32 offset; uint16 line_height; uint16 line_ascent; uint16 font_family; uint16 character_style; // not swapped uint16 point_size; uint16 red; uint16 green; uint16 blue; } *style = (struct style_data *) (sdata + i*10); style->offset = htonl(style->offset); style->line_height = htons(style->line_height); style->line_ascent = htons(style->line_ascent); style->font_family = htons(style->font_family); style->point_size = htons(style->point_size); style->red = htons(style->red); style->green = htons(style->green); style->blue = htons(style->blue); } } else { // add byteswapping code for other flavor types here ... } #endif } /* * Initialization */ void ClipInit(void) { } /* * Deinitialization */ void ClipExit(void) { } /* * Mac application reads clipboard */ void GetScrap(void **handle, uint32 type, int32 offset) { #if defined(__LP64__) D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); #warning Carbon scrapbook function are not implemented in 64-bit mode #else D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); ScrapRef theScrap; if (GetCurrentScrap(&theScrap) != noErr) { D(bug(" could not open scrap\n")); return; } Size byteCount; if (GetScrapFlavorSize(theScrap, type, &byteCount) == noErr) { // Allocate space for new scrap in MacOS side M68kRegisters r; r.d[0] = byteCount; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 scrap_area = r.a[0]; // Get the native clipboard data if (scrap_area) { uint8 * const data = Mac2HostAddr(scrap_area); if (GetScrapFlavorData(theScrap, type, &byteCount, data) == noErr) { SwapScrapData(type, data, byteCount, FALSE); // Add new data to clipboard static uint8 proc[] = { 0x59, 0x8f, // subq.l #4,sp 0xa9, 0xfc, // ZeroScrap() 0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp) 0xa9, 0xfe, // PutScrap() 0x58, 0x8f, // addq.l #4,sp M68K_RTS >> 8, M68K_RTS & 0xff }; r.d[0] = sizeof(proc); Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 proc_area = r.a[0]; if (proc_area) { Host2Mac_memcpy(proc_area, proc, sizeof(proc)); WriteMacInt32(proc_area + 6, byteCount); WriteMacInt32(proc_area + 12, type); WriteMacInt32(proc_area + 18, scrap_area); we_put_this_data = true; Execute68k(proc_area, &r); r.a[0] = proc_area; Execute68kTrap(0xa01f, &r); // DisposePtr } } r.a[0] = scrap_area; Execute68kTrap(0xa01f, &r); // DisposePtr } } #endif } /* * Mac application wrote to clipboard */ void PutScrap(uint32 type, void *scrap, int32 length) { #if defined(__LP64__) #warning Carbon scrapbook function are not implemented in 64-bit mode D(bug("PutScrap type %4.4s, data %08lx, length %ld\n", &type, scrap, length)); #else static bool clear = true; D(bug("PutScrap type %4.4s, data %08lx, length %ld\n", &type, scrap, length)); ScrapRef theScrap; if (we_put_this_data) { we_put_this_data = false; clear = true; return; } if (length <= 0) return; if (clear) { D(bug(" calling ClearCurrentScrap\n")); ClearCurrentScrap(); } if (GetCurrentScrap(&theScrap) != noErr) { D(bug(" could not open scrap\n")); return; } SwapScrapData(type, scrap, length, TRUE); if (PutScrapFlavor(theScrap, type, kScrapFlavorMaskNone, length, scrap) != noErr) { D(bug(" could not put to scrap\n")); //return; } SwapScrapData(type, scrap, length, FALSE); // swap it back #endif } BasiliskII/src/MacOSX/utils_macosx.h0000644000175000017500000000174511677014372017524 0ustar centriscentris/* * utils_macosx.h - Mac OS X utility functions. * * Copyright (C) 2011 Alexei Svitkine * * 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 */ #ifndef UTILS_MACOSX_H #define UTILS_MACOSX_H // Invokes the specified function with an NSAutoReleasePool in place. void NSAutoReleasePool_wrap(void (*fn)(void)); #endif BasiliskII/src/MacOSX/MacOSX_sound_if.h0000644000175000017500000000244610462412105017754 0ustar centriscentris/* * MacOSX_sound_if.h * BasiliskII * * Copyright 2006 Daniel Sumorok. All rights reserved. * * 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 */ typedef int (*audioCallback)(void); class AudioBackEnd; class OSXsoundOutput { private: static void getMoreSamples(void *arg); AudioBackEnd *player; audioCallback callback; public: OSXsoundOutput(); ~OSXsoundOutput(); int start(int bitsPerSample, int numChannels, int sampleRate); int stop(); int putBuffer(void *buffer, int numSamples); void setCallback(audioCallback fn); unsigned int bufferSizeFrames(); int sendAudioBuffer(void *buffer, int numFrames); }; BasiliskII/src/MacOSX/AudioBackEnd.h0000644000175000017500000000523010462406746017255 0ustar centriscentris/* * * This is based on Apple example software AudioBackEnd.cpp * * Copyright © 2004 Apple Computer, Inc., All Rights Reserved * Original Apple code modified by Daniel Sumorok * * 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 */ #ifndef __AudioBackEnd_H__ #define __AudioBackEnd_H__ #define checkErr( err) \ if(err) {\ OSStatus error = static_cast(err);\ fprintf(stderr, "AudioBackEnd Error: %ld -> %s: %d\n", error,\ __FILE__, \ __LINE__\ );\ fflush(stdout);\ } #include #include #include #include #include "AudioDevice.h" typedef void (*playthruCallback)(void *arg); class AudioBackEnd { public: AudioBackEnd(int bitsPerSample, int numChannels, int sampleRate); ~AudioBackEnd(); OSStatus Init(); OSStatus Start(); OSStatus Stop(); Boolean IsRunning(); void setCallback(playthruCallback func, void *arg); UInt32 BufferSizeFrames(); int sendAudioBuffer(void *buffer, int numFrames); private: OSStatus SetupGraph(); OSStatus CallbackSetup(); OSStatus SetupBuffers(); static OSStatus OutputProc(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData); AudioDevice mOutputDevice; AUGraph mGraph; AUNode mOutputNode; AudioUnit mOutputUnit; int mBitsPerSample; int mSampleRate; int mNumChannels; playthruCallback mCallback; void *mCallbackArg; UInt32 mBufferSizeFrames; UInt32 mFramesProcessed; UInt8 *mAudioBuffer; UInt32 mAudioBufferWriteIndex; UInt32 mAudioBufferReadIndex; UInt32 mBytesPerFrame; UInt32 mAudioBufferSize; }; #endif //__AudioBackEnd_H__ BasiliskII/src/MacOSX/Controller.mm0000644000175000017500000002315710736405220017307 0ustar centriscentris/* * Controller.m - Simple application window management. * * $Id: Controller.mm,v 1.15 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import "Controller.h" #import "Emulator.h" #import "sysdeps.h" // Types used in Basilisk C++ code #import #import #define DEBUG 0 #import #import "misc_macosx.h" #import "video_macosx.h" @implementation Controller // // Standard NSApplication methods that we override // - (id) init { #ifdef ENABLE_MULTIPLE emulators = [NSMutableArray new]; #endif return [super init]; } - (void) dealloc { #ifdef ENABLE_MULTIPLE [emulators dealloc]; #endif [super dealloc]; } - (void) awakeFromNib { #ifdef ENABLE_MULTIPLE [self NewEmulator: self]; // So the user gets something on screen #endif [[NSApplication sharedApplication] setDelegate: self]; // Enable applicationShouldTerminate } - (void) sendEvent: (NSEvent *)event; { // We can either process the event ourselves, // or pass it to our superclass for the other UI objects to process bool passToSuper = false; if ( [self isAnyEmulatorDisplayingSheets] || [[thePrefsEditor window] isVisible] || ! [self isAnyEmulatorRunning] ) passToSuper = true; if ( [[theEmulator screen] isFullScreen] ) passToSuper = false; if ( passToSuper ) [super sendEvent: event]; // NSApplication default else { NSEventType type = [event type]; if ( type == NSKeyUp || type == NSKeyDown || type == NSFlagsChanged ) [self dispatchKeyEvent: event type: type]; else [self dispatchEvent: event type: type]; } } // NSApplication methods which are invoked through delegation - (BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)app { return YES; } - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *)app { short count; char *stillRunningMessage; if ( [thePrefsEditor hasEdited] ) if ( ChoiceAlert("Preferences have been edited", "Save changes", "Quit") ) SavePrefs(); // if ( edited ) // { // NSString *title = [NSString stringWithCString: getString(STR_WARNING_ALERT_TITLE)], // *msg = @"Preferences have been edited", // *def = @"Save changes", // *alt = @"Quit Application", // *other = @"Continue"; // // switch ( NSRunAlertPanel(title, msg, def, alt, other, nil) ) // { // case NSAlertDefault: savePrefs(); // case NSAlertAlternate: return NSTerminateNow; // case NSAlertOther: return NSTerminateCancel; // } // } if ( [[thePrefsEditor window] isVisible] ) [[thePrefsEditor window] performClose: self]; count = [self emulatorCreatedCount]; if ( count > 0 ) { if ( count > 1 ) stillRunningMessage = "Emulators are still running\nExiting Basilisk may lose data"; else stillRunningMessage = "Emulator is still running\nExiting Basilisk may lose data"; if ( ! ChoiceAlert(stillRunningMessage, "Exit", "Continue") ) return NSTerminateCancel; // NSTerminateLater? } return NSTerminateNow; } // Event dispatching, called by sendEvent - (void) dispatchKeyEvent: (NSEvent *)event type: (NSEventType)type { EmulatorView *view; #ifdef ENABLE_MULTIPLE // We need to work out what window's Emulator should receive these messages int tmp; for ( tmp = 0; tmp < [emulators count], ++tmp ) { theEmulator = [emulators objectAtIndex: tmp]; view = [theEmulator screen]; if ( [ theEmulator isRunning ] && ( [[theEmulator window] isKeyWindow] || [view isFullScreen] ) ) break; } if ( tmp < [emulators count] ) // i.e. if we exited the for loop #else view = [theEmulator screen]; if ( [theEmulator isRunning] && ( [[theEmulator window] isKeyWindow] || [view isFullScreen] ) ) #endif { D(NSLog(@"Got a key event - %d\n", [event keyCode])); switch ( type ) { case NSKeyUp: [view keyUp: event]; break; case NSKeyDown: D(NSLog(@"%s - NSKeyDown - %@", __PRETTY_FUNCTION__, event)); [view keyDown: event]; break; case NSFlagsChanged: [view flagsChanged: event]; break; default: NSLog(@"%s - Sent a non-key event (logic error)", __PRETTY_FUNCTION__); [super sendEvent: event]; } } else // No Basilisk window is key (maybe a panel or pane). [super sendEvent: event]; // Call NSApplication default } - (void) dispatchEvent: (NSEvent *)event type: (NSEventType)type { EmulatorView *view; BOOL fullScreen; #ifdef ENABLE_MULTIPLE // We need to work out what window's Emulator should receive these messages int tmp; for ( tmp = 0; tmp < [emulators count], ++tmp ) { theEmulator = [emulators objectAtIndex: tmp]; view = [theEmulator screen]; fullScreen = [view isFullScreen]; if ( [theEmulator isRunning] && ( fullScreen || [[theEmulator window] isMainWindow] ) ) break; } if ( tmp < [emulators count] ) // i.e. if we exited the for loop #else view = [theEmulator screen]; fullScreen = [view isFullScreen]; if ( [theEmulator isRunning] && ( fullScreen || [[theEmulator window] isMainWindow] ) ) #endif { if ( fullScreen || [view mouseInView: event] ) { switch ( type ) { case NSLeftMouseDown: [view mouseDown: event]; break; case NSLeftMouseUp: [view mouseUp: event]; break; case NSLeftMouseDragged: case NSMouseMoved: if ( fullScreen ) [view fullscreenMouseMove]; else [view processMouseMove: event]; break; default: [super sendEvent: event]; // NSApplication default } return; } } // Either the pointer is not in the Emulator's screen, no Basilisk window is running, // or no Basilisk window is main (e.g. there might be a panel or pane up). // // We should just be calling NSApp's default sendEvent, but then for some reason // mouseMoved events are still passed to our EmulatorView, so we filter them out. if ( type != NSMouseMoved ) [super sendEvent: event]; } // Methods to display documentation: - (IBAction) HelpHowTo: (id)sender { NSString *path = [[NSBundle mainBundle] pathForResource: @"HowTo" ofType: @"html"]; if ( ! path ) InfoSheet(@"Cannot find HowTo.html", [theEmulator window]); else if ( ! [[NSWorkspace sharedWorkspace] openFile: path] ) InfoSheet(@"Cannot open HowTo.html with default app", [theEmulator window]); } - (IBAction) HelpToDo: (id)sender { NSString *path = [[NSBundle mainBundle] pathForResource: @"ToDo" ofType: @"html"]; if ( ! path ) InfoSheet(@"Cannot find ToDo.html", [theEmulator window]); else if ( ! [[NSWorkspace sharedWorkspace] openFile: path withApplication: @"TextEdit"] ) InfoSheet(@"Cannot open ToDo.html with TextEdit", [theEmulator window]); } - (IBAction) HelpVersions: (id)sender { NSString *path = [[NSBundle mainBundle] pathForResource: @"Versions" ofType: @"html"]; if ( ! path ) InfoSheet(@"Cannot find Versions.html", [theEmulator window]); else if ( ! [[NSWorkspace sharedWorkspace] openFile: path withApplication: @"TextEdit"] ) InfoSheet(@"Cannot open Versions.html with TextEdit", [theEmulator window]); } // Menu items which for managing more than one window #ifdef ENABLE_MULTIPLE - (IBAction) NewEmulator: (id)sender { NSString *title; if ( ! [NSBundle loadNibNamed:@"Win512x342" owner:self] ) { NSLog(@"%s - LoadNibNamed@Win512x342 failed", __PRETTY_FUNCTION__); return; } if ( theEmulator == nil) { NSLog(@"%s - Newly created emulator's NIB stuff not fully linked?", __PRETTY_FUNCTION__); return; } [emulators addObject: theEmulator]; title = [NSString localizedStringWithFormat:@"BasiliskII Emulator %d", [emulators count]]; [theEmulator -> win setTitle: title]; } - (IBAction) PauseAll: (id)sender { [emulators makeObjectsPerformSelector:@selector(Suspend:) withObject:self]; } - (IBAction) RunAll: (id)sender { [emulators makeObjectsPerformSelector:@selector(Resume:) withObject:self]; } - (IBAction) TerminateAll: (id)sender { [emulators makeObjectsPerformSelector:@selector(Terminate:) withObject:self]; } #endif - (BOOL) isAnyEmulatorDisplayingSheets { #ifdef ENABLE_MULTIPLE int tmp; for ( tmp = 0; tmp < [emulators count], ++tmp ) if ( [[[emulators objectAtIndex: tmp] window] attachedSheet] ) break; if ( tmp < [emulators count] ) // i.e. if we exited the for loop #else if ( [[theEmulator window] attachedSheet] ) #endif return TRUE; return FALSE; } - (BOOL) isAnyEmulatorRunning { #ifdef ENABLE_MULTIPLE int tmp; for ( tmp = 0; tmp < [emulators count], ++tmp ) if ( [[emulators objectAtIndex: tmp] isRunning] ) break; if ( tmp < [emulators count] ) // i.e. if we exited the for loop #else if ( [theEmulator isRunning] ) #endif return TRUE; return FALSE; } - (short) emulatorCreatedCount { short count = 0; #ifdef ENABLE_MULTIPLE int tmp; for ( tmp = 0; tmp < [emulators count], ++tmp ) if ( [[emulators objectAtIndex: tmp] uaeCreated] ) ++count; #else if ( [theEmulator uaeCreated] ) ++count; #endif return count; } @end BasiliskII/src/MacOSX/NNThread.h0000644000175000017500000000325710054573763016457 0ustar centriscentris// // NNThread.h -Not Nextstep Thread? // Nigel's Nice Thread? // // Revision 1.2, Tuesday May 25 2004 // // Created by Nigel Pearson on Tue Nov 28 2000. // Public Domain. No rights reserved. // // Define what flavour of threading to use: #define USE_NSTHREAD //#define USE_PTHREAD #import #import #import #ifdef USE_PTHREAD #include struct pthreadArgs // This duplicates most of the stuff in the NNThread object { id *object; SEL *sel; NSAutoreleasePool *pool; BOOL allocPool, *completed; }; #endif @interface NNThread : NSObject { id object; SEL sel; thread_t machThread; #ifdef USE_PTHREAD pthread_t pThread; struct pthreadArgs pthreadArgs; #endif NSAutoreleasePool *pool; BOOL allocPool, completed, suspended; } - (NNThread *) initWithAutoReleasePool; - (NNThread *) initSuspended: (BOOL) startSuspended withAutoreleasePool: (BOOL) allocatePool; - (void) perform: (SEL)action of: (id)receiver; - (void) resume; - (BOOL) start; - (void) suspend; - (void) terminate; @end typedef enum _NNTimeUnits { NNnanoSeconds = 1, NNmicroSeconds = 2, NNmilliSeconds = 3, NNseconds = 4 } NNTimeUnits; #import @interface NNTimer : NNThread { struct timespec delay; BOOL repeating; id timerObject; SEL timerSel; } - (NNTimer *) initWithAutoRelPool; - (void) changeIntervalTo: (int)number units: (NNTimeUnits)units; - (void) invalidate; - (void) perform: (SEL)action of: (id)receiver after: (int)number units: (NNTimeUnits)units; - (void) repeat: (SEL)action of: (id)receiver every: (int)number units: (NNTimeUnits)units; @endBasiliskII/src/MacOSX/NNThread.m0000644000175000017500000001204510054575266016457 0ustar centriscentris// // NNThread.m -Not Nextstep Thread? // Nigel's Nice Thread? // // Revision 1.4, Tuesday May 25 2004 // // Created by Nigel Pearson on Tue Nov 28 2000. // Public Domain. No rights reserved. // #import "NNThread.h" #import // For objc_msgSend() prototype @implementation NNThread // Define the wrapper first so that init knows about it without having to put it in the .h #ifdef USE_NSTHREAD - (void) wrapper { machThread = mach_thread_self(); if ( object == nil || sel == (SEL) nil || suspended ) thread_suspend (machThread); // Suspend myself if ( allocPool ) pool = [NSAutoreleasePool new]; // [object sel] caused "cannot find method" warnings, so I do it a non-obvious way: objc_msgSend (object, sel); completed = YES; if ( allocPool ) [pool release]; } #endif #ifdef USE_PTHREAD void * pthreadWrapper (void *arg) { struct pthreadArgs *args = arg; if ( args -> allocPool ) args -> pool = [NSAutoreleasePool new]; objc_msgSend (*(args->object), *(args->sel)); *(args->completed) = YES; if ( args -> allocPool ) [args -> pool release]; return NULL; } - (BOOL) wrapper { int error; pthreadArgs.object = &object; pthreadArgs.sel = &sel; pthreadArgs.allocPool = allocPool; pthreadArgs.completed = &completed; pthreadArgs.pool = nil; if ( object == nil || sel == (SEL) nil || suspended ) error = pthread_create_suspended_np (&pThread, NULL, &pthreadWrapper, &pthreadArgs); else error = pthread_create (&pThread, NULL, &pthreadWrapper, &pthreadArgs); if ( error ) NSLog(@"%s - pthread_create failed"); else machThread = pthread_mach_thread_np (pThread); return ! error; } #endif - (NNThread *) initSuspended: (BOOL) startSuspended withAutoreleasePool: (BOOL) allocatePool { self = [super init]; allocPool = allocatePool; completed = NO; suspended = startSuspended; object = nil; sel = (SEL) nil; #ifdef USE_NSTHREAD [NSThread detachNewThreadSelector:@selector(wrapper) toTarget:self withObject:nil]; #endif #ifdef USE_PTHREAD if ( ! [self wrapper] ) // Wrapper does the thread creation { NSLog(@"%s - pthread wrapper failed", __PRETTY_FUNCTION__); return nil; } #endif return self; } - (NNThread *) init { return [self initSuspended: YES withAutoreleasePool: NO]; } - (NNThread *) initWithAutoReleasePool { return [self initSuspended: YES withAutoreleasePool: YES]; } - (BOOL) completed { return completed; } - (void) perform: (SEL)action of: (id)receiver { object = receiver, sel = action; } - (void) resume { if ( suspended ) [self start]; else NSLog (@"%s - thread not suspended", __PRETTY_FUNCTION__); } - (BOOL) start { kern_return_t error; if ( object == nil || sel == (SEL) nil ) { NSLog (@"%s - cannot start thread, object or selector invalid", __PRETTY_FUNCTION__); return NO; } if ( ( error = thread_resume (machThread) ) != KERN_SUCCESS ) NSLog (@"%s - thread_resume() failed, returned %d", __PRETTY_FUNCTION__, error); suspended = NO; return YES; } - (void) suspend { if ( ! suspended ) { kern_return_t error; if ( ( error = thread_suspend (machThread) ) != KERN_SUCCESS ) NSLog (@"%s - thread_resume() failed, returned %d", __PRETTY_FUNCTION__, error); suspended = YES; } } - (void) terminate { kern_return_t error; if ( ( error = thread_terminate (machThread) ) != KERN_SUCCESS ) NSLog (@"%s - thread_terminate() failed, returned %d", __PRETTY_FUNCTION__, error); } @end @implementation NNTimer - (NNTimer *) init { self = [super init]; repeating = YES; return self; } - (NNTimer *) initWithAutoRelPool { self = [super init]; allocPool = YES; repeating = YES; return self; } - (void) changeIntervalTo: (int)number units: (NNTimeUnits)units { switch ( units ) { case NNnanoSeconds: delay.tv_nsec = number; delay.tv_sec = 0; break; case NNmicroSeconds: delay.tv_nsec = number * 1000; delay.tv_sec = 0; break; case NNmilliSeconds: delay.tv_nsec = number * 1000000; delay.tv_sec = 0; break; case NNseconds: delay.tv_nsec = 0; delay.tv_sec = number; break; default: NSLog (@"%s illegal units(%d)", __PRETTY_FUNCTION__, units); } } - (void) invalidate { repeating = NO; } - (void) timerLoop { // For some strange reason, Mac OS X does not have this prototype extern int nanosleep (const struct timespec *rqtp, struct timespec *rmtp); while ( repeating ) { nanosleep(&delay, NULL); completed = NO; // This caused a few warnings: // [timerObject timerSel]; // so I do it a non-obvious way: objc_msgSend (timerObject, timerSel); completed = YES; } } - (void) perform: (SEL)action of: (id)receiver after: (int)number units: (NNTimeUnits)units { object = self, sel = @selector(timerLoop), timerObject = receiver, timerSel = action, repeating = NO; [self changeIntervalTo: number units: units]; } - (void) repeat: (SEL)action of: (id)receiver every: (int)number units: (NNTimeUnits)units { object = self, sel = @selector(timerLoop), timerObject = receiver, timerSel = action, repeating = YES; [self changeIntervalTo: number units: units]; } @endBasiliskII/src/MacOSX/English.lproj/0000755000175000017500000000000011735674761017361 5ustar centriscentrisBasiliskII/src/MacOSX/English.lproj/InfoPlist.strings0000755000175000017500000000025611117525276022677 0ustar centriscentris/* Localized versions of Info.plist keys */ NSHumanReadableCopyright = "Copyright © 1997-2006 Christian Bauer et al. Freely distributable under the terms of the GNU GPL."; BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/0000755000175000017500000000000011735675027021635 5ustar centriscentrisBasiliskII/src/MacOSX/English.lproj/MainMenu.nib/Collapsed.tiff0000644000175000017500000000154607444541550024416 0ustar centriscentrisMM*¬=”Ž"¿¿ªn¿¿¿¿®O¿¿¿¿¿¿Ÿ3 ¿¿¿¿¿¿¿¹…¿¿¿¿¿¿Ÿ3 ¿¿¿¿®O¿¿ªn”Ž"=   N¤V^(R ü€' ü€'BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/Expanded.tiff0000644000175000017500000000154607444541550024240 0ustar centriscentrisMM*¬=”¿¿¿¿¿¿¿”=Ž¿¿¿¿¿¿¿Ž"ª¿¿¿¿¿ª"n¿¿¿¿¿n®¿¿¿®O¿¿¿OŸ¿Ÿ3¹3 …   N¤V^(R ü€' ü€'BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/resetH.tiff0000644000175000017500000002310607444541563023742 0ustar centriscentrisMM*%Œ6k *™HÀ&iÝ)5ˆó/<˜þ*7Šó )lÝJÀ +™k6"n :µ#1õ>R­ÿ[oÇÿuŠÛÿ‹åÿ—¨ëÿœ¯íÿ˜ªìÿŽ¢çÿ{ÞÿbvÎÿEYµÿ(8Œõ >µn"tLÊ.CœÿNiÁÿu‘ãÿ›µõÿ»ÑÿÿÐâÿÿÜìÿÿãñÿÿæòÿÿäñÿÿàîÿÿÔæÿÿÂ×ÿÿ¥¾ùÿœëÿVsÍÿ4L§ÿPÊtO 5²!9ÿ@_¹ÿgŠÞÿ°øÿ¬Ìÿÿ¿ÛÿÿËåÿÿÒéÿÿÔëÿÿÖëÿÿÖëÿÿ×ëÿÿ×ëÿÿÖëÿÿÑéÿÿÆáÿÿ³Óÿÿ”¹ÿÿo”éÿGjÆÿ&B›ÿ 9²O r YÞ&F›ÿBj¿ÿcŽÝÿ}¨ïÿ¹ùÿœÅûÿ¡Éûÿ¢Ëùÿ¢É÷ÿ¡Èõÿ Çõÿ Çôÿ Èôÿ£Éõÿ¥Ë÷ÿ¦Ìùÿ¥Íûÿ¡Éýÿ”Àýÿƒ°öÿi—æÿHsËÿ,P¨ÿ$aÞr   …/vö&L¡ÿ>k¼ÿS„Ðÿd—Þÿn¢åÿs¨æÿuªæÿuªãÿs¨ßÿq¦Ýÿr¥Üÿq¤Úÿq¤Úÿq¤Úÿr¥Üÿt§Þÿv¨àÿx¬ãÿx¬èÿv¬éÿr§éÿhäÿWŒ×ÿCsÄÿ,Uªÿ5ö …   †1}þ!Kžÿ3c³ÿCxÃÿO‡ÍÿW‘Ôÿ[–Õÿ]™Õÿ_˜Óÿa˜Òÿc™Ñÿe™ÑÿfšÑÿg›Ñÿg›Ñÿg›ÑÿfšÑÿf›ÑÿešÒÿcšÓÿb™Ôÿ`™Öÿ^™ØÿZ•×ÿSÒÿGÈÿ7k¹ÿ&T§ÿ8ˆþ †  v1uöJ›ÿ)_¬ÿ5o·ÿ?}ÂÿF†ÈÿO‹ËÿVÍÿ[”Îÿ^–Ïÿc™ÑÿgœÒÿjžÔÿmŸÔÿn Õÿn Õÿn ÕÿmŸÔÿkŸÔÿiœÔÿešÒÿa—Ðÿ\”ÏÿX’ÎÿRŽÌÿJŠÊÿB‚Æÿ8u¼ÿ-e±ÿQ¢ÿ7€öv   U #XßH—ÿZ§ÿ*i²ÿ4u»ÿA€ÂÿJˆÇÿSŽËÿZ“Îÿa˜Ñÿg›ÓÿlŸÕÿp¢×ÿr¥Ùÿu§Úÿv§Ûÿv§Ûÿv§Ûÿv§Úÿs¦Ùÿq¤×ÿm¡ÖÿhÓÿc™Òÿ\•ÐÿUÌÿN‰ÈÿEƒÅÿ9z¾ÿ-nµÿ#_ªÿOžÿ )aß U  #5·BÿV£ÿ"d­ÿ/q·ÿ<|ÀÿH…ÆÿRËÿ\”ÐÿcšÔÿjŸÖÿn¢Øÿs¦Úÿw©Ûÿy«Ýÿ|¬Þÿ}¬Þÿ}­Þÿ}­Þÿ}¬Þÿz«Ýÿx©Üÿu¨Ûÿk’¸ÿ]p„ÿeœÔÿ^—ÒÿWÍÿLˆÉÿA€Ãÿ4v»ÿ%h±ÿZ¨ÿJšÿ;·# ~ <„ÿQ ÿ`¬ÿ)mµÿ9z½ÿF…ÆÿQŽÌÿ[•ÑÿdœÕÿk¡Øÿq¥Ûÿu¨Üÿz«Þÿ}­Þÿ¯àÿ°àÿ‚°àÿ‚±àÿ‚±àÿ°àÿ€¯àÿz¢ÌÿhuƒÿXXXÿLU_ÿl¡×ÿhÕÿ_—ÓÿU‘ÏÿJˆÉÿ>Áÿ.q¹ÿ d°ÿW§ÿD’ÿ ~ 1 JÐ K™ÿ]ªÿ&kµÿ5w¾ÿDƒÇÿPÍÿZ•Òÿcœ×ÿk£Úÿq§ÜÿwªÞÿ{«ßÿ®àÿ‚±áÿ„²áÿ…³áÿ†´áÿ†´áÿ†´áÿ‚®×ÿpƒ–ÿ[\]ÿLLLÿ>>>ÿDLUÿq¤Øÿm£ÙÿfžØÿ^˜ÔÿSÏÿH‡Èÿ:|Áÿ,p¸ÿa­ÿR¢ÿ%SÐ1 | @‰ÿW§ÿf±ÿ1u¼ÿ?€ÅÿLŒÍÿW”Óÿb›Øÿj¢Ûÿq§ÝÿwªÞÿ|­ßÿ¯áÿ‚±áÿ…²áÿˆ´âÿ‰µâÿеâÿˆ³Ýÿv¤ÿ^acÿPPPÿBBBÿ:::ÿ999ÿCKSÿs£Ôÿq¥Ùÿl£ÜÿeØÿ[–ÔÿQÏÿD…Èÿ6yÀÿ%kµÿ]«ÿ I—ÿ | ;¿ O›ÿa¯ÿ*o¹ÿ:}ÄÿGˆÍÿU“Óÿ_›Øÿh¡Üÿo¦Þÿv«ßÿ|­àÿ€¯áÿƒ±áÿ†´áÿˆµâÿжãÿ‹·ãÿ{–±ÿchlÿRRRÿBBBÿ999ÿ999ÿ999ÿ999ÿCJQÿs Îÿu¨Úÿr¨ßÿk¢ÝÿbœÚÿY–ÕÿLŒÐÿ?Èÿ0t¾ÿ f³ÿV¦ÿ D¿ M;y÷Z§ÿ#j¶ÿ3xÁÿC…ÌÿPÓÿ\™ÙÿeŸÝÿm¦ßÿtªáÿ{­áÿ¯áÿƒ²áÿ†´âÿ‰¶ãÿ‹·ãÿ ÀÿgowÿUUUÿEEEÿ999ÿ999ÿBGLÿc€œÿ999ÿ999ÿBIPÿt Îÿx©Úÿw«áÿo§ßÿh¡Ýÿ_›ÚÿS“ÕÿG‰Ïÿ9}Åÿ)o»ÿ`¯ÿD‰÷M  € K“ÿc°ÿ,r¾ÿ;€ÈÿJŒÒÿV•ØÿažÝÿj¤àÿrªáÿy­âÿ¯ãÿƒ²ãÿ…¶äÿ‰·åÿ„§Íÿmy…ÿWWWÿIIIÿ999ÿ999ÿ>@Cÿd{”ÿlŒ­ÿeƒ¢ÿ999ÿ999ÿBIPÿw¢Íÿ|ªÝÿ{®ãÿt«âÿl¦àÿd Þÿ[™ÚÿOÔÿ@…Ìÿ1wÂÿ!h¶ÿV¢ÿ €  /«U ÿ#k¹ÿ3yÄÿA‡ÏÿP’Øÿ\›Ýÿg£àÿo¨âÿv¬äÿ|°åÿ³åÿ…µæÿƒ®Øÿq‚“ÿZZZÿLLLÿ999ÿ999ÿ999ÿ_rˆÿp°ÿnŒ¬ÿl‹ªÿg†¤ÿ999ÿ999ÿCIPÿz¤Ïÿ®ßÿ~±äÿx­äÿqªãÿj¥àÿ`žßÿV–ÚÿH‹Óÿ:€Éÿ)p½ÿ_¬ÿ5« &'LÍ_ªÿ+s¿ÿ;ÌÿIÕÿV˜Üÿa áÿk§ãÿs«åÿz¯çÿ€²èÿ‚±àÿsŠ¡ÿ^_aÿOOOÿ:::ÿ999ÿ999ÿWgwÿq®ÿp®ÿp®ÿt”³ÿu•¶ÿpޝÿ999ÿ999ÿCJPÿ|¦Òÿ‚±áÿ‚´èÿ|°çÿu­æÿn©ãÿe£âÿZ›ßÿN’Ùÿ@†Ïÿ0xÄÿ hµÿ -VÍ& , 9lå g³ÿ2zÇÿA‡ÒÿO“Ûÿ\žáÿg¥äÿpªçÿv®èÿ|°æÿt‘±ÿ`dgÿQQQÿ>>>ÿ999ÿ999ÿNZfÿpŽ­ÿq¯ÿr®ÿu”³ÿ{œ¼ÿ‚¤Çÿƒ¦Êÿ{Àÿ999ÿ999ÿCJPÿ¨Óÿ„³ãÿ…·ëÿ³êÿy°éÿr¬çÿj§åÿ`¡ãÿT—ÞÿFŒÖÿ8Ëÿ'n½ÿBwå,  1J‡ö&m¹ÿ7ÌÿFŒØÿT˜ßÿa£åÿk©èÿt®êÿq—½ÿdksÿSSSÿCCCÿ999ÿ999ÿGNVÿl‰¦ÿr’²ÿr’±ÿu•´ÿ{›½ÿ‚¥Èÿ‰®Óÿ¶Ýÿ޵Ûÿ¥Éÿ999ÿ999ÿDJQÿ«×ÿ‡µæÿ‡ºíÿƒ·íÿ|³ìÿv®ëÿn«éÿe¦çÿZ›âÿL‘Ûÿ=„Ðÿ,tÃÿS•ö1 5T˜þ+rÀÿ<„ÒÿK’ÝÿYäÿf¦êÿn¬íÿTm†ÿ999ÿ999ÿ999ÿ999ÿ@DHÿh„ ÿr”¶ÿr’´ÿu•¶ÿy›¾ÿ‚¥ÉÿНÕÿ‘·Þÿ–½çÿ™Áìÿ”½æÿ†«Ñÿ999ÿ999ÿDKRÿ…®Ùÿ‹¸éÿмñÿ†ºðÿ€·ðÿz³ïÿq®íÿi©ëÿ^¡çÿP–áÿAŠ×ÿ1{Èÿ`©þ5!8QŽö0wÄÿ@‰ÖÿP–áÿ\¡èÿh¨ëÿp®íÿv¯êÿc‡¬ÿBIPÿ999ÿ999ÿGGGÿWWWÿelsÿu’°ÿ€¤Éÿ‰¯Õÿ¸àÿ—¿éÿ›ÃîÿžÆòÿÇóÿ—¿êÿˆ­Óÿ999ÿ999ÿEKRÿ…±ÜÿŒ»ìÿÀõÿˆ½ôÿ„ºóÿ}·òÿu²ñÿm¬îÿa¤êÿTšäÿEŽÛÿ7Íÿ \žö8!":Eyç2zÆÿDÚÿR›åÿ`¥ìÿk¬ïÿr°îÿu¬çÿt¥ØÿošÆÿWn…ÿ=?Bÿ999ÿ999ÿJJJÿYYYÿq~Œÿ”ºàÿÅðÿ Éõÿ Ëöÿ¡Ë÷ÿ¡Ë÷ÿ™ÃíÿНÖÿ999ÿ999ÿELRÿˆ³àÿ¿ïÿÄ÷ÿ‹Á÷ÿ†½öÿºöÿx¶õÿo¯òÿe¨îÿWžçÿI’Þÿ:ƒÑÿP‡ç:"":6[Ó5|ÈÿGÞÿUéÿc¨ðÿm°óÿt±ðÿu­åÿr£Õÿl™Åÿi¸ÿfˆ¬ÿRbtÿ;<>ÿ999ÿ999ÿNNNÿ[[[ÿ•«ÿ£Îúÿ¤Ðýÿ¤Ðýÿ¤ÐýÿžÈóÿ³Ûÿ999ÿ999ÿELSÿ‹·åÿ’Ãõÿ“ÇýÿŽÅýÿˆÁüÿ‚¾ûÿ{¹ùÿr´÷ÿh¬óÿ\¢ìÿL–ãÿ=†Ôÿ>hÓ:"": $=¹7|ÆÿI“áÿX¢íÿf¬ôÿq³øÿx¶÷ÿ{³ïÿw¬àÿu¢ÐÿqšÂÿo”¹ÿq•¸ÿo‘¯ÿTbpÿ999ÿ999ÿ===ÿQQQÿ`bcÿ­Éÿ¨Ôþÿ§Ôÿÿ Ìõÿ¸Ýÿ999ÿ999ÿFMTÿ޽æÿ•Ç÷ÿ–Ëÿÿ’Èÿÿ‹Åÿÿ…Âÿÿ~¼þÿv·úÿj¯öÿ^¦ðÿO™æÿ@ˆÖÿ*F¹:"!8!˜6x¿ÿL•ãÿZ¤ïÿh¯÷ÿt·ýÿ}»üÿ‚½÷ÿ‚»ïÿ‚´ãÿ€¯×ÿ|¦Ëÿy¡Âÿyž¾ÿ| Àÿu”­ÿPZcÿ999ÿ999ÿCCCÿTTTÿhmqÿš¾Ûÿ£Ðõÿ“»Ýÿ999ÿ999ÿFMTÿ¿æÿ—Ë÷ÿ™Ðÿÿ•ÍÿÿŽÉÿÿ‡Åÿÿ€Àÿÿyºþÿm²úÿ`¨óÿRœéÿ?‡Óÿ &˜8!5 r/h§øL•âÿ]¦ðÿi±ûÿvºÿÿÀÿÿ†ÄýÿŒÇúÿŽÆôÿÃìÿ‹¼áÿ‡´Õÿƒ«Éÿ¥Áÿ¤¾ÿ§Áÿr¡ÿFLPÿ999ÿ999ÿGGGÿWWWÿoy€ÿ³ÎÿGGGÿ999ÿGNTÿ”Äæÿ›Ï÷ÿ›Ôÿÿ—Ñÿÿ‘ÌÿÿŠÈÿÿƒÄÿÿz½ÿÿo´üÿb©õÿSêÿ9y½ø r5 1L:\ÐK‘Üÿ]§óÿj²üÿw¼ÿÿ€Ãÿÿ‰ÉÿÿÏÿÿ–Ñýÿ˜ÑùÿšÏóÿ˜Ëêÿ”Âßÿ¹Óÿˆ°Çÿ„©Àÿ„©¾ÿ…ª¿ÿj€Žÿ@CEÿ999ÿ999ÿJJJÿLLLÿHHHÿ999ÿGOTÿ˜ÇæÿŸÔ÷ÿžØÿÿ™Õÿÿ“ÐÿÿËÿÿ„Çÿÿ|Àÿÿo¶þÿb¬øÿTéÿ DjÐL1  ,F &¡F‰Îÿ]§õÿj³þÿw¾ÿÿ‚Æÿÿ‹Íÿÿ’Óÿÿ™×ÿÿžÚþÿ¤Üýÿ¥Ûøÿ£×òÿžÏèÿ™ÈÝÿ’¼Ðÿ´Æÿ‰®¿ÿˆ®¿ÿ‡«¼ÿdw€ÿ<>?ÿ999ÿ999ÿ999ÿ999ÿHPTÿ™Êæÿ¡×÷ÿ¡Üÿÿ›Ùÿÿ•ÔÿÿŽÏÿÿ…Èÿÿ|Âÿÿp·ÿÿc­úÿP˜âÿ +¡F, &?k)R{ÝZ£îÿk´ÿÿw¿ÿÿ‚ÇÿÿŒÏÿÿ”Öÿÿ›Ûÿÿ¡ßÿÿ§âÿÿ«äþÿ­äüÿ«â÷ÿªÝðÿ¥ÖæÿžËÚÿ•ÀÎÿ·Äÿ‹²¿ÿ‹²¿ÿ†«·ÿZkpÿ999ÿ999ÿ999ÿHPTÿœÏæÿ¤Û÷ÿ£àÿÿÝÿÿ–×ÿÿÒÿÿ†Ëÿÿ|Ãÿÿp¸ÿÿb­úÿ0[‰Ýk?& 6Q-§Q”Øÿi³þÿxÀÿÿ‚ÉÿÿŒÐÿÿ•×ÿÿœÞÿÿ¢âÿÿ©æÿÿ­éÿÿ±ìÿÿ´îþÿµíûÿ²éöÿ¯äîÿ©ÚäÿŸÎ×ÿ–ÂËÿºÂÿŒ¶¾ÿ‹´¼ÿy›¢ÿMX[ÿ999ÿIQTÿÔæÿ¥á÷ÿ¤ãÿÿžßÿÿ˜ÛÿÿÓÿÿ†Íÿÿ|Äÿÿo¹ÿÿ\¤îÿ"3§Q6  -Fk$CcÍb©ðÿu¿ÿÿ€ÉÿÿŒÒÿÿ•Ùÿÿàÿÿ¤åÿÿªëÿÿ¯îÿÿ³ñÿÿ·óÿÿºöÿÿ»õþÿºóúÿ¹ïõÿ³çìÿªÝáÿ¡ÑÕÿ˜ÅÉÿŽº¿ÿˆ²¸ÿƒ­³ÿq‘—ÿYkoÿ Øæÿ§ä÷ÿ¦çÿÿ ãÿÿ˜ÝÿÿÕÿÿ†Íÿÿ{Äÿÿk´ûÿ*MpÍkF- $;T@q¢ép¹úÿ~ÈÿÿŠÑÿÿ“Ùÿÿœáÿÿ£èÿÿªìÿÿ°ñÿÿ¶ôÿÿ¹öÿÿ½úÿÿ¿üÿÿÁýÿÿÁüýÿ¿ùùÿ»óóÿ´êêÿ«ßßÿŸÑÒÿ”ÄÆÿº½ÿŒºÀÿ•ÈÐÿ¢Üèÿ¨ç÷ÿ¦éÿÿŸãÿÿ—ÝÿÿŽÕÿÿ„ÌÿÿwÁÿÿI~²é T;$ /G_ /¥X˜ÐùzÂýÿ‡Ðÿÿ‘Øÿÿšàÿÿ£çÿÿªíÿÿ°òÿÿ¶÷ÿÿºúÿÿ½þÿÿÀÿÿÿÃÿÿÿÆÿÿÿÄþþÿÄýýÿÁøøÿ»òòÿ²èèÿ§ÝÝÿœÐÑÿ™ÎÐÿÔÙÿ¤âëÿ¨êùÿ¥êÿÿžãÿÿ•ÜÿÿŒÔÿÿ€Éÿÿe¥àù%5¥_G/ #8Pf+>°f¦ßþÉýÿŽ×ÿÿ—àÿÿ¡çÿÿ¨îÿÿ®óÿÿ´øÿÿ¹ýÿÿ½ÿÿÿÀÿÿÿÃÿÿÿÅÿÿÿÅÿÿÿÆÿÿÿÅþþÿÃüüÿ¾÷÷ÿ·ððÿ­èèÿ§ãäÿ¥âçÿ¨éòÿ§ëúÿ£êÿÿœãÿÿ’Ûÿÿ‡Ðÿÿq¶íþ1C°fP8# +@Wf->°f¢Òù…Îýÿ”Ýÿÿžæÿÿ¦íÿÿ®óÿÿ³ùÿÿ¸ýÿÿ¼ÿÿÿÀÿÿÿÃÿÿÿÄÿÿÿÆÿÿÿÆÿÿÿÆÿÿÿÆÿÿÿÃþþÿ¾ûûÿ¸÷÷ÿ²ôôÿ®ïôÿ«ðùÿ¨îýÿ¡éÿÿ˜áÿÿÖÿÿq°ßù2C°fW@+ 0F\f%2¥Tƒ§é‡Îöÿ—áÿÿ¡êÿÿ¨ñÿÿ¯öÿÿµüÿÿºÿÿÿ¾ÿÿÿÀÿÿÿÃÿÿÿÄÿÿÿÅÿÿÿÄÿÿÿÄÿÿÿÁÿÿÿ¿ÿÿÿºþþÿµüýÿ°öüÿ«ñýÿ¤ìþÿœæÿÿŽÖûÿ]²é)6¥f\F0 "4H]f 8WlÍ‚Æêÿ—áýÿ¢íÿÿªóÿÿ°ùÿÿµþÿÿºÿÿÿ¼ÿÿÿ¾ÿÿÿÀÿÿÿÀÿÿÿÀÿÿÿ¿ÿÿÿ½ÿÿÿºÿÿÿ¶ÿÿÿ²üÿÿ¬öÿÿ¦ïÿÿœæÿÿŠÑóÿ=^rÍf]H4"  $5H\fp,7§NuŒÝ‹Ïëÿœäúÿ§ñÿÿ®øÿÿ²ýÿÿ¶ÿÿÿ¸ÿÿÿºÿÿÿ¹ÿÿÿ¹ÿÿÿ¹ÿÿÿ¶ÿÿÿ³þÿÿ¯ûÿÿªôÿÿ¢ëüÿ“ÙòÿT}’Ý0:§pf\H5$  $4FWffv)1¤BdsÐ¼Ðø˜Ýïÿ¢ëøÿ¨ôüÿ®øþÿ°ûþÿ±üÿÿ±ûÿÿ®ùþÿ«õýÿ¥îúÿœãòÿ†ÄÕøGjwÐ-4¤ vffWF4$  "0@P_fff ƒ*/£5NW¿Px‚×mž«éƒ¿Î÷Ñßþ„ÁÏ÷o¡­éTz…×7QY¿,1£ ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/resetN.tiff0000644000175000017500000002310607444541565023752 0ustar centriscentrisMM*%Œ6k$$$™===ÀZZZÝttt󃃃þvvvó\\\Ý@@@À%%%™k6"n666µzzzõ   ÿ½½½ÿÑÑÑÿÜÜÜÿäääÿæææÿåååÿßßßÿÕÕÕÿÄÄÄÿ¨¨¨ÿƒƒƒõ:::µn"tDDDÊŽŽŽÿºººÿÝÝÝÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿæææÿÅÅÅÿšššÿKKKÊtO...²ÿ¨¨¨ÿÊÊÊÿéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿÔÔÔÿ´´´ÿŽŽŽÿ222²O rSSSÞÿµµµÿÑÑÑÿãããÿïïïÿôôôÿôôôÿóóóÿñññÿïïïÿíííÿíííÿíííÿîîîÿñññÿóóóÿöööÿ÷÷÷ÿôôôÿêêêÿÚÚÚÿ¿¿¿ÿšššÿ\\\Þr  …mmmö–––ÿ¯¯¯ÿÅÅÅÿÓÓÓÿÚÚÚÿÝÝÝÿÜÜÜÿÚÚÚÿ×××ÿÔÔÔÿÓÓÓÿÒÒÒÿÑÑÑÿÒÒÒÿÓÓÓÿÔÔÔÿ×××ÿÚÚÚÿÝÝÝÿàààÿßßßÿÙÙÙÿÌÌÌÿ¶¶¶ÿ   ÿwwwö…  †pppþ‘‘‘ÿ§§§ÿ¶¶¶ÿÃÃÃÿÊÊÊÿÍÍÍÿÌÌÌÿËËËÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÉÉÉÿÊÊÊÿÊÊÊÿËËËÿÌÌÌÿÎÎÎÿÏÏÏÿÎÎÎÿÈÈÈÿ¼¼¼ÿ­­­ÿšššÿ{{{þ†  vmmmöŽŽŽÿ¡¡¡ÿ®®®ÿ¶¶¶ÿ¾¾¾ÿÁÁÁÿÄÄÄÿÆÆÆÿÇÇÇÿÈÈÈÿËËËÿÌÌÌÿÍÍÍÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿÍÍÍÿËËËÿÉÉÉÿÈÈÈÿÆÆÆÿÅÅÅÿÃÃÃÿÁÁÁÿ»»»ÿ²²²ÿ¦¦¦ÿ•••ÿvvvöv  USSSßÿ›››ÿ¨¨¨ÿ±±±ÿ···ÿ¼¼¼ÿÁÁÁÿÅÅÅÿÈÈÈÿËËËÿÎÎÎÿÐÐÐÿÒÒÒÿÒÒÒÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿÒÒÒÿÑÑÑÿÏÏÏÿÌÌÌÿÊÊÊÿÆÆÆÿÃÃÃÿ¿¿¿ÿºººÿ´´´ÿ«««ÿŸŸŸÿ”””ÿ[[[ßU  "///·„„„ÿ˜˜˜ÿ¡¡¡ÿ­­­ÿµµµÿ¼¼¼ÿÁÁÁÿÇÇÇÿÊÊÊÿÎÎÎÿÑÑÑÿÓÓÓÿÔÔÔÿÕÕÕÿÕÕÕÿÖÖÖÿ×××ÿ×××ÿÖÖÖÿÕÕÕÿÔÔÔÿÓÓÓÿ²²²ÿÿËËËÿÈÈÈÿÄÄÄÿ½½½ÿ¸¸¸ÿ°°°ÿ¥¥¥ÿ›››ÿŽŽŽÿ555·# ~yyyÿ–––ÿ¢¢¢ÿªªªÿµµµÿ½½½ÿÃÃÃÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÕÕÕÿÖÖÖÿ×××ÿØØØÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿØØØÿÆÆÆÿÿXXXÿ^^^ÿÏÏÏÿÍÍÍÿÊÊÊÿÅÅÅÿ¿¿¿ÿ¸¸¸ÿ­­­ÿ¥¥¥ÿšššÿ†††ÿ~ 1FFFÐŒŒŒÿŸŸŸÿ©©©ÿ³³³ÿ¼¼¼ÿÄÄÄÿÉÉÉÿÎÎÎÿÒÒÒÿÓÓÓÿÕÕÕÿ×××ÿØØØÿÚÚÚÿÚÚÚÿÚÚÚÿÛÛÛÿÛÛÛÿÛÛÛÿÑÑÑÿ“““ÿ\\\ÿLLLÿ>>>ÿTTTÿÏÏÏÿÐÐÐÿÐÐÐÿËËËÿÆÆÆÿ¿¿¿ÿ¶¶¶ÿ®®®ÿ¢¢¢ÿ”””ÿOOOÐ1 |ÿ˜˜˜ÿ¥¥¥ÿ°°°ÿ¹¹¹ÿÃÃÃÿÉÉÉÿÎÎÎÿÒÒÒÿÕÕÕÿÖÖÖÿØØØÿÙÙÙÿÚÚÚÿÛÛÛÿÜÜÜÿÜÜÜÿÜÜÜÿ×××ÿ¡¡¡ÿcccÿPPPÿBBBÿ:::ÿ999ÿRRRÿËËËÿÑÑÑÿÓÓÓÿÐÐÐÿËËËÿÅÅÅÿ¾¾¾ÿµµµÿ©©©ÿœœœÿŒŒŒÿ| 888¿’’’ÿ¡¡¡ÿ®®®ÿ¹¹¹ÿÁÁÁÿÉÉÉÿÐÐÐÿÓÓÓÿÖÖÖÿ×××ÿØØØÿÚÚÚÿÛÛÛÿÜÜÜÿÜÜÜÿÝÝÝÿÝÝÝÿ­­­ÿlllÿRRRÿBBBÿ999ÿ999ÿ999ÿ999ÿPPPÿÈÈÈÿÓÓÓÿÖÖÖÿÔÔÔÿÑÑÑÿÌÌÌÿÅÅÅÿ½½½ÿ³³³ÿ¦¦¦ÿšššÿ???¿ Msss÷ÿ©©©ÿ···ÿÁÁÁÿÈÈÈÿÏÏÏÿÓÓÓÿÖÖÖÿÙÙÙÿÚÚÚÿÛÛÛÿÜÜÜÿÜÜÜÿÝÝÝÿÝÝÝÿ»»»ÿvvvÿUUUÿEEEÿ999ÿ999ÿKKKÿ˜˜˜ÿ999ÿ999ÿOOOÿÇÇÇÿÓÓÓÿÙÙÙÿ×××ÿÔÔÔÿÑÑÑÿËËËÿÅÅÅÿºººÿ®®®ÿ£££ÿ÷M €‰‰‰ÿ¥¥¥ÿ±±±ÿ½½½ÿÇÇÇÿÎÎÎÿÓÓÓÿÖÖÖÿØØØÿÛÛÛÿÜÜÜÿÝÝÝÿÞÞÞÿÞÞÞÿÇÇÇÿƒƒƒÿWWWÿIIIÿ999ÿ999ÿBBBÿÿ¨¨¨ÿÿ999ÿ999ÿOOOÿÇÇÇÿÖÖÖÿÛÛÛÿÙÙÙÿ×××ÿÕÕÕÿÐÐÐÿËËËÿÂÂÂÿµµµÿ«««ÿ–––ÿ€  ***«———ÿ®®®ÿ¹¹¹ÿÅÅÅÿÎÎÎÿÓÓÓÿ×××ÿÚÚÚÿÜÜÜÿÝÝÝÿÞÞÞÿÞÞÞÿÒÒÒÿ‘‘‘ÿZZZÿLLLÿ999ÿ999ÿ999ÿ„„„ÿªªªÿ§§§ÿ¦¦¦ÿ   ÿ999ÿ999ÿOOOÿÉÉÉÿØØØÿÞÞÞÿÜÜÜÿÛÛÛÿÙÙÙÿÕÕÕÿÑÑÑÿÉÉÉÿ½½½ÿ³³³ÿ¢¢¢ÿ///« &EEEÍ¡¡¡ÿµµµÿ¿¿¿ÿÊÊÊÿÒÒÒÿÖÖÖÿÜÜÜÿÝÝÝÿÞÞÞÿàààÿÙÙÙÿÿaaaÿOOOÿ:::ÿ999ÿ999ÿuuuÿªªªÿ©©©ÿ©©©ÿ¯¯¯ÿ±±±ÿ«««ÿ999ÿ999ÿOOOÿËËËÿÙÙÙÿßßßÿÞÞÞÿÞÞÞÿÜÜÜÿÙÙÙÿÕÕÕÿÎÎÎÿÄÄÄÿºººÿ«««ÿOOOÍ& ,aaa娨¨ÿºººÿÅÅÅÿÐÐÐÿÖÖÖÿÚÚÚÿÞÞÞÿàààÿÝÝÝÿ«««ÿgggÿQQQÿ>>>ÿ999ÿ999ÿcccÿ¨¨¨ÿ«««ÿªªªÿ®®®ÿ···ÿÂÂÂÿÅÅÅÿºººÿ999ÿ999ÿPPPÿÍÍÍÿÛÛÛÿâââÿáááÿàààÿßßßÿÜÜÜÿØØØÿÓÓÓÿÊÊÊÿÀÀÀÿ±±±ÿnnnå,  1{{{ö¯¯¯ÿÁÁÁÿÌÌÌÿÕÕÕÿÛÛÛÿßßßÿâââÿ¸¸¸ÿrrrÿSSSÿCCCÿ999ÿ999ÿUUUÿ£££ÿ¯¯¯ÿ­­­ÿ±±±ÿ¹¹¹ÿÄÄÄÿÏÏÏÿÙÙÙÿ×××ÿÅÅÅÿ999ÿ999ÿPPPÿÏÏÏÿßßßÿæææÿåååÿãããÿãããÿàààÿÝÝÝÿØØØÿÏÏÏÿÆÆÆÿ¸¸¸ÿ‰‰‰ö1 5‰‰‰þ´´´ÿÆÆÆÿÐÐÐÿÚÚÚÿàààÿâââÿƒƒƒÿ999ÿ999ÿ999ÿ999ÿHHHÿœœœÿ±±±ÿ¯¯¯ÿ²²²ÿ¹¹¹ÿÄÄÄÿÎÎÎÿÙÙÙÿàààÿæææÿàààÿËËËÿ999ÿ999ÿPPPÿÒÒÒÿâââÿéééÿèèèÿçççÿæææÿäääÿàààÿÝÝÝÿÔÔÔÿËËËÿ½½½ÿšššþ5!8‚‚‚ö¹¹¹ÿËËËÿÕÕÕÿÞÞÞÿáááÿãããÿâââÿ¦¦¦ÿOOOÿ999ÿ999ÿGGGÿWWWÿrrrÿ­­­ÿÄÄÄÿÐÐÐÿÙÙÙÿâââÿçççÿëëëÿìììÿåååÿÎÎÎÿ999ÿ999ÿQQQÿÕÕÕÿåååÿìììÿëëëÿëëëÿêêêÿèèèÿäääÿàààÿØØØÿÐÐÐÿÂÂÂÿ‘‘‘ö8!":nnnç¼¼¼ÿÐÐÐÿÚÚÚÿâââÿæææÿåååÿÞÞÞÿÑÑÑÿÀÀÀÿ‚‚‚ÿBBBÿ999ÿ999ÿJJJÿYYYÿŠŠŠÿÜÜÜÿëëëÿðððÿñññÿòòòÿòòòÿéééÿÑÑÑÿ999ÿ999ÿRRRÿÚÚÚÿéééÿñññÿïïïÿïïïÿîîîÿìììÿéééÿäääÿÝÝÝÿÔÔÔÿÆÆÆÿ}}}ç:"":TTTÓ½½½ÿÓÓÓÿÝÝÝÿåååÿéééÿçççÿÝÝÝÿÍÍÍÿ¾¾¾ÿ²²²ÿ§§§ÿqqqÿ>>>ÿ999ÿ999ÿNNNÿ[[[ÿ§§§ÿóóóÿöööÿöööÿöööÿìììÿÕÕÕÿ999ÿ999ÿRRRÿÝÝÝÿíííÿõõõÿôôôÿòòòÿñññÿïïïÿìììÿèèèÿàààÿ×××ÿÉÉÉÿ```Ó:"":777¹¼¼¼ÿÖÖÖÿàààÿéééÿîîîÿìììÿçççÿÙÙÙÿÊÊÊÿ½½½ÿµµµÿµµµÿ­­­ÿoooÿ999ÿ999ÿ===ÿQQQÿcccÿÇÇÇÿúúúÿûûûÿñññÿÚÚÚÿ999ÿ999ÿSSSÿâââÿòòòÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿóóóÿñññÿìììÿäääÿÜÜÜÿÊÊÊÿ@@@¹:"!8˜¶¶¶ÿÙÙÙÿãããÿíííÿòòòÿôôôÿñññÿëëëÿâââÿÖÖÖÿËËËÿÂÂÂÿ¾¾¾ÿÀÀÀÿ­­­ÿcccÿ999ÿ999ÿCCCÿTTTÿqqqÿÛÛÛÿõõõÿÝÝÝÿ999ÿ999ÿTTTÿæææÿ÷÷÷ÿþþþÿýýýÿüüüÿúúúÿøøøÿõõõÿðððÿçççÿßßßÿÈÈÈÿ###˜8!5 r¡¡¡øÙÙÙÿåååÿðððÿöööÿùùùÿüüüÿúúúÿôôôÿìììÿáááÿÕÕÕÿÉÉÉÿÁÁÁÿ¾¾¾ÿÁÁÁÿ¡¡¡ÿPPPÿ999ÿ999ÿGGGÿWWWÿ€€€ÿÎÎÎÿGGGÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿøøøÿòòòÿéééÿàààÿ³³³ø r5 1LYYYÐÕÕÕÿæææÿòòòÿúúúÿþþþÿÿÿÿÿÿÿÿÿýýýÿùùùÿóóóÿêêêÿßßßÿÓÓÓÿÇÇÇÿÀÀÀÿ¾¾¾ÿ¿¿¿ÿŽŽŽÿEEEÿ999ÿ999ÿJJJÿLLLÿHHHÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿõõõÿëëëÿßßßÿfffÐL1  ,F$$$¡ÆÆÆÿåååÿôôôÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿøøøÿòòòÿèèèÿÝÝÝÿÐÐÐÿÆÆÆÿ¿¿¿ÿ¿¿¿ÿ¼¼¼ÿ€€€ÿ???ÿ999ÿ999ÿ999ÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿëëëÿØØØÿ***¡F, &?kwwwÝàààÿôôôÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿ÷÷÷ÿðððÿæææÿÚÚÚÿÎÎÎÿÄÄÄÿ¿¿¿ÿ¿¿¿ÿ···ÿpppÿ999ÿ999ÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿêêêÿ‡‡‡Ýk?& 6Q+++§ÌÌÌÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿöööÿîîîÿäääÿ×××ÿËËËÿÂÂÂÿ¾¾¾ÿ¼¼¼ÿ¢¢¢ÿ[[[ÿ999ÿTTTÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿàààÿ111§Q6  -Fk\\\ÍçççÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿúúúÿõõõÿìììÿáááÿÕÕÕÿÉÉÉÿ¿¿¿ÿ¸¸¸ÿ³³³ÿ———ÿoooÿæææÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿiiiÍkF- $;TžžžéúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿóóóÿêêêÿßßßÿÒÒÒÿÆÆÆÿ½½½ÿÀÀÀÿÐÐÐÿèèèÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°éT;$ /G_,,,¥ÏÏÏùüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿøøøÿòòòÿèèèÿÝÝÝÿÑÑÑÿÐÐÐÿÙÙÙÿëëëÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááù222¥_G/ #8Pf;;;°ÜÜÜþüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿ÷÷÷ÿðððÿèèèÿäääÿçççÿòòòÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëþBBB°fP8# +@Wf>>>°ÕÕÕùýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿ÷÷÷ÿôôôÿôôôÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿáááùCCC°fW@+ 0F\f111¥«««éõõõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿýýýÿþþþÿÿÿÿÿüüüÿ¶¶¶é555¥f\F0 "4H]fjjjÍéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿòòòÿrrrÍf]H4"  $5H\fp333§Ýîîîÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿôôôÿ———Ý777§pf\H5$  $4FWffv000¤uuuÐÒÒÒøïïïÿøøøÿüüüÿþþþÿþþþÿÿÿÿÿÿÿÿÿþþþÿýýýÿúúúÿóóóÿ×××øzzzÐ222¤vffWF4$  "0@P_fffƒ...£VVV¿€€€×§§§éÊÊÊ÷ÜÜÜþÌÌÌ÷©©©é‚‚‚×XXX¿000£ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/objects.nib0000644000175000017500000007172510005632764023762 0ustar centriscentris typedstreamè„@„„„NSIBObjectDataà„„NSObject…’„„„NSCustomObject)”„@@„„„NSString”„+ Controller†…†„iÇ–„„„NSMenuÌ”„i@@@„˜˜MainMenu†„„„NSMutableArray„„NSArray”™’„„„ NSMenuItemŸ”’™„ i@@IIi@@@@:i@„˜˜ NSBundleName†„˜˜†‚‚ÿÿÿ…„„„NSCustomResource)”–„˜˜NSImage†„˜˜NSMenuCheckmark††…„¤–¥„˜˜NSMenuMixedState††„submenuAction:…’…’„𛡄™ ’„ ’©Ÿ„˜˜About BasiliskII†¢‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ„˜˜Preferences...†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ‚À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ„˜˜Services†¢‚‚ÿÿÿ…£…§¡…’…’„𛄄„NSMutableString˜˜Services†„™†„˜˜_NSServicesMenu†††’„ ’©Ÿ‚À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ„˜˜Hide BasiliskII†„˜˜h†‚‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ„˜˜ Hide Others†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ„˜˜Show All†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ‚À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’©Ÿ„˜˜Quit BasiliskII†„˜˜q†‚‚ÿÿÿ…£…§……’…’…††„˜˜ _NSAppleMenu†††’„ ’™Ÿ„˜˜Commands†¢‚‚ÿÿÿ…£…§¡…’…’„š›Å„™’„ ’ÆŸ„˜˜ Power Up/Down†¢‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜Pause†„˜˜.†‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜Run†¢‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ‚À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜ Interrupt†¢‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜Restart†¢‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜ Terminate†¢‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜Zap PRAM†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ‚À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜Screen Benchmark†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜Screen Snapshot†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ‚À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜ Page Setup...†„˜˜P†‚‚ÿÿÿ…£…§……’…’…†’„ ’ÆŸ„˜˜Print...†„˜˜p†‚‚ÿÿÿ…£…§……’…’…††…††’„ ’™Ÿ„˜˜Edit†¢‚‚ÿÿÿ…£…§¡…’…’„𛄴˜Edit†„™’„ ’柄˜˜Undo†„˜˜z†‚‚ÿÿÿ…£…§……’…’…†’„ ’柄˜˜Redo†„˜˜Z†‚‚ÿÿÿ…£…§……’…’…†’„ ’柂À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’柄˜˜Cut†„˜˜x†‚‚ÿÿÿ…£…§……’…’…†’„ ’柄˜˜Copy†„˜˜c†‚‚ÿÿÿ…£…§……’…’…†’„ ’柄˜˜Paste†„˜˜v†‚‚ÿÿÿ…£…§……’…’…†’„ ’柄˜˜Clear†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’柄˜˜ Select All†„˜˜a†‚‚ÿÿÿ…£…§……’…’…††…††’„ ’™Ÿ„˜˜Window†¢‚‚ÿÿÿ…£…§¡…’…’„𛄴˜Window†„™’„ ’Ÿ„˜˜ Close Window†„˜˜w†‚‚ÿÿÿ…£…§……’…’…†’„ ’Ÿ„˜˜ Zoom Window†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’Ÿ„˜˜Minimize Window†„˜˜m†‚‚ÿÿÿ…£…§……’…’…†’„ ’Ÿ‚À¢¢‚‚ÿÿÿ…£…§……’…’…†’„ ’Ÿ„˜˜Bring All to Front†¢‚‚ÿÿÿ…£…§……’…’…††„˜˜_NSWindowsMenu†††’„ ’™Ÿ„˜˜Help†¢‚‚ÿÿÿ…£…§¡…’…’„𛄴˜Help†„™’„ ’Ÿ„˜˜OS X port HowTo†„˜˜?†‚‚ÿÿÿ…£…§……’…’…†’„ ’Ÿ„˜˜OS X port ToDo†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’Ÿ„˜˜OS X port Versions†¢‚‚ÿÿÿ…£…§……’…’…†’„ ’Ÿ„˜˜Basilisk II README†¢‚‚ÿÿÿ…£…§……’…’…††…†††„˜˜ _NSMainMenu††•–„ ’„𛄴˜ OtherViews†„™’„ ’Ÿ„˜˜Apple Standard (US)†¢‚‚ÿÿÿ…£…§„_popUpItemAction:…’„„„NSPopUpButtonCell1„„NSMenuItemCellÒ„„ NSButtonCell?„„ NSActionCell„„NSCellA”„ii‚„Aþ‚„@@@@…„„„NSFont”™$„[36c]þÿLucidaGrande„f „c®®®†……„i:…’…’„„„ NSPopUpButtonÌ„„NSButton„„ NSControl)„„NSView)„„ NSResponder”’„0’„„„NSBox*0’„0’„„„ NSTabView0’„0’…™„ @@@@ffffffff„™’6’„.’8™·…………·T T ’8’…’…’…„icc@„'©‚þ‚ª„˜˜Reset†*……¯…’…’:„ ssii@@@@@È‚†‚@ÿ¢„´˜†…„+™„[28c]þÿHelvetica­ ®®®®†…††’„.’8™·…………_T T ’8’…’…’…¸„'©‚þ‚ª„˜˜Save†*……¯…’…’?¹È‚†‚@ÿ¢„´˜†…>…††’„.’8™·………… T T ’8’…’…’…¸„'©‚þ‚ª„˜˜Load†*……¯…’…’C¹È‚†‚@ÿ¢„´˜†…>…††’„„„ NSTextField/’8™·…………/??’8’…’…’…¸„„„NSTextFieldCell>(©‚1þA‚@ª„˜˜ Prefs file:†*……¯…’…’G„c@@„„„NSColor”®„@@@„˜˜System†„˜˜ controlColor†„M®„ffƒ?*ª«††„M®¿N„˜˜controlTextColor†„M®À†††’…„:…†’„H’8™·…………J+’8’…’…’…¸„J©‚”qþA‚@ª„˜˜ /Users/b2user/.basilisk_ii_prefs†*……¯…’…’T½„M®¿N„˜˜textBackgroundColor†„M®À††„M®¿N„˜˜ textColor†S††’…Á…†’„.’8™·…………S$`!`!’8’…’…’…¸„'©‚þ‚ª„˜˜ Browse…†*……¯…’…’\¹È‚†‚@ÿ¢„´˜†…>…†††………¸¸’…’…’…’…†™·„™’5†………C·¼·¼’8’…’…’…„@@@icc„™’„„„ NSTabViewItem”„@@@@@@@„˜˜1†„0’…™·„™’„4’e™·„™’„0’g™·„™’„.’i™·…………T!T!’i’…’…’…¸„'©‚þ‚8ª„˜˜Add…†*……¯…’…’k¹È‚†‚@ÿ„´˜†„´˜†…>…††’„.’i™·…………WZ!Z!’i’…’…’…¸„'©‚þ‚8ª„˜˜Remove†*……¯…’…’p¹È‚†‚@ÿ„´˜†„´˜†…>…††’„.’i™·…………Ð`!`!’i’…’…’…¸„'©‚þ‚8ª„˜˜ Create…†*……¯…’…’u¹È‚†‚@ÿ„´˜†„´˜†…>…††’„.’i™·…………0T!T!’i’…’…’…¸„'©‚þ‚8ª„˜˜Delete†*……¯…’…’z¹È‚†‚@ÿ„´˜†„´˜†…>…††’„„„ NSScrollViewâ0’i™‚€·„™’„„„ NSClipView:0’™‚À·„™’„„„ NSTableView=/’‚™·„™†………OO’‚’…’…’…¸…„ @@@ff@@f::i„„„NSTableHeaderView0’„ƒ’™‚À·„™’ˆ†………bb’’…’ˆ’…’ˆ„@@ccc„M®¿N„˜˜controlBackgroundColor†P†…†™‚€·…………OO’Š’…’…’…’…†„„„ _NSCornerView0’™‚€·„™†………c’’…’…’…†„™’„„„ NSTableColumn)”„@fff@@cc„˜˜locked†  „„„NSTableHeaderCellJ©‚þª¢„+™$¬þÿLucidaGrande­ ®®®®†……¯…’…’…½„M®Àƒ>ªª«†„M®¿N„˜˜headerTextColor†S††„J©‚1þ@‚ª…*……¯…’…’…½YQ†’…†’„“Í„˜˜path†)))„–©‚þª„˜˜File containing image†—……¯…’…’…½˜™†„J©‚1þ@ª…*……¯…’…’…½YQ†’…††Œ„M®¿N„˜˜ gridColor†„M®Àƒ?††……‚¨ ’…’…’…††………b¡b¡’’…’…’…’…ÊŒ…†’„„„ NSScrollerÓ/’™‚€·„™†………c¡¡’’…’…’…¸…’„ff:ƒ?gŒò„ _doScroller:®®†’„¥’™‚€·„™†………œœQQ’’…’…’…¸…’Ѓ?}ÙÑ®®†’Вކ……… *s³s³’i’…’‚’…’¤’§’‚’Š’Ž„ffffi ‚„††………‹ä‹ä’g’…’…’…††……… øø’e’…’…’…„ff@@ccc„J©‚þª„˜˜Disk Images to mount†*……¯…’…’…½WQ†i’…†’„4’e™·„™’„0’«™·„™’„H’­™·………… *ss’­’…’…’…¸„J©‚”qþA‚@ª¢*……¯…’…’¯½WZ†’…Á…†’„.’­™·…………”`!`!’­’…’…’…¸„'©‚þ‚8ª„˜˜ Browse…†*……¯…’…’±¹È‚†‚@ÿ„´˜†„´˜†…>…†††………‹H‹H’«’…’…’…††……… \\’e’…’…’…Ó„J©‚þª„˜˜1Unix directory to mount (via ExtFS & MacOS 7.5.3)†*……¯…’…’…½WQ†­’…††……… !£Ž£Ž’…’…’…’…†„˜˜ Disk Volumes†L……6†’„cÄ„˜˜1†„0’…™·„™’„4’»™·„™’„0’½™·„™’„€’¿™‚€·„™’„ƒ’Á™‚À·„™’„†’Ù·„™†………bb’Ã’…’…’…¸…È„‰’„ƒ’Á™‚À·„™’dž………bb’Á’…’Ç’…’ÇÊŒ…†™‚€·…………bb’È’…’…’…’ņ„’Á™‚€·„™†………c’Á’…’…’…†„™’„“Í…ƒA£ è„–©‚þª„˜˜ID†—……¯…’…’…½˜™†„J©‚1þ@ª…*……¯…’…’ŽYQ†’ņ’„“Í„˜˜path†ƒC£Ç è„–©‚þª„˜˜ Unix Device†—……¯…’…’…½„M®¿N„˜˜ headerColor†Y†™†„J©‚1þ@ª…„+™$¬þÿLucidaGrande­ ®®®®†……¯…’…’ŽŒQ†’ņ†Œ¡……‚¨@’…’…’…††………bjbj’Á’…’Å’…’ÅÊŒ…†’„¥’Á™‚€·„™†………cjj’Á’…’…’…¸…’ÁЃ?ÁlÑ®®†’„¥’Á™‚€·„™†………œœuu’Á’…’…’…¸…’ÁЃ?}ÙÑ®®†’Ȓʆ……… *s|s|’¿’…’Ã’…’Ù’Û’Ã’È’ÊÒ ‚„†’„.’¿™·…………ÒZ!Z!’¿’…’…’…¸„'©‚þ‚ª„˜˜Add…†*……¯…’…’ݹÈ‚†‚@ÿ¢„´˜†…>…††’„.’¿™·…………+Z!Z!’¿’…’…’…¸„'©‚þ‚ª„˜˜Remove†*……¯…’…’á¹È‚†‚@ÿ¢„´˜†…>…†††………‹­‹­’½’…’…’…††……… ÆÁÁ’»’…’…’…Ó„J©‚þª„˜˜SCSI disks to mount†*……¯…’…’…½WQ†¿’…†’„4’»™·„™’„0’ç™·„™’„H’é™·…………K‚‚’é’…’…’…¸„J©‚1þA‚@ª„˜˜Modem port device:†*……¯…’…’ë½LQ†’…Á…†’„H’é™·…………+}}’é’…’…’…¸„J©‚1þA‚@ª„˜˜Printer port device:†*……¯…’…’î½LQ†’…Á…†’„H’é™·………… ~~’é’…’…’…¸„J©‚1þA‚@ª„˜˜EtherNet interface:†*……¯…’…’ñ½LQ†’…Á…†’„H’é™·…………ŒHññ’é’…’…’…¸„J©‚”qþA‚@ª¢*……¯…’…’ô½WZ†’…Á…†’„H’é™·…………Œ(ññ’é’…’…’…¸„J©‚”qþA‚@ª¢*……¯…’…’ö½WZ†’…Á…†’„H’é™·…………Œ ññ’é’…’…’…¸„J©‚”qþA‚@ª¢*……¯…’…’ø½WZ†’…Á…††………‹d‹d’ç’…’…’…††……… xx’»’…’…’…Ó„J©‚þª„˜˜Serial/Network†*……¯…’…’…½WQ†é’…††……… !£Ž£Ž’…’…’…’…†„˜˜Hardware†L……6†’„cÄ„˜˜2†5„˜˜ Emulation†L……6††ý*’…†™·„™’„4’5™·„™’„0’™·„™ ’„.’™·…………¤¡¡’’…’…’…¸„'©‚þª„˜˜Disable sound output†*……¯…’…’¹È‚H/’™·…………X/X/’’…’…’…¸…„#iiii:::ffffi@@@@@(ÿÿ………X‚„™’„„„ NSFormCell)(©‚qþ@‚ @ª„´˜†*……¯…’…’„f@2„)©‚þª„˜˜Width:†*……††’„©‚qþ@‚ @ª„´˜†*……¯…’…’Ù2„)©‚þª„˜˜Height:†*……†††LY…„©‚qþ@‚ @ª„´˜†*……¯…’…’…Ù2„)©‚þª„´˜Field:†*……††’…’…’…†’„H’™·…………äRŽŽ’’…’…’…¸„J©‚1þA‚@ª„˜˜Window refresh rate:†*……¯…’…’½LQ†’…Á…†’„’™·…………äp/p/’’…’…’…¸…×(ÿÿ………p‚„™’„©‚qþ@‚ @ª„´˜†*……¯…’…’"ÙI„)©‚þª„˜˜Delay:†*……††’„©‚qþ@‚ @ª„´˜†*……¯…’…’"ÙI„)©‚þª„˜˜ Frequency:†*……†††LY…„©‚qþ@‚ @ª„´˜†*……¯…’…’…ÙI„)©‚þª„´˜Field:†*……††’…’…’…†’„H’™·…………Y8""’’…’…’…¸„J©‚1þA‚@ª„˜˜ticks†*……¯…’…’0½LQ†’…Á…†’„H’™·…………Y ''’’…’…’…¸„J©‚1þA‚@ª„˜˜Hertz†*……¯…’…’3½LQ†’…Á…†’„H’™·…………>""’’…’…’…¸„J©‚”qþA‚@ª¢*……¯…’…’6½WZ†’…Á…†’„H’™·…………33’’…’…’…¸„J©‚1þA‚@ª„˜˜Depth:†*……¯…’…’8½LQ†’…Á…†’„H’™·…………e8**’’…’…’…¸„J©‚1þA‚@ª„˜˜pixels†*……¯…’…’;½LQ†’…Á…†’„H’™·…………e**’’…’…’…¸„J©‚1þA‚@ª„˜˜pixels†*……¯…’…’>½LQ†’…Á…†’„H’™·…………e""’’…’…’…¸„J©‚1þA‚@ª„˜˜bits†*……¯…’…’A½LQ†’…Á…†’„’™·…………Q’’’’…’…’…¸…×(………H‚D¨„™’„'©‚„þª„˜˜Screen†*……¯…’…’D¹È‚Hoooæ›››ÿ®®®ý¼¼¼ÿÀÀÀÿÀÀÀÿÁÁÁÿ¿¿¿ÿ»»»ÿ±±±þšššÿrrrò V`›››ÿ®®®û½½½ÿÃÃÃÿÄÄÄÿÃÃÃÿÁÁÁÿÂÂÂÿÁÁÁÿ½½½ÿ­­­û˜˜˜ÿ€r´´´ÿ¾¾¾úÌÌÌÿÒÒÒÿÓÓÓÿÕÕÕÿÔÔÔÿÒÒÒÿÏÏÏÿÍÍÍÿ¼¼¼ú³³³ÿ'''”n···ÿÍÍÍýØØØþàààÿáááÿäääÿäääÿãããÿÞÞÞÿÙÙÙÿÊÊÊý¸¸¸ÿ###Š  _œœœëÚÚÚÿàààýëëëÿïïïÿòòòÿðððÿíííÿêêêÿàààþØØØÿªªªôuCRRR¾ÚÚÚÿëëëþóóóÿúúúÿÿÿÿÿüüüÿ÷÷÷ÿñññÿèèèþÛÛÛÿgggÎQ ,€ŒŒŒâîîîÿûûûþþþþÿþþþÿýýýþþþþÿøøøÿðððÿžžžê3M™ƒƒƒÝíííþþþþÿÿÿÿÿÿÿÿÿÿÿÿÿóóóÿ“““ä"""¥U  *Y;;;¿xxxÚ¦¦¦ë«««ìÞEEEÄ •`/*Qs‰”•ŒwV/ 4HTUK7!    ºÂÊ(R ü€' ü€'†’„M®À†’…†I…††LY*„'©‚þª„˜˜Radio†*……¯…’…’…¹K‚H8Qÿ……„N’…®®®®®®®®®®®®®®ÀÛ®’„P™ÒÞMM* !' À666ï666ó###Ç 2 L222Ë\\\ÿƒƒƒÿ™™™ÿ™™™ÿ†††ÿbbbÿ111Ø _ ;KKKÔÿ¦¦¦ûÃÃÃýÑÑÑþÓÓÓÿÇÇÇý±±±û†††ÿKKKä P<<<§ÿ¡¡¡û¾¾¾ÿÌÌÌÿÑÑÑÿÔÔÔÿÒÒÒÿÇÇÇÿ¥¥¥û|||ÿ<<<À>oooæ›››ÿ®®®ý¼¼¼ÿÀÀÀÿÀÀÀÿÁÁÁÿ¿¿¿ÿ»»»ÿ±±±þšššÿrrrò V`›››ÿ®®®û½½½ÿÃÃÃÿÄÄÄÿÃÃÃÿÁÁÁÿÂÂÂÿÁÁÁÿ½½½ÿ­­­û˜˜˜ÿ€r´´´ÿ¾¾¾úÌÌÌÿÒÒÒÿÓÓÓÿÕÕÕÿÔÔÔÿÒÒÒÿÏÏÏÿÍÍÍÿ¼¼¼ú³³³ÿ'''”n···ÿÍÍÍýØØØþàààÿáááÿäääÿäääÿãããÿÞÞÞÿÙÙÙÿÊÊÊý¸¸¸ÿ###Š  _œœœëÚÚÚÿàààýëëëÿïïïÿòòòÿðððÿíííÿêêêÿàààþØØØÿªªªôuCRRR¾ÚÚÚÿëëëþóóóÿúúúÿÿÿÿÿüüüÿ÷÷÷ÿñññÿèèèþÛÛÛÿgggÎQ ,€ŒŒŒâîîîÿûûûþþþþÿþþþÿýýýþþþþÿøøøÿðððÿžžžê3M™ƒƒƒÝíííþþþþÿÿÿÿÿÿÿÿÿÿÿÿÿóóóÿ“““ä"""¥U  *Y;;;¿xxxÚ¦¦¦ë«««ìÞEEEÄ •`/*Qs‰”•ŒwV/ 4HTUK7!    ºÂÊ(R ü€' ü€'†’R’…†I…†’…’…’F††………‹e‹e’’…’…’…††……… yy’5’…’…’…Ó„J©‚þª„˜˜Graphics/Sound†*……¯…’…’…½WQ†’…†’3’„.’5™·…………Ê««’5’…’…’…¸„'©‚þª„˜˜Disable CD-ROM Driver†*……¯…’…’Y¹È‚H>’2’…’…’…¸„J©‚1þA‚@ª„˜˜ ROM file:†*……¯…’…’{½LQ†’…Á…†’„H’2™·…………NÖÖ’2’…’…’…¸„J©‚”qþA‚@ª„˜˜/Users/b2user/ROM†*……¯…’…’~½WZ†’…Á…†’„.’2™·…………)`!`!’2’…’…’…¸„'©‚þ‚8ª„˜˜ Browse…†*……¯…’…’¹È‚†‚@ÿ¢„´˜†…>…††’„.’2™·…………“;NN’2’…’…’…¸„'©‚þª„˜˜With FPU†*……¯…’…’…¹È‚Hó>’…’…’…’…–„´˜NSView†„˜˜ NSResponder††•–ui–„.’„0’…™·„™ ’„Ü’陂·„™†……… =XX’é’…’…’…–„˜˜ EmulatorView†„˜˜NSView††’„„„NSProgressIndicatorÜ0’陂L·…„„„ NSPSMatrix”„[12f]®®®†…… ²––’é’…’…’…„ccddcdd†’„.’陂 ·…………Û—1111’é’…’…’…¸„'©‚þ‚ª„˜˜Power†*……¯…’…’ó¹È‚T@ÿ¢„´˜†„¤–¥„˜˜ shutdownN††„¤–¥„˜˜ shutdownH††…††’„.’陂 ·…………h¡T T ’é’…’…’…¸„'©‚þ‚ª„˜˜Run†*……¯…’…’û¹È‚È„@ÿ„˜˜Pause†¢………††’è’„.’陂·…………… T T ’é’…’…’…¸„'©‚þ‚8ª„˜˜ Interrupt†*……¯…’…’ÿ¹È‚†‚@ÿ¢„´˜†…>…††’„.’陂·………… f f ’é’…’…’…¸„'©‚þ‚8ª„˜˜Zap PRAM†*……¯…’…’¹È‚†‚@ÿ¢„´˜†…>…††’„.’陂·………… ž ’é’…’…’…¸„'©‚þ‚ª¢*……¯…’…’¹È‚ÈD@ÿ¢„´˜†„¤–¥„˜˜Expanded††„¤–¥„˜˜ Collapsed††…††’„.’é™·…………‰ `!`!’é’…’…’…¸„'©‚þ‚ª„˜˜Snapshot†*……¯…’…’¹È‚†”@ÿ¢„´˜†………††’„„„NSSlider/’é™·…………tt’é’…’…’…¸„„„ NSSliderCellâ(©‚þª„´˜†„+™,„[44c]$þÿHelvetica-Oblique­ ®®®®†……¯…’…’„ddddiii< ††’„H’é™·………… ’é’…’…’…¸„J©‚1þA‚@ª„˜˜0†*……¯…’…’½LQ†’…Á…†’„H’é™·…………f ’é’…’…’…¸„J©‚1þA‚@ª„˜˜60†*……¯…’…’½LQ†’…Á…†’„H’é™·………… JJ’é’…’…’…¸„J©‚1þA‚@ª„˜˜ Frames/sec.†„+™$¬þÿLucidaGrande­ ®®®® †……¯…’…’½LQ†’…Á…††……… ÐÐ’…’…’…’…†™‚·…………Û1111’é’…’…’…¸„'©‚þ‚ª„˜˜Restart†*……¯…’…’è¹È‚D@ÿ¢„´˜†„¤–¥„˜˜resetN††„¤–¥„˜˜resetH††…††é–ìæ–îé––Ý¿–eb–ÈÆ–("–¿½–KD–­«–²–`5–ëé–Ð–ïæ–68–©Ÿ–…2––©2–s2–ÊÆ––„––„˜˜Emulator†…†•–«©–ðæ–´–ý6–ÞÛ––˜––Ò–ÍÆ–b6–Á¿–¯­–;–ÍÅ–\8–­©–óæ–¶––ÏÆ–é–Ô–ñé–b`–5–á¿–ÐÆ–¯©–öæ–zi––¸–›––ïé–ÿé–é–y2–„„„ NSImageView/’„0’…™·„™’„H’-™·…………%0j0j’-’…’…’…¸„J©‚±þA‚@ª„˜˜²Basilisk II, Version ??? A free, portable Mac II emulator Copyright © 1997—2004 Christian Bauer et al. Freely distributable under the terms of the GNU General Public License.†*……¯…’…’/½LQ†’…Á…†’+’„H’-™·…………Š66’-’…’…’…¸„J©‚1þA‚@ª„˜˜Mac OS X port ???†!……¯…’…’2½LQ†’…Á…††………ѕѕ’…’…’…’…†™·………„„„ NSMutableSet„„NSSet”„I’„˜˜Apple PDF pasteboard type†’„˜˜NeXT TIFF v4.0 pasteboard type†’„˜˜1NeXT Encapsulated PostScript v1.2 pasteboard type†’„˜˜NSFilenamesPboardType†’„˜˜Apple PICT pasteboard type††€€€€’-’…’…’…¸„„„ NSImageCell))©‚þª„¤–¥„˜˜NSApplicationIcon††………„iii†®†-–Ö–°©–,2–ÒÆ–‰2–ùæ–ãÛ–º–e`–ÑÅ–±­–Ø–²°–>–––ûæ–ÔÆ––¼–C8–0–ôé–ge–ÖÆ–8„„„NSWindowTemplateø”„ iiffffi@@@@@c̸‚px„˜˜BasiliskII Preferences†„˜˜NSWindow†„´˜View†8…„ffff€ê®À¸’„˜˜ PrefsWindow†®À¸†–é–ÅÁ–¾––{2–‹‰–ØÆ–·©–i–é––ig–þ™–/-–À–ÙÆ–óé–¸©–A–þ–2-–¡2–v2–ç»–ki–މ–3–ÛÆ–––»©–öé–G8–-„BðÑ•‚px„˜˜About BasiliskII†„˜˜NSPanel†„´˜View†-…ñ€ê®ÀÕ’„˜˜About†®À†–:8–23–’…–Y5–é–ÝÆ––Ÿ™–Ä–"–½©–„––„˜˜ PrefsEditor†…†•–~2–‰–«2–m2–A•–ÞÆ–£¡–éç–é–°–¿©––Æ–D––¹6–’‰–,–À©–áÆ–6–G•–pi– –øé–È–?8–»¹–ûé–ëé–…– –35–2–Ê–]5–p2–"–$"–àÛ–¦2–FD–Ä™–½»–æä–é„BðЂpx„˜˜BasiliskII Emulator†„˜˜NSWindow†„´˜View†é…ñ€ê®Àæ’„˜˜Window†®À†–«e–T8–Ì–œ…––5ý–ÆÄ–é–8–éæ–ä™––2–™–N•™ –À„˜˜111111†–]„˜˜ NSTextField1†–‰„˜˜NSMatrix†–¹„˜˜NSTabViewItem11†–­„˜˜12111†–ㄘ˜ NSTextField2†–ì„´˜4†–œ„˜˜ NSTableColumn†–¯„˜˜ NSTextField†–ô„˜˜ NSTextField21†–6„˜˜ NSTabView†–„˜˜ PopUpList†–넘˜ NSTextField7†–„´˜†–Ö„˜˜ NSMenuItem21†–¡„˜˜NSBox1†–T„˜˜ NSTextField3†–„´˜1†––„˜˜ NSMatrix1†–»„˜˜NSView†–$„˜˜ NSFormCell†–ᄘ˜ NSButton2†–„˜˜ NSButton6†–¯„˜˜ NSMenuItem†–e„˜˜NSView†–ï„´˜5†–D„˜˜ NSMatrix1†–G„˜˜About†–鄘˜NSView†–k„˜˜ NSButton1†–Ø„˜˜21†–Å„˜˜ NSTableView†–󄘘 NSButton3†–;„˜˜ NSTextField5†–°„˜˜ NSMenuItem21†–v„˜˜ NSTextField6†–b„˜˜NSTabViewItem1†–ý„˜˜NSTabViewItem2†–«„˜˜ NSTextField11†–Ä`–C„˜˜ NSButton2†–…„˜˜ NSTableView†–„˜˜NSForm†–"„˜˜ NSMenuItem†–3„˜˜ NSTextField1†–z„˜˜ NSButton31†–„˜˜NSButton†–,„˜˜ NSPopUpButton†–½„˜˜NSBox2†–„˜˜ NSTextField2†–‹„˜˜ NSButtonCell†–Æ`–£„˜˜NSView†– `–y„˜˜ NSTextField†–2„˜˜NSView†–+„˜˜ NSImageView†–`„˜˜NSMatrix†–Í„˜˜ NSTableColumn†–à„˜˜ NSTextField1†–Û„˜˜ NSMenuItem2†–±„˜˜ NSButton1†–ö„˜˜ NSTextField31†–m„˜˜ NSTextField2†–(„˜˜ NSFormCell1†–ÿ„˜˜ NSButton2†–˜„˜˜ NSButtonCell†–„˜˜NSBox2†–˜ NSTextField11†–„˜˜ NSTextField3†–넘˜ NSCustomView†–È„´˜1†–„˜˜ NSMenuItem1†–Ý„˜˜ NSMenuItem†–Ž„˜˜ NSButtonCell1†–-„˜˜NSView†–\„˜˜ NSButton3†–p„˜˜ NSButton2†–>„˜˜ NSTextField51†–¿„˜˜NSView†–ù„´˜2†–Þ„´˜5†–„˜˜ NSButton4†–·„˜˜ NSMenuItem1†–Û„˜˜ VolumeSize†–Ê„˜˜11†–²„˜˜ NSMenuItem2†–’„˜˜NSTableColumn1†–„˜˜ NSFormCell1†–›„˜˜ NSButtonCell1†–6„˜˜ NSTextField2†–G„˜˜ NSTextField4†–?„˜˜ NSButton1†–b„˜˜ NSButtonCell†–2„˜˜ NSTextField1†–Í„˜˜12†–¸„˜˜ NSMenuItem41†–L„˜˜ PrefsEditor†–„˜˜ NSButtonCell2†–•„´˜ File's Owner†–„´˜1†–Ñ„˜˜NSTableColumn1†–á„´˜6†–Y„˜˜NSButton†–¦„˜˜ NSTextField21†–û„˜˜NSButton†–8„˜˜NSView†–{„˜˜ NSTextField4†–„˜˜NSView†–«„˜˜NSBox1†–„˜˜ NSScrollView†–焘˜NSBox†–p„˜˜ NSTextField1†–ø„˜˜ NSTextField41†–A„˜˜Prefs†–…„˜˜ NSButton1†–„˜˜ NSTextField†–Á„˜˜ NSScrollView†–Ï„˜˜211†–3„˜˜NSBox3†–„´˜2†–/„˜˜ NSTextField†–)„˜˜Emulator†–»„˜˜ NSMenuItem51†–™„´˜MainMenu†–ñ„˜˜NSTextField111†–Þ„˜˜ NSTextField†–˜1†–"„˜˜NSForm1†–„˜˜ NSButtonCell2†–„˜˜ NSButton5†–Є˜˜121†–Ý„˜˜ NSButton11†–e„˜˜ NSButtonCell1†–i„˜˜NSView†–’„˜˜ NSButtonCell3†–„˜˜ NSFormCell†–„˜˜NSButton†–½„˜˜ NSMenuItem61†–5„˜˜NSView†–A„˜˜NSTextField511†–N„˜˜Window†–Ò„˜˜1211†–­„˜˜NSView†–u„˜˜ NSButton3†–鄘˜NSView†–8„˜˜ NSTextField4†–g„˜˜NSBox†–¿„˜˜ NSMenuItem2†–«„˜˜ NSMenuItem8†–„˜˜NSSlider†–©„˜˜ NSTextField7†–~„˜˜ NSTextField3†–0„˜˜ NSTextField†–:„˜˜NSButton†–Ô„˜˜12111†–脘˜ NSButton1†–„˜˜ NSTextField1†–é„´˜3†–s„˜˜ NSTextField5†’„6ì’N†’„™„’„„„NSNibControlConnectorÏ„„NSNibConnector”¿ð…„´˜cut:††’„ó¿ó…„´˜copy:††’„ó¿ö…„´˜paste:††’„ó¿û…„´˜ selectAll:††’„ó¿…„´˜performMiniaturize:††’„ó¿ …„´˜arrangeInFront:††’„ó¿á…„´˜print:††’„ó¿Þ…„´˜runPageLayout:††’„ó¿ù…„´˜clear:††’„ó¿é…„´˜undo:††’„ó¿ì…„´˜redo:††’„ó¿…„´˜ showHelp:††’„ó¿…„´˜ performZoom:††’„ó¿…„˜˜ performClose:††’„ó¿kL„˜˜ AddVolume:††’„ó¿uL„˜˜ CreateVolume:††’„ó¿zL„˜˜ DeleteVolume:††’„ó¿pL„˜˜ RemoveVolume:††’„ó¿±L„˜˜ BrowseExtFS:††’„ó¿¯L„˜˜ EditExtFS:††’„ó¿L„˜˜ChangeDisableSound:††’„ó¿$L„˜˜ EditDelay:††’„ó¿(L„˜˜EditFrequency:††’„ó¿yL„˜˜ EditBytes:††’„ó¿~L„˜˜ EditROMpath:††’„ó¿L„˜˜ BrowseROM:††’„ó¿­L„˜˜ ShowPrefs:††’„„„NSNibOutletConnectorÏô¿L¯„˜˜extFS††’„+¿L„˜˜width††’„+¿L„˜˜height††’„+¿L$„˜˜delay††’„+¿L(„˜˜ frequency††’„+¿L„˜˜ disableSound††’„+¿Ly„˜˜bytes††’„+¿L~„˜˜ROMfile††’„+¿L…„˜˜FPU††’„ó¿…L„˜˜ ChangeFPU:††’„ó¿©L„˜˜EditMB:††’„+¿L©„˜˜MB††’„+¿L‹„˜˜CPU68000††’„+¿LŽ„˜˜CPU68020††’„+¿L„˜˜CPU68030††’„+¿L’„˜˜CPU68040††’„+¿L›„˜˜IIci††’„+¿L„˜˜ quadra900††’„+¿L˜„˜˜classic††’„+¿Lb„˜˜ bootFromAny††’„+¿Le„˜˜ bootFromCD††’„+¿LY„˜˜ disableCD††’„ó¿`L„˜˜ChangeBootFrom:††’„+¿LÅ„˜˜ SCSIdisks††’„+¿Lô„˜˜modem††’„+¿Lö„˜˜printer††’„+¿Lø„˜˜etherNet††’„ó¿ÝL„˜˜AddSCSI:††’„ó¿áL„˜˜ RemoveSCSI:††’„ó¿‰L„˜˜ ChangeCPU:††’„ó¿YL„˜˜ChangeDisableCD:††’„+¿L…„˜˜ diskImages††’„+¿L6„˜˜depth††’„ó¿È)„˜˜ PowerKey:††’„ó¿Ê)„˜˜Suspend:††’„ó¿Í)„˜˜Resume:††’„ó¿Ð)„˜˜ Interrupt:††’„ó¿Ò)„˜˜Restart:††’„ó¿Ô)„˜˜ Terminate:††’„ó¿Ö)„˜˜ZapPRAM:††’„ó¿Û)„˜˜ Snapshot:††’„ó¿û)„˜˜ ToggleState:††’„ó¿ó)„˜˜ PowerKey:††’„ó¿)„˜˜ Snapshot:††’„ó¿)„˜˜ZapPRAM:††’„ó¿ÿ)„˜˜ Interrupt:††’„ó¿è)„˜˜Restart:††’„ó¿)„˜˜ SpeedChange:††’„+¿)˜ barberPole††’„+¿)N„˜˜win††’„+¿)„˜˜speed††’„+¿)û„˜˜ runOrPause††’„+¿)넘˜screen††’„ó¿:L„˜˜ ResetPrefs:††’„ó¿?L„˜˜ SavePrefs:††’„ó¿L„˜˜ ChangeScreen:††’„ó¿6L„˜˜ ChangeScreen:††’„+¿LN„˜˜emuWin††’„+¿L„˜˜emuFreq††’„+¿L)„˜˜ theEmulator††’„+¿LÛ„˜˜ newVolumeView††’„+¿LÞ„˜˜ newVolumeSize††’„+¿•)„˜˜ theEmulator††’„+¿•L„˜˜thePrefsEditor††’„ó¿«•„˜˜orderFrontStandardAboutPanel:††’„󿸕„˜˜hide:††’„ó¿»•„˜˜hideOtherApplications:††’„󿽕„˜˜unhideAllApplications:††’„ó¿À•„˜˜ terminate:††’„„„NSIBHelpConnector”¿p„˜˜NSToolTipHelpKey†„˜˜!Remove a disk image from the list††’„¶¿k·„˜˜&Add an existing disk image to the list††’„¶¿u·„˜˜/Create a new disk image, the add it to the list††’„¶¿z·„˜˜1Delete a disk image, then remove it from the list††’„¶¿¯·„˜˜+Enter the path of a Unix directory to mount††’„ó¿–L„˜˜ ChangeModel:††’„ó¿DL„˜˜ ChangeScreen:††’„+¿LA„˜˜panel††’„ó¿Ù)„˜˜ Benchmark:††’„+¿LF„˜˜screen††’„+¿LK„˜˜window††’„ó¿•„˜˜ HelpHowTo:††’„ó¿•„˜˜ HelpToDo:††’„ó¿•„˜˜ HelpVersions:††’„+¿LT„˜˜ prefsFile††’„ó¿\L„˜˜ BrowsePrefs:††’„ó¿CL„˜˜ LoadPrefs:††’„¶¿±„˜˜NSToolTipHelpKey†„˜˜3Choose a directory to mount on the emulated desktop††’„¶¿áÚ„˜˜&Remove this SCSI ID from the emulation††’„¶¿ÝÚ„˜˜'Add a SCSI device to emulate at this ID††’„¶¿Ú„˜˜,Note that sound is currently not implemented††’„¶¿øÚ„˜˜/Note that EtherNet is currently not implemented††’„¶¿\„˜˜NSToolTipHelpKey†„˜˜.Choose a different file to use for preferences††’„¶¿:儘˜!Reset all preferences to defaults††’„¶¿C儘˜)Load or reload preferences from this file††’„¶¿?儘˜#Save all preferences into this file††’„¶¿儘˜#Choose a file to use as a ROM image††’„+¿L,„˜˜keyboard††’„ó¿,L„˜˜ChangeKeyboard:††’„¶¿脘˜NSToolTipHelpKey†„˜˜Restart emulator††’„¶¿óô„˜˜Power on/off emulator††’„¶¿ô„˜˜Screen redraw speed††’„¶¿ô„˜˜Capture screen image††’„¶¿ûô„˜˜Start/pause/resume emulation††’„¶¿ÿô„˜˜Interrupt emulator††’„¶¿„˜˜NSToolTipHelpKey†„˜˜Clear emulated Parameter RAM†††’…™L„@iÃöYüö£[öàÁöi§öû ö²‚öÒðö öG°ög¦öF¡ö•öésö$íöüö­¬ö5?ö<öÀˆö[ýö¥\ö§öû0öãöÁ’ö \ö özšö‘ö]þöÛ öâÂö2§ö8ö7Aö=öÏ€öþö2œö§qöéëö'öÔö ö™öA[ö–öü%ö9Bö¼Ýöìtö_ÿöÈâöL‹öƒ>öŽŸöÎö©röö½½ö;YöÅ•öÔñö ö öâöäÃöeö;bö6ö/öaöÿ(öoöA öгö…?öÇ›ö«söàYöþ'ö=©öö6QöÝöë$ö]öãZöcö‡@öœžöÉ£öÍÊö?«öïuöö­tö¯©ö0ïö¾Þöˤö*öeö²ÑöÊãöçÄöVöbòö‰Aö©9ö¯uöWö·ðööìöA¬öͬöÖþööÞMöþö«ÒöÒ´öËögö{ÀöC°ö‹BöK¢ö öŸ8öñçöÄSö±vöéÅöëêö\²öÏ­öðö(îöö,Íöó)ök[ö¦¤ös½ö]óö«:öiöݾöE±ö°æöCö³wöö"ìöÑ®ö öm»ö´Ùö‰eö¸†öC¯öDöÀýöu™ököÌóöëÆöG²öØìöÆQöÛVö?Hö¿Æö[ö‘EöÔµöÓ³ögö"ö… öm3ö’ŸöáNöŹövöäö˜ö2öI³öáöóöíÇöeôö:Gö“Föè&öÕ´ö$"ö­öo4öµzööwöÐö¡¢öböD€öK´ö•Iö’¡ö¶Úö»‘öÂßö×µö&#öýöq5ö.öïîö3¦öM¶ö>ZöjöäöÎôöö—JöÖrö zöÙ½ö(&ö8Uös6ö/žö+ö¹{öñïöO·öï1öööòö««öÈIöÑÑö™Lööö¯ïöxöu7ö+öóÿö±ªö3ðöQöö¹Îö»|ö)#öÁÀö½–ö›Möçîö¨ö¸ÛöT±öÞXöøïöÄàöw8öS÷öدö-›öø öÜ¿ö*3öÐèö›öPö°ƒöYñööö5öùZö-7öé,öy9öÊö½}ö~ÊöUøö"ÏöŸQöôíöæ ö‹žöîðö {ö©¥öÞÀö»Íö¦ö/8ö\öøööy¿ö…^öv¾ö`õöú!öp¼ö{:öp\öWùö¿ñöÙšö¡Uö%ö££ö1:öáÌöN-öGöèöºÜö¿öúöÆáö3<ö};öͲ™™’„´˜IBCocoaFramework††BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/info.nib0000644000175000017500000000150010005632764023244 0ustar centriscentris IBDocumentLocation 3 11 521 240 0 4 1152 742 IBEditorPositions 29 3 256 365 44 0 0 1152 746 IBFramework Version 349.0 IBLockedObjects 288 IBOpenObjects 29 813 IBSystem Version 7D24 IBUserGuides VolumeSize guideLocations guidesLocked NO BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/classes.nib0000644000175000017500000000771707717317430023774 0ustar centriscentris{ IBClasses = ( { ACTIONS = { HelpHowTo = id; HelpToDo = id; HelpVersions = id; NewEmulator = id; PauseAll = id; RunAll = id; TerminateAll = id; }; CLASS = Controller; LANGUAGE = ObjC; OUTLETS = {theEmulator = id; thePrefsEditor = id; }; SUPERCLASS = NSApplication; }, { ACTIONS = { Benchmark = id; Interrupt = id; PowerKey = id; Restart = id; Resume = id; ScreenHideShow = id; Snapshot = id; SpeedChange = id; Suspend = id; Terminate = id; ToggleState = id; ZapPRAM = id; }; CLASS = Emulator; LANGUAGE = ObjC; OUTLETS = {barberPole = id; runOrPause = id; screen = id; speed = id; win = id; }; SUPERCLASS = NSObject; }, {CLASS = EmulatorView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { ACTIONS = { Interrupt = id; PowerKey = id; Restart = id; Resume = id; Snapshot = id; Suspend = id; Terminate = id; ZapPRAM = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { ACTIONS = { AddSCSI = id; AddVolume = id; BrowseExtFS = id; BrowsePrefs = id; BrowseROM = id; ChangeBootFrom = id; ChangeCPU = id; ChangeDisableCD = id; ChangeDisableSound = id; ChangeFPU = id; ChangeKeyboard = id; ChangeModel = id; ChangeScreen = id; CreateVolume = id; DeleteVolume = id; EditBytes = id; EditDelay = id; EditEtherNetDevice = id; EditExtFS = id; EditFrequency = id; EditMB = id; EditModemDevice = id; EditPrinterDevice = id; EditROMpath = id; LoadPrefs = id; RemoveSCSI = id; RemoveVolume = id; ResetPrefs = id; SavePrefs = id; ShowPrefs = id; }; CLASS = PrefsEditor; LANGUAGE = ObjC; OUTLETS = { CPU68000 = id; CPU68020 = id; CPU68030 = id; CPU68040 = id; FPU = id; IIci = id; MB = id; ROMfile = id; SCSIdisks = id; bootFromAny = id; bootFromCD = id; bytes = id; classic = id; delay = id; depth = id; disableCD = id; disableSound = id; diskImages = id; emuFreq = id; emuWin = id; etherNet = id; extFS = id; frequency = id; height = id; keyboard = id; modem = id; newVolumeSize = id; newVolumeView = id; panel = id; prefsFile = id; printer = id; quadra900 = id; screen = id; theEmulator = id; width = id; window = id; }; SUPERCLASS = NSObject; } ); IBVersion = 1; }BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/shutdownH.tiff0000644000175000017500000002310607444541567024477 0ustar centriscentrisMM*%Œ6k *™HÀ&iÝ)5ˆó/<˜þ*7Šó )lÝJÀ +™k6"n :µ#1õ>R­ÿ[oÇÿuŠÛÿ‹åÿ—¨ëÿœ¯íÿ˜ªìÿŽ¢çÿ{ÞÿbvÎÿEYµÿ(8Œõ >µn"tLÊ.CœÿNiÁÿu‘ãÿ›µõÿ»ÑÿÿÐâÿÿÜìÿÿãñÿÿæòÿÿäñÿÿàîÿÿÔæÿÿÂ×ÿÿ¥¾ùÿœëÿVsÍÿ4L§ÿPÊtO 5²!9ÿ@_¹ÿgŠÞÿ°øÿ¬Ìÿÿ¿ÛÿÿËåÿÿÒéÿÿÔëÿÿÖëÿÿÖëÿÿ×ëÿÿ×ëÿÿÖëÿÿÑéÿÿÆáÿÿ³Óÿÿ”¹ÿÿo”éÿGjÆÿ&B›ÿ 9²O r YÞ&F›ÿBj¿ÿcŽÝÿ}¨ïÿ¹ùÿœÅûÿ¡Éûÿ¢Ëùÿ¢É÷ÿ¡Èõÿ Çõÿ Çôÿ Èôÿ£Éõÿ¥Ë÷ÿ¦Ìùÿ¥Íûÿ¡Éýÿ”Àýÿƒ°öÿi—æÿHsËÿ,P¨ÿ$aÞr   …/vö&L¡ÿ>k¼ÿS„Ðÿd—Þÿn¢åÿs¨æÿuªæÿuªãÿs¨ßÿq¦Ýÿr¥Üÿq¤Úÿq¤Úÿq¤Úÿr¥Üÿt§Þÿv¨àÿx¬ãÿx¬èÿv¬éÿr§éÿhäÿWŒ×ÿCsÄÿ,Uªÿ5ö …   †1}þ!Kžÿ3c³ÿCxÃÿO‡ÍÿW‘Ôÿ[–Õÿ]™Õÿ_˜Óÿa˜Òÿc™Ñÿe™ÑÿfšÑÿg›Ñÿg›Ñÿg›ÑÿfšÑÿf›ÑÿešÒÿcšÓÿb™Ôÿ`™Öÿ^™ØÿZ•×ÿSÒÿGÈÿ7k¹ÿ&T§ÿ8ˆþ †  v1uöJ›ÿ)_¬ÿ5o·ÿ?}ÂÿF†ÈÿO‹ËÿVÍÿ[”Îÿ^–Ïÿc™ÑÿgœÒÿjžÔÿmŸÔÿHbÿ?N^ÿIdÿmŸÔÿkŸÔÿiœÔÿešÒÿa—Ðÿ\”ÏÿX’ÎÿRŽÌÿJŠÊÿB‚Æÿ8u¼ÿ-e±ÿQ¢ÿ7€öv   U #XßH—ÿZ§ÿ*i²ÿ4u»ÿA€ÂÿJˆÇÿSŽËÿZ“Îÿa˜Ñÿg›ÓÿlŸÕÿp¢×ÿr¥Ùÿt¦Øÿ$2Aÿ+9Iÿ$2Aÿu¦Øÿs¦Ùÿq¤×ÿm¡ÖÿhÓÿc™Òÿ\•ÐÿUÌÿN‰ÈÿEƒÅÿ9z¾ÿ-nµÿ#_ªÿOžÿ )aß U  #5·BÿV£ÿ"d­ÿ/q·ÿ<|ÀÿH…ÆÿRËÿ\”ÐÿcšÔÿjŸÖÿn¢Øÿs¦Úÿw©ÛÿxªÛÿy¨Ùÿ$1?ÿ#1?ÿ$1?ÿz¨ÙÿyªÛÿx©Üÿu¨Ûÿp¥Ùÿk ×ÿeœÔÿ^—ÒÿWÍÿLˆÉÿA€Ãÿ4v»ÿ%h±ÿZ¨ÿJšÿ;·# ~ <„ÿQ ÿ`¬ÿ)mµÿ9z½ÿF…ÆÿQŽÌÿ[•ÑÿdœÕÿk¡Øÿq¥Ûÿu¨Üÿv¦×ÿgŒ²ÿ}¬Üÿ{¨Õÿ#0=ÿ#/;ÿ#0=ÿ{¨Õÿ~¬Üÿi޶ÿy©Úÿx©Ýÿs¦Üÿm¢ÙÿhžÖÿ_—ÓÿU‘ÏÿJˆÉÿ>Áÿ.q¹ÿ d°ÿW§ÿD’ÿ ~ 1 JÐ K™ÿ]ªÿ&kµÿ5w¾ÿDƒÇÿPÍÿZ•Òÿcœ×ÿk£Úÿq§ÜÿwªÞÿe‰¯ÿSjƒÿ7ETÿ®Üÿ|§Òÿ#/:ÿ"-9ÿ#/:ÿ|¨Òÿ‚®Üÿ8ESÿUm†ÿh´ÿy«ßÿt¨Ýÿn¤ÛÿfžØÿ^˜ÔÿSÏÿH‡Èÿ:|Áÿ,p¸ÿa­ÿR¢ÿ%SÐ1 | @‰ÿW§ÿf±ÿ1u¼ÿ?€ÅÿLŒÍÿW”Óÿb›Øÿj¢Ûÿq§ÝÿpŸÏÿYv•ÿ:HWÿ.Mÿ$1?ÿ#0<ÿWu’ÿwœÃÿ|¢Êÿ„ªÑÿ„©Ïÿ%/:ÿ$.8ÿ%/:ÿ„©Ïÿ„ªÒÿ}£ÊÿwÂÿSoŠÿ#0=ÿ%3@ÿ1?Oÿg»ÿt«âÿl¦àÿd Þÿ[™ÚÿOÔÿ@…Ìÿ1wÂÿ!h¶ÿV¢ÿ €  /«U ÿ#k¹ÿ3yÄÿA‡ÏÿP’Øÿ\›Ýÿg£àÿo¨âÿq¥ÚÿB[uÿ)6Dÿ#/<ÿMh„ÿs˜¾ÿxžÃÿ‚§Îÿ‡®×ÿ†«Òÿ%/:ÿ$.8ÿ%/:ÿ…ªÑÿˆ®Öÿ‚§ÎÿyžÄÿt™¿ÿJb{ÿ$0=ÿ+8FÿHc~ÿw¬âÿqªãÿj¥àÿ`žßÿV–ÚÿH‹Óÿ:€Éÿ)p½ÿ_¬ÿ5« &'LÍ_ªÿ+s¿ÿ;ÌÿIÕÿV˜Üÿa áÿk§ãÿsªäÿ^‡±ÿ+:Iÿ#0=ÿ3DWÿtšÁÿxžÄÿ¦Ïÿˆ¯ÙÿŒ´Ûÿ‰®Õÿ&0;ÿ%/9ÿ&0;ÿ‰¯Ôÿ´Ûÿ‰¯Ùÿ§ÏÿyžÄÿi‹®ÿ2BTÿ#1>ÿ,:Hÿl˜Çÿu¬åÿn©ãÿe£âÿZ›ßÿN’Ùÿ@†Ïÿ0xÄÿ hµÿ -VÍ& , 9lå g³ÿ2zÇÿA‡ÒÿO“Ûÿ\žáÿg¥äÿpªçÿu¬åÿJi‰ÿ(5Dÿ"/;ÿRmŠÿyŸÆÿ¨Ñÿ‹²Üÿ¹åÿ‘¹ãÿ‹±Øÿ'1;ÿ%/9ÿ'1;ÿ²Øÿ“¹âÿ‘¹äÿбÚÿ¨ÏÿxŸÄÿLd~ÿ#/<ÿ)6EÿUxÿx®æÿr¬çÿj§åÿ`¡ãÿT—ÞÿFŒÖÿ8Ëÿ'n½ÿBwå,  1J‡ö&m¹ÿ7ÌÿFŒØÿT˜ßÿa£åÿk©èÿt­éÿw®åÿ9Qhÿ'4Bÿ".;ÿo“¹ÿ¨Ñÿ‹³Þÿ’¼æÿ–Àëÿ•¿æÿ޵Úÿ'1<ÿ&0:ÿ'1<ÿŽ´Úÿ•¿æÿ–Àëÿ’¼æÿвÜÿ§Ðÿ`€ ÿ#.;ÿ(5CÿAZtÿz¯çÿv­êÿn«éÿe¦çÿZ›âÿL‘Ûÿ=„Ðÿ,tÃÿS•ö1 5T˜þ+rÀÿ<„ÒÿK’ÝÿYäÿf¦êÿn¬íÿv°ëÿx¯æÿ+=Oÿ&3@ÿ#/;ÿ|¥Ïÿˆ³Þÿ‘½éÿ˜ÂïÿšÅñÿ–Àêÿ¶Þÿ'2=ÿ&0;ÿ(2=ÿ¶Þÿ—Áêÿ™Åñÿ—Âïÿ‘¼èÿˆ±Üÿu™¿ÿ#/;ÿ&3Aÿ.ASÿ{±èÿy²íÿq®íÿi©ëÿ^¡çÿP–áÿAŠ×ÿ1{Èÿ`©þ5!8QŽö0wÄÿ@‰ÖÿP–áÿ\¡èÿh©ìÿq°ðÿy³ïÿy°çÿ$2Aÿ#0=ÿ$0=ÿ‚­ØÿŽºçÿ–Âðÿ›ÆôÿœÇôÿ™Ãíÿ‘¸áÿI\qÿ'1<ÿRf}ÿ’¸áÿ™ÂíÿÈôÿšÆóÿ–Áïÿ޹æÿ‚¬Öÿ$0=ÿ#0=ÿ%3Bÿ~±èÿ|µïÿu²ñÿm¬îÿa¤êÿTšäÿEŽÛÿ7Íÿ \žö8!":Eyç2zÆÿDÚÿR›åÿ`¥ìÿk­ðÿu´ôÿ{´ñÿ|°çÿ,=Oÿ#0=ÿ%2>ÿ‰´áÿ”ÀïÿšÈ÷ÿÊøÿžÊøÿœÆñÿ•¼åÿ‰­Òÿ…¨Ëÿ‰­Òÿ•¼åÿ›ÆñÿŸÊ÷ÿžÊøÿšÇõÿ’¿íÿ}¥Îÿ&2>ÿ$1=ÿ.@Rÿ~²èÿ}·òÿx¶õÿo¯òÿe¨îÿWžçÿI’Þÿ:ƒÑÿP‡ç:"":6[Ó5|ÈÿGÞÿUéÿc¨ðÿn±õÿx·øÿ}¸ôÿ}²éÿ9Pgÿ$1>ÿ(5CÿªÖÿ—ÆöÿžÍþÿ Îþÿ¡Ïýÿ ÌøÿšÃíÿµÜÿ‹°ÖÿµÜÿšÃíÿ¡Ìøÿ¢Ïýÿ¡ÎþÿžÌüÿ–Åõÿp“¸ÿ)6Cÿ$1>ÿ@Xqÿ´ëÿºöÿ{¹ùÿr´÷ÿh¬óÿ\¢ìÿL–ãÿ=†Ôÿ>hÓ:"": $=¹7|ÆÿI“áÿX¢íÿf¬ôÿq´ùÿ{ºýÿ€»ùÿ~¶íÿLi‡ÿ%1?ÿ.;Gÿgˆ§ÿšËøÿ¡Ñÿÿ¤Òÿÿ¥Óÿÿ¤Ñûÿ Êóÿ˜Áèÿ–¾äÿšÂéÿ Ëôÿ¥Òüÿ¦Ôÿÿ¤Òÿÿ¢Ðþÿ›É÷ÿ\y“ÿ-:Fÿ%2?ÿXx™ÿ·íÿ‚½ùÿ~¼þÿv·úÿj¯öÿ^¦ðÿO™æÿ@ˆÖÿ*F¹:"!8!˜6x¿ÿL•ãÿZ¤ïÿh¯÷ÿt¸þÿ~½ÿÿƒ¾ùÿ¹íÿc‰­ÿ&3?ÿ+8DÿH^oÿ™Èñÿ¥Õÿÿ§×ÿÿ©×ÿÿ©×ýÿ§Ôùÿ¤Ñôÿ£Ïòÿ¤Ñôÿ¨Öúÿ©×ýÿ©×ÿÿ¨×ÿÿ¥Õþÿ‹´×ÿDXhÿ)6Aÿ&3?ÿu¢Éÿ…¼îÿ„Áúÿ€Àÿÿyºþÿm²úÿ`¨óÿRœéÿ?‡Óÿ &˜8!5 r/h§øL•âÿ]¦ðÿi±ûÿvºÿÿÀÿÿ„Âúÿ†¾ïÿ}¯ØÿBZmÿ(6@ÿ8GQÿp¨ÿ§ØýÿªÜÿÿ«Üÿÿ­Þÿÿ­Üýÿ¬Ûüÿ«Ûûÿ¬Ûüÿ­Ýýÿ®Þÿÿ¬Üÿÿ«Üÿÿ§Øüÿfƒ˜ÿ6DNÿ(5?ÿGauÿ„·ßÿˆÀðÿˆÅûÿƒÄÿÿz½ÿÿo´üÿb©õÿSêÿ9y½ø r5 1L:\ÐK‘Üÿ]§óÿj²üÿw¼ÿÿ€Ãÿÿ‡Çüÿ‰Äòÿ†»âÿdŠ¥ÿ)7@ÿ-;Dÿ?NWÿ€¥»ÿ®áÿÿ¯áÿÿ±ãÿÿ²âÿÿ²âÿÿ²âÿÿ²âÿÿ±ãÿÿ±ãÿÿ¯âÿÿ¬ßýÿw˜¬ÿ>MVÿ,:Bÿ*8AÿuŸ¼ÿ‰¾äÿŒÆóÿ‹Éüÿ„Çÿÿ|Àÿÿo¶þÿb¬øÿTéÿ DjÐL1  ,F &¡F‰Îÿ]§õÿj³þÿw¾ÿÿ‚ÆÿÿŠËýÿŒËõÿ‹Ãçÿ‡ºØÿYxŠÿ,:Aÿ1@HÿCRZÿ}ž­ÿ¥Ôéÿµèÿÿ·èÿÿ¶èÿÿ¶èÿÿ¶èÿÿ¶èÿÿµèÿÿ¡Íâÿv”¢ÿBQXÿ/>Eÿ+9Aÿaƒ–ÿмÚÿŽÇêÿÍ÷ÿÎþÿ…Èÿÿ|Âÿÿp·ÿÿc­úÿP˜âÿ +¡F, &?k)R{ÝZ£îÿk´ÿÿw¿ÿÿ‚Çÿÿ‹Îþÿ‘Ñùÿ‘ÌîÿŒÂÞÿ„³ÊÿYvƒÿ.=Cÿ1AGÿCSYÿbx€ÿ†¨³ÿÈÕÿ°áñÿºîÿÿ³åõÿŸÉ×ÿ‚£®ÿ_t|ÿBRWÿ1AFÿ.°f¦ßþÉýÿŽ×ÿÿ—àÿÿ æþÿ§ìýÿ©ìøÿªêñÿ¨æèÿ¦ààÿ£ÙÙÿ¤ÖÖÿ¤ÔÔÿ£ÓÓÿ£ÒÒÿ¤ÓÓÿ¤ÔÔÿ¤ÖÖÿ¦ÚÚÿ§ààÿ«èéÿ­íòÿ­ðùÿ©îýÿ£êÿÿœãÿÿ’Ûÿÿ‡Ðÿÿq¶íþ1C°fP8# +@Wf->°f¢Òù…Îýÿ”Ýÿÿžæÿÿ¦íÿÿ­ñýÿ¯ôúÿ±óõÿ°ïïÿ¯ééÿ®ããÿ«ÞÞÿªÛÛÿ©ÚÚÿªÛÛÿ­ßßÿ¯ääÿ±êêÿ³ððÿ³ööÿ²õúÿ®ôýÿ©ðÿÿ¡éÿÿ˜áÿÿÖÿÿq°ßù2C°fW@+ 0F\f%2¥Tƒ§é‡Îöÿ—áÿÿ¡êÿÿ¨ñÿÿ®õþÿ³ùüÿ¶úúÿ·ööÿ·óóÿ¸ððÿ·îîÿ·ííÿ·îîÿ¸ððÿ¸óóÿ¹÷÷ÿ·úúÿµüýÿ±øþÿ¬óÿÿ¥íÿÿœæÿÿŽÖûÿ]²é)6¥f\F0 "4H]f 8WlÍ‚Æêÿ—áýÿ¢íÿÿªóÿÿ°ùÿÿ´ýþÿ¹ýýÿºüüÿ»ûûÿ¼úúÿ»ùùÿ¼úúÿ¼ûûÿ»üüÿ¹þþÿ¶ÿÿÿ²üÿÿ¬öÿÿ¦ïÿÿœæÿÿŠÑóÿ=^rÍf]H4"  $5H\fp,7§NuŒÝ‹Ïëÿœäúÿ§ñÿÿ®øÿÿ²ýÿÿ¶ÿÿÿ¸ÿÿÿºÿÿÿ¹ÿÿÿ¹ÿÿÿ¹ÿÿÿ¶ÿÿÿ³þÿÿ¯ûÿÿªôÿÿ¢ëüÿ“ÙòÿT}’Ý0:§pf\H5$  $4FWffv)1¤BdsÐ¼Ðø˜Ýïÿ¢ëøÿ¨ôüÿ®øþÿ°ûþÿ±üÿÿ±ûÿÿ®ùþÿ«õýÿ¥îúÿœãòÿ†ÄÕøGjwÐ-4¤ vffWF4$  "0@P_fff ƒ*/£5NW¿Px‚×mž«éƒ¿Î÷Ñßþ„ÁÏ÷o¡­éTz…×7QY¿,1£ ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/English.lproj/MainMenu.nib/shutdownN.tiff0000644000175000017500000002310607444541571024500 0ustar centriscentrisMM*%Œ6k$$$™===ÀZZZÝttt󃃃þvvvó\\\Ý@@@À%%%™k6"n666µzzzõ   ÿ½½½ÿÑÑÑÿÜÜÜÿäääÿæææÿåååÿßßßÿÕÕÕÿÄÄÄÿ¨¨¨ÿƒƒƒõ:::µn"tDDDÊŽŽŽÿºººÿÝÝÝÿòòòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿæææÿÅÅÅÿšššÿKKKÊtO...²ÿ¨¨¨ÿÊÊÊÿéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿÔÔÔÿ´´´ÿŽŽŽÿ222²O rSSSÞÿµµµÿÑÑÑÿãããÿïïïÿôôôÿôôôÿóóóÿñññÿïïïÿíííÿíííÿíííÿîîîÿñññÿóóóÿöööÿ÷÷÷ÿôôôÿêêêÿÚÚÚÿ¿¿¿ÿšššÿ\\\Þr  …mmmö–––ÿ¯¯¯ÿÅÅÅÿÓÓÓÿÚÚÚÿÝÝÝÿÜÜÜÿÚÚÚÿ×××ÿÔÔÔÿÓÓÓÿÒÒÒÿÑÑÑÿÒÒÒÿÓÓÓÿÔÔÔÿ×××ÿÚÚÚÿÝÝÝÿàààÿßßßÿÙÙÙÿÌÌÌÿ¶¶¶ÿ   ÿwwwö…  †pppþ‘‘‘ÿ§§§ÿ¶¶¶ÿÃÃÃÿÊÊÊÿÍÍÍÿÌÌÌÿËËËÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿÉÉÉÿÊÊÊÿÊÊÊÿËËËÿÌÌÌÿÎÎÎÿÏÏÏÿÎÎÎÿÈÈÈÿ¼¼¼ÿ­­­ÿšššÿ{{{þ†  vmmmöŽŽŽÿ¡¡¡ÿ®®®ÿ¶¶¶ÿ¾¾¾ÿÁÁÁÿÄÄÄÿÆÆÆÿÇÇÇÿÈÈÈÿËËËÿÌÌÌÿÍÍÍÿ{{{ÿ\\\ÿ}}}ÿÎÎÎÿÍÍÍÿËËËÿÉÉÉÿÈÈÈÿÆÆÆÿÅÅÅÿÃÃÃÿÁÁÁÿ»»»ÿ²²²ÿ¦¦¦ÿ•••ÿvvvöv  USSSßÿ›››ÿ¨¨¨ÿ±±±ÿ···ÿ¼¼¼ÿÁÁÁÿÅÅÅÿÈÈÈÿËËËÿÎÎÎÿÐÐÐÿÒÒÒÿÐÐÐÿ???ÿFFFÿ???ÿÑÑÑÿÒÒÒÿÑÑÑÿÏÏÏÿÌÌÌÿÊÊÊÿÆÆÆÿÃÃÃÿ¿¿¿ÿºººÿ´´´ÿ«««ÿŸŸŸÿ”””ÿ[[[ßU  "///·„„„ÿ˜˜˜ÿ¡¡¡ÿ­­­ÿµµµÿ¼¼¼ÿÁÁÁÿÇÇÇÿÊÊÊÿÎÎÎÿÑÑÑÿÓÓÓÿÔÔÔÿÓÓÓÿÐÐÐÿ===ÿ===ÿ===ÿÑÑÑÿÓÓÓÿÔÔÔÿÓÓÓÿÑÑÑÿÏÏÏÿËËËÿÈÈÈÿÄÄÄÿ½½½ÿ¸¸¸ÿ°°°ÿ¥¥¥ÿ›››ÿŽŽŽÿ555·# ~yyyÿ–––ÿ¢¢¢ÿªªªÿµµµÿ½½½ÿÃÃÃÿÉÉÉÿÍÍÍÿÐÐÐÿÓÓÓÿÕÕÕÿÏÏÏÿ­­­ÿÕÕÕÿÏÏÏÿ;;;ÿ:::ÿ;;;ÿÏÏÏÿÕÕÕÿ°°°ÿÒÒÒÿÕÕÕÿÔÔÔÿÑÑÑÿÎÎÎÿÊÊÊÿÅÅÅÿ¿¿¿ÿ¸¸¸ÿ­­­ÿ¥¥¥ÿšššÿ†††ÿ~ 1FFFÐŒŒŒÿŸŸŸÿ©©©ÿ³³³ÿ¼¼¼ÿÄÄÄÿÉÉÉÿÎÎÎÿÒÒÒÿÓÓÓÿÕÕÕÿ©©©ÿÿRRRÿÕÕÕÿËËËÿ999ÿ777ÿ999ÿËËËÿÕÕÕÿRRRÿ‚‚‚ÿ¯¯¯ÿÖÖÖÿÔÔÔÿÒÒÒÿÐÐÐÿËËËÿÆÆÆÿ¿¿¿ÿ¶¶¶ÿ®®®ÿ¢¢¢ÿ”””ÿOOOÐ1 |ÿ˜˜˜ÿ¥¥¥ÿ°°°ÿ¹¹¹ÿÃÃÃÿÉÉÉÿÎÎÎÿÒÒÒÿÕÕÕÿÇÇÇÿ‘‘‘ÿUUUÿHHHÿ@@@ÿÔÔÔÿËËËÿ888ÿ666ÿ888ÿËËËÿÔÔÔÿ@@@ÿIIIÿVVVÿ–––ÿÍÍÍÿÕÕÕÿÓÓÓÿÐÐÐÿËËËÿÅÅÅÿ¾¾¾ÿµµµÿ©©©ÿœœœÿŒŒŒÿ| 888¿’’’ÿ¡¡¡ÿ®®®ÿ¹¹¹ÿÁÁÁÿÉÉÉÿÐÐÐÿÓÓÓÿÖÖÖÿÇÇÇÿ†††ÿNNNÿ???ÿ>>>ÿ\\\ÿÑÑÑÿÊÊÊÿ888ÿ666ÿ888ÿÊÊÊÿÑÑÑÿ]]]ÿ>>>ÿ???ÿOOOÿÿÒÒÒÿÖÖÖÿÔÔÔÿÑÑÑÿÌÌÌÿÅÅÅÿ½½½ÿ³³³ÿ¦¦¦ÿšššÿ???¿ Msss÷ÿ©©©ÿ···ÿÁÁÁÿÈÈÈÿÏÏÏÿÓÓÓÿÖÖÖÿØØØÿÿMMMÿ>>>ÿ;;;ÿ†††ÿÇÇÇÿÌÌÌÿÉÉÉÿ888ÿ666ÿ888ÿÉÉÉÿÍÍÍÿÃÃÃÿÿ<<<ÿ>>>ÿNNNÿ˜˜˜ÿØØØÿ×××ÿÔÔÔÿÑÑÑÿËËËÿÅÅÅÿºººÿ®®®ÿ£££ÿ÷M €‰‰‰ÿ¥¥¥ÿ±±±ÿ½½½ÿÇÇÇÿÎÎÎÿÓÓÓÿÖÖÖÿ×××ÿ¥¥¥ÿKKKÿ===ÿ;;;ÿŽŽŽÿ½½½ÿÄÄÄÿÌÌÌÿÉÉÉÿ888ÿ777ÿ888ÿÉÉÉÿÌÌÌÿÄÄÄÿ½½½ÿ†††ÿ;;;ÿ>>>ÿMMMÿµµµÿÙÙÙÿ×××ÿÕÕÕÿÐÐÐÿËËËÿÂÂÂÿµµµÿ«««ÿ–––ÿ€  ***«———ÿ®®®ÿ¹¹¹ÿÅÅÅÿÎÎÎÿÓÓÓÿ×××ÿÚÚÚÿÒÒÒÿqqqÿBBBÿ:::ÿ€€€ÿ¹¹¹ÿ¾¾¾ÿÈÈÈÿÐÐÐÿÌÌÌÿ999ÿ777ÿ999ÿËËËÿÐÐÐÿÉÉÉÿ¾¾¾ÿ¹¹¹ÿxxxÿ;;;ÿDDDÿ{{{ÿÚÚÚÿÛÛÛÿÙÙÙÿÕÕÕÿÑÑÑÿÉÉÉÿ½½½ÿ³³³ÿ¢¢¢ÿ///« &EEEÍ¡¡¡ÿµµµÿ¿¿¿ÿÊÊÊÿÒÒÒÿÖÖÖÿÜÜÜÿÜÜÜÿ«««ÿGGGÿ;;;ÿTTTÿºººÿ¾¾¾ÿÇÇÇÿÓÓÓÿÖÖÖÿÏÏÏÿ999ÿ777ÿ999ÿÏÏÏÿÖÖÖÿÓÓÓÿÇÇÇÿ¾¾¾ÿ¨¨¨ÿQQQÿ;;;ÿFFFÿÀÀÀÿÝÝÝÿÜÜÜÿÙÙÙÿÕÕÕÿÎÎÎÿÄÄÄÿºººÿ«««ÿOOOÍ& ,aaa娨¨ÿºººÿÅÅÅÿÐÐÐÿÖÖÖÿÚÚÚÿÞÞÞÿÝÝÝÿƒƒƒÿAAAÿ999ÿ………ÿÀÀÀÿËËËÿÖÖÖÿÝÝÝÿÜÜÜÿÒÒÒÿ:::ÿ888ÿ:::ÿÒÒÒÿÜÜÜÿÝÝÝÿÕÕÕÿÊÊÊÿ¿¿¿ÿzzzÿ:::ÿBBBÿ–––ÿÝÝÝÿßßßÿÜÜÜÿØØØÿÓÓÓÿÊÊÊÿÀÀÀÿ±±±ÿnnnå,  1{{{ö¯¯¯ÿÁÁÁÿÌÌÌÿÕÕÕÿÛÛÛÿßßßÿáááÿÞÞÞÿeeeÿ@@@ÿ999ÿ²²²ÿËËËÿÙÙÙÿâââÿæææÿâââÿÖÖÖÿ;;;ÿ999ÿ;;;ÿÖÖÖÿâââÿæææÿâââÿØØØÿÊÊÊÿšššÿ999ÿAAAÿpppÿßßßÿâââÿàààÿÝÝÝÿØØØÿÏÏÏÿÆÆÆÿ¸¸¸ÿ‰‰‰ö1 5‰‰‰þ´´´ÿÆÆÆÿÐÐÐÿÚÚÚÿàààÿâââÿãããÿÞÞÞÿMMMÿ>>>ÿ:::ÿÈÈÈÿØØØÿãããÿéééÿëëëÿåååÿÙÙÙÿ;;;ÿ999ÿ;;;ÿÙÙÙÿåååÿëëëÿéééÿâââÿÖÖÖÿ¹¹¹ÿ:::ÿ???ÿQQQÿßßßÿäääÿäääÿàààÿÝÝÝÿÔÔÔÿËËËÿ½½½ÿšššþ5!8‚‚‚ö¹¹¹ÿËËËÿÕÕÕÿÞÞÞÿâââÿæææÿæææÿÞÞÞÿ???ÿ;;;ÿ;;;ÿÑÑÑÿàààÿéééÿîîîÿîîîÿçççÿÚÚÚÿnnnÿ:::ÿyyyÿÚÚÚÿçççÿîîîÿíííÿèèèÿßßßÿÏÏÏÿ:::ÿ;;;ÿ@@@ÿàààÿçççÿèèèÿäääÿàààÿØØØÿÐÐÐÿÂÂÂÿ‘‘‘ö8!":nnnç¼¼¼ÿÐÐÐÿÚÚÚÿâââÿçççÿëëëÿèèèÿßßßÿLLLÿ<<<ÿ===ÿÛÛÛÿéééÿñññÿòòòÿòòòÿìììÿàààÿÎÎÎÿÇÇÇÿÎÎÎÿàààÿìììÿòòòÿòòòÿðððÿèèèÿÈÈÈÿ===ÿ<<<ÿOOOÿáááÿêêêÿìììÿéééÿäääÿÝÝÝÿÔÔÔÿÆÆÆÿ}}}ç:"":TTTÓ½½½ÿÓÓÓÿÝÝÝÿåååÿëëëÿîîîÿëëëÿáááÿdddÿ===ÿAAAÿÐÐÐÿîîîÿöööÿöööÿöööÿñññÿçççÿÖÖÖÿÐÐÐÿÖÖÖÿçççÿñññÿöööÿöööÿõõõÿíííÿ±±±ÿAAAÿ===ÿnnnÿâââÿìììÿïïïÿìììÿèèèÿàààÿ×××ÿÉÉÉÿ```Ó:"":777¹¼¼¼ÿÖÖÖÿàààÿéééÿïïïÿòòòÿðððÿæææÿƒƒƒÿ===ÿFFFÿ¤¤¤ÿôôôÿûûûÿûûûÿûûûÿ÷÷÷ÿïïïÿäääÿàààÿåååÿðððÿøøøÿüüüÿüüüÿúúúÿóóóÿ‘‘‘ÿEEEÿ===ÿ•••ÿæææÿñññÿóóóÿñññÿìììÿäääÿÜÜÜÿÊÊÊÿ@@@¹:"!8˜¶¶¶ÿÙÙÙÿãããÿíííÿóóóÿ÷÷÷ÿóóóÿéééÿ­­­ÿ???ÿDDDÿoooÿñññÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿôôôÿòòòÿôôôÿúúúÿýýýÿÿÿÿÿÿÿÿÿþþþÿ×××ÿhhhÿAAAÿ???ÿÇÇÇÿëëëÿõõõÿøøøÿõõõÿðððÿçççÿßßßÿÈÈÈÿ###˜8!5 r¡¡¡øÙÙÙÿåååÿðððÿöööÿùùùÿùùùÿïïïÿØØØÿmmmÿ@@@ÿQQQÿ¨¨¨ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿüüüÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ˜˜˜ÿNNNÿ???ÿuuuÿßßßÿðððÿûûûÿûûûÿøøøÿòòòÿéééÿàààÿ³³³ø r5 1LYYYÐÕÕÕÿæææÿòòòÿúúúÿþþþÿüüüÿòòòÿâââÿ¥¥¥ÿ@@@ÿDDDÿWWWÿ»»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ¬¬¬ÿVVVÿBBBÿAAAÿ¼¼¼ÿäääÿóóóÿüüüÿÿÿÿÿüüüÿõõõÿëëëÿßßßÿfffÐL1  ,F$$$¡ÆÆÆÿåååÿôôôÿýýýÿÿÿÿÿýýýÿõõõÿçççÿØØØÿŠŠŠÿAAAÿHHHÿZZZÿ­­­ÿéééÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâââÿ¢¢¢ÿXXXÿEEEÿAAAÿ–––ÿÚÚÚÿêêêÿ÷÷÷ÿþþþÿÿÿÿÿÿÿÿÿøøøÿëëëÿØØØÿ***¡F, &?kwwwÝàààÿôôôÿþþþÿÿÿÿÿþþþÿùùùÿîîîÿÞÞÞÿÊÊÊÿƒƒƒÿCCCÿGGGÿYYYÿ€€€ÿ³³³ÿÕÕÕÿñññÿÿÿÿÿõõõÿ×××ÿ®®®ÿ|||ÿWWWÿFFFÿBBBÿŠŠŠÿÕÕÕÿàààÿðððÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿêêêÿ‡‡‡Ýk?& 6Q+++§ÌÌÌÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿôôôÿçççÿÙÙÙÿÌÌÌÿÿEEEÿGGGÿNNNÿZZZÿcccÿhhhÿiiiÿhhhÿcccÿZZZÿMMMÿFFFÿEEEÿ˜˜˜ÿÓÓÓÿÚÚÚÿéééÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿàààÿ111§Q6  -Fk\\\Íçççÿþþþÿÿÿÿÿÿÿÿÿþþþÿúúúÿðððÿãããÿ×××ÿÓÓÓÿ¯¯¯ÿzzzÿEEEÿHHHÿIIIÿIIIÿJJJÿIIIÿIIIÿGGGÿEEEÿ{{{ÿ¾¾¾ÿÓÓÓÿØØØÿäääÿñññÿúúúÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿôôôÿiiiÍkF- $;Tžžžéúúúÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿøøøÿîîîÿâââÿ×××ÿÓÓÓÿÕÕÕÿ¿¿¿ÿ›››ÿvvvÿXXXÿHHHÿXXXÿwwwÿÿÇÇÇÿÔÔÔÿÓÓÓÿØØØÿãããÿïïïÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°éT;$ /G_,,,¥ÏÏÏùüüüÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ÷÷÷ÿîîîÿãããÿÚÚÚÿÕÕÕÿÓÓÓÿÔÔÔÿÖÖÖÿ×××ÿ×××ÿ×××ÿÖÖÖÿÔÔÔÿÓÓÓÿÕÕÕÿÚÚÚÿäääÿïïïÿøøøÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááù222¥_G/ #8Pf;;;°ÜÜÜþüüüÿÿÿÿÿÿÿÿÿþþþÿýýýÿøøøÿñññÿèèèÿàààÿÙÙÙÿÖÖÖÿÔÔÔÿÓÓÓÿÒÒÒÿÓÓÓÿÔÔÔÿÖÖÖÿÚÚÚÿàààÿéééÿòòòÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëþBBB°fP8# +@Wf>>>°ÕÕÕùýýýÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿúúúÿõõõÿïïïÿéééÿãããÿÞÞÞÿÛÛÛÿÚÚÚÿÛÛÛÿßßßÿäääÿêêêÿðððÿöööÿúúúÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááùCCC°fW@+ 0F\f111¥«««éõõõÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿúúúÿöööÿóóóÿðððÿîîîÿíííÿîîîÿðððÿóóóÿ÷÷÷ÿúúúÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿ¶¶¶é555¥f\F0 "4H]fjjjÍéééÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿúúúÿûûûÿüüüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿòòòÿrrrÍf]H4"  $5H\fp333§Ýîîîÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿôôôÿ———Ý777§pf\H5$  $4FWffv000¤uuuÐÒÒÒøïïïÿøøøÿüüüÿþþþÿþþþÿÿÿÿÿÿÿÿÿþþþÿýýýÿúúúÿóóóÿ×××øzzzÐ222¤vffWF4$  "0@P_fffƒ...£VVV¿€€€×§§§éÊÊÊ÷ÜÜÜþÌÌÌ÷©©©é‚‚‚×XXX¿000£ƒfff_P@0"  +8GT`fffffffffffffff`TG8+  #/;FQZafffffffffaZQF;/#  $-6?FLQUWXWUQLF?6-$   &,158:::851,&   !"""!    11&.%„&6&>(R ü€' ü€'BasiliskII/src/MacOSX/config_macosx.h0000644000175000017500000000507010736405220017613 0ustar centriscentris/* * config_macosx.h - MacOS X macros determined at compile-time * * $Id: config_macosx.h,v 1.3 2008/01/01 09:40:32 gbeauche Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* Supported platforms are: ppc, ppc64, x86, x86_64 */ #if ! defined __ppc__ && ! defined __ppc64__ && ! defined __i386__ && ! defined __x86_64__ # error "Unsupported architecture. Please fix arch-specific macros" #endif /* Size of data types */ #define SIZEOF_FLOAT 4 #define SIZEOF_DOUBLE 8 #if defined __ppc__ || defined __ppc64__ # if defined __LONG_DOUBLE_128__ # define SIZEOF_LONG_DOUBLE 16 # else # define SIZEOF_LONG_DOUBLE 8 # endif #else # define SIZEOF_LONG_DOUBLE 16 #endif #define SIZEOF_SHORT 2 #define SIZEOF_INT 4 #if defined __ppc64__ || defined __x86_64__ # define SIZEOF_LONG 8 #else # define SIZEOF_LONG 4 #endif #define SIZEOF_LONG_LONG 8 #define SIZEOF_VOID_P SIZEOF_LONG /* ILP32 or LP64 */ /* Endian-ness of data types */ #if ! defined __LITTLE_ENDIAN__ # define WORDS_BIGENDIAN 1 #endif /* Define to the floating point format of the host machine. */ #define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT /* Define to 1 if the host machine stores floating point numbers in memory with the word containing the sign bit at the lowest address, or to 0 if it does it the other way around. This macro should not be defined if the ordering is the same as for multi-word integers. */ /* #undef HOST_FLOAT_WORDS_BIG_ENDIAN */ /* Define if your system supports Mach exceptions. */ #define HAVE_MACH_EXCEPTIONS 1 /* Define to 1 if you have the header file. */ #define HAVE_MACH_MACH_H 1 /* Define to 1 if you have the `mach_task_self' function. */ #define HAVE_MACH_TASK_SELF 1 /* Define if your system has a working vm_allocate()-based memory allocator. */ #define HAVE_MACH_VM 1 /* Define if the __PAGEZERO Mach-O Low Memory Globals hack works. */ #define PAGEZERO_HACK 1 BasiliskII/src/MacOSX/AudioBackEnd.cpp0000644000175000017500000002141010462406746017606 0ustar centriscentris/* * * This is based on Apple example software AudioBackEnd.cpp * * Copyright © 2004 Apple Computer, Inc., All Rights Reserved * Original Apple code modified by Daniel Sumorok * * 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 */ #include "AudioBackEnd.h" #pragma mark ---Public Methods--- AudioBackEnd::AudioBackEnd(int bitsPerSample, int numChannels, int sampleRate): mBitsPerSample(bitsPerSample), mSampleRate(sampleRate), mNumChannels(numChannels), mCallback(NULL), mCallbackArg(NULL), mBufferSizeFrames(0), mFramesProcessed(0), mAudioBuffer(NULL), mAudioBufferWriteIndex(0), mAudioBufferReadIndex(0), mBytesPerFrame(0), mAudioBufferSize(0) { OSStatus err = noErr; err = Init(); if(err) { fprintf(stderr,"AudioBackEnd ERROR: Cannot Init AudioBackEnd"); exit(1); } } AudioBackEnd::~AudioBackEnd() { //clean up Stop(); AUGraphClose(mGraph); DisposeAUGraph(mGraph); if(mAudioBuffer != NULL) { delete mAudioBuffer; mAudioBuffer = NULL; mAudioBufferSize = 0; } } OSStatus AudioBackEnd::Init() { OSStatus err = noErr; err = SetupGraph(); checkErr(err); err = SetupBuffers(); checkErr(err); err = AUGraphInitialize(mGraph); checkErr(err); return err; } #pragma mark --- Operation--- OSStatus AudioBackEnd::Start() { OSStatus err = noErr; if(!IsRunning()) { mFramesProcessed = 0; mAudioBufferWriteIndex = 0; mAudioBufferReadIndex = 0; err = AUGraphStart(mGraph); } return err; } OSStatus AudioBackEnd::Stop() { OSStatus err = noErr; if(IsRunning()) { err = AUGraphStop(mGraph); } return err; } Boolean AudioBackEnd::IsRunning() { OSStatus err = noErr; Boolean graphRunning; err = AUGraphIsRunning(mGraph,&graphRunning); return (graphRunning); } #pragma mark - #pragma mark --Private methods--- OSStatus AudioBackEnd::SetupGraph() { OSStatus err = noErr; AURenderCallbackStruct output; UInt32 size; ComponentDescription outDesc; AudioDeviceID out; //Make a New Graph err = NewAUGraph(&mGraph); checkErr(err); //Open the Graph, AudioUnits are opened but not initialized err = AUGraphOpen(mGraph); checkErr(err); outDesc.componentType = kAudioUnitType_Output; outDesc.componentSubType = kAudioUnitSubType_DefaultOutput; outDesc.componentManufacturer = kAudioUnitManufacturer_Apple; outDesc.componentFlags = 0; outDesc.componentFlagsMask = 0; ////////////////////////// ///MAKE NODES //This creates a node in the graph that is an AudioUnit, using //the supplied ComponentDescription to find and open that unit err = AUGraphNewNode(mGraph, &outDesc, 0, NULL, &mOutputNode); checkErr(err); //Get Audio Units from AUGraph node err = AUGraphGetNodeInfo(mGraph, mOutputNode, NULL, NULL, NULL, &mOutputUnit); checkErr(err); err = AUGraphUpdate(mGraph, NULL); checkErr(err); size = sizeof(AudioDeviceID); err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &out); checkErr(err); mOutputDevice.Init(out, false); //Set the Current Device to the Default Output Unit. err = AudioUnitSetProperty(mOutputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &out, sizeof(out)); checkErr(err); output.inputProc = OutputProc; output.inputProcRefCon = this; err = AudioUnitSetProperty(mOutputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output)); checkErr(err); return err; } //Allocate Audio Buffer List(s) to hold the data from input. OSStatus AudioBackEnd::SetupBuffers() { OSStatus err = noErr; UInt32 safetyOffset; AudioStreamBasicDescription asbd; UInt32 propertySize; propertySize = sizeof(mBufferSizeFrames); err = AudioUnitGetProperty(mOutputUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &mBufferSizeFrames, &propertySize); propertySize = sizeof(safetyOffset); safetyOffset = 0; err = AudioUnitGetProperty(mOutputUnit, kAudioDevicePropertySafetyOffset, kAudioUnitScope_Global, 0, &safetyOffset, &propertySize); asbd.mFormatID = 0x6c70636d; // 'lpcm' asbd.mFormatFlags = (kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsPacked); asbd.mChannelsPerFrame = mNumChannels; asbd.mSampleRate = mSampleRate; if(asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) { asbd.mBitsPerChannel = mBitsPerSample; } else if(asbd.mFormatFlags & kAudioFormatFlagIsFloat) { asbd.mBitsPerChannel = 32; } else { asbd.mBitsPerChannel = 0; } asbd.mFramesPerPacket = 1; asbd.mBytesPerFrame = (asbd.mBitsPerChannel / 8) * asbd.mChannelsPerFrame; asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket; asbd.mReserved = 0; mBytesPerFrame = asbd.mBytesPerFrame; if((mBytesPerFrame & (mBytesPerFrame - 1)) != 0) { printf("Audio buffer size must be a power of two!\n"); return -1; } propertySize = sizeof(asbd); err = AudioUnitSetProperty(mOutputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &asbd, propertySize); checkErr(err); if(mAudioBuffer != NULL) { delete mAudioBuffer; mAudioBufferSize = 0; } mAudioBufferSize = mBytesPerFrame * mBufferSizeFrames * 2; mAudioBuffer = new UInt8[mAudioBufferSize]; bzero(mAudioBuffer, mAudioBufferSize); return err; } #pragma mark - #pragma mark -- IO Procs -- OSStatus AudioBackEnd::OutputProc(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *TimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { OSStatus err = noErr; AudioBackEnd *This = (AudioBackEnd *)inRefCon; UInt8 *dstPtr; UInt32 bytesToCopy; UInt32 bytesUntilEnd; This->mFramesProcessed += inNumberFrames; dstPtr = (UInt8 *)ioData->mBuffers[0].mData; if(This->mAudioBuffer == NULL) { bzero(dstPtr, inNumberFrames * This->mBytesPerFrame); return noErr; } bytesToCopy = inNumberFrames * This->mBytesPerFrame; bytesUntilEnd = This->mAudioBufferSize - This->mAudioBufferReadIndex; if(bytesUntilEnd < bytesToCopy) { memcpy(dstPtr, &This->mAudioBuffer[This->mAudioBufferReadIndex], bytesUntilEnd); memcpy(dstPtr, This->mAudioBuffer, bytesToCopy - bytesUntilEnd); This->mAudioBufferReadIndex = bytesToCopy - bytesUntilEnd; } else { memcpy(dstPtr, &This->mAudioBuffer[This->mAudioBufferReadIndex], bytesToCopy); This->mAudioBufferReadIndex += bytesToCopy; } while(This->mFramesProcessed >= This->mBufferSizeFrames) { This->mFramesProcessed -= This->mBufferSizeFrames; if(This->mCallback != NULL) { This->mCallback(This->mCallbackArg); } } return err; } void AudioBackEnd::setCallback(playthruCallback func, void *arg) { mCallback = func; mCallbackArg = arg; } UInt32 AudioBackEnd::BufferSizeFrames() { return mBufferSizeFrames; } int AudioBackEnd::sendAudioBuffer(void *buffer, int numFrames) { UInt8 *dstBuffer; int totalBytes; mAudioBufferWriteIndex += (mAudioBufferSize / 2); mAudioBufferWriteIndex &= (mAudioBufferSize - 1); dstBuffer = &mAudioBuffer[mAudioBufferWriteIndex]; totalBytes = mBytesPerFrame * numFrames; memcpy(dstBuffer, buffer, totalBytes); dstBuffer += totalBytes; bzero(dstBuffer, (mBufferSizeFrames * mBytesPerFrame) - totalBytes); return numFrames; } BasiliskII/src/MacOSX/Emulator.mm0000644000175000017500000002436111263327363016761 0ustar centriscentris/* * Emulator.mm - Class whose actions are attached to GUI widgets in a window, * used to control a single Basilisk II emulated Macintosh. * * $Id: Emulator.mm,v 1.14 2009/10/08 09:20:51 nigel Exp $ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #import "Emulator.h" #import "EmulatorView.h" #import "sysdeps.h" // Types used in Basilisk C++ code #import "main_macosx.h" // Prototypes for QuitEmuNoExit() and InitEmulator() #import "misc_macosx.h" // Some other prototypes #import "video_macosx.h" // Some window/view globals #import "adb.h" #import "main.h" #import "prefs.h" #import "timer.h" #undef check // memory.h defines a check macro, // which may clash with an OS X one on 10.1 or 10.2 #import "cpu_emulation.h" #define DEBUG 0 #import "debug.h" @implementation Emulator // NSWindow method, which is invoked via delegation - (BOOL) windowShouldClose: (id)sender { if ( uaeCreated ) { NSLog(@"windowShouldClose returning NO"); return NO; // Should initiate poweroff and return NSTerminateLater ? } NSLog(@"windowShouldClose returning YES"); return YES; } // Default methods - (Emulator *) init { int frameSkip; self = [super init]; running = NO; // Save churn when application loads // running = YES; uaeCreated = NO; frameSkip = PrefsFindInt32("frameskip"); if ( frameSkip ) redrawDelay = frameSkip / 60.0; else redrawDelay = 0.0; // We do this so that we can work out if we are in full screen mode: parse_screen_prefs(PrefsFindString("screen")); [self createThreads]; return self; } - (void) awakeFromNib { the_win = win; // Set global for access by Basilisk C++ code [win setDelegate: self]; // Enable windowShouldClose calling // Try to speed up everything //[win setHasShadow: NO]; // This causes view & window to now be drawn correctly [win useOptimizedDrawing: YES]; [win makeKeyAndOrderFront:self]; if ( redrawDelay ) [speed setFloatValue: 1.0 / redrawDelay]; else [speed setFloatValue: 60.0]; if ( runOrPause == nil ) NSLog(@"%s - runOrPause button pointer is nil!", __PRETTY_FUNCTION__); [self runUpdate]; } // Helpers which other classes use to access our private stuff - (BOOL) isRunning { return running; } - (BOOL) uaeCreated { return uaeCreated; } - (EmulatorView *) screen { return screen; } - (NSSlider *) speed { return speed; } - (NSWindow *) window { return win; } // Update some UI elements - (void) runUpdate { if ( running ) [runOrPause setState: NSOnState]; // Running. Change button label to 'Pause' else [runOrPause setState: NSOffState]; // Paused. Change button label to 'Run' [win setDocumentEdited: uaeCreated]; // Set the little dimple in the close button } // Methods invoked by buttons & menu items - (IBAction) Benchmark: (id)sender; { BOOL wasRunning = running; if ( running ) [self Suspend: self]; [screen benchmark]; if ( wasRunning ) [self Resume: self]; } #ifdef NIGEL - (IBAction) EjectCD: (id)sender; { NSString *path; const char *cdrom = PrefsFindString("cdrom"); if ( cdrom ) { #include #define KERNEL #include struct statfs buf; if ( fsstat(path, &buf) < 0 ) return; path = [NSString stringWithCString: cdrom]; [[NSWorkspace sharedWorkspace] unmountAndEjectDeviceAtPath: path]; // [path release]; } } #endif - (IBAction) Interrupt: (id)sender; { WarningSheet (@"Interrupt action not yet supported", win); } - (IBAction) PowerKey: (id)sender; { if ( uaeCreated ) // If Mac has started { ADBKeyDown(0x7f); // Send power key, which is also ADBKeyUp(0x7f); // called ADB_RESET or ADB_POWER } else { running = YES; // Start emulator [self runUpdate]; [self Resume: nil]; } } - (IBAction) Restart: (id)sender { if ( ! running ) { running = YES; // Start emulator [self runUpdate]; [self Resume: nil]; } if ( running ) #ifdef UAE_CPU_HAS_RESET reset680x0(); #else { uaeCreated = NO; [redraw suspend]; NSLog (@"%s - uae_cpu reset not yet supported, will try to fake it", __PRETTY_FUNCTION__); [screen clear]; [screen display]; [emul terminate]; QuitEmuNoExit(); // OK. We have killed & cleaned up. Now, start afresh: #include int argc = 0; char **argv; PrefsInit(NULL, argc, argv); SysInit(); emul = [NNThread new]; [emul perform:@selector(emulThread) of:self]; [emul start]; if ( display_type != DISPLAY_SCREEN ) [redraw resume]; } #endif } - (IBAction) Resume: (id)sender { [RTC resume]; [emul resume]; if ( display_type != DISPLAY_SCREEN ) [redraw resume]; [tick resume]; [xPRAM resume]; } - (IBAction) ScreenHideShow: (NSButton *)sender; { WarningSheet(@"Nigel doesn't know how to shrink or grow this window", @"Maybe you can grab the source code and have a go yourself?", nil, win); } - (IBAction) Snapshot: (id) sender { if ( screen == nil || uaeCreated == NO ) WarningSheet(@"The emulator has not yet started.", @"There is no screen output to snapshot", nil, win); else { NSData *TIFFdata; [self Suspend: self]; TIFFdata = [screen TIFFrep]; if ( TIFFdata == nil ) NSLog(@"%s - Unable to convert Basilisk screen to a TIFF representation", __PRETTY_FUNCTION__); else { NSSavePanel *sp = [NSSavePanel savePanel]; [sp setRequiredFileType:@"tiff"]; if ( [sp runModalForDirectory:NSHomeDirectory() file:@"B2-screen-snapshot.tiff"] == NSOKButton ) if ( ! [TIFFdata writeToFile:[sp filename] atomically:YES] ) NSLog(@"%s - Could not write TIFF data to file @%", __PRETTY_FUNCTION__, [sp filename]); } if ( running ) [self Resume: self]; } } - (IBAction) SpeedChange: (NSSlider *)sender { float frequency = [sender floatValue]; [redraw suspend]; if ( frequency == 0.0 ) redrawDelay = 0.0; else { frequencyToTickDelay(frequency); redrawDelay = 1.0 / frequency; [redraw changeIntervalTo: (int)(redrawDelay * 1e6) units: NNmicroSeconds]; if ( running && display_type != DISPLAY_SCREEN ) [redraw resume]; } } - (IBAction) Suspend: (id)sender { [RTC suspend]; [emul suspend]; [redraw suspend]; [tick suspend]; [xPRAM suspend]; } - (IBAction) ToggleState: (NSButton *)sender { running = [sender state]; // State of the toggled NSButton if ( running ) [self Resume: nil]; else [self Suspend: nil]; } - (IBAction) Terminate: (id)sender; { [self exitThreads]; [win performClose: self]; } #include #define XPRAM_SIZE 256 uint8 lastXPRAM[XPRAM_SIZE]; // Copy of PRAM - (IBAction) ZapPRAM: (id)sender; { memset(XPRAM, 0, XPRAM_SIZE); memset(lastXPRAM, 0, XPRAM_SIZE); ZapPRAM(); } // // Threads, Timers and stuff to manage them: // - (void) createThreads { #ifdef USE_PTHREADS // Make UI threadsafe: [NSThread detachNewThreadSelector:(SEL)"" toTarget:nil withObject:nil]; //emul = [[NNThread alloc] initWithAutoReleasePool]; #endif emul = [NNThread new]; RTC = [NNTimer new]; redraw = [[NNTimer alloc] initWithAutoRelPool]; tick = [NNTimer new]; xPRAM = [NNTimer new]; [emul perform:@selector(emulThread) of:self]; [RTC repeat:@selector(RTCinterrupt) of:self every:1 units:NNseconds]; [redraw repeat:@selector(redrawScreen) of:self every:(int)(1000*redrawDelay) units:NNmilliSeconds]; [tick repeat:@selector(tickInterrupt) of:self every:16625 units:NNmicroSeconds]; [xPRAM repeat:@selector(xPRAMbackup) of:self every:60 units:NNseconds]; if ( running ) // Start emulator, then threads in most economical order { [emul start]; [xPRAM start]; [RTC start]; if ( display_type != DISPLAY_SCREEN ) [redraw start]; [tick start]; } } - (void) exitThreads { running = NO; [emul terminate]; [emul release]; emul = nil; [tick invalidate]; [tick release]; tick = nil; [redraw invalidate]; [redraw release]; redraw = nil; [RTC invalidate]; [RTC release]; RTC = nil; [xPRAM invalidate]; [xPRAM release]; xPRAM = nil; } - (void) emulThread { NSAutoreleasePool *pool = [NSAutoreleasePool new]; if ( ! InitEmulator() ) { [redraw suspend]; // Stop the barberpole ErrorSheet(@"Cannot start Emulator", @"", @"Quit", win); } else { memcpy(lastXPRAM, XPRAM, XPRAM_SIZE); uaeCreated = YES; // Enable timers to access emulated Mac's memory while ( screen == nil ) // If we are still loading from Nib? [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow: 1.0]]; [self runUpdate]; // Set the window close gadget to dimpled Start680x0(); // Start 68k and jump to ROM boot routine puts ("Emulator exited normally"); } [pool release]; QuitEmulator(); } - (void) RTCinterrupt { if ( ! uaeCreated ) return; WriteMacInt32 (0x20c, TimerDateTime() ); // Update MacOS time SetInterruptFlag(INTFLAG_1HZ); TriggerInterrupt(); } - (void) redrawScreen { if ( display_type == DISPLAY_SCREEN ) { NSLog(@"We are in fullscreen mode - why was redrawScreen() called?"); return; } [barberPole animate:self]; // wobble the pole [screen setNeedsDisplay: YES]; // redisplay next time through runLoop // Or, use a direct method. e.g. // [screen display] or [screen cgDrawInto: ...]; } #include // For #define INTFLAG_60HZ #include // For ROMVersion #include "macos_util_macosx.h" // For HasMacStarted() - (void) tickInterrupt { if ( ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted() ) { SetInterruptFlag (INTFLAG_60HZ); TriggerInterrupt (); } } - (void) xPRAMbackup { if ( uaeCreated && memcmp(lastXPRAM, XPRAM, XPRAM_SIZE) ) // if PRAM changed from copy { memcpy (lastXPRAM, XPRAM, XPRAM_SIZE); // re-copy SaveXPRAM (); // and save to disk } } @end BasiliskII/src/MacOSX/BasiliskII.pbproj/0000755000175000017500000000000011735674761020121 5ustar centriscentrisBasiliskII/src/MacOSX/BasiliskII.pbproj/project.pbxproj0000644000175000017500000012666610355111663023176 0ustar centriscentris// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 34; objects = { 00EC0D3FFFF8DE1B95877872 = { fileEncoding = 4; isa = PBXFileReference; path = misc_macosx.mm; refType = 2; }; 00EC0D43FFF8DF2B95877872 = { fileRef = 29B97324FDCFA39411CA2CEA; isa = PBXBuildFile; settings = { }; }; 00EC0D44FFF8DF2B95877872 = { fileRef = 29B97325FDCFA39411CA2CEA; isa = PBXBuildFile; settings = { }; }; 00EC2983FFEE9C5495877872 = { isa = PBXFileReference; path = NNThread.h; refType = 2; }; 00EC2984FFEE9C5495877872 = { isa = PBXFileReference; path = NNThread.m; refType = 2; }; 00EC2986FFEE9C5495877872 = { fileRef = 00EC2984FFEE9C5495877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00EC4BFDFFD1D45E95877872 = { isa = PBXFileReference; path = misc_macosx.h; refType = 2; }; 00ED5A0FFF9F1BC995877872 = { isa = PBXFileReference; name = adb.h; path = ../include/adb.h; refType = 2; }; 00ED5A10FF9F1BC995877872 = { isa = PBXFileReference; name = audio.h; path = ../include/audio.h; refType = 2; }; 00ED5A11FF9F1BC995877872 = { isa = PBXFileReference; name = audio_defs.h; path = ../include/audio_defs.h; refType = 2; }; 00ED5A12FF9F1BC995877872 = { isa = PBXFileReference; name = cdrom.h; path = ../include/cdrom.h; refType = 2; }; 00ED5A13FF9F1BC995877872 = { isa = PBXFileReference; name = clip.h; path = ../include/clip.h; refType = 2; }; 00ED5A14FF9F1BC995877872 = { isa = PBXFileReference; name = debug.h; path = ../include/debug.h; refType = 2; }; 00ED5A15FF9F1BC995877872 = { isa = PBXFileReference; name = disk.h; path = ../include/disk.h; refType = 2; }; 00ED5A16FF9F1BC995877872 = { isa = PBXFileReference; name = emul_op.h; path = ../include/emul_op.h; refType = 2; }; 00ED5A17FF9F1BC995877872 = { isa = PBXFileReference; name = ether.h; path = ../include/ether.h; refType = 2; }; 00ED5A18FF9F1BC995877872 = { isa = PBXFileReference; name = ether_defs.h; path = ../include/ether_defs.h; refType = 2; }; 00ED5A19FF9F1BC995877872 = { isa = PBXFileReference; name = extfs.h; path = ../include/extfs.h; refType = 2; }; 00ED5A1AFF9F1BC995877872 = { isa = PBXFileReference; name = extfs_defs.h; path = ../include/extfs_defs.h; refType = 2; }; 00ED5A1BFF9F1BC995877872 = { isa = PBXFileReference; name = macos_util.h; path = ../include/macos_util.h; refType = 2; }; 00ED5A1CFF9F1BC995877872 = { isa = PBXFileReference; name = main.h; path = ../include/main.h; refType = 2; }; 00ED5A1DFF9F1BC995877872 = { isa = PBXFileReference; name = prefs.h; path = ../include/prefs.h; refType = 2; }; 00ED5A1EFF9F1BC995877872 = { isa = PBXFileReference; name = prefs_editor.h; path = ../include/prefs_editor.h; refType = 2; }; 00ED5A1FFF9F1BC995877872 = { isa = PBXFileReference; name = rom_patches.h; path = ../include/rom_patches.h; refType = 2; }; 00ED5A20FF9F1BC995877872 = { isa = PBXFileReference; name = rsrc_patches.h; path = ../include/rsrc_patches.h; refType = 2; }; 00ED5A21FF9F1BC995877872 = { isa = PBXFileReference; name = scsi.h; path = ../include/scsi.h; refType = 2; }; 00ED5A22FF9F1BC995877872 = { isa = PBXFileReference; name = serial.h; path = ../include/serial.h; refType = 2; }; 00ED5A23FF9F1BC995877872 = { isa = PBXFileReference; name = serial_defs.h; path = ../include/serial_defs.h; refType = 2; }; 00ED5A24FF9F1BC995877872 = { isa = PBXFileReference; name = slot_rom.h; path = ../include/slot_rom.h; refType = 2; }; 00ED5A25FF9F1BC995877872 = { isa = PBXFileReference; name = sony.h; path = ../include/sony.h; refType = 2; }; 00ED5A26FF9F1BC995877872 = { isa = PBXFileReference; name = sys.h; path = ../include/sys.h; refType = 2; }; 00ED5A27FF9F1BC995877872 = { isa = PBXFileReference; name = timer.h; path = ../include/timer.h; refType = 2; }; 00ED5A28FF9F1BC995877872 = { isa = PBXFileReference; name = user_strings.h; path = ../include/user_strings.h; refType = 2; }; 00ED5A29FF9F1BC995877872 = { isa = PBXFileReference; name = version.h; path = ../include/version.h; refType = 2; }; 00ED5A2AFF9F1BC995877872 = { isa = PBXFileReference; name = video.h; path = ../include/video.h; refType = 2; }; 00ED5A2BFF9F1BC995877872 = { isa = PBXFileReference; name = video_defs.h; path = ../include/video_defs.h; refType = 2; }; 00ED5A2CFF9F1BC995877872 = { isa = PBXFileReference; name = xpram.h; path = ../include/xpram.h; refType = 2; }; 00ED5A2DFF9F1BC995877872 = { fileRef = 00ED5A0FFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A2EFF9F1BC995877872 = { fileRef = 00ED5A10FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A2FFF9F1BC995877872 = { fileRef = 00ED5A11FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A30FF9F1BC995877872 = { fileRef = 00ED5A12FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A31FF9F1BC995877872 = { fileRef = 00ED5A13FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A32FF9F1BC995877872 = { fileRef = 00ED5A14FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A33FF9F1BC995877872 = { fileRef = 00ED5A15FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A34FF9F1BC995877872 = { fileRef = 00ED5A16FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A35FF9F1BC995877872 = { fileRef = 00ED5A17FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A36FF9F1BC995877872 = { fileRef = 00ED5A18FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A37FF9F1BC995877872 = { fileRef = 00ED5A19FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A38FF9F1BC995877872 = { fileRef = 00ED5A1AFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A39FF9F1BC995877872 = { fileRef = 00ED5A1BFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A3AFF9F1BC995877872 = { fileRef = 00ED5A1CFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A3BFF9F1BC995877872 = { fileRef = 00ED5A1DFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A3CFF9F1BC995877872 = { fileRef = 00ED5A1EFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A3DFF9F1BC995877872 = { fileRef = 00ED5A1FFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A3EFF9F1BC995877872 = { fileRef = 00ED5A20FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A3FFF9F1BC995877872 = { fileRef = 00ED5A21FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A40FF9F1BC995877872 = { fileRef = 00ED5A22FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A41FF9F1BC995877872 = { fileRef = 00ED5A23FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A42FF9F1BC995877872 = { fileRef = 00ED5A24FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A43FF9F1BC995877872 = { fileRef = 00ED5A25FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A44FF9F1BC995877872 = { fileRef = 00ED5A26FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A45FF9F1BC995877872 = { fileRef = 00ED5A27FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A46FF9F1BC995877872 = { fileRef = 00ED5A28FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A47FF9F1BC995877872 = { fileRef = 00ED5A29FF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A48FF9F1BC995877872 = { fileRef = 00ED5A2AFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A49FF9F1BC995877872 = { fileRef = 00ED5A2BFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A4AFF9F1BC995877872 = { fileRef = 00ED5A2CFF9F1BC995877872; isa = PBXBuildFile; settings = { }; }; 00ED5A50FF9F41EE95877872 = { children = ( 00ED5A65FF9F427D95877872, 00ED5A64FF9F427D95877872, 00ED5A66FF9F427D95877872, 00ED5A67FF9F427D95877872, 00ED5A68FF9F427D95877872, 00ED5A69FF9F427D95877872, 00ED5A6AFF9F427D95877872, 00ED5A6BFF9F427D95877872, 00ED5A51FF9F41EE95877872, 00ED5A52FF9F41EE95877872, 00ED5A53FF9F41EE95877872, 00ED5A54FF9F41EE95877872, 00ED5A55FF9F41EE95877872, 00ED5A56FF9F41EE95877872, 00ED5A57FF9F41EE95877872, 00ED5A58FF9F41EE95877872, 00ED5A59FF9F41EE95877872, 00ED5A6CFF9F427D95877872, 00ED5A6DFF9F427D95877872, 00ED5A6EFF9F427D95877872, 03958313007872167F000001, ); isa = PBXGroup; name = common; refType = 4; }; 00ED5A51FF9F41EE95877872 = { isa = PBXFileReference; name = main.cpp; path = ../main.cpp; refType = 2; }; 00ED5A52FF9F41EE95877872 = { isa = PBXFileReference; name = prefs.cpp; path = ../prefs.cpp; refType = 2; }; 00ED5A53FF9F41EE95877872 = { isa = PBXFileReference; name = rom_patches.cpp; path = ../rom_patches.cpp; refType = 2; }; 00ED5A54FF9F41EE95877872 = { isa = PBXFileReference; name = rsrc_patches.cpp; path = ../rsrc_patches.cpp; refType = 2; }; 00ED5A55FF9F41EE95877872 = { isa = PBXFileReference; name = scsi.cpp; path = ../scsi.cpp; refType = 2; }; 00ED5A56FF9F41EE95877872 = { isa = PBXFileReference; name = serial.cpp; path = ../serial.cpp; refType = 2; }; 00ED5A57FF9F41EE95877872 = { isa = PBXFileReference; name = slot_rom.cpp; path = ../slot_rom.cpp; refType = 2; }; 00ED5A58FF9F41EE95877872 = { isa = PBXFileReference; name = sony.cpp; path = ../sony.cpp; refType = 2; }; 00ED5A59FF9F41EE95877872 = { isa = PBXFileReference; name = timer.cpp; path = ../timer.cpp; refType = 2; }; 00ED5A5AFF9F41EE95877872 = { children = ( 1A5BA124008C04377F000001, 021D87E7FF9F440695877872, 04D13625FF9F17C295877872, 04D13627FF9F182095877872, 00F248B9FF9FB3E495877872, ); isa = PBXGroup; name = dummy; path = ""; refType = 2; }; 00ED5A5BFF9F41EE95877872 = { fileRef = 00ED5A59FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A5CFF9F41EE95877872 = { fileRef = 00ED5A51FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A5EFF9F41EE95877872 = { fileRef = 00ED5A53FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A5FFF9F41EE95877872 = { fileRef = 00ED5A54FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A60FF9F41EE95877872 = { fileRef = 00ED5A55FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A61FF9F41EE95877872 = { fileRef = 00ED5A56FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A62FF9F41EE95877872 = { fileRef = 00ED5A57FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A63FF9F41EE95877872 = { fileRef = 00ED5A58FF9F41EE95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A64FF9F427D95877872 = { isa = PBXFileReference; name = audio.cpp; path = ../audio.cpp; refType = 2; }; 00ED5A65FF9F427D95877872 = { isa = PBXFileReference; name = adb.cpp; path = ../adb.cpp; refType = 2; }; 00ED5A66FF9F427D95877872 = { isa = PBXFileReference; name = cdrom.cpp; path = ../cdrom.cpp; refType = 2; }; 00ED5A67FF9F427D95877872 = { isa = PBXFileReference; name = disk.cpp; path = ../disk.cpp; refType = 2; }; 00ED5A68FF9F427D95877872 = { isa = PBXFileReference; name = emul_op.cpp; path = ../emul_op.cpp; refType = 2; }; 00ED5A69FF9F427D95877872 = { isa = PBXFileReference; name = ether.cpp; path = ../ether.cpp; refType = 2; }; 00ED5A6AFF9F427D95877872 = { isa = PBXFileReference; name = extfs.cpp; path = ../extfs.cpp; refType = 2; }; 00ED5A6BFF9F427D95877872 = { isa = PBXFileReference; name = macos_util.cpp; path = ../macos_util.cpp; refType = 2; }; 00ED5A6CFF9F427D95877872 = { isa = PBXFileReference; name = user_strings.cpp; path = ../user_strings.cpp; refType = 2; }; 00ED5A6DFF9F427D95877872 = { isa = PBXFileReference; name = video.cpp; path = ../video.cpp; refType = 2; }; 00ED5A6EFF9F427D95877872 = { isa = PBXFileReference; name = xpram.cpp; path = ../xpram.cpp; refType = 2; }; 00ED5A6FFF9F427D95877872 = { fileRef = 00ED5A6CFF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A70FF9F427D95877872 = { fileRef = 00ED5A6DFF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A71FF9F427D95877872 = { fileRef = 00ED5A6EFF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A72FF9F427D95877872 = { fileRef = 00ED5A6BFF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A73FF9F427D95877872 = { fileRef = 00ED5A68FF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A74FF9F427D95877872 = { fileRef = 00ED5A69FF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A76FF9F427D95877872 = { fileRef = 00ED5A66FF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A77FF9F427D95877872 = { fileRef = 00ED5A67FF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A78FF9F427D95877872 = { fileRef = 00ED5A65FF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A79FF9F427D95877872 = { fileRef = 00ED5A64FF9F427D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A7AFF9F42A995877872 = { children = ( 00F248BDFF9FB58D95877872, 00ED5A7BFF9F42CA95877872, 00F248D5FFA011DD95877872, F5BACDE8042F21EF01A80001, 338FF87200CF1E867F000001, 00ED5A83FF9F42CA95877872, 00ED5A84FF9F42CA95877872, 00ED5A85FF9F42CA95877872, 00ED5A86FF9F42CA95877872, 00ED5A87FF9F42CA95877872, 00ED5A88FF9F42CA95877872, 00ED5A89FF9F42CA95877872, ); isa = PBXGroup; name = uae_cpu; refType = 4; }; 00ED5A7BFF9F42CA95877872 = { isa = PBXFileReference; name = basilisk_glue.cpp; path = ../uae_cpu/basilisk_glue.cpp; refType = 2; }; 00ED5A83FF9F42CA95877872 = { isa = PBXFileReference; name = m68k.h; path = ../uae_cpu/m68k.h; refType = 2; }; 00ED5A84FF9F42CA95877872 = { isa = PBXFileReference; name = memory.cpp; path = ../uae_cpu/memory.cpp; refType = 2; }; 00ED5A85FF9F42CA95877872 = { isa = PBXFileReference; name = memory.h; path = ../uae_cpu/memory.h; refType = 2; }; 00ED5A86FF9F42CA95877872 = { isa = PBXFileReference; name = newcpu.cpp; path = ../uae_cpu/newcpu.cpp; refType = 2; }; 00ED5A87FF9F42CA95877872 = { isa = PBXFileReference; name = newcpu.h; path = ../uae_cpu/newcpu.h; refType = 2; }; 00ED5A88FF9F42CA95877872 = { isa = PBXFileReference; name = readcpu.cpp; path = ../uae_cpu/readcpu.cpp; refType = 2; }; 00ED5A89FF9F42CA95877872 = { isa = PBXFileReference; name = readcpu.h; path = ../uae_cpu/readcpu.h; refType = 2; }; 00ED5A8BFF9F42CA95877872 = { fileRef = 00ED5A83FF9F42CA95877872; isa = PBXBuildFile; settings = { }; }; 00ED5A8CFF9F42CA95877872 = { fileRef = 00ED5A85FF9F42CA95877872; isa = PBXBuildFile; settings = { }; }; 00ED5A8DFF9F42CA95877872 = { fileRef = 00ED5A87FF9F42CA95877872; isa = PBXBuildFile; settings = { }; }; 00ED5A8EFF9F42CA95877872 = { fileRef = 00ED5A89FF9F42CA95877872; isa = PBXBuildFile; settings = { }; }; 00ED5A92FF9F42CA95877872 = { fileRef = 00ED5A7BFF9F42CA95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A98FF9F42CA95877872 = { fileRef = 00ED5A84FF9F42CA95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A99FF9F42CA95877872 = { fileRef = 00ED5A86FF9F42CA95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00ED5A9AFF9F42CA95877872 = { fileRef = 00ED5A88FF9F42CA95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00F23975FFC35BA495877872 = { isa = PBXFileReference; path = EmulatorView.h; refType = 2; }; 00F23976FFC35BA495877872 = { isa = PBXFileReference; path = EmulatorView.mm; refType = 2; }; 00F23978FFC35BA495877872 = { fileRef = 00F23976FFC35BA495877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00F248B9FF9FB3E495877872 = { isa = PBXFileReference; name = serial_dummy.cpp; path = ../dummy/serial_dummy.cpp; refType = 2; }; 00F248BAFF9FB3E495877872 = { fileRef = 00F248B9FF9FB3E495877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00F248BDFF9FB58D95877872 = { children = ( 00F248BEFF9FB58D95877872, F644DFFC02435DC30108A02E, F644DFFD02435DC30108A02E, F644DFFE02435DC30108A02E, F644DFFF02435DC30108A02E, F644E00002435DC30108A02E, F644E00102435DC30108A02E, F644E00202435DC30108A02E, F644E00302435DC30108A02E, 00F248C0FF9FB58D95877872, 00F248C1FF9FB58D95877872, ); isa = PBXGroup; name = Generated; refType = 4; }; 00F248BEFF9FB58D95877872 = { isa = PBXFileReference; path = cpudefs.cpp; refType = 2; }; 00F248C0FF9FB58D95877872 = { isa = PBXFileReference; path = cpustbl.cpp; refType = 2; }; 00F248C1FF9FB58D95877872 = { isa = PBXFileReference; path = cputbl.h; refType = 2; }; 00F248C2FF9FB58D95877872 = { fileRef = 00F248C1FF9FB58D95877872; isa = PBXBuildFile; settings = { }; }; 00F248C3FF9FB58D95877872 = { fileRef = 00F248BEFF9FB58D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00F248C5FF9FB58D95877872 = { fileRef = 00F248C0FF9FB58D95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 00F248D5FFA011DD95877872 = { isa = PBXFileReference; name = cpu_emulation.h; path = ../uae_cpu/cpu_emulation.h; refType = 2; }; 00F248D6FFA011DD95877872 = { fileRef = 00F248D5FFA011DD95877872; isa = PBXBuildFile; settings = { }; }; //000 //001 //002 //003 //004 //010 //011 //012 //013 //014 0107BC67000E46CF95877872 = { isa = PBXFileReference; path = PrefsEditor.h; refType = 2; }; 0107BC68000E46CF95877872 = { isa = PBXFileReference; path = PrefsEditor.mm; refType = 2; }; 0107BC6A000E46CF95877872 = { fileRef = 0107BC68000E46CF95877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 01159A85003A9D6195877872 = { isa = PBXFileReference; path = Controller.h; refType = 2; }; 011A888DFFE976C995877872 = { children = ( 00ED5A0FFF9F1BC995877872, 00ED5A10FF9F1BC995877872, 00ED5A11FF9F1BC995877872, 00ED5A12FF9F1BC995877872, 00ED5A13FF9F1BC995877872, 00ED5A14FF9F1BC995877872, 00ED5A15FF9F1BC995877872, 00ED5A16FF9F1BC995877872, 00ED5A17FF9F1BC995877872, 00ED5A18FF9F1BC995877872, 00ED5A19FF9F1BC995877872, 00ED5A1AFF9F1BC995877872, 00ED5A1BFF9F1BC995877872, 00ED5A1CFF9F1BC995877872, 00ED5A1DFF9F1BC995877872, 00ED5A1EFF9F1BC995877872, 00ED5A1FFF9F1BC995877872, 00ED5A20FF9F1BC995877872, 00ED5A21FF9F1BC995877872, 00ED5A22FF9F1BC995877872, 00ED5A23FF9F1BC995877872, 00ED5A24FF9F1BC995877872, 00ED5A25FF9F1BC995877872, 00ED5A26FF9F1BC995877872, 00ED5A27FF9F1BC995877872, 00ED5A28FF9F1BC995877872, 00ED5A29FF9F1BC995877872, 00ED5A2AFF9F1BC995877872, 00ED5A2BFF9F1BC995877872, 00ED5A2CFF9F1BC995877872, ); isa = PBXGroup; name = include; path = ""; refType = 4; }; 011D89AA0071AA4C7F000001 = { buildRules = ( ); buildSettings = { COPY_PHASE_STRIP = NO; OPTIMIZATION_CFLAGS = "-O0"; }; isa = PBXBuildStyle; name = Development; }; 011D89AB0071AA4C7F000001 = { buildRules = ( ); buildSettings = { COPY_PHASE_STRIP = YES; OPTIMIZATION_CFLAGS = "-O3"; }; isa = PBXBuildStyle; name = Deployment; }; 0130A85800A96A627F000001 = { isa = PBXFileReference; path = sysdeps.h; refType = 2; }; 0160729200BCA6097F000001 = { isa = PBXFrameworkReference; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; refType = 0; }; 0160729300BCA6097F000001 = { fileRef = 0160729200BCA6097F000001; isa = PBXBuildFile; settings = { }; }; 018DC3970071BA107F000001 = { isa = PBXFileReference; path = BasiliskII.icns; refType = 4; }; 018DC3980071BA107F000001 = { fileRef = 018DC3970071BA107F000001; isa = PBXBuildFile; settings = { }; }; 0193367AFFD1B91B95877872 = { children = ( 0193367BFFD1B98495877872, F5028E5F04DB9DD30135D59B, 0193367EFFD1BA0395877872, 0193367FFFD1BA0395877872, 01933680FFD1BA0395877872, 01933681FFD1BA0395877872, F59F45A4020E2BD601A80001, F59F45A5020E2BD601A80001, 01933682FFD1BA0395877872, ); isa = PBXGroup; name = "generic Unix"; path = ""; refType = 4; }; 0193367BFFD1B98495877872 = { isa = PBXFileReference; name = ether_unix.cpp; path = ../Unix/ether_unix.cpp; refType = 2; }; 0193367EFFD1BA0395877872 = { isa = PBXFileReference; name = sys_unix.cpp; path = ../Unix/sys_unix.cpp; refType = 2; }; 0193367FFFD1BA0395877872 = { isa = PBXFileReference; name = timer_unix.cpp; path = ../Unix/timer_unix.cpp; refType = 2; }; 01933680FFD1BA0395877872 = { isa = PBXFileReference; name = user_strings_unix.cpp; path = ../Unix/user_strings_unix.cpp; refType = 2; }; 01933681FFD1BA0395877872 = { isa = PBXFileReference; name = user_strings_unix.h; path = ../Unix/user_strings_unix.h; refType = 2; }; 01933682FFD1BA0395877872 = { isa = PBXFileReference; name = xpram_unix.cpp; path = ../Unix/xpram_unix.cpp; refType = 2; }; 01933683FFD1BA0395877872 = { fileRef = 01933681FFD1BA0395877872; isa = PBXBuildFile; settings = { }; }; 01933685FFD1BA0395877872 = { fileRef = 0193367EFFD1BA0395877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 01933686FFD1BA0395877872 = { fileRef = 0193367FFFD1BA0395877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 01933687FFD1BA0395877872 = { fileRef = 01933680FFD1BA0395877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 01933688FFD1BA0395877872 = { fileRef = 01933682FFD1BA0395877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 01BDE8DC007837927F000001 = { isa = PBXFileReference; path = Versions.html; refType = 2; }; 01BDE8DD007837927F000001 = { fileRef = 01BDE8DC007837927F000001; isa = PBXBuildFile; settings = { }; }; 01BDE8DE0078384A7F000001 = { isa = PBXFileReference; path = ToDo.html; refType = 2; }; 01BDE8DF0078384A7F000001 = { fileRef = 01BDE8DE0078384A7F000001; isa = PBXBuildFile; settings = { }; }; 01BE253E00A65BFA7F000001 = { fileRef = 00ED5A6AFF9F427D95877872; isa = PBXBuildFile; settings = { }; }; //010 //011 //012 //013 //014 //020 //021 //022 //023 //024 021D87E7FF9F440695877872 = { isa = PBXFileReference; name = clip_dummy.cpp; path = ../dummy/clip_dummy.cpp; refType = 2; }; 021D87E9FF9F440695877872 = { fileRef = 021D87E7FF9F440695877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; //020 //021 //022 //023 //024 //030 //031 //032 //033 //034 03958313007872167F000001 = { isa = PBXFileReference; name = prefs_items.cpp; path = ../prefs_items.cpp; refType = 2; }; 03958314007872167F000001 = { fileRef = 03958313007872167F000001; isa = PBXBuildFile; settings = { }; }; //030 //031 //032 //033 //034 //040 //041 //042 //043 //044 043355C9FE30361CC02AAC07 = { buildActionMask = 2147483647; files = ( ); isa = PBXRezBuildPhase; name = "ResourceManager Resources"; }; 04D13618FF9F161695877872 = { children = ( 00ED5A50FF9F41EE95877872, 00ED5A5AFF9F41EE95877872, 011A888DFFE976C995877872, 00ED5A7AFF9F42A995877872, 0193367AFFD1B91B95877872, ); isa = PBXGroup; name = "BasiliskII Sources"; path = ""; refType = 4; }; 04D13625FF9F17C295877872 = { isa = PBXFileReference; name = ether_dummy.cpp; path = ../dummy/ether_dummy.cpp; refType = 2; }; 04D13626FF9F17C295877872 = { fileRef = 04D13625FF9F17C295877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; 04D13627FF9F182095877872 = { isa = PBXFileReference; name = scsi_dummy.cpp; path = ../dummy/scsi_dummy.cpp; refType = 2; }; 04D13628FF9F182095877872 = { fileRef = 04D13627FF9F182095877872; isa = PBXBuildFile; settings = { ATTRIBUTES = ( ); }; }; //040 //041 //042 //043 //044 //050 //051 //052 //053 //054 05CD28AEFFEE4D6995877872 = { isa = PBXFileReference; path = Emulator.h; refType = 2; }; 05CD28AFFFEE4D6995877872 = { isa = PBXFileReference; path = Emulator.mm; refType = 2; }; //050 //051 //052 //053 //054 //080 //081 //082 //083 //084 080E96DCFE201CFB7F000001 = { fileRef = 29B97318FDCFA39411CA2CEA; isa = PBXBuildFile; settings = { }; }; 080E96DDFE201D6D7F000001 = { children = ( 01159A85003A9D6195877872, 0FEE9ED700AF47597F000001, 05CD28AEFFEE4D6995877872, 05CD28AFFFEE4D6995877872, 00F23975FFC35BA495877872, 00F23976FFC35BA495877872, 00EC2983FFEE9C5495877872, 00EC2984FFEE9C5495877872, 0107BC67000E46CF95877872, 0107BC68000E46CF95877872, ); isa = PBXGroup; name = "Objective-C Classes"; path = ""; refType = 4; }; 089C165CFE840E0CC02AAC07 = { children = ( 089C165DFE840E0CC02AAC07, ); isa = PBXVariantGroup; name = InfoPlist.strings; refType = 4; }; 089C165DFE840E0CC02AAC07 = { isa = PBXFileReference; name = English; path = English.lproj/InfoPlist.strings; refType = 4; }; 089C165EFE840E0CC02AAC07 = { fileRef = 089C165CFE840E0CC02AAC07; isa = PBXBuildFile; settings = { }; }; //080 //081 //082 //083 //084 //0F0 //0F1 //0F2 //0F3 //0F4 0FEE9ED700AF47597F000001 = { isa = PBXFileReference; path = Controller.mm; refType = 2; }; 0FEE9ED800AF47597F000001 = { fileRef = 0FEE9ED700AF47597F000001; isa = PBXBuildFile; settings = { }; }; //0F0 //0F1 //0F2 //0F3 //0F4 //100 //101 //102 //103 //104 1058C7A1FEA54F0111CA2CBB = { isa = PBXFrameworkReference; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; refType = 0; }; 1058C7A3FEA54F0111CA2CBB = { fileRef = 1058C7A1FEA54F0111CA2CBB; isa = PBXBuildFile; settings = { }; }; //100 //101 //102 //103 //104 //130 //131 //132 //133 //134 13A81DD900421B6A95877872 = { isa = PBXFileReference; path = nowrite.icns; refType = 2; }; 13A81DDA00421B6A95877872 = { fileRef = 13A81DD900421B6A95877872; isa = PBXBuildFile; settings = { }; }; //130 //131 //132 //133 //134 //170 //171 //172 //173 //174 17587328FF379C6511CA2CBB = { isa = PBXApplicationReference; path = BasiliskII.app; refType = 3; }; //170 //171 //172 //173 //174 //180 //181 //182 //183 //184 18AB34C500AA6EAE7F000001 = { isa = PBXFileReference; path = config.h; refType = 2; }; //180 //181 //182 //183 //184 //190 //191 //192 //193 //194 19C28FACFE9D520D11CA2CBB = { children = ( 17587328FF379C6511CA2CBB, ); isa = PBXGroup; name = Products; refType = 4; }; //190 //191 //192 //193 //194 //1A0 //1A1 //1A2 //1A3 //1A4 1A5BA122008C02B47F000001 = { isa = PBXFileReference; path = prefs_macosx.cpp; refType = 2; }; 1A5BA123008C02B47F000001 = { fileRef = 1A5BA122008C02B47F000001; isa = PBXBuildFile; settings = { }; }; 1A5BA124008C04377F000001 = { isa = PBXFileReference; name = audio_dummy.cpp; path = ../dummy/audio_dummy.cpp; refType = 2; }; //1A0 //1A1 //1A2 //1A3 //1A4 //1D0 //1D1 //1D2 //1D3 //1D4 1D71E7E400C2362F7F000001 = { fileRef = 00ED5A52FF9F41EE95877872; isa = PBXBuildFile; settings = { }; }; //1D0 //1D1 //1D2 //1D3 //1D4 //290 //291 //292 //293 //294 29B97313FDCFA39411CA2CEA = { buildStyles = ( 011D89AA0071AA4C7F000001, 011D89AB0071AA4C7F000001, ); isa = PBXProject; mainGroup = 29B97314FDCFA39411CA2CEA; projectDirPath = ""; targets = ( 29B97326FDCFA39411CA2CEA, ); }; 29B97314FDCFA39411CA2CEA = { children = ( 04D13618FF9F161695877872, 29B97315FDCFA39411CA2CEA, 29B97317FDCFA39411CA2CEA, 29B97323FDCFA39411CA2CEA, 19C28FACFE9D520D11CA2CBB, ); isa = PBXGroup; name = BasiliskII; path = ""; refType = 4; }; 29B97315FDCFA39411CA2CEA = { children = ( 18AB34C500AA6EAE7F000001, F59F45B0020FC25D01A80001, 0130A85800A96A627F000001, F66A596A021B9B1701877872, F59F4590020CD8DE01A80001, F59F45A2020E1C5A01A80001, F5B887500207D11D01A80001, 00EC4BFDFFD1D45E95877872, 00EC0D3FFFF8DE1B95877872, 1A5BA122008C02B47F000001, F51A2DB7042B25ED0187C272, F59F4595020D42B301A80001, F59F459B020D559E01A80001, 080E96DDFE201D6D7F000001, ); isa = PBXGroup; name = "Mac OS X specific Sources"; path = ""; refType = 4; }; 29B97317FDCFA39411CA2CEA = { children = ( 018DC3970071BA107F000001, F50E39510187F78A01877872, F52D357004EC78CA0187C272, 089C165CFE840E0CC02AAC07, 29B97318FDCFA39411CA2CEA, 13A81DD900421B6A95877872, F5495FEC018CD1890116CB19, 01BDE8DE0078384A7F000001, 01BDE8DC007837927F000001, ); isa = PBXGroup; name = Resources; path = ""; refType = 4; }; 29B97318FDCFA39411CA2CEA = { children = ( 29B97319FDCFA39411CA2CEA, ); isa = PBXVariantGroup; name = MainMenu.nib; path = ""; refType = 4; }; 29B97319FDCFA39411CA2CEA = { isa = PBXFileReference; name = English; path = English.lproj/MainMenu.nib; refType = 4; }; 29B97323FDCFA39411CA2CEA = { children = ( 29B97324FDCFA39411CA2CEA, F562922B0213394501000102, F606CD3B023748C5015CB6F1, 1058C7A1FEA54F0111CA2CBB, 0160729200BCA6097F000001, 29B97325FDCFA39411CA2CEA, F51A2DBD042B27920187C272, ); isa = PBXGroup; name = Frameworks; path = ""; refType = 4; }; 29B97324FDCFA39411CA2CEA = { isa = PBXFrameworkReference; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; refType = 0; }; 29B97325FDCFA39411CA2CEA = { isa = PBXFrameworkReference; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; refType = 0; }; 29B97326FDCFA39411CA2CEA = { buildPhases = ( 29B97327FDCFA39411CA2CEA, 29B97328FDCFA39411CA2CEA, 29B9732BFDCFA39411CA2CEA, 29B9732DFDCFA39411CA2CEA, 043355C9FE30361CC02AAC07, ); buildSettings = { DEBUGGING_SYMBOLS = NO; FRAMEWORK_SEARCH_PATHS = "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Versions/A/Frameworks\""; HEADER_SEARCH_PATHS = "../include ../uae_cpu ../Unix ../slirp"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = .; OTHER_CFLAGS = "-DHAVE_CONFIG_H -D_REENTRANT"; OTHER_LDFLAGS = ""; PRODUCT_NAME = BasiliskII; SECTORDER_FLAGS = ""; WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; WRAPPER_EXTENSION = app; }; dependencies = ( ); isa = PBXApplicationTarget; name = BasiliskII; productInstallPath = "$(HOME)/Applications"; productName = BasiliskII; productReference = 17587328FF379C6511CA2CBB; productSettingsXML = " CFBundleDevelopmentRegion English CFBundleExecutable BasiliskII CFBundleGetInfoString Basilisk II version 1.0, Copyright © 1997-2005 Christian Bauer et al. Mac OS X port 15 CFBundleIconFile BasiliskII.icns CFBundleIdentifier CFBundleInfoDictionaryVersion 6.0 CFBundleName BasiliskII CFBundlePackageType APPL CFBundleShortVersionString Basilisk II 1.0, Mac OS X port 15 CFBundleSignature ???? NSHelpFile README.txt NSMainNibFile MainMenu NSPrincipalClass Controller "; shouldUseHeadermap = 1; }; 29B97327FDCFA39411CA2CEA = { buildActionMask = 2147483647; files = ( 00F248C2FF9FB58D95877872, 00ED5A2DFF9F1BC995877872, 00ED5A2EFF9F1BC995877872, 00ED5A2FFF9F1BC995877872, 00ED5A30FF9F1BC995877872, 00ED5A31FF9F1BC995877872, 00ED5A32FF9F1BC995877872, 00ED5A33FF9F1BC995877872, 00ED5A34FF9F1BC995877872, 00ED5A35FF9F1BC995877872, 00ED5A36FF9F1BC995877872, 00ED5A37FF9F1BC995877872, 00ED5A38FF9F1BC995877872, 00ED5A39FF9F1BC995877872, 00ED5A3AFF9F1BC995877872, 00ED5A3BFF9F1BC995877872, 00ED5A3CFF9F1BC995877872, 00ED5A3DFF9F1BC995877872, 00ED5A3EFF9F1BC995877872, 00ED5A3FFF9F1BC995877872, 00ED5A40FF9F1BC995877872, 00ED5A41FF9F1BC995877872, 00ED5A42FF9F1BC995877872, 00ED5A43FF9F1BC995877872, 00ED5A44FF9F1BC995877872, 00ED5A45FF9F1BC995877872, 00ED5A46FF9F1BC995877872, 00ED5A47FF9F1BC995877872, 00ED5A48FF9F1BC995877872, 00ED5A49FF9F1BC995877872, 00ED5A4AFF9F1BC995877872, 00F248D6FFA011DD95877872, 00ED5A8BFF9F42CA95877872, 00ED5A8CFF9F42CA95877872, 00ED5A8DFF9F42CA95877872, 00ED5A8EFF9F42CA95877872, 01933683FFD1BA0395877872, F59F45A6020E2BD601A80001, ); isa = PBXHeadersBuildPhase; name = Headers; }; 29B97328FDCFA39411CA2CEA = { buildActionMask = 2147483647; files = ( 080E96DCFE201CFB7F000001, 089C165EFE840E0CC02AAC07, 13A81DDA00421B6A95877872, 018DC3980071BA107F000001, 01BDE8DD007837927F000001, 01BDE8DF0078384A7F000001, F50E39520187F78A01877872, F5495FED018CD1890116CB19, F52D357104EC78CA0187C272, ); isa = PBXResourcesBuildPhase; name = "Bundle Resources"; }; 29B9732BFDCFA39411CA2CEA = { buildActionMask = 2147483647; files = ( 0FEE9ED800AF47597F000001, F59F459D020D559E01A80001, 00F23978FFC35BA495877872, 00EC2986FFEE9C5495877872, 0107BC6A000E46CF95877872, 00F248C3FF9FB58D95877872, F644E00402435DC30108A02E, F644E00502435DC30108A02E, F644E00602435DC30108A02E, F644E00702435DC30108A02E, F644E00802435DC30108A02E, F644E00902435DC30108A02E, F644E00A02435DC30108A02E, F644E00B02435DC30108A02E, 00F248C5FF9FB58D95877872, F59F4592020CDBFD01A80001, F5B887510207D11E01A80001, F579F2640213ECB101877872, 1A5BA123008C02B47F000001, F59F459C020D559E01A80001, F51A2DB9042B25ED0187C272, 00ED5A78FF9F427D95877872, 00ED5A79FF9F427D95877872, 00ED5A76FF9F427D95877872, 00ED5A77FF9F427D95877872, 00ED5A73FF9F427D95877872, 00ED5A74FF9F427D95877872, 01BE253E00A65BFA7F000001, 00ED5A72FF9F427D95877872, 00ED5A5CFF9F41EE95877872, 1D71E7E400C2362F7F000001, 03958314007872167F000001, 00ED5A5EFF9F41EE95877872, 00ED5A5FFF9F41EE95877872, 00ED5A60FF9F41EE95877872, 00ED5A61FF9F41EE95877872, 00ED5A62FF9F41EE95877872, 00ED5A63FF9F41EE95877872, 00ED5A5BFF9F41EE95877872, 00ED5A6FFF9F427D95877872, 00ED5A70FF9F427D95877872, 00ED5A71FF9F427D95877872, F5ABCD4E0210E31501A80001, 021D87E9FF9F440695877872, 04D13626FF9F17C295877872, 04D13628FF9F182095877872, 00F248BAFF9FB3E495877872, 00ED5A92FF9F42CA95877872, 00ED5A98FF9F42CA95877872, 00ED5A99FF9F42CA95877872, 00ED5A9AFF9F42CA95877872, F5BACDE9042F21EF01A80001, F5028E6004DB9DD30135D59B, 01933685FFD1BA0395877872, 01933686FFD1BA0395877872, 01933687FFD1BA0395877872, F59F45A7020E2BD601A80001, 01933688FFD1BA0395877872, ); isa = PBXSourcesBuildPhase; name = Sources; }; 29B9732DFDCFA39411CA2CEA = { buildActionMask = 2147483647; files = ( 1058C7A3FEA54F0111CA2CBB, 00EC0D43FFF8DF2B95877872, 00EC0D44FFF8DF2B95877872, 0160729300BCA6097F000001, F562922C0213394501000102, F606CD3C023748C5015CB6F1, F51A2DBE042B27930187C272, ); isa = PBXFrameworksBuildPhase; name = "Frameworks & Libraries"; }; //290 //291 //292 //293 //294 //330 //331 //332 //333 //334 338FF87200CF1E867F000001 = { isa = PBXFileReference; name = fpu_uae.cpp; path = ../uae_cpu/fpu/fpu_uae.cpp; refType = 2; }; //330 //331 //332 //333 //334 //F50 //F51 //F52 //F53 //F54 F5028E5F04DB9DD30135D59B = { isa = PBXFileReference; name = sigsegv.cpp; path = ../Unix/sigsegv.cpp; refType = 2; }; F5028E6004DB9DD30135D59B = { fileRef = F5028E5F04DB9DD30135D59B; isa = PBXBuildFile; settings = { }; }; F50E39510187F78A01877872 = { isa = PBXFileReference; path = Credits.html; refType = 4; }; F50E39520187F78A01877872 = { fileRef = F50E39510187F78A01877872; isa = PBXBuildFile; settings = { }; }; F51A2DB7042B25ED0187C272 = { isa = PBXFileReference; path = sys_darwin.cpp; refType = 2; }; F51A2DB9042B25ED0187C272 = { fileRef = F51A2DB7042B25ED0187C272; isa = PBXBuildFile; settings = { }; }; F51A2DBD042B27920187C272 = { isa = PBXFrameworkReference; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; refType = 0; }; F51A2DBE042B27930187C272 = { fileRef = F51A2DBD042B27920187C272; isa = PBXBuildFile; settings = { }; }; F52D357004EC78CA0187C272 = { isa = PBXFileReference; path = HowTo.html; refType = 2; }; F52D357104EC78CA0187C272 = { fileRef = F52D357004EC78CA0187C272; isa = PBXBuildFile; settings = { }; }; F5495FEC018CD1890116CB19 = { isa = PBXFileReference; path = README.txt; refType = 2; }; F5495FED018CD1890116CB19 = { fileRef = F5495FEC018CD1890116CB19; isa = PBXBuildFile; settings = { }; }; F562922B0213394501000102 = { isa = PBXFrameworkReference; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; refType = 0; }; F562922C0213394501000102 = { fileRef = F562922B0213394501000102; isa = PBXBuildFile; settings = { }; }; F579F2640213ECB101877872 = { fileRef = 00EC0D3FFFF8DE1B95877872; isa = PBXBuildFile; settings = { }; }; F59F4590020CD8DE01A80001 = { isa = PBXFileReference; path = extfs_macosx.mm; refType = 2; }; F59F4592020CDBFD01A80001 = { fileRef = F59F4590020CD8DE01A80001; isa = PBXBuildFile; settings = { }; }; F59F4595020D42B301A80001 = { isa = PBXFileReference; path = video_macosx.h; refType = 2; }; F59F459B020D559E01A80001 = { isa = PBXFileReference; path = video_macosx.mm; refType = 2; }; F59F459C020D559E01A80001 = { fileRef = F59F459B020D559E01A80001; isa = PBXBuildFile; settings = { }; }; F59F459D020D559E01A80001 = { fileRef = 05CD28AFFFEE4D6995877872; isa = PBXBuildFile; settings = { }; }; F59F45A2020E1C5A01A80001 = { isa = PBXFileReference; path = main_macosx.h; refType = 2; }; F59F45A4020E2BD601A80001 = { isa = PBXFileReference; name = vm_alloc.cpp; path = ../Unix/vm_alloc.cpp; refType = 2; }; F59F45A5020E2BD601A80001 = { isa = PBXFileReference; name = vm_alloc.h; path = ../Unix/vm_alloc.h; refType = 2; }; F59F45A6020E2BD601A80001 = { fileRef = F59F45A5020E2BD601A80001; isa = PBXBuildFile; settings = { }; }; F59F45A7020E2BD601A80001 = { fileRef = F59F45A4020E2BD601A80001; isa = PBXBuildFile; settings = { }; }; F59F45B0020FC25D01A80001 = { isa = PBXFileReference; path = macos_util_macosx.h; refType = 4; }; F5ABCD4E0210E31501A80001 = { fileRef = 1A5BA124008C04377F000001; isa = PBXBuildFile; settings = { }; }; F5B887500207D11D01A80001 = { isa = PBXFileReference; path = main_macosx.mm; refType = 2; }; F5B887510207D11E01A80001 = { fileRef = F5B887500207D11D01A80001; isa = PBXBuildFile; settings = { }; }; F5BACDE8042F21EF01A80001 = { isa = PBXFileReference; name = fpu_ieee.cpp; path = ../uae_cpu/fpu/fpu_ieee.cpp; refType = 2; }; F5BACDE9042F21EF01A80001 = { fileRef = F5BACDE8042F21EF01A80001; isa = PBXBuildFile; settings = { }; }; //F50 //F51 //F52 //F53 //F54 //F60 //F61 //F62 //F63 //F64 F606CD3B023748C5015CB6F1 = { isa = PBXFrameworkReference; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; refType = 0; }; F606CD3C023748C5015CB6F1 = { fileRef = F606CD3B023748C5015CB6F1; isa = PBXBuildFile; settings = { }; }; F644DFFC02435DC30108A02E = { isa = PBXFileReference; path = cpuemu1.cpp; refType = 2; }; F644DFFD02435DC30108A02E = { isa = PBXFileReference; path = cpuemu2.cpp; refType = 2; }; F644DFFE02435DC30108A02E = { isa = PBXFileReference; path = cpuemu3.cpp; refType = 2; }; F644DFFF02435DC30108A02E = { isa = PBXFileReference; path = cpuemu4.cpp; refType = 2; }; F644E00002435DC30108A02E = { isa = PBXFileReference; path = cpuemu5.cpp; refType = 2; }; F644E00102435DC30108A02E = { isa = PBXFileReference; path = cpuemu6.cpp; refType = 2; }; F644E00202435DC30108A02E = { isa = PBXFileReference; path = cpuemu7.cpp; refType = 2; }; F644E00302435DC30108A02E = { isa = PBXFileReference; path = cpuemu8.cpp; refType = 2; }; F644E00402435DC30108A02E = { fileRef = F644DFFC02435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F644E00502435DC30108A02E = { fileRef = F644DFFD02435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F644E00602435DC30108A02E = { fileRef = F644DFFE02435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F644E00702435DC30108A02E = { fileRef = F644DFFF02435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F644E00802435DC30108A02E = { fileRef = F644E00002435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F644E00902435DC30108A02E = { fileRef = F644E00102435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F644E00A02435DC30108A02E = { fileRef = F644E00202435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F644E00B02435DC30108A02E = { fileRef = F644E00302435DC30108A02E; isa = PBXBuildFile; settings = { }; }; F66A596A021B9B1701877872 = { isa = PBXFileReference; path = extfs_macosx.h; refType = 4; }; }; rootObject = 29B97313FDCFA39411CA2CEA; } BasiliskII/src/MacOSX/Info.plist0000644000175000017500000000203610463360254016576 0ustar centriscentris CFBundleDevelopmentRegion English CFBundleExecutable BasiliskII CFBundleGetInfoString Basilisk II version 1.0, Copyright © 1997-2006 Christian Bauer et al. Mac OS X port 19 CFBundleIconFile BasiliskII.icns CFBundleIdentifier CFBundleInfoDictionaryVersion 6.0 CFBundleName BasiliskII CFBundlePackageType APPL CFBundleShortVersionString Basilisk II 1.0, Mac OS X port 19 CFBundleSignature ???? NSHelpFile README.txt NSMainNibFile MainMenu NSPrincipalClass Controller BasiliskII/src/MacOSX/macos_util_macosx.h0000644000175000017500000000774410736405220020517 0ustar centriscentris/* * $Id: macos_util_macosx.h,v 1.5 2008/01/01 09:40:32 gbeauche Exp $ * * macos_util_macosx.h - Work around clashes with the enums in * Based on: * * macos_util.h - MacOS definitions/utility functions * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef MACOS_UTIL_H #define MACOS_UTIL_H #include "cpu_emulation.h" #import /* * Queues */ enum { // QElem struct qLink = 0, qType = 4, qData = 6 }; enum { // QHdr struct qFlags = 0, qHead = 2, qTail = 6 }; /* * Definitions for Device Manager */ // Misc constants enum { // IOParam struct ioTrap = 6, ioCmdAddr = 8, ioCompletion = 12, ioResult = 16, ioNamePtr = 18, ioVRefNum = 22, ioRefNum = 24, ioVersNum = 26, ioPermssn = 27, ioMisc = 28, ioBuffer = 32, ioReqCount = 36, ioActCount = 40, ioPosMode = 44, ioPosOffset = 46, ioWPosOffset = 46, // Wide positioning offset when ioPosMode has kWidePosOffsetBit set SIZEOF_IOParam = 50 }; enum { // CntrlParam struct csCode = 26, csParam = 28 }; enum { // DrvSts struct dsTrack = 0, dsWriteProt = 2, dsDiskInPlace = 3, dsInstalled = 4, dsSides = 5, dsQLink = 6, dsQType = 10, dsQDrive = 12, dsQRefNum = 14, dsQFSID = 16, dsTwoSideFmt = 18, dsNewIntf = 19, dsDiskErrs = 20, dsMFMDrive = 22, dsMFMDisk = 23, dsTwoMegFmt = 24 }; enum { // DrvSts2 struct dsDriveSize = 18, dsDriveS1 = 20, dsDriveType = 22, dsDriveManf = 24, dsDriveChar = 26, dsDriveMisc = 28, SIZEOF_DrvSts = 30 }; enum { // DCtlEntry struct dCtlDriver = 0, dCtlFlags = 4, dCtlQHdr = 6, dCtlPosition = 16, dCtlStorage = 20, dCtlRefNum = 24, dCtlCurTicks = 26, dCtlWindow = 30, dCtlDelay = 34, dCtlEMask = 36, dCtlMenu = 38, dCtlSlot = 40, dCtlSlotId = 41, dCtlDevBase = 42, dCtlOwner = 46, dCtlExtDev = 50, dCtlFillByte = 51, dCtlNodeID = 52 }; /* * Definitions for Deferred Task Manager */ enum { // DeferredTask struct dtFlags = 6, dtAddr = 8, dtParam = 12, dtReserved = 16 }; // Definitions for DebugUtil() Selector enum { duDebuggerGetMax = 0, duDebuggerEnter = 1, duDebuggerExit = 2, duDebuggerPoll = 3, duGetPageState = 4, duPageFaultFatal = 5, duDebuggerLockMemory = 6, duDebuggerUnlockMemory = 7, duEnterSupervisorMode = 8 }; // Functions extern void EnqueueMac(uint32 elem, uint32 list); // Enqueue QElem in list extern int FindFreeDriveNumber(int num); // Find first free drive number, starting at "num" extern void MountVolume(void *fh); // Mount volume with given file handle (see sys.h) extern void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size); // Calculate disk image file layout given file size and first 256 data bytes extern uint32 DebugUtil(uint32 Selector); // DebugUtil() Replacement extern uint32 TimeToMacTime(time_t t); // Convert time_t value to MacOS time // Construct four-character-code #define FOURCC(a,b,c,d) (((uint32)(a) << 24) | ((uint32)(b) << 16) | ((uint32)(c) << 8) | (uint32)(d)) // Emulator identification codes (4 and 2 characters) const uint32 EMULATOR_ID_4 = 0x62617369; // 'basi' const uint16 EMULATOR_ID_2 = 0x6261; // 'ba' // Test if basic MacOS initializations (of the ROM) are done static inline bool HasMacStarted(void) { return ReadMacInt32(0xcfc) == FOURCC('W','L','S','C'); // Mac warm start flag } #endif BasiliskII/src/slirp/0000755000175000017500000000000011735674751014701 5ustar centriscentrisBasiliskII/src/slirp/if.c0000644000175000017500000001727211676271736015454 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include int if_mtu, if_mru; int if_comp; int if_maxlinkhdr; int if_queued = 0; /* Number of packets queued so far */ int if_thresh = 10; /* Number of packets queued before we start sending * (to prevent allocing too many mbufs) */ struct mbuf if_fastq; /* fast queue (for interactive data) */ struct mbuf if_batchq; /* queue for non-interactive data */ struct mbuf *next_m; /* Pointer to next mbuf to output */ #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) void ifs_insque(ifm, ifmhead) struct mbuf *ifm, *ifmhead; { ifm->ifs_next = ifmhead->ifs_next; ifmhead->ifs_next = ifm; ifm->ifs_prev = ifmhead; ifm->ifs_next->ifs_prev = ifm; } void ifs_remque(ifm) struct mbuf *ifm; { ifm->ifs_prev->ifs_next = ifm->ifs_next; ifm->ifs_next->ifs_prev = ifm->ifs_prev; } void if_init() { #if 0 /* * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, * and 8 bytes for PPP, but need to have it on an 8byte boundary */ #ifdef USE_PPP if_maxlinkhdr = 48; #else if_maxlinkhdr = 40; #endif #else /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ if_maxlinkhdr = 2 + 14 + 40; #endif if_mtu = 1500; if_mru = 1500; if_comp = IF_AUTOCOMP; if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; // sl_compress_init(&comp_s); next_m = &if_batchq; } #if 0 /* * This shouldn't be needed since the modem is blocking and * we don't expect any signals, but what the hell.. */ inline int writen(fd, bptr, n) int fd; char *bptr; int n; { int ret; int total; /* This should succeed most of the time */ ret = send(fd, bptr, n,0); if (ret == n || ret <= 0) return ret; /* Didn't write everything, go into the loop */ total = ret; while (n > total) { ret = send(fd, bptr+total, n-total,0); if (ret <= 0) return ret; total += ret; } return total; } /* * if_input - read() the tty, do "top level" processing (ie: check for any escapes), * and pass onto (*ttyp->if_input) * * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet. */ #define INBUFF_SIZE 2048 /* XXX */ void if_input(ttyp) struct ttys *ttyp; { u_char if_inbuff[INBUFF_SIZE]; int if_n; DEBUG_CALL("if_input"); DEBUG_ARG("ttyp = %lx", (long)ttyp); if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0); DEBUG_MISC((dfd, " read %d bytes\n", if_n)); if (if_n <= 0) { if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { if (ttyp->up) link_up--; tty_detached(ttyp, 0); } return; } if (if_n == 1) { if (*if_inbuff == '0') { ttyp->ones = 0; if (++ttyp->zeros >= 5) slirp_exit(0); return; } if (*if_inbuff == '1') { ttyp->zeros = 0; if (++ttyp->ones >= 5) tty_detached(ttyp, 0); return; } } ttyp->ones = ttyp->zeros = 0; (*ttyp->if_input)(ttyp, if_inbuff, if_n); } #endif /* * if_output: Queue packet into an output queue. * There are 2 output queue's, if_fastq and if_batchq. * Each output queue is a doubly linked list of double linked lists * of mbufs, each list belonging to one "session" (socket). This * way, we can output packets fairly by sending one packet from each * session, instead of all the packets from one session, then all packets * from the next session, etc. Packets on the if_fastq get absolute * priority, but if one session hogs the link, it gets "downgraded" * to the batchq until it runs out of packets, then it'll return * to the fastq (eg. if the user does an ls -alR in a telnet session, * it'll temporarily get downgraded to the batchq) */ void if_output(so, ifm) struct socket *so; struct mbuf *ifm; { struct mbuf *ifq; int on_fastq = 1; DEBUG_CALL("if_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("ifm = %lx", (long)ifm); /* * First remove the mbuf from m_usedlist, * since we're gonna use m_next and m_prev ourselves * XXX Shouldn't need this, gotta change dtom() etc. */ if (ifm->m_flags & M_USEDLIST) { remque(ifm); ifm->m_flags &= ~M_USEDLIST; } /* * See if there's already a batchq list for this session. * This can include an interactive session, which should go on fastq, * but gets too greedy... hence it'll be downgraded from fastq to batchq. * We mustn't put this packet back on the fastq (or we'll send it out of order) * XXX add cache here? */ for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) { if (so == ifq->ifq_so) { /* A match! */ ifm->ifq_so = so; ifs_insque(ifm, ifq->ifs_prev); goto diddit; } } /* No match, check which queue to put it on */ if (so && (so->so_iptos & IPTOS_LOWDELAY)) { ifq = if_fastq.ifq_prev; on_fastq = 1; /* * Check if this packet is a part of the last * packet's session */ if (ifq->ifq_so == so) { ifm->ifq_so = so; ifs_insque(ifm, ifq->ifs_prev); goto diddit; } } else ifq = if_batchq.ifq_prev; /* Create a new doubly linked list for this session */ ifm->ifq_so = so; ifs_init(ifm); insque(ifm, ifq); diddit: ++if_queued; if (so) { /* Update *_queued */ so->so_queued++; so->so_nqueued++; /* * Check if the interactive session should be downgraded to * the batchq. A session is downgraded if it has queued 6 * packets without pausing, and at least 3 of those packets * have been sent over the link * (XXX These are arbitrary numbers, probably not optimal..) */ if (on_fastq && ((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) { /* Remove from current queue... */ remque(ifm->ifs_next); /* ...And insert in the new. That'll teach ya! */ insque(ifm->ifs_next, &if_batchq); } } #ifndef FULL_BOLT /* * This prevents us from malloc()ing too many mbufs */ if (link_up) { /* if_start will check towrite */ if_start(); } #endif } /* * Send a packet * We choose a packet based on it's position in the output queues; * If there are packets on the fastq, they are sent FIFO, before * everything else. Otherwise we choose the first packet from the * batchq and send it. the next packet chosen will be from the session * after this one, then the session after that one, and so on.. So, * for example, if there are 3 ftp session's fighting for bandwidth, * one packet will be sent from the first session, then one packet * from the second session, then one packet from the third, then back * to the first, etc. etc. */ void if_start(void) { struct mbuf *ifm, *ifqt; DEBUG_CALL("if_start"); if (if_queued == 0) return; /* Nothing to do */ again: /* check if we can really output */ if (!slirp_can_output()) return; /* * See which queue to get next packet from * If there's something in the fastq, select it immediately */ if (if_fastq.ifq_next != &if_fastq) { ifm = if_fastq.ifq_next; } else { /* Nothing on fastq, see if next_m is valid */ if (next_m != &if_batchq) ifm = next_m; else ifm = if_batchq.ifq_next; /* Set which packet to send on next iteration */ next_m = ifm->ifq_next; } /* Remove it from the queue */ ifqt = ifm->ifq_prev; remque(ifm); --if_queued; /* If there are more packets for this session, re-queue them */ if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { insque(ifm->ifs_next, ifqt); ifs_remque(ifm); } /* Update so_queued */ if (ifm->ifq_so) { if (--ifm->ifq_so->so_queued == 0) /* If there's no more queued, reset nqueued */ ifm->ifq_so->so_nqueued = 0; } /* Encapsulate the packet for sending */ if_encap((uint8_t*)ifm->m_data, ifm->m_len); m_free(ifm); if (if_queued) goto again; } BasiliskII/src/slirp/if.h0000644000175000017500000000310310241066313015421 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifndef _IF_H_ #define _IF_H_ #define IF_COMPRESS 0x01 /* We want compression */ #define IF_NOCOMPRESS 0x02 /* Do not do compression */ #define IF_AUTOCOMP 0x04 /* Autodetect (default) */ #define IF_NOCIDCOMP 0x08 /* CID compression */ /* Needed for FreeBSD */ #undef if_mtu extern int if_mtu; extern int if_mru; /* MTU and MRU */ extern int if_comp; /* Flags for compression */ extern int if_maxlinkhdr; extern int if_queued; /* Number of packets queued so far */ extern int if_thresh; /* Number of packets queued before we start sending * (to prevent allocing too many mbufs) */ extern struct mbuf if_fastq; /* fast queue (for interactive data) */ extern struct mbuf if_batchq; /* queue for non-interactive data */ extern struct mbuf *next_m; #define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) /* Interface statistics */ struct slirp_ifstats { u_int out_pkts; /* Output packets */ u_int out_bytes; /* Output bytes */ u_int out_errpkts; /* Output Error Packets */ u_int out_errbytes; /* Output Error Bytes */ u_int in_pkts; /* Input packets */ u_int in_bytes; /* Input bytes */ u_int in_errpkts; /* Input Error Packets */ u_int in_errbytes; /* Input Error Bytes */ u_int bytes_saved; /* Number of bytes that compression "saved" */ /* ie: number of bytes that didn't need to be sent over the link * because of compression */ u_int in_mbad; /* Bad incoming packets */ }; #endif BasiliskII/src/slirp/ip.h0000644000175000017500000002341211735673707015464 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)ip.h 8.1 (Berkeley) 6/10/93 * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp */ #ifndef _IP_H_ #define _IP_H_ #ifdef WORDS_BIGENDIAN # ifndef NTOHL # define NTOHL(d) # endif # ifndef NTOHS # define NTOHS(d) # endif # ifndef HTONL # define HTONL(d) # endif # ifndef HTONS # define HTONS(d) # endif #else # ifndef NTOHL # define NTOHL(d) ((d) = ntohl((d))) # endif # ifndef NTOHS # define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) # endif # ifndef HTONL # define HTONL(d) ((d) = htonl((d))) # endif # ifndef HTONS # define HTONS(d) ((d) = htons((u_int16_t)(d))) # endif #endif typedef u_int32_t n_long; /* long as received from the net */ /* * Definitions for internet protocol version 4. * Per RFC 791, September 1981. */ #define IPVERSION 4 /* * Structure of an internet header, naked of options. */ #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct ip { #ifdef WORDS_BIGENDIAN u_char ip_v:4, /* version */ ip_hl:4; /* header length */ #else u_char ip_hl:4, /* header length */ ip_v:4; /* version */ #endif u_int8_t ip_tos; /* type of service */ u_int16_t ip_len; /* total length */ u_int16_t ip_id; /* identification */ u_int16_t ip_off; /* fragment offset field */ #define IP_DF 0x4000 /* don't fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_int8_t ip_ttl; /* time to live */ u_int8_t ip_p; /* protocol */ u_int16_t ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */ } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif #define IP_MAXPACKET 65535 /* maximum packet size */ /* * Definitions for IP type of service (ip_tos) */ #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 /* * Definitions for options. */ #define IPOPT_COPIED(o) ((o)&0x80) #define IPOPT_CLASS(o) ((o)&0x60) #define IPOPT_NUMBER(o) ((o)&0x1f) #define IPOPT_CONTROL 0x00 #define IPOPT_RESERVED1 0x20 #define IPOPT_DEBMEAS 0x40 #define IPOPT_RESERVED2 0x60 #define IPOPT_EOL 0 /* end of option list */ #define IPOPT_NOP 1 /* no operation */ #define IPOPT_RR 7 /* record packet route */ #define IPOPT_TS 68 /* timestamp */ #define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ #define IPOPT_LSRR 131 /* loose source route */ #define IPOPT_SATID 136 /* satnet id */ #define IPOPT_SSRR 137 /* strict source route */ /* * Offsets to fields in options other than EOL and NOP. */ #define IPOPT_OPTVAL 0 /* option ID */ #define IPOPT_OLEN 1 /* option length */ #define IPOPT_OFFSET 2 /* offset within option */ #define IPOPT_MINOFF 4 /* min value of above */ /* * Time stamp option structure. */ #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct ip_timestamp { u_int8_t ipt_code; /* IPOPT_TS */ u_int8_t ipt_len; /* size of structure (variable) */ u_int8_t ipt_ptr; /* index of current entry */ #ifdef WORDS_BIGENDIAN u_char ipt_oflw:4, /* overflow counter */ ipt_flg:4; /* flags, see below */ #else u_char ipt_flg:4, /* flags, see below */ ipt_oflw:4; /* overflow counter */ #endif union ipt_timestamp { n_long ipt_time[1]; struct ipt_ta { struct in_addr ipt_addr; n_long ipt_time; } ipt_ta[1]; } ipt_timestamp; } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif /* flag bits for ipt_flg */ #define IPOPT_TS_TSONLY 0 /* timestamps only */ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */ /* bits for security (not byte swapped) */ #define IPOPT_SECUR_UNCLASS 0x0000 #define IPOPT_SECUR_CONFID 0xf135 #define IPOPT_SECUR_EFTO 0x789a #define IPOPT_SECUR_MMMM 0xbc4d #define IPOPT_SECUR_RESTR 0xaf13 #define IPOPT_SECUR_SECRET 0xd788 #define IPOPT_SECUR_TOPSECRET 0x6bc5 /* * Internet implementation parameters. */ #define MAXTTL 255 /* maximum time to live (seconds) */ #define IPDEFTTL 64 /* default ttl, from RFC 1340 */ #define IPFRAGTTL 60 /* time to live for frags, slowhz */ #define IPTTLDEC 1 /* subtracted when forwarding */ #define IP_MSS 576 /* default maximum segment size */ #ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ #include #else #if SIZEOF_CHAR_P == 4 typedef caddr_t caddr32_t; #else typedef u_int32_t caddr32_t; #endif #endif #if SIZEOF_CHAR_P == 4 typedef struct ipq *ipqp_32; typedef struct ipasfrag *ipasfragp_32; #else typedef caddr32_t ipqp_32; typedef caddr32_t ipasfragp_32; #endif /* * Overlay for ip header used by other protocols (tcp, udp). */ #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct ipovly { caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ u_int8_t ih_x1; /* (unused) */ u_int8_t ih_pr; /* protocol */ u_int16_t ih_len; /* protocol length */ struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif /* * Ip reassembly queue structure. Each fragment * being reassembled is attached to one of these structures. * They are timed out after ipq_ttl drops to 0, and may also * be reclaimed if memory becomes tight. * size 28 bytes */ struct ipq { ipqp_32 next,prev; /* to other reass headers */ u_int8_t ipq_ttl; /* time for reass q to live */ u_int8_t ipq_p; /* protocol of this fragment */ u_int16_t ipq_id; /* sequence id for reassembly */ ipasfragp_32 ipq_next,ipq_prev; /* to ip headers of fragments */ struct in_addr ipq_src,ipq_dst; }; /* * Ip header, when holding a fragment. * * Note: ipf_next must be at same offset as ipq_next above */ struct ipasfrag { #ifdef WORDS_BIGENDIAN u_char ip_v:4, ip_hl:4; #else u_char ip_hl:4, ip_v:4; #endif /* BUG : u_int changed to u_int8_t. * sizeof(u_int)==4 on linux 2.0 */ u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit * to avoid destroying tos (PPPDTRuu); * copied from (ip_off&IP_MF) */ u_int16_t ip_len; u_int16_t ip_id; u_int16_t ip_off; u_int8_t ip_ttl; u_int8_t ip_p; u_int16_t ip_sum; ipasfragp_32 ipf_next; /* next fragment */ ipasfragp_32 ipf_prev; /* previous fragment */ }; /* * Structure stored in mbuf in inpcb.ip_options * and passed to ip_output when ip options are in use. * The actual length of the options (including ipopt_dst) * is in m_len. */ #define MAX_IPOPTLEN 40 struct ipoption { struct in_addr ipopt_dst; /* first-hop dst if source routed */ int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. */ struct ipstat { u_long ips_total; /* total packets received */ u_long ips_badsum; /* checksum bad */ u_long ips_tooshort; /* packet too short */ u_long ips_toosmall; /* not enough data */ u_long ips_badhlen; /* ip header length < data size */ u_long ips_badlen; /* ip length < ip header length */ u_long ips_fragments; /* fragments received */ u_long ips_fragdropped; /* frags dropped (dups, out of space) */ u_long ips_fragtimeout; /* fragments timed out */ u_long ips_forward; /* packets forwarded */ u_long ips_cantforward; /* packets rcvd for unreachable dest */ u_long ips_redirectsent; /* packets forwarded on same net */ u_long ips_noproto; /* unknown or unsupported protocol */ u_long ips_delivered; /* datagrams delivered to upper level*/ u_long ips_localout; /* total ip packets generated here */ u_long ips_odropped; /* lost packets due to nobufs, etc. */ u_long ips_reassembled; /* total packets reassembled ok */ u_long ips_fragmented; /* datagrams successfully fragmented */ u_long ips_ofragments; /* output fragments created */ u_long ips_cantfrag; /* don't fragment flag was set, etc. */ u_long ips_badoptions; /* error in option processing */ u_long ips_noroute; /* packets discarded due to no route */ u_long ips_badvers; /* ip version != 4 */ u_long ips_rawout; /* total raw ip packets generated */ u_long ips_unaligned; /* times the ip packet was not aligned */ }; extern struct ipstat ipstat; extern struct ipq ipq; /* ip reass. queue */ extern u_int16_t ip_id; /* ip packet ctr, for ids */ extern int ip_defttl; /* default IP ttl */ #endif BasiliskII/src/slirp/libslirp.h0000644000175000017500000000161310713053556016660 0ustar centriscentris#ifndef _LIBSLIRP_H #define _LIBSLIRP_H #ifdef _WIN32 #include int inet_aton(const char *cp, struct in_addr *ia); #else #include #include #endif #ifdef __cplusplus extern "C" { #endif int slirp_init(void); int slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); void slirp_input(const uint8 *pkt, int pkt_len); /* you must provide the following functions: */ int slirp_can_output(void); void slirp_output(const uint8 *pkt, int pkt_len); int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port); int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, int guest_port); extern const char *tftp_prefix; extern char slirp_hostname[33]; #ifdef __cplusplus } #endif #endif BasiliskII/src/slirp/tcp_var.h0000644000175000017500000002447411735673707016523 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp */ #ifndef _TCP_VAR_H_ #define _TCP_VAR_H_ #include "tcpip.h" #include "tcp_timer.h" #if SIZEOF_CHAR_P == 4 typedef struct tcpiphdr *tcpiphdrp_32; #else typedef u_int32_t tcpiphdrp_32; #endif /* * Tcp control block, one per tcp; fields: */ struct tcpcb { tcpiphdrp_32 seg_next; /* sequencing queue */ tcpiphdrp_32 seg_prev; short t_state; /* state of this connection */ short t_timer[TCPT_NTIMERS]; /* tcp timers */ short t_rxtshift; /* log(2) of rexmt exp. backoff */ short t_rxtcur; /* current retransmit value */ short t_dupacks; /* consecutive dup acks recd */ u_short t_maxseg; /* maximum segment size */ char t_force; /* 1 if forcing out a byte */ u_short t_flags; #define TF_ACKNOW 0x0001 /* ack peer immediately */ #define TF_DELACK 0x0002 /* ack, but try to delay it */ #define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ #define TF_NOOPT 0x0008 /* don't use tcp options */ #define TF_SENTFIN 0x0010 /* have sent FIN */ #define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ #define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ #define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ #define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ #define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ /* Make it static for now */ /* struct tcpiphdr *t_template; / * skeletal packet for transmit */ struct tcpiphdr t_template; struct socket *t_socket; /* back pointer to socket */ /* * The following fields are used as in the protocol specification. * See RFC783, Dec. 1981, page 21. */ /* send sequence variables */ tcp_seq snd_una; /* send unacknowledged */ tcp_seq snd_nxt; /* send next */ tcp_seq snd_up; /* send urgent pointer */ tcp_seq snd_wl1; /* window update seg seq number */ tcp_seq snd_wl2; /* window update seg ack number */ tcp_seq iss; /* initial send sequence number */ u_int32_t snd_wnd; /* send window */ /* receive sequence variables */ u_int32_t rcv_wnd; /* receive window */ tcp_seq rcv_nxt; /* receive next */ tcp_seq rcv_up; /* receive urgent pointer */ tcp_seq irs; /* initial receive sequence number */ /* * Additional variables for this implementation. */ /* receive variables */ tcp_seq rcv_adv; /* advertised window */ /* retransmit variables */ tcp_seq snd_max; /* highest sequence number sent; * used to recognize retransmits */ /* congestion control (for slow start, source quench, retransmit after loss) */ u_int32_t snd_cwnd; /* congestion-controlled window */ u_int32_t snd_ssthresh; /* snd_cwnd size threshold for * for slow start exponential to * linear switch */ /* * transmit timing stuff. See below for scale of srtt and rttvar. * "Variance" is actually smoothed difference. */ short t_idle; /* inactivity time */ short t_rtt; /* round trip time */ tcp_seq t_rtseq; /* sequence number being timed */ short t_srtt; /* smoothed round-trip time */ short t_rttvar; /* variance in round-trip time */ u_short t_rttmin; /* minimum rtt allowed */ u_int32_t max_sndwnd; /* largest window peer has offered */ /* out-of-band data */ char t_oobflags; /* have some */ char t_iobc; /* input character */ #define TCPOOB_HAVEDATA 0x01 #define TCPOOB_HADDATA 0x02 short t_softerror; /* possible error not yet reported */ /* RFC 1323 variables */ u_char snd_scale; /* window scaling for send window */ u_char rcv_scale; /* window scaling for recv window */ u_char request_r_scale; /* pending window scaling */ u_char requested_s_scale; u_int32_t ts_recent; /* timestamp echo data */ u_int32_t ts_recent_age; /* when last updated */ tcp_seq last_ack_sent; }; #define sototcpcb(so) ((so)->so_tcpcb) /* * The smoothed round-trip time and estimated variance * are stored as fixed point numbers scaled by the values below. * For convenience, these scales are also used in smoothing the average * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). * With these scales, srtt has 3 bits to the right of the binary point, * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the * binary point, and is smoothed with an ALPHA of 0.75. */ #define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ #define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ #define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ #define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ /* * The initial retransmission should happen at rtt + 4 * rttvar. * Because of the way we do the smoothing, srtt and rttvar * will each average +1/2 tick of bias. When we compute * the retransmit timer, we want 1/2 tick of rounding and * 1 extra tick because of +-1/2 tick uncertainty in the * firing of the timer. The bias will give us exactly the * 1.5 tick we need. But, because the bias is * statistical, we have to test that we don't drop below * the minimum feasible timer (which is 2 ticks). * This macro assumes that the value of TCP_RTTVAR_SCALE * is the same as the multiplier for rttvar. */ #define TCP_REXMTVAL(tp) \ (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) /* XXX * We want to avoid doing m_pullup on incoming packets but that * means avoiding dtom on the tcp reassembly code. That in turn means * keeping an mbuf pointer in the reassembly queue (since we might * have a cluster). As a quick hack, the source & destination * port numbers (which are no longer needed once we've located the * tcpcb) are overlayed with an mbuf pointer. */ #if SIZEOF_CHAR_P == 4 typedef struct mbuf *mbufp_32; #else typedef u_int32_t mbufp_32; #endif #define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) /* * TCP statistics. * Many of these should be kept per connection, * but that's inconvenient at the moment. */ struct tcpstat { u_long tcps_connattempt; /* connections initiated */ u_long tcps_accepts; /* connections accepted */ u_long tcps_connects; /* connections established */ u_long tcps_drops; /* connections dropped */ u_long tcps_conndrops; /* embryonic connections dropped */ u_long tcps_closed; /* conn. closed (includes drops) */ u_long tcps_segstimed; /* segs where we tried to get rtt */ u_long tcps_rttupdated; /* times we succeeded */ u_long tcps_delack; /* delayed acks sent */ u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ u_long tcps_rexmttimeo; /* retransmit timeouts */ u_long tcps_persisttimeo; /* persist timeouts */ u_long tcps_keeptimeo; /* keepalive timeouts */ u_long tcps_keepprobe; /* keepalive probes sent */ u_long tcps_keepdrops; /* connections dropped in keepalive */ u_long tcps_sndtotal; /* total packets sent */ u_long tcps_sndpack; /* data packets sent */ u_long tcps_sndbyte; /* data bytes sent */ u_long tcps_sndrexmitpack; /* data packets retransmitted */ u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ u_long tcps_sndacks; /* ack-only packets sent */ u_long tcps_sndprobe; /* window probes sent */ u_long tcps_sndurg; /* packets sent with URG only */ u_long tcps_sndwinup; /* window update-only packets sent */ u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ u_long tcps_rcvtotal; /* total packets received */ u_long tcps_rcvpack; /* packets received in sequence */ u_long tcps_rcvbyte; /* bytes received in sequence */ u_long tcps_rcvbadsum; /* packets received with ccksum errs */ u_long tcps_rcvbadoff; /* packets received with bad offset */ /* u_long tcps_rcvshort; */ /* packets received too short */ u_long tcps_rcvduppack; /* duplicate-only packets received */ u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ u_long tcps_rcvpartduppack; /* packets with some duplicate data */ u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ u_long tcps_rcvoopack; /* out-of-order packets received */ u_long tcps_rcvoobyte; /* out-of-order bytes received */ u_long tcps_rcvpackafterwin; /* packets with data after window */ u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ u_long tcps_rcvafterclose; /* packets rcvd after "close" */ u_long tcps_rcvwinprobe; /* rcvd window probe packets */ u_long tcps_rcvdupack; /* rcvd duplicate acks */ u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ u_long tcps_rcvackpack; /* rcvd ack packets */ u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ u_long tcps_rcvwinupd; /* rcvd window update packets */ /* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ u_long tcps_predack; /* times hdr predict ok for acks */ u_long tcps_preddat; /* times hdr predict ok for data pkts */ u_long tcps_socachemiss; /* tcp_last_so misses */ u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ }; extern struct tcpstat tcpstat; /* tcp statistics */ extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ #endif BasiliskII/src/slirp/ip_input.c0000644000175000017500000004146711735673707016710 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp */ /* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #include "ip_icmp.h" int ip_defttl; struct ipstat ipstat; struct ipq ipq; /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */ void ip_init() { ipq.next = ipq.prev = (ipqp_32)&ipq; ip_id = tt.tv_sec & 0xffff; udp_init(); tcp_init(); ip_defttl = IPDEFTTL; } /* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ void ip_input(m) struct mbuf *m; { register struct ip *ip; int hlen; DEBUG_CALL("ip_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); ipstat.ips_total++; if (m->m_len < sizeof (struct ip)) { ipstat.ips_toosmall++; return; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { ipstat.ips_badvers++; goto bad; } hlen = ip->ip_hl << 2; if (hlenm->m_len) {/* min header length */ ipstat.ips_badhlen++; /* or packet too short */ goto bad; } /* keep ip header intact for ICMP reply * ip->ip_sum = cksum(m, hlen); * if (ip->ip_sum) { */ if(cksum(m,hlen)) { ipstat.ips_badsum++; goto bad; } /* * Convert fields to host representation. */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_len < ip->ip_len) { ipstat.ips_tooshort++; goto bad; } /* Should drop packet if mbuf too long? hmmm... */ if (m->m_len > ip->ip_len) m_adj(m, ip->ip_len - m->m_len); /* check ip_ttl for a correct ICMP reply */ if(ip->ip_ttl==0 || ip->ip_ttl==1) { icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); goto bad; } /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ /* We do no IP options */ /* if (hlen > sizeof (struct ip) && ip_dooptions(m)) * goto next; */ /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) * * XXX This should fail, don't fragment yet */ if (ip->ip_off &~ IP_DF) { register struct ipq *fp; /* * Look for queue of fragments * of this datagram. */ for (fp = (struct ipq *) ipq.next; fp != &ipq; fp = (struct ipq *) fp->next) if (ip->ip_id == fp->ipq_id && ip->ip_src.s_addr == fp->ipq_src.s_addr && ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ip->ip_p == fp->ipq_p) goto found; fp = 0; found: /* * Adjust ip_len to not reflect header, * set ip_mff if more fragments are expected, * convert offset of this to bytes. */ ip->ip_len -= hlen; if (ip->ip_off & IP_MF) ((struct ipasfrag *)ip)->ipf_mff |= 1; else ((struct ipasfrag *)ip)->ipf_mff &= ~1; ip->ip_off <<= 3; /* * If datagram marked as having more fragments * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. */ if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { ipstat.ips_fragments++; ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == 0) return; ipstat.ips_reassembled++; m = dtom(ip); } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen; /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; switch (ip->ip_p) { case IPPROTO_TCP: tcp_input(m, hlen, (struct socket *)NULL); break; case IPPROTO_UDP: udp_input(m, hlen); break; case IPPROTO_ICMP: icmp_input(m, hlen); break; default: ipstat.ips_noproto++; m_free(m); } return; bad: m_freem(m); return; } /* * Take incoming datagram fragment and try to * reassemble it into whole datagram. If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */ struct ip * ip_reass(ip, fp) register struct ipasfrag *ip; register struct ipq *fp; { register struct mbuf *m = dtom(ip); register struct ipasfrag *q; int hlen = ip->ip_hl << 2; int i, next; DEBUG_CALL("ip_reass"); DEBUG_ARG("ip = %lx", (long)ip); DEBUG_ARG("fp = %lx", (long)fp); DEBUG_ARG("m = %lx", (long)m); /* * Presence of header sizes in mbufs * would confuse code below. * Fragment m_data is concatenated. */ m->m_data += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { struct mbuf *t; if ((t = m_get()) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); insque_32(fp, &ipq); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; fp->ipq_src = ((struct ip *)ip)->ip_src; fp->ipq_dst = ((struct ip *)ip)->ip_dst; q = (struct ipasfrag *)fp; goto insert; } /* * Find a segment which begins after this one does. */ for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *)q->ipf_next) if (q->ip_off > ip->ip_off) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if (q->ipf_prev != (ipasfragp_32)fp) { i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; m_adj(dtom(ip), i); ip->ip_off += i; ip->ip_len -= i; } } /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { i = (ip->ip_off + ip->ip_len) - q->ip_off; if (i < q->ip_len) { q->ip_len -= i; q->ip_off += i; m_adj(dtom(q), i); break; } q = (struct ipasfrag *) q->ipf_next; m_freem(dtom((struct ipasfrag *) q->ipf_prev)); ip_deq((struct ipasfrag *) q->ipf_prev); } insert: /* * Stick new segment in its place; * check for complete reassembly. */ ip_enq(ip, (struct ipasfrag *) q->ipf_prev); next = 0; for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *) q->ipf_next) { if (q->ip_off != next) return (0); next += q->ip_len; } if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) return (0); /* * Reassembly is complete; concatenate fragments. */ q = (struct ipasfrag *) fp->ipq_next; m = dtom(q); q = (struct ipasfrag *) q->ipf_next; while (q != (struct ipasfrag *)fp) { struct mbuf *t; t = dtom(q); q = (struct ipasfrag *) q->ipf_next; m_cat(m, t); } /* * Create header for new ip packet by * modifying header of first packet; * dequeue and discard fragment reassembly header. * Make header visible. */ ip = (struct ipasfrag *) fp->ipq_next; /* * If the fragments concatenated to an mbuf that's * bigger than the total size of the fragment, then and * m_ext buffer was alloced. But fp->ipq_next points to * the old buffer (in the mbuf), so we must point ip * into the new buffer. */ if (m->m_flags & M_EXT) { int delta; delta = (char *)ip - m->m_dat; ip = (struct ipasfrag *)(m->m_ext + delta); } /* DEBUG_ARG("ip = %lx", (long)ip); * ip=(struct ipasfrag *)m->m_data; */ ip->ip_len = next; ip->ipf_mff &= ~1; ((struct ip *)ip)->ip_src = fp->ipq_src; ((struct ip *)ip)->ip_dst = fp->ipq_dst; remque_32(fp); (void) m_free(dtom(fp)); m = dtom(ip); m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); return ((struct ip *)ip); dropfrag: ipstat.ips_fragdropped++; m_freem(m); return (0); } /* * Free a fragment reassembly header and all * associated datagrams. */ void ip_freef(fp) struct ipq *fp; { register struct ipasfrag *q, *p; for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { p = (struct ipasfrag *) q->ipf_next; ip_deq(q); m_freem(dtom(q)); } remque_32(fp); (void) m_free(dtom(fp)); } /* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */ void ip_enq(p, prev) register struct ipasfrag *p, *prev; { DEBUG_CALL("ip_enq"); DEBUG_ARG("prev = %lx", (long)prev); p->ipf_prev = (ipasfragp_32) prev; p->ipf_next = prev->ipf_next; ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; prev->ipf_next = (ipasfragp_32) p; } /* * To ip_enq as remque is to insque. */ void ip_deq(p) register struct ipasfrag *p; { ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; } /* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */ void ip_slowtimo() { register struct ipq *fp; DEBUG_CALL("ip_slowtimo"); fp = (struct ipq *) ipq.next; if (fp == 0) return; while (fp != &ipq) { --fp->ipq_ttl; fp = (struct ipq *) fp->next; if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { ipstat.ips_fragtimeout++; ip_freef((struct ipq *) fp->prev); } } } /* * Do option processing on a datagram, * possibly discarding it if bad options are encountered, * or forwarding it if source-routed. * Returns 1 if packet has been forwarded/freed, * 0 if the packet should be processed further. */ #ifdef notdef int ip_dooptions(m) struct mbuf *m; { register struct ip *ip = mtod(m, struct ip *); register u_char *cp; register struct ip_timestamp *ipt; register struct in_ifaddr *ia; /* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */ int opt, optlen, cnt, off, code, type, forward = 0; struct in_addr *sin, dst; typedef u_int32_t n_time; n_time ntime; dst = ip->ip_dst; cp = (u_char *)(ip + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else { optlen = cp[IPOPT_OLEN]; if (optlen <= 0 || optlen > cnt) { code = &cp[IPOPT_OLEN] - (u_char *)ip; goto bad; } } switch (opt) { default: break; /* * Source routing with record. * Find interface with current destination address. * If none on this machine then drop if strictly routed, * or do nothing if loosely routed. * Record interface address and bring up next address * component. If strictly routed make sure next * address is on directly accessible net. */ case IPOPT_LSRR: case IPOPT_SSRR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } ipaddr.sin_addr = ip->ip_dst; ia = (struct in_ifaddr *) ifa_ifwithaddr((struct sockaddr *)&ipaddr); if (ia == 0) { if (opt == IPOPT_SSRR) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } /* * Loose routing, and not at next destination * yet; nothing to do except forward. */ break; } off--; / * 0 origin * / if (off > optlen - sizeof(struct in_addr)) { /* * End of source route. Should be for us. */ save_rte(cp, ip->ip_src); break; } /* * locate outgoing interface */ bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); if (opt == IPOPT_SSRR) { #define INA struct in_ifaddr * #define SA struct sockaddr * if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) ia = (INA)ifa_ifwithnet((SA)&ipaddr); } else ia = ip_rtaddr(ipaddr.sin_addr); if (ia == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } ip->ip_dst = ipaddr.sin_addr; bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); /* * Let ip_intr's mcast routing check handle mcast pkts */ forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); break; case IPOPT_RR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } /* * If no space remains, ignore. */ off--; * 0 origin * if (off > optlen - sizeof(struct in_addr)) break; bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); /* * locate outgoing interface; if we're the destination, * use the incoming interface (should be same). */ if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_HOST; goto bad; } bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); break; case IPOPT_TS: code = cp - (u_char *)ip; ipt = (struct ip_timestamp *)cp; if (ipt->ipt_len < 5) goto bad; if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { if (++ipt->ipt_oflw == 0) goto bad; break; } sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); switch (ipt->ipt_flg) { case IPOPT_TS_TSONLY: break; case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; ipaddr.sin_addr = dst; ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, m->m_pkthdr.rcvif); if (ia == 0) continue; bcopy((caddr_t)&IA_SIN(ia)->sin_addr, (caddr_t)sin, sizeof(struct in_addr)); ipt->ipt_ptr += sizeof(struct in_addr); break; case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&ipaddr) == 0) continue; ipt->ipt_ptr += sizeof(struct in_addr); break; default: goto bad; } ntime = iptime(); bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, sizeof(n_time)); ipt->ipt_ptr += sizeof(n_time); } } if (forward) { ip_forward(m, 1); return (1); } } } return (0); bad: /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */ /* Not yet */ icmp_error(m, type, code, 0, 0); ipstat.ips_badoptions++; return (1); } #endif /* notdef */ /* * Strip out IP options, at higher * level protocol in the kernel. * Second argument is buffer to which options * will be moved, and return value is their length. * (XXX) should be deleted; last arg currently ignored. */ void ip_stripoptions(m, mopt) register struct mbuf *m; struct mbuf *mopt; { register int i; struct ip *ip = mtod(m, struct ip *); register caddr_t opts; int olen; olen = (ip->ip_hl<<2) - sizeof (struct ip); opts = (caddr_t)(ip + 1); i = m->m_len - (sizeof (struct ip) + olen); memcpy(opts, opts + olen, (unsigned)i); m->m_len -= olen; ip->ip_hl = sizeof(struct ip) >> 2; } BasiliskII/src/slirp/debug.c0000644000175000017500000002653410241066313016121 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * Portions copyright (c) 2000 Kelly Price. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include FILE *dfd = NULL; #ifdef DEBUG int dostats = 1; #else int dostats = 0; #endif int slirp_debug = 0; extern char *strerror _P((int)); /* Carry over one item from main.c so that the tty's restored. * Only done when the tty being used is /dev/tty --RedWolf */ extern struct termios slirp_tty_settings; extern int slirp_tty_restore; void debug_init(file, dbg) char *file; int dbg; { /* Close the old debugging file */ if (dfd) fclose(dfd); dfd = fopen(file,"w"); if (dfd != NULL) { #if 0 fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION); #endif fprintf(dfd,"Debugging Started level %i.\r\n",dbg); fflush(dfd); slirp_debug = dbg; } else { lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n", file, strerror(errno)); } } /* * Dump a packet in the same format as tcpdump -x */ #ifdef DEBUG void dump_packet(dat, n) void *dat; int n; { u_char *pptr = (u_char *)dat; int j,k; n /= 16; n++; DEBUG_MISC((dfd, "PACKET DUMPED: \n")); for(j = 0; j < n; j++) { for(k = 0; k < 6; k++) DEBUG_MISC((dfd, "%02x ", *pptr++)); DEBUG_MISC((dfd, "\n")); fflush(dfd); } } #endif #if 0 /* * Statistic routines * * These will print statistics to the screen, the debug file (dfd), or * a buffer, depending on "type", so that the stats can be sent over * the link as well. */ void ttystats(ttyp) struct ttys *ttyp; { struct slirp_ifstats *is = &ttyp->ifstats; char buff[512]; lprint(" \r\n"); if (if_comp & IF_COMPRESS) strcpy(buff, "on"); else if (if_comp & IF_NOCOMPRESS) strcpy(buff, "off"); else strcpy(buff, "off (for now)"); lprint("Unit %d:\r\n", ttyp->unit); lprint(" using %s encapsulation (VJ compression is %s)\r\n", ( #ifdef USE_PPP ttyp->proto==PROTO_PPP?"PPP": #endif "SLIP"), buff); lprint(" %d baudrate\r\n", ttyp->baud); lprint(" interface is %s\r\n", ttyp->up?"up":"down"); lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid); #ifndef FULL_BOLT lprint(" towrite is %d bytes\r\n", ttyp->towrite); #endif if (ttyp->zeros) lprint(" %d zeros have been typed\r\n", ttyp->zeros); else if (ttyp->ones) lprint(" %d ones have been typed\r\n", ttyp->ones); lprint("Interface stats:\r\n"); lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes); lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes); lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes); lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes); lprint(" %6d bad input packets\r\n", is->in_mbad); } void allttystats() { struct ttys *ttyp; for (ttyp = ttys; ttyp; ttyp = ttyp->next) ttystats(ttyp); } #endif void ipstats() { lprint(" \r\n"); lprint("IP stats:\r\n"); lprint(" %6d total packets received (%d were unaligned)\r\n", ipstat.ips_total, ipstat.ips_unaligned); lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers); lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum); lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort); lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall); lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen); lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen); lprint(" %6d fragments received\r\n", ipstat.ips_fragments); lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped); lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout); lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled); lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented); lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments); lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto); lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); } #if 0 void vjstats() { lprint(" \r\n"); lprint("VJ compression stats:\r\n"); lprint(" %6d outbound packets (%d compressed)\r\n", comp_s.sls_packets, comp_s.sls_compressed); lprint(" %6d searches for connection stats (%d misses)\r\n", comp_s.sls_searches, comp_s.sls_misses); lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin); lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin); lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin); lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed); } #endif void tcpstats() { lprint(" \r\n"); lprint("TCP stats:\r\n"); lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); lprint(" %6d data packets (%d bytes)\r\n", tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); lprint(" %6d data packets retransmitted (%d bytes)\r\n", tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte); lprint(" %6d ack-only packets (%d delayed)\r\n", tcpstat.tcps_sndacks, tcpstat.tcps_delack); lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg); lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe); lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); lprint(" %6d acks (for %d bytes)\r\n", tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch); lprint(" %6d packets received in sequence (%d bytes)\r\n", tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); lprint(" %6d completely duplicate packets (%d bytes)\r\n", tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); lprint(" %6d out-of-order packets (%d bytes)\r\n", tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte); lprint(" %6d packets of data after window (%d bytes)\r\n", tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin); lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe); lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd); lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose); lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); lprint(" %6d discarded for bad header offset fields\r\n", tcpstat.tcps_rcvbadoff); lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); lprint(" %6d connections closed (including %d drop)\r\n", tcpstat.tcps_closed, tcpstat.tcps_drops); lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops); lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n", tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated); lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo); lprint(" %6d connections dropped by rxmt timeout\r\n", tcpstat.tcps_timeoutdrop); lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo); lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo); lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe); lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops); lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); /* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ /* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ } void udpstats() { lprint(" \r\n"); lprint("UDP stats:\r\n"); lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets); lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops); lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum); lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen); lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss); lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); } void icmpstats() { lprint(" \r\n"); lprint("ICMP stats:\r\n"); lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received); lprint(" %6d were too short\r\n", icmpstat.icps_tooshort); lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum); lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp); lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype); lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); } void mbufstats() { struct mbuf *m; int i; lprint(" \r\n"); lprint("Mbuf stats:\r\n"); lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max); i = 0; for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next) i++; lprint(" %6d mbufs on free list\r\n", i); i = 0; for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) i++; lprint(" %6d mbufs on used list\r\n", i); lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued); } void sockstats() { char buff[256]; int n; struct socket *so; lprint(" \r\n"); lprint( "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); for (so = tcb.so_next; so != &tcb; so = so->so_next) { n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); while (n < 17) buff[n++] = ' '; buff[17] = 0; lprint("%s %3d %15s %5d ", buff, so->s, inet_ntoa(so->so_laddr), ntohs(so->so_lport)); lprint("%15s %5d %5d %5d\r\n", inet_ntoa(so->so_faddr), ntohs(so->so_fport), so->so_rcv.sb_cc, so->so_snd.sb_cc); } for (so = udb.so_next; so != &udb; so = so->so_next) { n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); while (n < 17) buff[n++] = ' '; buff[17] = 0; lprint("%s %3d %15s %5d ", buff, so->s, inet_ntoa(so->so_laddr), ntohs(so->so_lport)); lprint("%15s %5d %5d %5d\r\n", inet_ntoa(so->so_faddr), ntohs(so->so_fport), so->so_rcv.sb_cc, so->so_snd.sb_cc); } } #if 0 void slirp_exit(exit_status) int exit_status; { struct ttys *ttyp; DEBUG_CALL("slirp_exit"); DEBUG_ARG("exit_status = %d", exit_status); if (dostats) { lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; if (!dfd) debug_init("slirp_stats", 0xf); lprint_arg = (char **)&dfd; ipstats(); tcpstats(); udpstats(); icmpstats(); mbufstats(); sockstats(); allttystats(); vjstats(); } for (ttyp = ttys; ttyp; ttyp = ttyp->next) tty_detached(ttyp, 1); if (slirp_forked) { /* Menendez time */ if (kill(getppid(), SIGQUIT) < 0) lprint("Couldn't kill parent process %ld!\n", (long) getppid()); } /* Restore the terminal if we gotta */ if(slirp_tty_restore) tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */ exit(exit_status); } #endif BasiliskII/src/slirp/debug.h0000644000175000017500000000241310241066313016114 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define PRN_STDERR 1 #define PRN_SPRINTF 2 extern FILE *dfd; extern FILE *lfd; extern int dostats; extern int slirp_debug; #define DBG_CALL 0x1 #define DBG_MISC 0x2 #define DBG_ERROR 0x4 #define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR #ifdef DEBUG #define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } #define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } #define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } #define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } #define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } #else #define DEBUG_CALL(x) #define DEBUG_ARG(x, y) #define DEBUG_ARGS(x) #define DEBUG_MISC(x) #define DEBUG_ERROR(x) #endif void debug_init _P((char *, int)); //void ttystats _P((struct ttys *)); void allttystats _P((void)); void ipstats _P((void)); void vjstats _P((void)); void tcpstats _P((void)); void udpstats _P((void)); void icmpstats _P((void)); void mbufstats _P((void)); void sockstats _P((void)); void slirp_exit _P((int)); BasiliskII/src/slirp/ip_output.c0000644000175000017500000001242111735673707017075 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp */ /* * Changes and additions relating to SLiRP are * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include u_int16_t ip_id; /* * IP output. The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed. */ int ip_output(so, m0) struct socket *so; struct mbuf *m0; { register struct ip *ip; register struct mbuf *m = m0; register int hlen = sizeof(struct ip ); int len, off, error = 0; DEBUG_CALL("ip_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m0 = %lx", (long)m0); /* We do no options */ /* if (opt) { * m = ip_insertoptions(m, opt, &len); * hlen = len; * } */ ip = mtod(m, struct ip *); /* * Fill in IP header. */ ip->ip_v = IPVERSION; ip->ip_off &= IP_DF; ip->ip_id = htons(ip_id++); ip->ip_hl = hlen >> 2; ipstat.ips_localout++; /* * Verify that we have any chance at all of being able to queue * the packet or packet fragments */ /* XXX Hmmm... */ /* if (if_queued > if_thresh && towrite <= 0) { * error = ENOBUFS; * goto bad; * } */ /* * If small enough for interface, can just send directly. */ if ((u_int16_t)ip->ip_len <= if_mtu) { ip->ip_len = htons((u_int16_t)ip->ip_len); ip->ip_off = htons((u_int16_t)ip->ip_off); ip->ip_sum = 0; ip->ip_sum = cksum(m, hlen); if_output(so, m); goto done; } /* * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. */ if (ip->ip_off & IP_DF) { error = -1; ipstat.ips_cantfrag++; goto bad; } len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ if (len < 8) { error = -1; goto bad; } { int mhlen, firstlen = len; struct mbuf **mnext = &m->m_nextpkt; /* * Loop through length of segment after first fragment, * make new header and copy data of each part and link onto chain. */ m0 = m; mhlen = sizeof (struct ip); for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) { register struct ip *mhip; m = m_get(); if (m == 0) { error = -1; ipstat.ips_odropped++; goto sendorfree; } m->m_data += if_maxlinkhdr; mhip = mtod(m, struct ip *); *mhip = *ip; /* No options */ /* if (hlen > sizeof (struct ip)) { * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); * mhip->ip_hl = mhlen >> 2; * } */ m->m_len = mhlen; mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); if (ip->ip_off & IP_MF) mhip->ip_off |= IP_MF; if (off + len >= (u_int16_t)ip->ip_len) len = (u_int16_t)ip->ip_len - off; else mhip->ip_off |= IP_MF; mhip->ip_len = htons((u_int16_t)(len + mhlen)); if (m_copy(m, m0, off, len) < 0) { error = -1; goto sendorfree; } mhip->ip_off = htons((u_int16_t)mhip->ip_off); mhip->ip_sum = 0; mhip->ip_sum = cksum(m, mhlen); *mnext = m; mnext = &m->m_nextpkt; ipstat.ips_ofragments++; } /* * Update first fragment by trimming what's been copied out * and updating header, then send each fragment (in order). */ m = m0; m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len); ip->ip_len = htons((u_int16_t)m->m_len); ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); ip->ip_sum = 0; ip->ip_sum = cksum(m, hlen); sendorfree: for (m = m0; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) if_output(so, m); else m_freem(m); } if (error == 0) ipstat.ips_fragmented++; } done: return (error); bad: m_freem(m0); goto done; } BasiliskII/src/slirp/tcp_input.c0000644000175000017500000013715111735673707017062 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94 * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #include #include "ip_icmp.h" struct socket tcb; int tcprexmtthresh = 3; struct socket *tcp_last_so = &tcb; tcp_seq tcp_iss; /* tcp initial send seq # */ #define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) /* for modulo comparisons of timestamps */ #define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) #define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) /* * Insert segment ti into reassembly queue of tcp with * control block tp. Return TH_FIN if reassembly now includes * a segment with FIN. The macro form does the common case inline * (segment is the next to be received on an established connection, * and the queue is empty), avoiding linkage into and removal * from the queue and repetition of various conversions. * Set DELACK for segments received in order, but ack immediately * when segments are out of order (so fast retransmit can work). */ #ifdef TCP_ACK_HACK #define TCP_REASS(tp, ti, m, so, flags) {\ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (tcpiphdrp_32)(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) {\ if (ti->ti_flags & TH_PUSH) \ tp->t_flags |= TF_ACKNOW; \ else \ tp->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ tcpstat.tcps_rcvpack++;\ tcpstat.tcps_rcvbyte += (ti)->ti_len;\ if (so->so_emu) { \ if (tcp_emu((so),(m))) sbappend((so), (m)); \ } else \ sbappend((so), (m)); \ /* sorwakeup(so); */ \ } else {\ (flags) = tcp_reass((tp), (ti), (m)); \ tp->t_flags |= TF_ACKNOW; \ } \ } #else #define TCP_REASS(tp, ti, m, so, flags) { \ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (tcpiphdrp_32)(tp) && \ (tp)->t_state == TCPS_ESTABLISHED) { \ tp->t_flags |= TF_DELACK; \ (tp)->rcv_nxt += (ti)->ti_len; \ flags = (ti)->ti_flags & TH_FIN; \ tcpstat.tcps_rcvpack++;\ tcpstat.tcps_rcvbyte += (ti)->ti_len;\ if (so->so_emu) { \ if (tcp_emu((so),(m))) sbappend(so, (m)); \ } else \ sbappend((so), (m)); \ /* sorwakeup(so); */ \ } else { \ (flags) = tcp_reass((tp), (ti), (m)); \ tp->t_flags |= TF_ACKNOW; \ } \ } #endif int tcp_reass(tp, ti, m) register struct tcpcb *tp; register struct tcpiphdr *ti; struct mbuf *m; { register struct tcpiphdr *q; struct socket *so = tp->t_socket; int flags; /* * Call with ti==0 after become established to * force pre-ESTABLISHED data up to user socket. */ if (ti == 0) goto present; /* * Find a segment which begins after this one does. */ for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; q = (struct tcpiphdr *)q->ti_next) if (SEQ_GT(q->ti_seq, ti->ti_seq)) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { register int i; q = (struct tcpiphdr *)q->ti_prev; /* conversion to int (in i) handles seq wraparound */ i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { if (i >= ti->ti_len) { tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += ti->ti_len; m_freem(m); /* * Try to present any queued data * at the left window edge to the user. * This is needed after the 3-WHS * completes. */ goto present; /* ??? */ } m_adj(m, i); ti->ti_len -= i; ti->ti_seq += i; } q = (struct tcpiphdr *)(q->ti_next); } tcpstat.tcps_rcvoopack++; tcpstat.tcps_rcvoobyte += ti->ti_len; REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct tcpiphdr *)tp) { register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; if (i <= 0) break; if (i < q->ti_len) { q->ti_seq += i; q->ti_len -= i; m_adj((struct mbuf *) REASS_MBUF(q), i); break; } q = (struct tcpiphdr *)q->ti_next; m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); remque_32((void *)(q->ti_prev)); m_freem(m); } /* * Stick new segment in its place. */ insque_32(ti, (void *)(q->ti_prev)); present: /* * Present data to user, advancing rcv_nxt through * completed sequence space. */ if (!TCPS_HAVEESTABLISHED(tp->t_state)) return (0); ti = (struct tcpiphdr *) tp->seg_next; if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) return (0); if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) return (0); do { tp->rcv_nxt += ti->ti_len; flags = ti->ti_flags & TH_FIN; remque_32(ti); m = (struct mbuf *) REASS_MBUF(ti); /* XXX */ ti = (struct tcpiphdr *)ti->ti_next; /* if (so->so_state & SS_FCANTRCVMORE) */ if (so->so_state & SS_FCANTSENDMORE) m_freem(m); else { if (so->so_emu) { if (tcp_emu(so,m)) sbappend(so, m); } else sbappend(so, m); } } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); /* sorwakeup(so); */ return (flags); } /* * TCP input routine, follows pages 65-76 of the * protocol specification dated September, 1981 very closely. */ void tcp_input(m, iphlen, inso) register struct mbuf *m; int iphlen; struct socket *inso; { struct ip save_ip, *ip; register struct tcpiphdr *ti; caddr_t optp = NULL; int optlen = 0; int len, tlen, off; register struct tcpcb *tp = 0; register int tiflags; struct socket *so = 0; int todrop, acked, ourfinisacked, needoutput = 0; /* int dropsocket = 0; */ int iss = 0; u_long tiwin; int ret; /* int ts_present = 0; */ DEBUG_CALL("tcp_input"); DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", (long )m, iphlen, (long )inso )); /* * If called with m == 0, then we're continuing the connect */ if (m == NULL) { so = inso; /* Re-set a few variables */ tp = sototcpcb(so); m = so->so_m; so->so_m = 0; ti = so->so_ti; tiwin = ti->ti_win; tiflags = ti->ti_flags; goto cont_conn; } tcpstat.tcps_rcvtotal++; /* * Get IP and TCP header together in first mbuf. * Note: IP leaves IP header in first mbuf. */ ti = mtod(m, struct tcpiphdr *); if (iphlen > sizeof(struct ip )) { ip_stripoptions(m, (struct mbuf *)0); iphlen=sizeof(struct ip ); } /* XXX Check if too short */ /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ ip=mtod(m, struct ip *); save_ip = *ip; save_ip.ip_len+= iphlen; /* * Checksum extended TCP header and data. */ tlen = ((struct ip *)ti)->ip_len; ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_len = htons((u_int16_t)tlen); len = sizeof(struct ip ) + tlen; /* keep checksum for ICMP reply * ti->ti_sum = cksum(m, len); * if (ti->ti_sum) { */ if(cksum(m, len)) { tcpstat.tcps_rcvbadsum++; goto drop; } /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX */ off = ti->ti_off << 2; if (off < sizeof (struct tcphdr) || off > tlen) { tcpstat.tcps_rcvbadoff++; goto drop; } tlen -= off; ti->ti_len = tlen; if (off > sizeof (struct tcphdr)) { optlen = off - sizeof (struct tcphdr); optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr); /* * Do quick retrieval of timestamp options ("options * prediction?"). If timestamp is the only option and it's * formatted as recommended in RFC 1323 appendix A, we * quickly get the values now and not bother calling * tcp_dooptions(), etc. */ /* if ((optlen == TCPOLEN_TSTAMP_APPA || * (optlen > TCPOLEN_TSTAMP_APPA && * optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && * *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) && * (ti->ti_flags & TH_SYN) == 0) { * ts_present = 1; * ts_val = ntohl(*(u_int32_t *)(optp + 4)); * ts_ecr = ntohl(*(u_int32_t *)(optp + 8)); * optp = NULL; / * we've parsed the options * / * } */ } tiflags = ti->ti_flags; /* * Convert TCP protocol specific fields to host format. */ NTOHL(ti->ti_seq); NTOHL(ti->ti_ack); NTOHS(ti->ti_win); NTOHS(ti->ti_urp); /* * Drop TCP, IP headers and TCP options. */ m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); /* * Locate pcb for segment. */ findso: so = tcp_last_so; if (so->so_fport != ti->ti_dport || so->so_lport != ti->ti_sport || so->so_laddr.s_addr != ti->ti_src.s_addr || so->so_faddr.s_addr != ti->ti_dst.s_addr) { so = solookup(&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); if (so) tcp_last_so = so; ++tcpstat.tcps_socachemiss; } /* * If the state is CLOSED (i.e., TCB does not exist) then * all data in the incoming segment is discarded. * If the TCB exists but is in CLOSED state, it is embryonic, * but should either do a listen or a connect soon. * * state == CLOSED means we've done socreate() but haven't * attached it to a protocol yet... * * XXX If a TCB does not exist, and the TH_SYN flag is * the only flag set, then create a session, mark it * as if it was LISTENING, and continue... */ if (so == 0) { if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) goto dropwithreset; if ((so = socreate()) == NULL) goto dropwithreset; if (tcp_attach(so) < 0) { free(so); /* Not sofree (if it failed, it's not insqued) */ goto dropwithreset; } sbreserve(&so->so_snd, tcp_sndspace); sbreserve(&so->so_rcv, tcp_rcvspace); /* tcp_last_so = so; */ /* XXX ? */ /* tp = sototcpcb(so); */ so->so_laddr = ti->ti_src; so->so_lport = ti->ti_sport; so->so_faddr = ti->ti_dst; so->so_fport = ti->ti_dport; if ((so->so_iptos = tcp_tos(so)) == 0) so->so_iptos = ((struct ip *)ti)->ip_tos; tp = sototcpcb(so); tp->t_state = TCPS_LISTEN; } /* * If this is a still-connecting socket, this probably * a retransmit of the SYN. Whether it's a retransmit SYN * or something else, we nuke it. */ if (so->so_state & SS_ISFCONNECTING) goto drop; tp = sototcpcb(so); /* XXX Should never fail */ if (tp == 0) goto dropwithreset; if (tp->t_state == TCPS_CLOSED) goto drop; /* Unscale the window into a 32-bit value. */ /* if ((tiflags & TH_SYN) == 0) * tiwin = ti->ti_win << tp->snd_scale; * else */ tiwin = ti->ti_win; /* * Segment received on connection. * Reset idle time and keep-alive timer. */ tp->t_idle = 0; if (so_options) tp->t_timer[TCPT_KEEP] = tcp_keepintvl; else tp->t_timer[TCPT_KEEP] = tcp_keepidle; /* * Process options if not in LISTEN state, * else do it below (after getting remote address). */ if (optp && tp->t_state != TCPS_LISTEN) tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , */ /* &ts_present, &ts_val, &ts_ecr); */ /* * Header prediction: check for the two common cases * of a uni-directional data xfer. If the packet has * no control flags, is in-sequence, the window didn't * change and we're not retransmitting, it's a * candidate. If the length is zero and the ack moved * forward, we're the sender side of the xfer. Just * free the data acked & wake any higher level process * that was blocked waiting for space. If the length * is non-zero and the ack didn't move, we're the * receiver side. If we're getting packets in-order * (the reassembly queue is empty), add the data to * the socket buffer and note that we need a delayed ack. * * XXX Some of these tests are not needed * eg: the tiwin == tp->snd_wnd prevents many more * predictions.. with no *real* advantage.. */ if (tp->t_state == TCPS_ESTABLISHED && (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && /* (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */ ti->ti_seq == tp->rcv_nxt && tiwin && tiwin == tp->snd_wnd && tp->snd_nxt == tp->snd_max) { /* * If last ACK falls within this segment's sequence numbers, * record the timestamp. */ /* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { * tp->ts_recent_age = tcp_now; * tp->ts_recent = ts_val; * } */ if (ti->ti_len == 0) { if (SEQ_GT(ti->ti_ack, tp->snd_una) && SEQ_LEQ(ti->ti_ack, tp->snd_max) && tp->snd_cwnd >= tp->snd_wnd) { /* * this is a pure ack for outstanding data. */ ++tcpstat.tcps_predack; /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); * else */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp, tp->t_rtt); acked = ti->ti_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; sbdrop(&so->so_snd, acked); tp->snd_una = ti->ti_ack; m_freem(m); /* * If all outstanding data are acked, stop * retransmit timer, otherwise restart timer * using current (possibly backed-off) value. * If process is waiting for space, * wakeup/selwakeup/signal. If data * are ready to send, let tcp_output * decide between more output or persist. */ if (tp->snd_una == tp->snd_max) tp->t_timer[TCPT_REXMT] = 0; else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; /* * There's room in so_snd, sowwakup will read() * from the socket if we can */ /* if (so->so_snd.sb_flags & SB_NOTIFY) * sowwakeup(so); */ /* * This is called because sowwakeup might have * put data into so_snd. Since we don't so sowwakeup, * we don't need this.. XXX??? */ if (so->so_snd.sb_cc) (void) tcp_output(tp); return; } } else if (ti->ti_ack == tp->snd_una && tp->seg_next == (tcpiphdrp_32)tp && ti->ti_len <= sbspace(&so->so_rcv)) { /* * this is a pure, in-sequence data packet * with nothing on the reassembly queue and * we have enough buffer space to take it. */ ++tcpstat.tcps_preddat; tp->rcv_nxt += ti->ti_len; tcpstat.tcps_rcvpack++; tcpstat.tcps_rcvbyte += ti->ti_len; /* * Add data to socket buffer. */ if (so->so_emu) { if (tcp_emu(so,m)) sbappend(so, m); } else sbappend(so, m); /* * XXX This is called when data arrives. Later, check * if we can actually write() to the socket * XXX Need to check? It's be NON_BLOCKING */ /* sorwakeup(so); */ /* * If this is a short packet, then ACK now - with Nagel * congestion avoidance sender won't send more until * he gets an ACK. * * It is better to not delay acks at all to maximize * TCP throughput. See RFC 2581. */ tp->t_flags |= TF_ACKNOW; tcp_output(tp); return; } } /* header prediction */ /* * Calculate amount of space in receive window, * and then do TCP input processing. * Receive window is amount of space in rcv queue, * but not less than advertised window. */ { int win; win = sbspace(&so->so_rcv); if (win < 0) win = 0; tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); } switch (tp->t_state) { /* * If the state is LISTEN then ignore segment if it contains an RST. * If the segment contains an ACK then it is bad and send a RST. * If it does not contain a SYN then it is not interesting; drop it. * Don't bother responding if the destination was a broadcast. * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial * tp->iss, and send a segment: * * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. * Fill in remote peer address fields if not previously specified. * Enter SYN_RECEIVED state, and process any other fields of this * segment in this state. */ case TCPS_LISTEN: { if (tiflags & TH_RST) goto drop; if (tiflags & TH_ACK) goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; /* * This has way too many gotos... * But a bit of spaghetti code never hurt anybody :) */ /* * If this is destined for the control address, then flag to * tcp_ctl once connected, otherwise connect */ if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) { int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff; if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) { #if 0 if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { /* Command or exec adress */ so->so_state |= SS_CTL; } else #endif { /* May be an add exec */ struct ex_list *ex_ptr; for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if(ex_ptr->ex_fport == so->so_fport && lastbyte == ex_ptr->ex_addr) { so->so_state |= SS_CTL; break; } } } if(so->so_state & SS_CTL) goto cont_input; } /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ } if (so->so_emu & EMU_NOCONNECT) { so->so_emu &= ~EMU_NOCONNECT; goto cont_input; } if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { u_char code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", errno,strerror(errno))); if(errno == ECONNREFUSED) { /* ACK the SYN, send RST to refuse the connection */ tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0, TH_RST|TH_ACK); } else { if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; HTONL(ti->ti_seq); /* restore tcp header */ HTONL(ti->ti_ack); HTONS(ti->ti_win); HTONS(ti->ti_urp); m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); *ip=save_ip; icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); } tp = tcp_close(tp); m_free(m); } else { /* * Haven't connected yet, save the current mbuf * and ti, and return * XXX Some OS's don't tell us whether the connect() * succeeded or not. So we must time it out. */ so->so_m = m; so->so_ti = ti; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->t_state = TCPS_SYN_RECEIVED; } return; cont_conn: /* m==NULL * Check if the connect succeeded */ if (so->so_state & SS_NOFDREF) { tp = tcp_close(tp); goto dropwithreset; } cont_input: tcp_template(tp); if (optp) tcp_dooptions(tp, (u_char *)optp, optlen, ti); /* , */ /* &ts_present, &ts_val, &ts_ecr); */ if (iss) tp->iss = iss; else tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tp->irs = ti->ti_seq; tcp_sendseqinit(tp); tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; tp->t_state = TCPS_SYN_RECEIVED; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tcpstat.tcps_accepts++; goto trimthenstep6; } /* case TCPS_LISTEN */ /* * If the state is SYN_SENT: * if seg contains an ACK, but not for our SYN, drop the input. * if seg contains a RST, then drop the connection. * if seg does not contain SYN, then drop it. * Otherwise this is an acceptable SYN segment * initialize tp->rcv_nxt and tp->irs * if seg contains ack then advance tp->snd_una * if SYN has been acked change to ESTABLISHED else SYN_RCVD state * arrange for segment to be acked (eventually) * continue processing rest of data/controls, beginning with URG */ case TCPS_SYN_SENT: if ((tiflags & TH_ACK) && (SEQ_LEQ(ti->ti_ack, tp->iss) || SEQ_GT(ti->ti_ack, tp->snd_max))) goto dropwithreset; if (tiflags & TH_RST) { if (tiflags & TH_ACK) tp = tcp_drop(tp,0); /* XXX Check t_softerror! */ goto drop; } if ((tiflags & TH_SYN) == 0) goto drop; if (tiflags & TH_ACK) { tp->snd_una = ti->ti_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; } tp->t_timer[TCPT_REXMT] = 0; tp->irs = ti->ti_seq; tcp_rcvseqinit(tp); tp->t_flags |= TF_ACKNOW; if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { tcpstat.tcps_connects++; soisfconnected(so); tp->t_state = TCPS_ESTABLISHED; /* Do window scaling on this connection? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { * tp->snd_scale = tp->requested_s_scale; * tp->rcv_scale = tp->request_r_scale; * } */ (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0); /* * if we didn't have to retransmit the SYN, * use its rtt as our initial srtt & rtt var. */ if (tp->t_rtt) tcp_xmit_timer(tp, tp->t_rtt); } else tp->t_state = TCPS_SYN_RECEIVED; trimthenstep6: /* * Advance ti->ti_seq to correspond to first data byte. * If data, trim to stay within window, * dropping FIN if necessary. */ ti->ti_seq++; if (ti->ti_len > tp->rcv_wnd) { todrop = ti->ti_len - tp->rcv_wnd; m_adj(m, -todrop); ti->ti_len = tp->rcv_wnd; tiflags &= ~TH_FIN; tcpstat.tcps_rcvpackafterwin++; tcpstat.tcps_rcvbyteafterwin += todrop; } tp->snd_wl1 = ti->ti_seq - 1; tp->rcv_up = ti->ti_seq; goto step6; } /* switch tp->t_state */ /* * States other than LISTEN or SYN_SENT. * First check timestamp, if present. * Then check that at least some bytes of segment are within * receive window. If segment begins before rcv_nxt, * drop leading data (and SYN); if nothing left, just ack. * * RFC 1323 PAWS: If we have a timestamp reply on this segment * and it's less than ts_recent, drop it. */ /* if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && * TSTMP_LT(ts_val, tp->ts_recent)) { * */ /* Check to see if ts_recent is over 24 days old. */ /* if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { */ /* * * Invalidate ts_recent. If this segment updates * * ts_recent, the age will be reset later and ts_recent * * will get a valid value. If it does not, setting * * ts_recent to zero will at least satisfy the * * requirement that zero be placed in the timestamp * * echo reply when ts_recent isn't valid. The * * age isn't reset until we get a valid ts_recent * * because we don't want out-of-order segments to be * * dropped when ts_recent is old. * */ /* tp->ts_recent = 0; * } else { * tcpstat.tcps_rcvduppack++; * tcpstat.tcps_rcvdupbyte += ti->ti_len; * tcpstat.tcps_pawsdrop++; * goto dropafterack; * } * } */ todrop = tp->rcv_nxt - ti->ti_seq; if (todrop > 0) { if (tiflags & TH_SYN) { tiflags &= ~TH_SYN; ti->ti_seq++; if (ti->ti_urp > 1) ti->ti_urp--; else tiflags &= ~TH_URG; todrop--; } /* * Following if statement from Stevens, vol. 2, p. 960. */ if (todrop > ti->ti_len || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { /* * Any valid FIN must be to the left of the window. * At this point the FIN must be a duplicate or out * of sequence; drop it. */ tiflags &= ~TH_FIN; /* * Send an ACK to resynchronize and drop any data. * But keep on processing for RST or ACK. */ tp->t_flags |= TF_ACKNOW; todrop = ti->ti_len; tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += todrop; } else { tcpstat.tcps_rcvpartduppack++; tcpstat.tcps_rcvpartdupbyte += todrop; } m_adj(m, todrop); ti->ti_seq += todrop; ti->ti_len -= todrop; if (ti->ti_urp > todrop) ti->ti_urp -= todrop; else { tiflags &= ~TH_URG; ti->ti_urp = 0; } } /* * If new data are received on a connection after the * user processes are gone, then RST the other end. */ if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { tp = tcp_close(tp); tcpstat.tcps_rcvafterclose++; goto dropwithreset; } /* * If segment ends after window, drop trailing data * (and PUSH and FIN); if nothing left, just ACK. */ todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); if (todrop > 0) { tcpstat.tcps_rcvpackafterwin++; if (todrop >= ti->ti_len) { tcpstat.tcps_rcvbyteafterwin += ti->ti_len; /* * If a new connection request is received * while in TIME_WAIT, drop the old connection * and start over if the sequence numbers * are above the previous ones. */ if (tiflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { iss = tp->rcv_nxt + TCP_ISSINCR; tp = tcp_close(tp); goto findso; } /* * If window is closed can only take segments at * window edge, and have to drop data and PUSH from * incoming segments. Continue processing, but * remember to ack. Otherwise, drop segment * and ack. */ if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { tp->t_flags |= TF_ACKNOW; tcpstat.tcps_rcvwinprobe++; } else goto dropafterack; } else tcpstat.tcps_rcvbyteafterwin += todrop; m_adj(m, -todrop); ti->ti_len -= todrop; tiflags &= ~(TH_PUSH|TH_FIN); } /* * If last ACK falls within this segment's sequence numbers, * record its timestamp. */ /* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + * ((tiflags & (TH_SYN|TH_FIN)) != 0))) { * tp->ts_recent_age = tcp_now; * tp->ts_recent = ts_val; * } */ /* * If the RST bit is set examine the state: * SYN_RECEIVED STATE: * If passive open, return to LISTEN state. * If active open, inform user that connection was refused. * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: * Inform user that connection was reset, and close tcb. * CLOSING, LAST_ACK, TIME_WAIT STATES * Close the tcb. */ if (tiflags&TH_RST) switch (tp->t_state) { case TCPS_SYN_RECEIVED: /* so->so_error = ECONNREFUSED; */ goto close; case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: /* so->so_error = ECONNRESET; */ close: tp->t_state = TCPS_CLOSED; tcpstat.tcps_drops++; tp = tcp_close(tp); goto drop; case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: tp = tcp_close(tp); goto drop; } /* * If a SYN is in the window, then this is an * error and we send an RST and drop the connection. */ if (tiflags & TH_SYN) { tp = tcp_drop(tp,0); goto dropwithreset; } /* * If the ACK bit is off we drop the segment and return. */ if ((tiflags & TH_ACK) == 0) goto drop; /* * Ack processing. */ switch (tp->t_state) { /* * In SYN_RECEIVED state if the ack ACKs our SYN then enter * ESTABLISHED state and continue processing, otherwise * send an RST. una<=ack<=max */ case TCPS_SYN_RECEIVED: if (SEQ_GT(tp->snd_una, ti->ti_ack) || SEQ_GT(ti->ti_ack, tp->snd_max)) goto dropwithreset; tcpstat.tcps_connects++; tp->t_state = TCPS_ESTABLISHED; /* * The sent SYN is ack'ed with our sequence number +1 * The first data byte already in the buffer will get * lost if no correction is made. This is only needed for * SS_CTL since the buffer is empty otherwise. * tp->snd_una++; or: */ tp->snd_una=ti->ti_ack; if (so->so_state & SS_CTL) { /* So tcp_ctl reports the right state */ ret = tcp_ctl(so); if (ret == 1) { soisfconnected(so); so->so_state &= ~SS_CTL; /* success XXX */ } else if (ret == 2) { so->so_state = SS_NOFDREF; /* CTL_CMD */ } else { needoutput = 1; tp->t_state = TCPS_FIN_WAIT_1; } } else { soisfconnected(so); } /* Do window scaling? */ /* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == * (TF_RCVD_SCALE|TF_REQ_SCALE)) { * tp->snd_scale = tp->requested_s_scale; * tp->rcv_scale = tp->request_r_scale; * } */ (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0); tp->snd_wl1 = ti->ti_seq - 1; /* Avoid ack processing; snd_una==ti_ack => dup ack */ goto synrx_to_est; /* fall into ... */ /* * In ESTABLISHED state: drop duplicate ACKs; ACK out of range * ACKs. If the ack is in the range * tp->snd_una < ti->ti_ack <= tp->snd_max * then advance tp->snd_una to ti->ti_ack and drop * data from the retransmission queue. If this ACK reflects * more up to date window information we update our window information. */ case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { tcpstat.tcps_rcvdupack++; DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", (long )m, (long )so)); /* * If we have outstanding data (other than * a window probe), this is a completely * duplicate ack (ie, window info didn't * change), the ack is the biggest we've * seen and we've seen exactly our rexmt * threshold of them, assume a packet * has been dropped and retransmit it. * Kludge snd_nxt & the congestion * window so we send only this one * packet. * * We know we're losing at the current * window size so do congestion avoidance * (set ssthresh to half the current window * and pull our congestion window back to * the new ssthresh). * * Dup acks mean that packets have left the * network (they're now cached at the receiver) * so bump cwnd by the amount in the receiver * to keep a constant cwnd packets in the * network. */ if (tp->t_timer[TCPT_REXMT] == 0 || ti->ti_ack != tp->snd_una) tp->t_dupacks = 0; else if (++tp->t_dupacks == tcprexmtthresh) { tcp_seq onxt = tp->snd_nxt; u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; if (win < 2) win = 2; tp->snd_ssthresh = win * tp->t_maxseg; tp->t_timer[TCPT_REXMT] = 0; tp->t_rtt = 0; tp->snd_nxt = ti->ti_ack; tp->snd_cwnd = tp->t_maxseg; (void) tcp_output(tp); tp->snd_cwnd = tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks; if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; goto drop; } else if (tp->t_dupacks > tcprexmtthresh) { tp->snd_cwnd += tp->t_maxseg; (void) tcp_output(tp); goto drop; } } else tp->t_dupacks = 0; break; } synrx_to_est: /* * If the congestion window was inflated to account * for the other side's cached packets, retract it. */ if (tp->t_dupacks > tcprexmtthresh && tp->snd_cwnd > tp->snd_ssthresh) tp->snd_cwnd = tp->snd_ssthresh; tp->t_dupacks = 0; if (SEQ_GT(ti->ti_ack, tp->snd_max)) { tcpstat.tcps_rcvacktoomuch++; goto dropafterack; } acked = ti->ti_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; /* * If we have a timestamp reply, update smoothed * round trip time. If no timestamp is present but * transmit timer is running and timed sequence * number was acked, update smoothed round trip time. * Since we now have an rtt measurement, cancel the * timer backoff (cf., Phil Karn's retransmit alg.). * Recompute the initial retransmit timer. */ /* if (ts_present) * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); * else */ if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp,tp->t_rtt); /* * If all outstanding data is acked, stop retransmit * timer and remember to restart (more output or persist). * If there is more data to be acked, restart retransmit * timer, using current (possibly backed-off) value. */ if (ti->ti_ack == tp->snd_max) { tp->t_timer[TCPT_REXMT] = 0; needoutput = 1; } else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; /* * When new data is acked, open the congestion window. * If the window gives us less than ssthresh packets * in flight, open exponentially (maxseg per packet). * Otherwise open linearly: maxseg per window * (maxseg^2 / cwnd per packet). */ { register u_int cw = tp->snd_cwnd; register u_int incr = tp->t_maxseg; if (cw > tp->snd_ssthresh) incr = incr * incr / cw; tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); } if (acked > so->so_snd.sb_cc) { tp->snd_wnd -= so->so_snd.sb_cc; sbdrop(&so->so_snd, (int )so->so_snd.sb_cc); ourfinisacked = 1; } else { sbdrop(&so->so_snd, acked); tp->snd_wnd -= acked; ourfinisacked = 0; } /* * XXX sowwakup is called when data is acked and there's room for * for more data... it should read() the socket */ /* if (so->so_snd.sb_flags & SB_NOTIFY) * sowwakeup(so); */ tp->snd_una = ti->ti_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; switch (tp->t_state) { /* * In FIN_WAIT_1 STATE in addition to the processing * for the ESTABLISHED state if our FIN is now acknowledged * then enter FIN_WAIT_2. */ case TCPS_FIN_WAIT_1: if (ourfinisacked) { /* * If we can't receive any more * data, then closing user can proceed. * Starting the timer is contrary to the * specification, but if we don't get a FIN * we'll hang forever. */ if (so->so_state & SS_FCANTRCVMORE) { soisfdisconnected(so); tp->t_timer[TCPT_2MSL] = tcp_maxidle; } tp->t_state = TCPS_FIN_WAIT_2; } break; /* * In CLOSING STATE in addition to the processing for * the ESTABLISHED state if the ACK acknowledges our FIN * then enter the TIME-WAIT state, otherwise ignore * the segment. */ case TCPS_CLOSING: if (ourfinisacked) { tp->t_state = TCPS_TIME_WAIT; tcp_canceltimers(tp); tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; soisfdisconnected(so); } break; /* * In LAST_ACK, we may still be waiting for data to drain * and/or to be acked, as well as for the ack of our FIN. * If our FIN is now acknowledged, delete the TCB, * enter the closed state and return. */ case TCPS_LAST_ACK: if (ourfinisacked) { tp = tcp_close(tp); goto drop; } break; /* * In TIME_WAIT state the only thing that should arrive * is a retransmission of the remote FIN. Acknowledge * it and restart the finack timer. */ case TCPS_TIME_WAIT: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; goto dropafterack; } } /* switch(tp->t_state) */ step6: /* * Update window information. * Don't look at window if no ACK: TAC's send garbage on first SYN. */ if ((tiflags & TH_ACK) && (SEQ_LT(tp->snd_wl1, ti->ti_seq) || (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { /* keep track of pure window updates */ if (ti->ti_len == 0 && tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) tcpstat.tcps_rcvwinupd++; tp->snd_wnd = tiwin; tp->snd_wl1 = ti->ti_seq; tp->snd_wl2 = ti->ti_ack; if (tp->snd_wnd > tp->max_sndwnd) tp->max_sndwnd = tp->snd_wnd; needoutput = 1; } /* * Process segments with URG. */ if ((tiflags & TH_URG) && ti->ti_urp && TCPS_HAVERCVDFIN(tp->t_state) == 0) { /* * This is a kludge, but if we receive and accept * random urgent pointers, we'll crash in * soreceive. It's hard to imagine someone * actually wanting to send this much urgent data. */ if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { ti->ti_urp = 0; tiflags &= ~TH_URG; goto dodata; } /* * If this segment advances the known urgent pointer, * then mark the data stream. This should not happen * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since * a FIN has been received from the remote side. * In these states we ignore the URG. * * According to RFC961 (Assigned Protocols), * the urgent pointer points to the last octet * of urgent data. We continue, however, * to consider it to indicate the first octet * of data past the urgent section as the original * spec states (in one of two places). */ if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { tp->rcv_up = ti->ti_seq + ti->ti_urp; so->so_urgc = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt); /* -1; */ tp->rcv_up = ti->ti_seq + ti->ti_urp; } } else /* * If no out of band data is expected, * pull receive urgent pointer along * with the receive window. */ if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) tp->rcv_up = tp->rcv_nxt; dodata: /* * Process the segment text, merging it into the TCP sequencing queue, * and arranging for acknowledgment of receipt if necessary. * This process logically involves adjusting tp->rcv_wnd as data * is presented to the user (this happens in tcp_usrreq.c, * case PRU_RCVD). If a FIN has already been received on this * connection then we just ignore the text. */ if ((ti->ti_len || (tiflags&TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { TCP_REASS(tp, ti, m, so, tiflags); /* * Note the amount of data that peer has sent into * our window, in order to estimate the sender's * buffer size. */ len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt); } else { m_free(m); tiflags &= ~TH_FIN; } /* * If FIN is received ACK the FIN and let the user know * that the connection is closing. */ if (tiflags & TH_FIN) { if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { /* * If we receive a FIN we can't send more data, * set it SS_FDRAIN * Shutdown the socket if there is no rx data in the * buffer. * soread() is called on completion of shutdown() and * will got to TCPS_LAST_ACK, and use tcp_output() * to send the FIN. */ /* sofcantrcvmore(so); */ sofwdrain(so); tp->t_flags |= TF_ACKNOW; tp->rcv_nxt++; } switch (tp->t_state) { /* * In SYN_RECEIVED and ESTABLISHED STATES * enter the CLOSE_WAIT state. */ case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: if(so->so_emu == EMU_CTL) /* no shutdown on socket */ tp->t_state = TCPS_LAST_ACK; else tp->t_state = TCPS_CLOSE_WAIT; break; /* * If still in FIN_WAIT_1 STATE FIN has not been acked so * enter the CLOSING state. */ case TCPS_FIN_WAIT_1: tp->t_state = TCPS_CLOSING; break; /* * In FIN_WAIT_2 state enter the TIME_WAIT state, * starting the time-wait timer, turning off the other * standard timers. */ case TCPS_FIN_WAIT_2: tp->t_state = TCPS_TIME_WAIT; tcp_canceltimers(tp); tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; soisfdisconnected(so); break; /* * In TIME_WAIT state restart the 2 MSL time_wait timer. */ case TCPS_TIME_WAIT: tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; break; } } /* * If this is a small packet, then ACK now - with Nagel * congestion avoidance sender won't send more until * he gets an ACK. * * See above. */ /* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) { */ /* if ((ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg && * (so->so_iptos & IPTOS_LOWDELAY) == 0) || * ((so->so_iptos & IPTOS_LOWDELAY) && * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { */ if (ti->ti_len && (unsigned)ti->ti_len <= 5 && ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { tp->t_flags |= TF_ACKNOW; } /* * Return any desired output. */ if (needoutput || (tp->t_flags & TF_ACKNOW)) { (void) tcp_output(tp); } return; dropafterack: /* * Generate an ACK dropping incoming segment if it occupies * sequence space, where the ACK reflects our state. */ if (tiflags & TH_RST) goto drop; m_freem(m); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); return; dropwithreset: /* reuses m if m!=NULL, m_free() unnecessary */ if (tiflags & TH_ACK) tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); else { if (tiflags & TH_SYN) ti->ti_len++; tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK); } return; drop: /* * Drop space held by incoming segment and return. */ m_free(m); return; } /* , ts_present, ts_val, ts_ecr) */ /* int *ts_present; * u_int32_t *ts_val, *ts_ecr; */ void tcp_dooptions(tp, cp, cnt, ti) struct tcpcb *tp; u_char *cp; int cnt; struct tcpiphdr *ti; { u_int16_t mss; int opt, optlen; DEBUG_CALL("tcp_dooptions"); DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; if (opt == TCPOPT_EOL) break; if (opt == TCPOPT_NOP) optlen = 1; else { optlen = cp[1]; if (optlen <= 0) break; } switch (opt) { default: continue; case TCPOPT_MAXSEG: if (optlen != TCPOLEN_MAXSEG) continue; if (!(ti->ti_flags & TH_SYN)) continue; memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); NTOHS(mss); (void) tcp_mss(tp, mss); /* sets t_maxseg */ break; /* case TCPOPT_WINDOW: * if (optlen != TCPOLEN_WINDOW) * continue; * if (!(ti->ti_flags & TH_SYN)) * continue; * tp->t_flags |= TF_RCVD_SCALE; * tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); * break; */ /* case TCPOPT_TIMESTAMP: * if (optlen != TCPOLEN_TIMESTAMP) * continue; * *ts_present = 1; * memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); * NTOHL(*ts_val); * memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); * NTOHL(*ts_ecr); * */ /* * * A timestamp received in a SYN makes * * it ok to send timestamp requests and replies. * */ /* if (ti->ti_flags & TH_SYN) { * tp->t_flags |= TF_RCVD_TSTMP; * tp->ts_recent = *ts_val; * tp->ts_recent_age = tcp_now; * } */ break; } } } /* * Pull out of band byte out of a segment so * it doesn't appear in the user's data queue. * It is still reflected in the segment length for * sequencing purposes. */ #ifdef notdef void tcp_pulloutofband(so, ti, m) struct socket *so; struct tcpiphdr *ti; register struct mbuf *m; { int cnt = ti->ti_urp - 1; while (cnt >= 0) { if (m->m_len > cnt) { char *cp = mtod(m, caddr_t) + cnt; struct tcpcb *tp = sototcpcb(so); tp->t_iobc = *cp; tp->t_oobflags |= TCPOOB_HAVEDATA; memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); m->m_len--; return; } cnt -= m->m_len; m = m->m_next; /* XXX WRONG! Fix it! */ if (m == 0) break; } panic("tcp_pulloutofband"); } #endif /* notdef */ /* * Collect new round-trip time estimate * and update averages and current timeout. */ void tcp_xmit_timer(tp, rtt) register struct tcpcb *tp; int rtt; { register short delta; DEBUG_CALL("tcp_xmit_timer"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("rtt = %d", rtt); tcpstat.tcps_rttupdated++; if (tp->t_srtt != 0) { /* * srtt is stored as fixed point with 3 bits after the * binary point (i.e., scaled by 8). The following magic * is equivalent to the smoothing algorithm in rfc793 with * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed * point). Adjust rtt to origin 0. */ delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); if ((tp->t_srtt += delta) <= 0) tp->t_srtt = 1; /* * We accumulate a smoothed rtt variance (actually, a * smoothed mean difference), then set the retransmit * timer to smoothed rtt + 4 times the smoothed variance. * rttvar is stored as fixed point with 2 bits after the * binary point (scaled by 4). The following is * equivalent to rfc793 smoothing with an alpha of .75 * (rttvar = rttvar*3/4 + |delta| / 4). This replaces * rfc793's wired-in beta. */ if (delta < 0) delta = -delta; delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); if ((tp->t_rttvar += delta) <= 0) tp->t_rttvar = 1; } else { /* * No rtt measurement yet - use the unsmoothed rtt. * Set the variance to half the rtt (so our first * retransmit happens at 3*rtt). */ tp->t_srtt = rtt << TCP_RTT_SHIFT; tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); } tp->t_rtt = 0; tp->t_rxtshift = 0; /* * the retransmit should happen at rtt + 4 * rttvar. * Because of the way we do the smoothing, srtt and rttvar * will each average +1/2 tick of bias. When we compute * the retransmit timer, we want 1/2 tick of rounding and * 1 extra tick because of +-1/2 tick uncertainty in the * firing of the timer. The bias will give us exactly the * 1.5 tick we need. But, because the bias is * statistical, we have to test that we don't drop below * the minimum feasible timer (which is 2 ticks). */ TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ /* * We received an ack for a packet that wasn't retransmitted; * it is probably safe to discard any error indications we've * received recently. This isn't quite right, but close enough * for now (a route might have failed after we sent a segment, * and the return path might not be symmetrical). */ tp->t_softerror = 0; } /* * Determine a reasonable value for maxseg size. * If the route is known, check route for mtu. * If none, use an mss that can be handled on the outgoing * interface without forcing IP to fragment; if bigger than * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES * to utilize large mbufs. If no route is found, route has no mtu, * or the destination isn't local, use a default, hopefully conservative * size (usually 512 or the default IP max size, but no more than the mtu * of the interface), as we can't discover anything about intervening * gateways or networks. We also initialize the congestion/slow start * window to be a single segment if the destination isn't local. * While looking at the routing entry, we also initialize other path-dependent * parameters from pre-set or cached values in the routing entry. */ int tcp_mss(tp, offer) register struct tcpcb *tp; u_int offer; { struct socket *so = tp->t_socket; int mss; DEBUG_CALL("tcp_mss"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("offer = %d", offer); mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); if (offer) mss = min(mss, offer); mss = max(mss, 32); if (mss < tp->t_maxseg || offer != 0) tp->t_maxseg = mss; tp->snd_cwnd = mss; sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); DEBUG_MISC((dfd, " returning mss = %d\n", mss)); return mss; } BasiliskII/src/slirp/ctl.h0000644000175000017500000000021310241066313015604 0ustar centriscentris#define CTL_CMD 0 #define CTL_EXEC 1 #define CTL_ALIAS 2 #define CTL_DNS 3 #define CTL_SPECIAL "10.0.2.0" #define CTL_LOCAL "10.0.2.15" BasiliskII/src/slirp/tcp.h0000644000175000017500000001422011735673707015637 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcp.h 8.1 (Berkeley) 6/10/93 * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp */ #ifndef _TCP_H_ #define _TCP_H_ typedef u_int32_t tcp_seq; #define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ #define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ extern int tcp_rcvspace; extern int tcp_sndspace; extern struct socket *tcp_last_so; #define TCP_SNDSPACE 8192 #define TCP_RCVSPACE 8192 /* * TCP header. * Per RFC 793, September, 1981. */ #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct tcphdr { u_int16_t th_sport; /* source port */ u_int16_t th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ #ifdef WORDS_BIGENDIAN u_char th_off:4, /* data offset */ th_x2:4; /* (unused) */ #else u_char th_x2:4, /* (unused) */ th_off:4; /* data offset */ #endif u_int8_t th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 u_int16_t th_win; /* window */ u_int16_t th_sum; /* checksum */ u_int16_t th_urp; /* urgent pointer */ } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif #include "tcp_var.h" #define TCPOPT_EOL 0 #define TCPOPT_NOP 1 #define TCPOPT_MAXSEG 2 #define TCPOLEN_MAXSEG 4 #define TCPOPT_WINDOW 3 #define TCPOLEN_WINDOW 3 #define TCPOPT_SACK_PERMITTED 4 /* Experimental */ #define TCPOLEN_SACK_PERMITTED 2 #define TCPOPT_SACK 5 /* Experimental */ #define TCPOPT_TIMESTAMP 8 #define TCPOLEN_TIMESTAMP 10 #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ #define TCPOPT_TSTAMP_HDR \ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) /* * Default maximum segment size for TCP. * With an IP MSS of 576, this is 536, * but 512 is probably more convenient. * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). * * We make this 1460 because we only care about Ethernet in the qemu context. */ #define TCP_MSS 1460 #define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ #define TCP_MAX_WINSHIFT 14 /* maximum window shift */ /* * User-settable options (used with setsockopt). * * We don't use the system headers on unix because we have conflicting * local structures. We can't avoid the system definitions on Windows, * so we undefine them. */ #undef TCP_NODELAY #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ #undef TCP_MAXSEG /* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ /* * TCP FSM state definitions. * Per RFC793, September, 1981. */ #define TCP_NSTATES 11 #define TCPS_CLOSED 0 /* closed */ #define TCPS_LISTEN 1 /* listening for connection */ #define TCPS_SYN_SENT 2 /* active, have sent syn */ #define TCPS_SYN_RECEIVED 3 /* have send and received syn */ /* states < TCPS_ESTABLISHED are those where connections not established */ #define TCPS_ESTABLISHED 4 /* established */ #define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ /* states > TCPS_CLOSE_WAIT are those where user has closed */ #define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ #define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ #define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ /* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ #define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ #define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ #define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) #define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) #define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) /* * TCP sequence numbers are 32 bit integers operated * on with modular arithmetic. These macros can be * used to compare such integers. */ #define SEQ_LT(a,b) ((int)((a)-(b)) < 0) #define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) #define SEQ_GT(a,b) ((int)((a)-(b)) > 0) #define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) /* * Macros to initialize tcp sequence numbers for * send and receive from initial send and receive * sequence numbers. */ #define tcp_rcvseqinit(tp) \ (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 #define tcp_sendseqinit(tp) \ (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss #define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ extern tcp_seq tcp_iss; /* tcp initial send seq # */ extern char *tcpstates[]; #endif BasiliskII/src/slirp/udp.c0000644000175000017500000004166511735673707015651 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #include #include "ip_icmp.h" struct udpstat udpstat; struct socket udb; /* * UDP protocol implementation. * Per RFC 768, August, 1980. */ #ifndef COMPAT_42 int udpcksum = 1; #else int udpcksum = 0; /* XXX */ #endif struct socket *udp_last_so = &udb; void udp_init() { udb.so_next = udb.so_prev = &udb; } /* m->m_data points at ip packet header * m->m_len length ip packet * ip->ip_len length data (IPDU) */ void udp_input(m, iphlen) register struct mbuf *m; int iphlen; { register struct ip *ip; register struct udphdr *uh; /* struct mbuf *opts = 0;*/ int len; struct ip save_ip; struct socket *so; DEBUG_CALL("udp_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("iphlen = %d", iphlen); udpstat.udps_ipackets++; /* * Strip IP options, if any; should skip this, * make available to user, and use on returned packets, * but we don't yet have a way to check the checksum * with options still present. */ if(iphlen > sizeof(struct ip)) { ip_stripoptions(m, (struct mbuf *)0); iphlen = sizeof(struct ip); } /* * Get IP and UDP header together in first mbuf. */ ip = mtod(m, struct ip *); uh = (struct udphdr *)((caddr_t)ip + iphlen); /* * Make mbuf data length reflect UDP length. * If not enough data to reflect UDP length, drop. */ len = ntohs((u_int16_t)uh->uh_ulen); if (ip->ip_len != len) { if (len > ip->ip_len) { udpstat.udps_badlen++; goto bad; } m_adj(m, len - ip->ip_len); ip->ip_len = len; } /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ save_ip = *ip; save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ /* * Checksum extended UDP header and data. */ if (udpcksum && uh->uh_sum) { ((struct ipovly *)ip)->ih_next = 0; ((struct ipovly *)ip)->ih_prev = 0; ((struct ipovly *)ip)->ih_x1 = 0; ((struct ipovly *)ip)->ih_len = uh->uh_ulen; /* keep uh_sum for ICMP reply * uh->uh_sum = cksum(m, len + sizeof (struct ip)); * if (uh->uh_sum) { */ if(cksum(m, len + sizeof(struct ip))) { udpstat.udps_badsum++; goto bad; } } /* * handle DHCP/BOOTP */ if (ntohs(uh->uh_dport) == BOOTP_SERVER) { bootp_input(m); goto bad; } /* * handle TFTP */ if (ntohs(uh->uh_dport) == TFTP_SERVER) { tftp_input(m); goto bad; } /* * Locate pcb for datagram. */ so = udp_last_so; if (so->so_lport != uh->uh_sport || so->so_laddr.s_addr != ip->ip_src.s_addr) { struct socket *tmp; for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { if (tmp->so_lport == uh->uh_sport && tmp->so_laddr.s_addr == ip->ip_src.s_addr) { tmp->so_faddr.s_addr = ip->ip_dst.s_addr; tmp->so_fport = uh->uh_dport; so = tmp; break; } } if (tmp == &udb) { so = NULL; } else { udpstat.udpps_pcbcachemiss++; udp_last_so = so; } } if (so == NULL) { /* * If there's no socket for this packet, * create one */ if ((so = socreate()) == NULL) goto bad; if(udp_attach(so) == -1) { DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); goto bad; } /* * Setup fields */ /* udp_last_so = so; */ so->so_laddr = ip->ip_src; so->so_lport = uh->uh_sport; if ((so->so_iptos = udp_tos(so)) == 0) so->so_iptos = ip->ip_tos; /* * XXXXX Here, check if it's in udpexec_list, * and if it is, do the fork_exec() etc. */ } so->so_faddr = ip->ip_dst; /* XXX */ so->so_fport = uh->uh_dport; /* XXX */ iphlen += sizeof(struct udphdr); m->m_len -= iphlen; m->m_data += iphlen; /* * Now we sendto() the packet. */ if (so->so_emu) udp_emu(so, m); if(sosendto(so,m) == -1) { m->m_len += iphlen; m->m_data -= iphlen; *ip=save_ip; DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); } m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ /* restore the orig mbuf packet */ m->m_len += iphlen; m->m_data -= iphlen; *ip=save_ip; so->so_m=m; /* ICMP backup */ return; bad: m_freem(m); /* if (opts) m_freem(opts); */ return; } int udp_output2(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, int iptos) { register struct udpiphdr *ui; int error = 0; DEBUG_CALL("udp_output"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr); /* * Adjust for header */ m->m_data -= sizeof(struct udpiphdr); m->m_len += sizeof(struct udpiphdr); /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ ui->ui_src = saddr->sin_addr; ui->ui_dst = daddr->sin_addr; ui->ui_sport = saddr->sin_port; ui->ui_dport = daddr->sin_port; ui->ui_ulen = ui->ui_len; /* * Stuff checksum and output datagram. */ ui->ui_sum = 0; if (udpcksum) { if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) ui->ui_sum = 0xffff; } ((struct ip *)ui)->ip_len = m->m_len; ((struct ip *)ui)->ip_ttl = ip_defttl; ((struct ip *)ui)->ip_tos = iptos; udpstat.udps_opackets++; error = ip_output(so, m); return (error); } int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *addr) { struct sockaddr_in saddr, daddr; saddr = *addr; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { saddr.sin_addr.s_addr = so->so_faddr.s_addr; if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) saddr.sin_addr.s_addr = alias_addr.s_addr; } daddr.sin_addr = so->so_laddr; daddr.sin_port = so->so_lport; return udp_output2(so, m, &saddr, &daddr, so->so_iptos); } int udp_attach(so) struct socket *so; { struct sockaddr_in addr; if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { /* * Here, we bind() the socket. Although not really needed * (sendto() on an unbound socket will bind it), it's done * here so that emulation of ytalk etc. don't have to do it */ addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { int lasterrno=errno; closesocket(so->s); so->s=-1; #ifdef _WIN32 WSASetLastError(lasterrno); #else errno=lasterrno; #endif } else { /* success, insert in queue */ so->so_expire = curtime + SO_EXPIRE; insque(so,&udb); } } return(so->s); } void udp_detach(so) struct socket *so; { closesocket(so->s); /* if (so->so_m) m_free(so->so_m); done by sofree */ sofree(so); } struct tos_t udptos[] = { {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ {0, 0, 0, 0} }; u_int8_t udp_tos(so) struct socket *so; { int i = 0; while(udptos[i].tos) { if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { so->so_emu = udptos[i].emu; return udptos[i].tos; } i++; } return 0; } #ifdef EMULATE_TALK #include "talkd.h" #endif /* * Here, talk/ytalk/ntalk requests must be emulated */ void udp_emu(so, m) struct socket *so; struct mbuf *m; { struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); #ifdef EMULATE_TALK CTL_MSG_OLD *omsg; CTL_MSG *nmsg; char buff[sizeof(CTL_MSG)]; u_char type; struct talk_request { struct talk_request *next; struct socket *udp_so; struct socket *tcp_so; } *req; static struct talk_request *req_tbl = 0; #endif struct cu_header { uint16_t d_family; // destination family uint16_t d_port; // destination port uint32_t d_addr; // destination address uint16_t s_family; // source family uint16_t s_port; // source port uint32_t so_addr; // source address uint32_t seqn; // sequence number uint16_t message; // message uint16_t data_type; // data type uint16_t pkt_len; // packet length } *cu_head; switch(so->so_emu) { #ifdef EMULATE_TALK case EMU_TALK: case EMU_NTALK: /* * Talk emulation. We always change the ctl_addr to get * some answers from the daemon. When an ANNOUNCE comes, * we send LEAVE_INVITE to the local daemons. Also when a * DELETE comes, we send copies to the local daemons. */ if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; #define IS_OLD (so->so_emu == EMU_TALK) #define COPY_MSG(dest, src) { dest->type = src->type; \ dest->id_num = src->id_num; \ dest->pid = src->pid; \ dest->addr = src->addr; \ dest->ctl_addr = src->ctl_addr; \ memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } #define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) /* old_sockaddr to sockaddr_in */ if (IS_OLD) { /* old talk */ omsg = mtod(m, CTL_MSG_OLD*); nmsg = (CTL_MSG *) buff; type = omsg->type; OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); } else { /* new talk */ omsg = (CTL_MSG_OLD *) buff; nmsg = mtod(m, CTL_MSG *); type = nmsg->type; OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); } if (type == LOOK_UP) return; /* for LOOK_UP this is enough */ if (IS_OLD) { /* make a copy of the message */ COPY_MSG(nmsg, omsg); nmsg->vers = 1; nmsg->answer = 0; } else COPY_MSG(omsg, nmsg); /* * If if is an ANNOUNCE message, we go through the * request table to see if a tcp port has already * been redirected for this socket. If not, we solisten() * a new socket and add this entry to the table. * The port number of the tcp socket and our IP * are put to the addr field of the message structures. * Then a LEAVE_INVITE is sent to both local daemon * ports, 517 and 518. This is why we have two copies * of the message, one in old talk and one in new talk * format. */ if (type == ANNOUNCE) { int s; u_short temp_port; for(req = req_tbl; req; req = req->next) if (so == req->udp_so) break; /* found it */ if (!req) { /* no entry for so, create new */ req = (struct talk_request *) malloc(sizeof(struct talk_request)); req->udp_so = so; req->tcp_so = solisten(0, OTOSIN(omsg, addr)->sin_addr.s_addr, OTOSIN(omsg, addr)->sin_port, SS_FACCEPTONCE); req->next = req_tbl; req_tbl = req; } /* replace port number in addr field */ addrlen = sizeof(addr); getsockname(req->tcp_so->s, (struct sockaddr *) &addr, &addrlen); OTOSIN(omsg, addr)->sin_port = addr.sin_port; OTOSIN(omsg, addr)->sin_addr = our_addr; OTOSIN(nmsg, addr)->sin_port = addr.sin_port; OTOSIN(nmsg, addr)->sin_addr = our_addr; /* send LEAVE_INVITEs */ temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; omsg->type = nmsg->type = LEAVE_INVITE; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; addr.sin_port = htons(517); sendto(s, (char *)omsg, sizeof(*omsg), 0, (struct sockaddr *)&addr, sizeof(addr)); addr.sin_port = htons(518); sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *) &addr, sizeof(addr)); closesocket(s) ; omsg->type = nmsg->type = ANNOUNCE; OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; } /* * If it is a DELETE message, we send a copy to the * local daemons. Then we delete the entry corresponding * to our socket from the request table. */ if (type == DELETE) { struct talk_request *temp_req, *req_next; int s; u_short temp_port; temp_port = OTOSIN(omsg, ctl_addr)->sin_port; OTOSIN(omsg, ctl_addr)->sin_port = 0; OTOSIN(nmsg, ctl_addr)->sin_port = 0; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); addr.sin_addr = our_addr; addr.sin_family = AF_INET; addr.sin_port = htons(517); sendto(s, (char *)omsg, sizeof(*omsg), 0, (struct sockaddr *)&addr, sizeof(addr)); addr.sin_port = htons(518); sendto(s, (char *)nmsg, sizeof(*nmsg), 0, (struct sockaddr *)&addr, sizeof(addr)); closesocket(s); OTOSIN(omsg, ctl_addr)->sin_port = temp_port; OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; /* delete table entry */ if (so == req_tbl->udp_so) { temp_req = req_tbl; req_tbl = req_tbl->next; free(temp_req); } else { temp_req = req_tbl; for(req = req_tbl->next; req; req = req_next) { req_next = req->next; if (so == req->udp_so) { temp_req->next = req_next; free(req); break; } else { temp_req = req; } } } } return; #endif case EMU_CUSEEME: /* * Cu-SeeMe emulation. * Hopefully the packet is more that 16 bytes long. We don't * do any other tests, just replace the address and port * fields. */ if (m->m_len >= sizeof (*cu_head)) { if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) return; cu_head = mtod(m, struct cu_header *); cu_head->s_port = addr.sin_port; cu_head->so_addr = our_addr.s_addr; } return; } } struct socket * udp_listen(port, laddr, lport, flags) u_int port; u_int32_t laddr; u_int lport; int flags; { struct sockaddr_in addr; struct socket *so; socklen_t addrlen = sizeof(struct sockaddr_in); int opt = 1; if ((so = socreate()) == NULL) { free(so); return NULL; } so->s = socket(AF_INET,SOCK_DGRAM,0); so->so_expire = curtime + SO_EXPIRE; insque(so,&udb); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = port; if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { udp_detach(so); return NULL; } setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); /* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ getsockname(so->s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = alias_addr; else so->so_faddr = addr.sin_addr; so->so_lport = lport; so->so_laddr.s_addr = laddr; if (flags != SS_FACCEPTONCE) so->so_expire = 0; so->so_state = SS_ISFCONNECTED; return so; } BasiliskII/src/slirp/udp.h0000644000175000017500000001031311735673707015640 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)udp.h 8.1 (Berkeley) 6/10/93 * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp */ #ifndef _UDP_H_ #define _UDP_H_ #define UDP_TTL 0x60 #define UDP_UDPDATALEN 16192 extern struct socket *udp_last_so; /* * Udp protocol header. * Per RFC 768, September, 1981. */ #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct udphdr { u_int16_t uh_sport; /* source port */ u_int16_t uh_dport; /* destination port */ int16_t uh_ulen; /* udp length */ u_int16_t uh_sum; /* udp checksum */ } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif /* * UDP kernel structures and variables. */ struct udpiphdr { struct ipovly ui_i; /* overlaid ip structure */ struct udphdr ui_u; /* udp header */ }; #define ui_next ui_i.ih_next #define ui_prev ui_i.ih_prev #define ui_x1 ui_i.ih_x1 #define ui_pr ui_i.ih_pr #define ui_len ui_i.ih_len #define ui_src ui_i.ih_src #define ui_dst ui_i.ih_dst #define ui_sport ui_u.uh_sport #define ui_dport ui_u.uh_dport #define ui_ulen ui_u.uh_ulen #define ui_sum ui_u.uh_sum struct udpstat { /* input statistics: */ u_long udps_ipackets; /* total input packets */ u_long udps_hdrops; /* packet shorter than header */ u_long udps_badsum; /* checksum error */ u_long udps_badlen; /* data length larger than packet */ u_long udps_noport; /* no socket on port */ u_long udps_noportbcast; /* of above, arrived as broadcast */ u_long udps_fullsock; /* not delivered, input socket full */ u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ /* output statistics: */ u_long udps_opackets; /* total output packets */ }; /* * Names for UDP sysctl objects */ #define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ #define UDPCTL_MAXID 2 extern struct udpstat udpstat; extern struct socket udb; struct mbuf; void udp_init _P((void)); void udp_input _P((register struct mbuf *, int)); int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *)); int udp_attach _P((struct socket *)); void udp_detach _P((struct socket *)); u_int8_t udp_tos _P((struct socket *)); void udp_emu _P((struct socket *, struct mbuf *)); struct socket * udp_listen _P((u_int, u_int32_t, u_int, int)); int udp_output2(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, int iptos); #endif BasiliskII/src/slirp/ip_icmp.c0000644000175000017500000002436111735673707016473 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp */ #include "slirp.h" #include "ip_icmp.h" struct icmpstat icmpstat; /* The message sent when emulating PING */ /* Be nice and tell them it's just a psuedo-ping packet */ char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; /* list of actions for icmp_error() on RX of an icmp message */ static int icmp_flush[19] = { /* ECHO REPLY (0) */ 0, 1, 1, /* DEST UNREACH (3) */ 1, /* SOURCE QUENCH (4)*/ 1, /* REDIRECT (5) */ 1, 1, 1, /* ECHO (8) */ 0, /* ROUTERADVERT (9) */ 1, /* ROUTERSOLICIT (10) */ 1, /* TIME EXCEEDED (11) */ 1, /* PARAMETER PROBLEM (12) */ 1, /* TIMESTAMP (13) */ 0, /* TIMESTAMP REPLY (14) */ 0, /* INFO (15) */ 0, /* INFO REPLY (16) */ 0, /* ADDR MASK (17) */ 0, /* ADDR MASK REPLY (18) */ 0 }; /* * Process a received ICMP message. */ void icmp_input(m, hlen) struct mbuf *m; int hlen; { register struct icmp *icp; register struct ip *ip=mtod(m, struct ip *); int icmplen=ip->ip_len; /* int code; */ DEBUG_CALL("icmp_input"); DEBUG_ARG("m = %lx", (long )m); DEBUG_ARG("m_len = %d", m->m_len); icmpstat.icps_received++; /* * Locate icmp structure in mbuf, and check * that its not corrupted and of at least minimum length. */ if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ icmpstat.icps_tooshort++; freeit: m_freem(m); goto end_error; } m->m_len -= hlen; m->m_data += hlen; icp = mtod(m, struct icmp *); if (cksum(m, icmplen)) { icmpstat.icps_checksum++; goto freeit; } m->m_len += hlen; m->m_data -= hlen; /* icmpstat.icps_inhist[icp->icmp_type]++; */ /* code = icp->icmp_code; */ DEBUG_ARG("icmp_type = %d", icp->icmp_type); switch (icp->icmp_type) { case ICMP_ECHO: icp->icmp_type = ICMP_ECHOREPLY; ip->ip_len += hlen; /* since ip_input subtracts this */ if (ip->ip_dst.s_addr == alias_addr.s_addr) { icmp_reflect(m); } else { struct socket *so; struct sockaddr_in addr; if ((so = socreate()) == NULL) goto freeit; if(udp_attach(so) == -1) { DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); m_free(m); goto end_error; } so->so_m = m; so->so_faddr = ip->ip_dst; so->so_fport = htons(7); so->so_laddr = ip->ip_src; so->so_lport = htons(9); so->so_iptos = ip->ip_tos; so->so_type = IPPROTO_ICMP; so->so_state = SS_ISFCONNECTED; /* Send the packet */ addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ switch(ntohl(so->so_faddr.s_addr) & 0xff) { case CTL_DNS: addr.sin_addr = dns_addr; break; case CTL_ALIAS: default: addr.sin_addr = loopback_addr; break; } } else { addr.sin_addr = so->so_faddr; } addr.sin_port = so->so_fport; if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, (struct sockaddr *)&addr, sizeof(addr)) == -1) { DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", errno,strerror(errno))); icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); udp_detach(so); } } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ break; case ICMP_UNREACH: /* XXX? report error? close socket? */ case ICMP_TIMXCEED: case ICMP_PARAMPROB: case ICMP_SOURCEQUENCH: case ICMP_TSTAMP: case ICMP_MASKREQ: case ICMP_REDIRECT: icmpstat.icps_notsupp++; m_freem(m); break; default: icmpstat.icps_badtype++; m_freem(m); } /* swith */ end_error: /* m is m_free()'d xor put in a socket xor or given to ip_send */ return; } /* * Send an ICMP message in response to a situation * * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). * MUST NOT change this header information. * MUST NOT reply to a multicast/broadcast IP address. * MUST NOT reply to a multicast/broadcast MAC address. * MUST reply to only the first fragment. */ /* * Send ICMP_UNREACH back to the source regarding msrc. * mbuf *msrc is used as a template, but is NOT m_free()'d. * It is reported as the bad ip packet. The header should * be fully correct and in host byte order. * ICMP fragmentation is illegal. All machines must accept 576 bytes in one * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 */ #define ICMP_MAXDATALEN (IP_MSS-28) void icmp_error(msrc, type, code, minsize, message) struct mbuf *msrc; u_char type; u_char code; int minsize; char *message; { unsigned hlen, shlen, s_ip_len; register struct ip *ip; register struct icmp *icp; register struct mbuf *m; DEBUG_CALL("icmp_error"); DEBUG_ARG("msrc = %lx", (long )msrc); DEBUG_ARG("msrc_len = %d", msrc->m_len); if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; /* check msrc */ if(!msrc) goto end_error; ip = mtod(msrc, struct ip *); #if DEBUG { char bufa[20], bufb[20]; strcpy(bufa, inet_ntoa(ip->ip_src)); strcpy(bufb, inet_ntoa(ip->ip_dst)); DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); } #endif if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ shlen=ip->ip_hl << 2; s_ip_len=ip->ip_len; if(ip->ip_p == IPPROTO_ICMP) { icp = (struct icmp *)((char *)ip + shlen); /* * Assume any unknown ICMP type is an error. This isn't * specified by the RFC, but think about it.. */ if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; } /* make a copy */ if(!(m=m_get())) goto end_error; /* get mbuf */ { int new_m_size; new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; if(new_m_size>m->m_size) m_inc(m, new_m_size); } memcpy(m->m_data, msrc->m_data, msrc->m_len); m->m_len = msrc->m_len; /* copy msrc to m */ /* make the header of the reply packet */ ip = mtod(m, struct ip *); hlen= sizeof(struct ip ); /* no options in reply */ /* fill in icmp */ m->m_data += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ s_ip_len=ICMP_MAXDATALEN; m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ /* min. size = 8+sizeof(struct ip)+8 */ icp->icmp_type = type; icp->icmp_code = code; icp->icmp_id = 0; icp->icmp_seq = 0; memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ HTONS(icp->icmp_ip.ip_len); HTONS(icp->icmp_ip.ip_id); HTONS(icp->icmp_ip.ip_off); #if DEBUG if(message) { /* DEBUG : append message to ICMP packet */ int message_len; char *cpnt; message_len=strlen(message); if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; cpnt=(char *)m->m_data+m->m_len; memcpy(cpnt, message, message_len); m->m_len+=message_len; } #endif icp->icmp_cksum = 0; icp->icmp_cksum = cksum(m, m->m_len); m->m_data -= hlen; m->m_len += hlen; /* fill in ip */ ip->ip_hl = hlen >> 2; ip->ip_len = m->m_len; ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ ip->ip_ttl = MAXTTL; ip->ip_p = IPPROTO_ICMP; ip->ip_dst = ip->ip_src; /* ip adresses */ ip->ip_src = alias_addr; (void ) ip_output((struct socket *)NULL, m); icmpstat.icps_reflect++; end_error: return; } #undef ICMP_MAXDATALEN /* * Reflect the ip packet back to the source */ void icmp_reflect(m) struct mbuf *m; { register struct ip *ip = mtod(m, struct ip *); int hlen = ip->ip_hl << 2; int optlen = hlen - sizeof(struct ip ); register struct icmp *icp; /* * Send an icmp packet back to the ip level, * after supplying a checksum. */ m->m_data += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); icp->icmp_cksum = 0; icp->icmp_cksum = cksum(m, ip->ip_len - hlen); m->m_data -= hlen; m->m_len += hlen; /* fill in ip */ if (optlen > 0) { /* * Strip out original options by copying rest of first * mbuf's data back, and adjust the IP length. */ memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen, (unsigned )(m->m_len - hlen)); hlen -= optlen; ip->ip_hl = hlen >> 2; ip->ip_len -= optlen; m->m_len -= optlen; } ip->ip_ttl = MAXTTL; { /* swap */ struct in_addr icmp_dst; icmp_dst = ip->ip_dst; ip->ip_dst = ip->ip_src; ip->ip_src = icmp_dst; } (void ) ip_output((struct socket *)NULL, m); icmpstat.icps_reflect++; } BasiliskII/src/slirp/ip_icmp.h0000644000175000017500000001432411735673707016476 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp */ #ifndef _NETINET_IP_ICMP_H_ #define _NETINET_IP_ICMP_H_ /* * Interface Control Message Protocol Definitions. * Per RFC 792, September 1981. */ typedef u_int32_t n_time; /* * Structure of an icmp header. */ #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct icmp { u_char icmp_type; /* type of message, see below */ u_char icmp_code; /* type sub code */ u_short icmp_cksum; /* ones complement cksum of struct */ union { u_char ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { u_short icd_id; u_short icd_seq; } ih_idseq; int ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { u_short ipm_void; u_short ipm_nextmtu; } ih_pmtu; } icmp_hun; #define icmp_pptr icmp_hun.ih_pptr #define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq #define icmp_void icmp_hun.ih_void #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu union { struct id_ts { n_time its_otime; n_time its_rtime; n_time its_ttime; } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; uint32_t id_mask; char id_data[1]; } icmp_dun; #define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_ttime icmp_dun.id_ts.its_ttime #define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif /* * Lower bounds on packet lengths for various types. * For the error advice packets must first insure that the * packet is large enought to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. */ #define ICMP_MINLEN 8 /* abs minimum */ #define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ #define ICMP_MASKLEN 12 /* address mask */ #define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ #define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) /* N.B.: must separately check that ip_hl >= 5 */ /* * Definition of type and code field values. */ #define ICMP_ECHOREPLY 0 /* echo reply */ #define ICMP_UNREACH 3 /* dest unreachable, codes: */ #define ICMP_UNREACH_NET 0 /* bad net */ #define ICMP_UNREACH_HOST 1 /* bad host */ #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ #define ICMP_UNREACH_PORT 3 /* bad port */ #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ #define ICMP_REDIRECT 5 /* shorter route, codes: */ #define ICMP_REDIRECT_NET 0 /* for network */ #define ICMP_REDIRECT_HOST 1 /* for host */ #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ #define ICMP_ECHO 8 /* echo service */ #define ICMP_ROUTERADVERT 9 /* router advertisement */ #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ #define ICMP_TIMXCEED 11 /* time exceeded, code: */ #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ #define ICMP_PARAMPROB 12 /* ip header bad */ #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ #define ICMP_TSTAMP 13 /* timestamp request */ #define ICMP_TSTAMPREPLY 14 /* timestamp reply */ #define ICMP_IREQ 15 /* information request */ #define ICMP_IREQREPLY 16 /* information reply */ #define ICMP_MASKREQ 17 /* address mask request */ #define ICMP_MASKREPLY 18 /* address mask reply */ #define ICMP_MAXTYPE 18 #define ICMP_INFOTYPE(type) \ ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) void icmp_input _P((struct mbuf *, int)); void icmp_error _P((struct mbuf *, u_char, u_char, int, char *)); void icmp_reflect _P((struct mbuf *)); #endif BasiliskII/src/slirp/slirp_config.h0000644000175000017500000000643610713053556017526 0ustar centriscentris/* * User definable configuration options */ /* Undefine if you don't want talk emulation */ #undef EMULATE_TALK /* Define if you want the connection to be probed */ /* XXX Not working yet, so ignore this for now */ #undef PROBE_CONN /* Define to 1 if you want KEEPALIVE timers */ #define DO_KEEPALIVE 0 /* Define to MAX interfaces you expect to use at once */ /* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ /* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ #define MAX_INTERFACES 1 #define MAX_PPP_INTERFACES 1 /* Define if you want slirp's socket in /tmp */ /* XXXXXX Do this in ./configure */ #undef USE_TMPSOCKET /* Define if you want slirp to use cfsetXspeed() on the terminal */ #undef DO_CFSETSPEED /* Define this if you want slirp to write to the tty as fast as it can */ /* This should only be set if you are using load-balancing, slirp does a */ /* pretty good job on single modems already, and seting this will make */ /* interactive sessions less responsive */ /* XXXXX Talk about having fast modem as unit 0 */ #undef FULL_BOLT /* * Define if you want slirp to use less CPU * You will notice a small lag in interactive sessions, but it's not that bad * Things like Netscape/ftp/etc. are completely unaffected * This is mainly for sysadmins who have many slirp users */ #undef USE_LOWCPU /* Define this if your compiler doesn't like prototypes */ #ifndef __STDC__ #define NO_PROTOTYPES #endif /*********************************************************/ /* * Autoconf defined configuration options * You shouldn't need to touch any of these */ /* Ignore this */ #undef DUMMY_PPP /* XXX: Define according to how time.h should be included */ #undef TIME_WITH_SYS_TIME #define TIME_WITH_SYS_TIME 0 #undef HAVE_SYS_TIME_H /* Define if your sprintf returns char * instead of int */ #undef BAD_SPRINTF /* Define if you have readv */ #undef HAVE_READV /* Define if iovec needs to be declared */ #undef DECLARE_IOVEC #ifdef _WIN32 #define DECLARE_IOVEC #endif /* Define if a declaration of sprintf/fprintf is needed */ #undef DECLARE_SPRINTF /* Define if you have sys/stropts.h */ #undef HAVE_SYS_STROPTS_H /* Define if your compiler doesn't like prototypes */ #undef NO_PROTOTYPES /* Define if you don't have u_int32_t etc. typedef'd */ #undef NEED_TYPEDEFS #ifdef __sun__ #define NEED_TYPEDEFS #endif /* Define to sizeof(char *) */ #define SIZEOF_CHAR_P SIZEOF_VOID_P /* Define if you have random() */ #undef HAVE_RANDOM /* Define if you have srandom() */ #undef HAVE_SRANDOM /* Define if you have setenv */ #undef HAVE_SETENV /* Define if you have index() */ #undef HAVE_INDEX /* Define if you have bcmp() */ #undef HAVE_BCMP /* Define if you have drand48 */ #undef HAVE_DRAND48 /* Define if you have memmove */ #define HAVE_MEMMOVE /* Define if you have gethostid */ #undef HAVE_GETHOSTID /* Define if you DON'T have unix-domain sockets */ #undef NO_UNIX_SOCKETS #ifdef _WIN32 #define NO_UNIX_SOCKETS #endif /* Define if gettimeofday only takes one argument */ #undef GETTIMEOFDAY_ONE_ARG /* Define if you have revoke() */ #undef HAVE_REVOKE /* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ #undef HAVE_GRANTPT /* Define if you have fchmod */ #undef HAVE_FCHMOD /* Define if you have */ #undef HAVE_SYS_TYPES32_H BasiliskII/src/slirp/slirp.c0000644000175000017500000004051410713053556016167 0ustar centriscentris#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; const uint8_t special_ethaddr[6] = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 }; uint8_t client_ethaddr[6]; int do_slowtimo; int link_up; struct timeval tt; FILE *lfd; struct ex_list *exec_list; /* XXX: suppress those select globals */ fd_set *global_readfds, *global_writefds, *global_xfds; char slirp_hostname[33]; #ifdef _WIN32 static int get_dns_addr(struct in_addr *pdns_addr) { FIXED_INFO *FixedInfo=NULL; ULONG BufLen; DWORD ret; IP_ADDR_STRING *pIPAddr; struct in_addr tmp_addr; FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); BufLen = sizeof(FIXED_INFO); if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; } FixedInfo = GlobalAlloc(GPTR, BufLen); } if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; } return -1; } 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; while ( pIPAddr ) { printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); pIPAddr = pIPAddr ->Next; } #endif if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; } return 0; } #else static int get_dns_addr(struct in_addr *pdns_addr) { char buff[512]; char buff2[256]; FILE *f; int found = 0; struct in_addr tmp_addr; f = fopen("/etc/resolv.conf", "r"); if (!f) return -1; lprint("IP address of your DNS(s): "); while (fgets(buff, 512, f) != NULL) { if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { if (!inet_aton(buff2, &tmp_addr)) continue; if (tmp_addr.s_addr == loopback_addr.s_addr) tmp_addr = our_addr; /* If it's the first one, set it to dns_addr */ if (!found) *pdns_addr = tmp_addr; else lprint(", "); if (++found > 3) { lprint("(more)"); break; } else lprint("%s", inet_ntoa(tmp_addr)); } } fclose(f); if (!found) return -1; return 0; } #endif #ifdef _WIN32 void slirp_cleanup(void) { WSACleanup(); } #endif int slirp_init(void) { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); #ifdef _WIN32 { WSADATA Data; WSAStartup(MAKEWORD(2,0), &Data); atexit(slirp_cleanup); } #endif link_up = 1; if_init(); ip_init(); /* Initialise mbufs *after* setting the MTU */ m_init(); /* set default addresses */ inet_aton("127.0.0.1", &loopback_addr); if (get_dns_addr(&dns_addr) < 0) return -1; inet_aton(CTL_SPECIAL, &special_addr); alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); getouraddr(); return 0; } #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) #define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) #define UPD_NFDS(x) if (nfds < (x)) nfds = (x) /* * curtime kept to an accuracy of 1ms */ #ifdef _WIN32 static void updtime(void) { struct _timeb tb; _ftime(&tb); curtime = (u_int)tb.time * (u_int)1000; curtime += (u_int)tb.millitm; } #else static void updtime(void) { gettimeofday(&tt, 0); curtime = (u_int)tt.tv_sec * (u_int)1000; curtime += (u_int)tt.tv_usec / (u_int)1000; if ((tt.tv_usec % 1000) >= 500) curtime++; } #endif int slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) { struct socket *so, *so_next; int nfds; int timeout, tmp_time; /* fail safe */ global_readfds = NULL; global_writefds = NULL; global_xfds = NULL; nfds = *pnfds; /* * First, TCP sockets */ do_slowtimo = 0; if (link_up) { /* * *_slowtimo needs calling if there are IP fragments * in the fragment queue, or there are TCP connections active */ do_slowtimo = ((tcb.so_next != &tcb) || ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; /* * See if we need a tcp_fasttimo */ if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) time_fasttimo = curtime; /* Flag when we want a fasttimo */ /* * NOFDREF can include still connecting to local-host, * newly socreated() sockets etc. Don't want to select these. */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; /* * Set for reading sockets which are accepting */ if (so->so_state & SS_FACCEPTCONN) { FD_SET(so->s, readfds); UPD_NFDS(so->s); continue; } /* * Set for writing sockets which are connecting */ if (so->so_state & SS_ISFCONNECTING) { FD_SET(so->s, writefds); UPD_NFDS(so->s); continue; } /* * Set for writing if we are connected, can send more, and * we have something to send */ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { FD_SET(so->s, writefds); UPD_NFDS(so->s); } /* * Set for reading (and urgent data) if we are connected, can * receive more, and we have room for it XXX /2 ? */ if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { FD_SET(so->s, readfds); FD_SET(so->s, xfds); UPD_NFDS(so->s); } } /* * UDP sockets */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; /* * See if it's timed out */ if (so->so_expire) { if (so->so_expire <= curtime) { udp_detach(so); continue; } else do_slowtimo = 1; /* Let socket expire */ } /* * When UDP packets are received from over the * link, they're sendto()'d straight away, so * no need for setting for writing * Limit the number of packets queued by this session * to 4. Note that even though we try and limit this * to 4 packets, the session could have more queued * if the packets needed to be fragmented * (XXX <= 4 ?) */ if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { FD_SET(so->s, readfds); UPD_NFDS(so->s); } } } /* * Setup timeout to use minimum CPU usage, especially when idle */ timeout = -1; /* * If a slowtimo is needed, set timeout to 5ms from the last * slow timeout. If a fast timeout is needed, set timeout within * 2ms of when it was requested. */ # define SLOW_TIMO 5 # define FAST_TIMO 2 if (do_slowtimo) { timeout = (SLOW_TIMO - (curtime - last_slowtimo)) * 1000; if (timeout < 0) timeout = 0; else if (timeout > (SLOW_TIMO * 1000)) timeout = SLOW_TIMO * 1000; /* Can only fasttimo if we also slowtimo */ if (time_fasttimo) { tmp_time = (FAST_TIMO - (curtime - time_fasttimo)) * 1000; if (tmp_time < 0) tmp_time = 0; /* Choose the smallest of the 2 */ if (tmp_time < timeout) timeout = tmp_time; } } *pnfds = nfds; /* * Adjust the timeout to make the minimum timeout * 2ms (XXX?) to lessen the CPU load */ if (timeout < (FAST_TIMO * 1000)) timeout = FAST_TIMO * 1000; return timeout; } void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) { struct socket *so, *so_next; int ret; global_readfds = readfds; global_writefds = writefds; global_xfds = xfds; /* Update time */ updtime(); /* * See if anything has timed out */ if (link_up) { if (time_fasttimo && ((curtime - time_fasttimo) >= FAST_TIMO)) { tcp_fasttimo(); time_fasttimo = 0; } if (do_slowtimo && ((curtime - last_slowtimo) >= SLOW_TIMO)) { ip_slowtimo(); tcp_slowtimo(); last_slowtimo = curtime; } } /* * Check sockets */ if (link_up) { /* * Check TCP sockets */ for (so = tcb.so_next; so != &tcb; so = so_next) { so_next = so->so_next; /* * FD_ISSET is meaningless on these sockets * (and they can crash the program) */ if (so->so_state & SS_NOFDREF || so->s == -1) continue; /* * Check for URG data * This will soread as well, so no need to * test for readfds below if this succeeds */ if (FD_ISSET(so->s, xfds)) sorecvoob(so); /* * Check sockets for reading */ else if (FD_ISSET(so->s, readfds)) { /* * Check for incoming connections */ if (so->so_state & SS_FACCEPTCONN) { tcp_connect(so); continue; } /* else */ ret = soread(so); /* Output it if we read something */ if (ret > 0) tcp_output(sototcpcb(so)); } /* * Check sockets for writing */ if (FD_ISSET(so->s, writefds)) { /* * Check for non-blocking, still-connecting sockets */ if (so->so_state & SS_ISFCONNECTING) { /* Connected */ so->so_state &= ~SS_ISFCONNECTING; ret = send(so->s, &ret, 0, 0); if (ret < 0) { /* XXXXX Must fix, zero bytes is a NOP */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* else failed */ so->so_state = SS_NOFDREF; } /* else so->so_state &= ~SS_ISFCONNECTING; */ /* * Continue tcp_input */ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); /* continue; */ } else ret = sowrite(so); /* * XXXXX If we wrote something (a lot), there * could be a need for a window update. * In the worst case, the remote will send * a window probe to get things going again */ } /* * Probe a still-connecting, non-blocking socket * to check if it's still alive */ #ifdef PROBE_CONN if (so->so_state & SS_ISFCONNECTING) { ret = recv(so->s, (char *)&ret, 0,0); if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* Still connecting, continue */ /* else failed */ so->so_state = SS_NOFDREF; /* tcp_input will take care of it */ } else { ret = send(so->s, &ret, 0,0); if (ret < 0) { /* XXX */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ENOTCONN) continue; /* else failed */ so->so_state = SS_NOFDREF; } else so->so_state &= ~SS_ISFCONNECTING; } tcp_input((struct mbuf *)NULL, sizeof(struct ip),so); } /* SS_ISFCONNECTING */ #endif } /* * Now UDP sockets. * Incoming packets are sent straight away, they're not buffered. * Incoming UDP data isn't buffered either. */ for (so = udb.so_next; so != &udb; so = so_next) { so_next = so->so_next; if (so->s != -1 && FD_ISSET(so->s, readfds)) { sorecvfrom(so); } } } /* * See if we can start outputting */ if (if_queued && link_up) if_start(); /* clear global file descriptor sets. * these reside on the stack in vl.c * so they're unusable if we're not in * slirp_select_fill or slirp_select_poll. */ global_readfds = NULL; global_writefds = NULL; global_xfds = NULL; } #define ETH_ALEN 6 #define ETH_HLEN 14 #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_ARP 0x0806 /* Address Resolution packet */ #define ARPOP_REQUEST 1 /* ARP request */ #define ARPOP_REPLY 2 /* ARP reply */ struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ unsigned short h_proto; /* packet type ID field */ }; struct arphdr { unsigned short ar_hrd; /* format of hardware address */ unsigned short ar_pro; /* format of protocol address */ unsigned char ar_hln; /* length of hardware address */ unsigned char ar_pln; /* length of protocol address */ unsigned short ar_op; /* ARP opcode (command) */ /* * Ethernet looks like this : This bit is variable sized however... */ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ unsigned char ar_sip[4]; /* sender IP address */ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ unsigned char ar_tip[4]; /* target IP address */ }; void arp_input(const uint8_t *pkt, int pkt_len) { struct ethhdr *eh = (struct ethhdr *)pkt; struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; struct ethhdr *reh = (struct ethhdr *)arp_reply; struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); int ar_op; struct ex_list *ex_ptr; ar_op = ntohs(ah->ar_op); switch(ar_op) { case ARPOP_REQUEST: if (!memcmp(ah->ar_tip, &special_addr, 3)) { if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) goto arp_ok; for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_addr == ah->ar_tip[3]) goto arp_ok; } return; arp_ok: /* XXX: make an ARP request to have the client address */ memcpy(client_ethaddr, eh->h_source, ETH_ALEN); /* ARP request for alias/dns mac address */ memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); reh->h_source[5] = ah->ar_tip[3]; reh->h_proto = htons(ETH_P_ARP); rah->ar_hrd = htons(1); rah->ar_pro = htons(ETH_P_IP); rah->ar_hln = ETH_ALEN; rah->ar_pln = 4; rah->ar_op = htons(ARPOP_REPLY); memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); memcpy(rah->ar_sip, ah->ar_tip, 4); memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); memcpy(rah->ar_tip, ah->ar_sip, 4); slirp_output(arp_reply, sizeof(arp_reply)); } break; default: break; } } void slirp_input(const uint8_t *pkt, int pkt_len) { struct mbuf *m; int proto; if (pkt_len < ETH_HLEN) return; proto = (pkt[12] << 8) | pkt[13]; switch(proto) { case ETH_P_ARP: arp_input(pkt, pkt_len); break; case ETH_P_IP: m = m_get(); if (!m) return; /* Note: we add to align the IP header */ m->m_len = pkt_len + 2; memcpy(m->m_data + 2, pkt, pkt_len); m->m_data += 2 + ETH_HLEN; m->m_len -= 2 + ETH_HLEN; ip_input(m); break; default: break; } } /* output the IP packet to the ethernet device */ void if_encap(const uint8_t *ip_data, int ip_data_len) { uint8_t buf[1600]; struct ethhdr *eh = (struct ethhdr *)buf; if (ip_data_len + ETH_HLEN > sizeof(buf)) return; memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); /* XXX: not correct */ eh->h_source[5] = CTL_ALIAS; eh->h_proto = htons(ETH_P_IP); memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); slirp_output(buf, ip_data_len + ETH_HLEN); } int slirp_redir(int is_udp, int host_port, struct in_addr guest_addr, int guest_port) { if (is_udp) { if (!udp_listen(htons(host_port), guest_addr.s_addr, htons(guest_port), 0)) return -1; } else { if (!solisten(htons(host_port), guest_addr.s_addr, htons(guest_port), 0)) return -1; } return 0; } int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, int guest_port) { return add_exec(&exec_list, do_pty, (char *)args, addr_low_byte, htons(guest_port)); } BasiliskII/src/slirp/slirp.h0000644000175000017500000001655210424642724016201 0ustar centriscentris#ifndef __COMMON_H__ #define __COMMON_H__ #define CONFIG_QEMU #define DEBUG 1 #ifndef CONFIG_QEMU #include "version.h" #endif #include "config.h" #include "slirp_config.h" #ifdef _WIN32 # include typedef uint8_t u_int8_t; typedef uint16_t u_int16_t; typedef uint32_t u_int32_t; typedef uint64_t u_int64_t; typedef char *caddr_t; typedef int socklen_t; typedef unsigned long ioctlsockopt_t; # include # include # include # include # define USE_FIONBIO 1 # define EWOULDBLOCK WSAEWOULDBLOCK # define EINPROGRESS WSAEINPROGRESS # define ENOTCONN WSAENOTCONN # define EHOSTUNREACH WSAEHOSTUNREACH # define ENETUNREACH WSAENETUNREACH # define ECONNREFUSED WSAECONNREFUSED /* Basilisk II Router defines those */ # define udp_read_completion slirp_udp_read_completion # define write_udp slirp_write_udp # define init_udp slirp_init_udp # define final_udp slirp_final_udp #else typedef int ioctlsockopt_t; # define ioctlsocket ioctl # define closesocket(s) close(s) # define O_BINARY 0 #endif #include #ifdef HAVE_SYS_BITYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #include #ifdef NEED_TYPEDEFS typedef char int8_t; typedef unsigned char u_int8_t; # if SIZEOF_SHORT == 2 typedef short int16_t; typedef unsigned short u_int16_t; # else # if SIZEOF_INT == 2 typedef int int16_t; typedef unsigned int u_int16_t; # else #error Cannot find a type with sizeof() == 2 # endif # endif # if SIZEOF_SHORT == 4 typedef short int32_t; typedef unsigned short u_int32_t; # else # if SIZEOF_INT == 4 typedef int int32_t; typedef unsigned int u_int32_t; # else #error Cannot find a type with sizeof() == 4 # endif # endif #endif /* NEED_TYPEDEFS */ /* Basilisk II types glue */ typedef u_int8_t uint8; typedef u_int16_t uint16; typedef u_int32_t uint32; #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #include #include #ifndef HAVE_MEMMOVE #define memmove(x, y, z) bcopy(y, x, z) #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_STRING_H # include #else # include #endif #ifndef _WIN32 #include #endif #ifndef _P #ifndef NO_PROTOTYPES # define _P(x) x #else # define _P(x) () #endif #endif #ifndef _WIN32 #include #include #endif #ifdef GETTIMEOFDAY_ONE_ARG #define gettimeofday(x, y) gettimeofday(x) #endif /* Systems lacking strdup() definition in . */ #if defined(ultrix) char *strdup _P((const char *)); #endif /* Systems lacking malloc() definition in . */ #if defined(ultrix) || defined(hcx) void *malloc _P((size_t arg)); void free _P((void *ptr)); #endif #ifndef HAVE_INET_ATON int inet_aton _P((const char *cp, struct in_addr *ia)); #endif #include #ifndef NO_UNIX_SOCKETS #include #endif #include #ifdef HAVE_SYS_SIGNAL_H # include #endif #ifndef _WIN32 #include #endif #if defined(HAVE_SYS_IOCTL_H) # include #endif #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_SYS_WAIT_H # include #endif #ifdef HAVE_SYS_FILIO_H # include #endif #ifdef USE_PPP #include #endif #ifdef __STDC__ #include #else #include #endif #include /* Avoid conflicting with the libc insque() and remque(), which have different prototypes. */ #define insque slirp_insque #define remque slirp_remque #ifdef HAVE_SYS_STROPTS_H #include #endif #include "debug.h" #if defined __GNUC__ #define PACKED__ __attribute__ ((packed)) #elif defined __sgi #define PRAGMA_PACK_SUPPORTED 1 #define PACKED__ #else #error "Packed attribute or pragma shall be supported" #endif #include "ip.h" #include "tcp.h" #include "tcp_timer.h" #include "tcp_var.h" #include "tcpip.h" #include "udp.h" #include "icmp_var.h" #include "mbuf.h" #include "sbuf.h" #include "socket.h" #include "if.h" #include "main.h" #include "misc.h" #include "ctl.h" #ifdef USE_PPP #include "ppp/pppd.h" #include "ppp/ppp.h" #endif #include "bootp.h" #include "tftp.h" #include "libslirp.h" extern struct ttys *ttys_unit[MAX_INTERFACES]; #ifndef NULL #define NULL (void *)0 #endif #ifndef FULL_BOLT void if_start _P((void)); #else void if_start _P((struct ttys *)); #endif #ifdef BAD_SPRINTF # define vsprintf vsprintf_len # define sprintf sprintf_len extern int vsprintf_len _P((char *, const char *, va_list)); extern int sprintf_len _P((char *, const char *, ...)); #endif #ifdef DECLARE_SPRINTF # ifndef BAD_SPRINTF extern int vsprintf _P((char *, const char *, va_list)); # endif extern int vfprintf _P((FILE *, const char *, va_list)); #endif #ifndef HAVE_STRERROR extern char *strerror _P((int error)); #endif #ifndef HAVE_INDEX char *index _P((const char *, int)); #endif #ifndef HAVE_GETHOSTID long gethostid _P((void)); #endif void lprint _P((const char *, ...)); extern int do_echo; #if SIZEOF_CHAR_P == 4 # define insque_32 insque # define remque_32 remque #else inline void insque_32 _P((void *, void *)); inline void remque_32 _P((void *)); #endif #ifndef _WIN32 #include #endif #define DEFAULT_BAUD 115200 /* cksum.c */ int cksum(struct mbuf *m, int len); /* if.c */ void if_init _P((void)); void if_output _P((struct socket *, struct mbuf *)); /* ip_input.c */ void ip_init _P((void)); void ip_input _P((struct mbuf *)); struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); void ip_freef _P((struct ipq *)); void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); void ip_deq _P((register struct ipasfrag *)); void ip_slowtimo _P((void)); void ip_stripoptions _P((register struct mbuf *, struct mbuf *)); /* ip_output.c */ int ip_output _P((struct socket *, struct mbuf *)); /* tcp_input.c */ int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct mbuf *)); void tcp_input _P((register struct mbuf *, int, struct socket *)); void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); void tcp_xmit_timer _P((register struct tcpcb *, int)); int tcp_mss _P((register struct tcpcb *, u_int)); /* tcp_output.c */ int tcp_output _P((register struct tcpcb *)); void tcp_setpersist _P((register struct tcpcb *)); /* tcp_subr.c */ void tcp_init _P((void)); void tcp_template _P((struct tcpcb *)); void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int)); struct tcpcb * tcp_newtcpcb _P((struct socket *)); struct tcpcb * tcp_close _P((register struct tcpcb *)); void tcp_drain _P((void)); void tcp_sockclosed _P((struct tcpcb *)); int tcp_fconnect _P((struct socket *)); void tcp_connect _P((struct socket *)); int tcp_attach _P((struct socket *)); u_int8_t tcp_tos _P((struct socket *)); int tcp_emu _P((struct socket *, struct mbuf *)); int tcp_ctl _P((struct socket *)); struct tcpcb *tcp_drop(struct tcpcb *tp, int err); #ifdef USE_PPP #define MIN_MRU MINMRU #define MAX_MRU MAXMRU #else #define MIN_MRU 128 #define MAX_MRU 16384 #endif #ifndef _WIN32 #define min(x,y) ((x) < (y) ? (x) : (y)) #define max(x,y) ((x) > (y) ? (x) : (y)) #endif #ifdef _WIN32 #undef errno #define errno (WSAGetLastError()) #endif #endif BasiliskII/src/slirp/tcp_subr.c0000644000175000017500000010503511735673707016672 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define WANT_SYS_IOCTL_H #include #include /* patchable/settable parameters for tcp */ int tcp_mssdflt = TCP_MSS; int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ int tcp_rcvspace; /* You may want to change this */ int tcp_sndspace; /* Keep small if you have an error prone link */ /* * Tcp initialization */ void tcp_init() { tcp_iss = 1; /* wrong */ tcb.so_next = tcb.so_prev = &tcb; /* tcp_rcvspace = our Window we advertise to the remote */ tcp_rcvspace = TCP_RCVSPACE; tcp_sndspace = TCP_SNDSPACE; /* Make sure tcp_sndspace is at least 2*MSS */ if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); } /* * Create template to be used to send tcp packets on a connection. * Call after host entry created, fills * in a skeletal tcp/ip header, minimizing the amount of work * necessary when the connection is used. */ /* struct tcpiphdr * */ void tcp_template(tp) struct tcpcb *tp; { struct socket *so = tp->t_socket; register struct tcpiphdr *n = &tp->t_template; n->ti_next = n->ti_prev = 0; n->ti_x1 = 0; n->ti_pr = IPPROTO_TCP; n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); n->ti_src = so->so_faddr; n->ti_dst = so->so_laddr; n->ti_sport = so->so_fport; n->ti_dport = so->so_lport; n->ti_seq = 0; n->ti_ack = 0; n->ti_x2 = 0; n->ti_off = 5; n->ti_flags = 0; n->ti_win = 0; n->ti_sum = 0; n->ti_urp = 0; } /* * Send a single message to the TCP at address specified by * the given TCP/IP header. If m == 0, then we make a copy * of the tcpiphdr at ti and send directly to the addressed host. * This is used to force keep alive messages out using the TCP * template for a connection tp->t_template. If flags are given * then we send a message back to the TCP which originated the * segment ti, and discard the mbuf containing it and any other * attached mbufs. * * In any case the ack and sequence number of the transmitted * segment are as specified by the parameters. */ void tcp_respond(tp, ti, m, ack, seq, flags) struct tcpcb *tp; register struct tcpiphdr *ti; register struct mbuf *m; tcp_seq ack, seq; int flags; { register int tlen; int win = 0; DEBUG_CALL("tcp_respond"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("ti = %lx", (long)ti); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("ack = %u", ack); DEBUG_ARG("seq = %u", seq); DEBUG_ARG("flags = %x", flags); if (tp) win = sbspace(&tp->t_socket->so_rcv); if (m == 0) { if ((m = m_get()) == NULL) return; #ifdef TCP_COMPAT_42 tlen = 1; #else tlen = 0; #endif m->m_data += if_maxlinkhdr; *mtod(m, struct tcpiphdr *) = *ti; ti = mtod(m, struct tcpiphdr *); flags = TH_ACK; } else { /* * ti points into m so the next line is just making * the mbuf point to ti */ m->m_data = (caddr_t)ti; m->m_len = sizeof (struct tcpiphdr); tlen = 0; #define xchg(a,b,type) { type t; t=a; a=b; b=t; } xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); xchg(ti->ti_dport, ti->ti_sport, u_int16_t); #undef xchg } ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); tlen += sizeof (struct tcpiphdr); m->m_len = tlen; ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_seq = htonl(seq); ti->ti_ack = htonl(ack); ti->ti_x2 = 0; ti->ti_off = sizeof (struct tcphdr) >> 2; ti->ti_flags = flags; if (tp) ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); else ti->ti_win = htons((u_int16_t)win); ti->ti_urp = 0; ti->ti_sum = 0; ti->ti_sum = cksum(m, tlen); ((struct ip *)ti)->ip_len = tlen; if(flags & TH_RST) ((struct ip *)ti)->ip_ttl = MAXTTL; else ((struct ip *)ti)->ip_ttl = ip_defttl; (void) ip_output((struct socket *)0, m); } /* * Create a new TCP control block, making an * empty reassembly queue and hooking it to the argument * protocol control block. */ struct tcpcb * tcp_newtcpcb(so) struct socket *so; { register struct tcpcb *tp; tp = (struct tcpcb *)malloc(sizeof(*tp)); if (tp == NULL) return ((struct tcpcb *)0); memset((char *) tp, 0, sizeof(struct tcpcb)); tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; tp->t_maxseg = tcp_mssdflt; tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; tp->t_socket = so; /* * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives * reasonable initial retransmit time. */ tp->t_srtt = TCPTV_SRTTBASE; tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; tp->t_rttmin = TCPTV_MIN; TCPT_RANGESET(tp->t_rxtcur, ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, TCPTV_MIN, TCPTV_REXMTMAX); tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->t_state = TCPS_CLOSED; so->so_tcpcb = tp; return (tp); } /* * Drop a TCP connection, reporting * the specified error. If connection is synchronized, * then send a RST to peer. */ struct tcpcb *tcp_drop(struct tcpcb *tp, int err) { /* tcp_drop(tp, errno) register struct tcpcb *tp; int errno; { */ DEBUG_CALL("tcp_drop"); DEBUG_ARG("tp = %lx", (long)tp); DEBUG_ARG("errno = %d", errno); if (TCPS_HAVERCVDSYN(tp->t_state)) { tp->t_state = TCPS_CLOSED; (void) tcp_output(tp); tcpstat.tcps_drops++; } else tcpstat.tcps_conndrops++; /* if (errno == ETIMEDOUT && tp->t_softerror) * errno = tp->t_softerror; */ /* so->so_error = errno; */ return (tcp_close(tp)); } /* * Close a TCP control block: * discard all space held by the tcp * discard internet protocol block * wake up any sleepers */ struct tcpcb * tcp_close(tp) register struct tcpcb *tp; { register struct tcpiphdr *t; struct socket *so = tp->t_socket; register struct mbuf *m; DEBUG_CALL("tcp_close"); DEBUG_ARG("tp = %lx", (long )tp); /* free the reassembly queue, if any */ t = (struct tcpiphdr *) tp->seg_next; while (t != (struct tcpiphdr *)tp) { t = (struct tcpiphdr *)t->ti_next; m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); remque_32((struct tcpiphdr *) t->ti_prev); m_freem(m); } /* It's static */ /* if (tp->t_template) * (void) m_free(dtom(tp->t_template)); */ /* free(tp, M_PCB); */ free(tp); so->so_tcpcb = 0; soisfdisconnected(so); /* clobber input socket cache if we're closing the cached connection */ if (so == tcp_last_so) tcp_last_so = &tcb; closesocket(so->s); sbfree(&so->so_rcv); sbfree(&so->so_snd); sofree(so); tcpstat.tcps_closed++; return ((struct tcpcb *)0); } void tcp_drain() { /* XXX */ } /* * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. */ #ifdef notdef void tcp_quench(i, errno) int errno; { struct tcpcb *tp = intotcpcb(inp); if (tp) tp->snd_cwnd = tp->t_maxseg; } #endif /* notdef */ /* * TCP protocol interface to socket abstraction. */ /* * User issued close, and wish to trail through shutdown states: * if never received SYN, just forget it. If got a SYN from peer, * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. * If already got a FIN from peer, then almost done; go to LAST_ACK * state. In all other cases, have already sent FIN to peer (e.g. * after PRU_SHUTDOWN), and just have to play tedious game waiting * for peer to send FIN or not respond to keep-alives, etc. * We can let the user exit from the close as soon as the FIN is acked. */ void tcp_sockclosed(tp) struct tcpcb *tp; { DEBUG_CALL("tcp_sockclosed"); DEBUG_ARG("tp = %lx", (long)tp); switch (tp->t_state) { case TCPS_CLOSED: case TCPS_LISTEN: case TCPS_SYN_SENT: tp->t_state = TCPS_CLOSED; tp = tcp_close(tp); break; case TCPS_SYN_RECEIVED: case TCPS_ESTABLISHED: tp->t_state = TCPS_FIN_WAIT_1; break; case TCPS_CLOSE_WAIT: tp->t_state = TCPS_LAST_ACK; break; } /* soisfdisconnecting(tp->t_socket); */ if (tp && tp->t_state >= TCPS_FIN_WAIT_2) soisfdisconnected(tp->t_socket); if (tp) tcp_output(tp); } /* * Connect to a host on the Internet * Called by tcp_input * Only do a connect, the tcp fields will be set in tcp_input * return 0 if there's a result of the connect, * else return -1 means we're still connecting * The return value is almost always -1 since the socket is * nonblocking. Connect returns after the SYN is sent, and does * not wait for ACK+SYN. */ int tcp_fconnect(so) struct socket *so; { int ret=0; DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %lx", (long )so); if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { int opt, s=so->s; struct sockaddr_in addr; fd_nonblock(s); opt = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); opt = 1; setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ switch(ntohl(so->so_faddr.s_addr) & 0xff) { case CTL_DNS: addr.sin_addr = dns_addr; break; case CTL_ALIAS: default: addr.sin_addr = loopback_addr; break; } } else addr.sin_addr = so->so_faddr; addr.sin_port = so->so_fport; DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " "addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); /* We don't care what port we get */ ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); /* * If it's not in progress, it failed, so we just return 0, * without clearing SS_NOFDREF */ soisfconnecting(so); } return(ret); } /* * Accept the socket and connect to the local-host * * We have a problem. The correct thing to do would be * to first connect to the local-host, and only if the * connection is accepted, then do an accept() here. * But, a) we need to know who's trying to connect * to the socket to be able to SYN the local-host, and * b) we are already connected to the foreign host by * the time it gets to accept(), so... We simply accept * here and SYN the local-host. */ void tcp_connect(inso) struct socket *inso; { struct socket *so; struct sockaddr_in addr; socklen_t addrlen = sizeof(struct sockaddr_in); struct tcpcb *tp; int s, opt; DEBUG_CALL("tcp_connect"); DEBUG_ARG("inso = %lx", (long)inso); /* * If it's an SS_ACCEPTONCE socket, no need to socreate() * another socket, just use the accept() socket. */ if (inso->so_state & SS_FACCEPTONCE) { /* FACCEPTONCE already have a tcpcb */ so = inso; } else { if ((so = socreate()) == NULL) { /* If it failed, get rid of the pending connection */ closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); return; } if (tcp_attach(so) < 0) { free(so); /* NOT sofree */ return; } so->so_laddr = inso->so_laddr; so->so_lport = inso->so_lport; } (void) tcp_mss(sototcpcb(so), 0); if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { tcp_close(sototcpcb(so)); /* This will sofree() as well */ return; } fd_nonblock(s); opt = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); opt = 1; setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); opt = 1; setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); so->so_fport = addr.sin_port; so->so_faddr = addr.sin_addr; /* Translate connections from localhost to the real hostname */ if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) so->so_faddr = alias_addr; /* Close the accept() socket, set right state */ if (inso->so_state & SS_FACCEPTONCE) { closesocket(so->s); /* If we only accept once, close the accept() socket */ so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ /* if it's not FACCEPTONCE, it's already NOFDREF */ } so->s = s; so->so_iptos = tcp_tos(so); tp = sototcpcb(so); tcp_template(tp); /* Compute window scaling to request. */ /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) * tp->request_r_scale++; */ /* soisconnecting(so); */ /* NOFDREF used instead */ tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tcp_sendseqinit(tp); tcp_output(tp); } /* * Attach a TCPCB to a socket. */ int tcp_attach(so) struct socket *so; { if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) return -1; insque(so, &tcb); return 0; } /* * Set the socket's type of service field */ struct tos_t tcptos[] = { {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ {0, 0, 0, 0} }; struct emu_t *tcpemu = 0; /* * Return TOS according to the above table */ u_int8_t tcp_tos(so) struct socket *so; { int i = 0; struct emu_t *emup; while(tcptos[i].tos) { if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { so->so_emu = tcptos[i].emu; return tcptos[i].tos; } i++; } /* Nope, lets see if there's a user-added one */ for (emup = tcpemu; emup; emup = emup->next) { if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || (emup->lport && (ntohs(so->so_lport) == emup->lport))) { so->so_emu = emup->emu; return emup->tos; } } return 0; } int do_echo = -1; /* * Emulate programs that try and connect to us * This includes ftp (the data connection is * initiated by the server) and IRC (DCC CHAT and * DCC SEND) for now * * NOTE: It's possible to crash SLiRP by sending it * unstandard strings to emulate... if this is a problem, * more checks are needed here * * XXX Assumes the whole command came in one packet * * XXX Some ftp clients will have their TOS set to * LOWDELAY and so Nagel will kick in. Because of this, * we'll get the first letter, followed by the rest, so * we simply scan for ORT instead of PORT... * DCC doesn't have this problem because there's other stuff * in the packet before the DCC command. * * Return 1 if the mbuf m is still valid and should be * sbappend()ed * * NOTE: if you return 0 you MUST m_free() the mbuf! */ int tcp_emu(so, m) struct socket *so; struct mbuf *m; { u_int n1, n2, n3, n4, n5, n6; char buff[256]; u_int32_t laddr; u_int lport; char *bptr; DEBUG_CALL("tcp_emu"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); switch(so->so_emu) { int x, i; case EMU_IDENT: /* * Identification protocol as per rfc-1413 */ { struct socket *tmpso; struct sockaddr_in addr; socklen_t addrlen = sizeof(struct sockaddr_in); struct sbuf *so_rcv = &so->so_rcv; memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m->m_data[m->m_len] = 0; /* NULL terminate */ if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { HTONS(n1); HTONS(n2); /* n2 is the one on our host */ for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && tmpso->so_lport == n2 && tmpso->so_faddr.s_addr == so->so_faddr.s_addr && tmpso->so_fport == n1) { if (getsockname(tmpso->s, (struct sockaddr *)&addr, &addrlen) == 0) n2 = ntohs(addr.sin_port); break; } } } so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); so_rcv->sb_rptr = so_rcv->sb_data; so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; } m_free(m); return 0; } #if 0 case EMU_RLOGIN: /* * Rlogin emulation * First we accumulate all the initial option negotiation, * then fork_exec() rlogin according to the options */ { int i, i2, n; char *ptr; char args[100]; char term[100]; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { memcpy(so_snd->sb_wptr, "Permission denied\n", 18); so_snd->sb_wptr += 18; so_snd->sb_cc += 18; tcp_sockclosed(sototcpcb(so)); m_free(m); return 0; } /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); /* * Check if we have all the initial options, * and build argument list to rlogin while we're here */ n = 0; ptr = so_rcv->sb_data; args[0] = 0; term[0] = 0; while (ptr < so_rcv->sb_wptr) { if (*ptr++ == 0) { n++; if (n == 2) { sprintf(args, "rlogin -l %s %s", ptr, inet_ntoa(so->so_faddr)); } else if (n == 3) { i2 = so_rcv->sb_wptr - ptr; for (i = 0; i < i2; i++) { if (ptr[i] == '/') { ptr[i] = 0; #ifdef HAVE_SETENV sprintf(term, "%s", ptr); #else sprintf(term, "TERM=%s", ptr); #endif ptr[i] = '/'; break; } } } } } if (n != 4) return 0; /* We have it, set our term variable and fork_exec() */ #ifdef HAVE_SETENV setenv("TERM", term, 1); #else putenv(term); #endif fork_exec(so, args, 2); term[0] = 0; so->so_emu = 0; /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; return 0; } case EMU_RSH: /* * rsh emulation * First we accumulate all the initial option negotiation, * then rsh_exec() rsh according to the options */ { int n; char *ptr; char *user; char *args; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; /* First check if they have a priveladged port, or too much data has arrived */ if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { memcpy(so_snd->sb_wptr, "Permission denied\n", 18); so_snd->sb_wptr += 18; so_snd->sb_cc += 18; tcp_sockclosed(sototcpcb(so)); m_free(m); return 0; } /* Append the current data */ memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); so_rcv->sb_wptr += m->m_len; so_rcv->sb_rptr += m->m_len; m_free(m); /* * Check if we have all the initial options, * and build argument list to rlogin while we're here */ n = 0; ptr = so_rcv->sb_data; user=""; args=""; if (so->extra==NULL) { struct socket *ns; struct tcpcb* tp; int port=atoi(ptr); if (port <= 0) return 0; if (port > 1023 || port < 512) { memcpy(so_snd->sb_wptr, "Permission denied\n", 18); so_snd->sb_wptr += 18; so_snd->sb_cc += 18; tcp_sockclosed(sototcpcb(so)); return 0; } if ((ns=socreate()) == NULL) return 0; if (tcp_attach(ns)<0) { free(ns); return 0; } ns->so_laddr=so->so_laddr; ns->so_lport=htons(port); (void) tcp_mss(sototcpcb(ns), 0); ns->so_faddr=so->so_faddr; ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ if (ns->so_faddr.s_addr == 0 || ns->so_faddr.s_addr == loopback_addr.s_addr) ns->so_faddr = alias_addr; ns->so_iptos = tcp_tos(ns); tp = sototcpcb(ns); tcp_template(tp); /* Compute window scaling to request. */ /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) * tp->request_r_scale++; */ /*soisfconnecting(ns);*/ tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; tcp_sendseqinit(tp); tcp_output(tp); so->extra=ns; } while (ptr < so_rcv->sb_wptr) { if (*ptr++ == 0) { n++; if (n == 2) { user=ptr; } else if (n == 3) { args=ptr; } } } if (n != 4) return 0; rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); so->so_emu = 0; so->extra=NULL; /* And finally, send the client a 0 character */ so_snd->sb_wptr[0] = 0; so_snd->sb_wptr++; so_snd->sb_cc++; return 0; } case EMU_CTL: { int num; struct sbuf *so_snd = &so->so_snd; struct sbuf *so_rcv = &so->so_rcv; /* * If there is binary data here, we save it in so->so_m */ if (!so->so_m) { int rxlen; char *rxdata; rxdata=mtod(m, char *); for (rxlen=m->m_len; rxlen; rxlen--) { if (*rxdata++ & 0x80) { so->so_m = m; return 0; } } } /* if(so->so_m==NULL) */ /* * Append the line */ sbappendsb(so_rcv, m); /* To avoid going over the edge of the buffer, we reset it */ if (so_snd->sb_cc == 0) so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; /* * A bit of a hack: * If the first packet we get here is 1 byte long, then it * was done in telnet character mode, therefore we must echo * the characters as they come. Otherwise, we echo nothing, * because in linemode, the line is already echoed * XXX two or more control connections won't work */ if (do_echo == -1) { if (m->m_len == 1) do_echo = 1; else do_echo = 0; } if (do_echo) { sbappendsb(so_snd, m); m_free(m); tcp_output(sototcpcb(so)); /* XXX */ } else m_free(m); num = 0; while (num < so->so_rcv.sb_cc) { if (*(so->so_rcv.sb_rptr + num) == '\n' || *(so->so_rcv.sb_rptr + num) == '\r') { int n; *(so_rcv->sb_rptr + num) = 0; if (ctl_password && !ctl_password_ok) { /* Need a password */ if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) { if (strcmp(buff, ctl_password) == 0) { ctl_password_ok = 1; n = sprintf(so_snd->sb_wptr, "Password OK.\r\n"); goto do_prompt; } } n = sprintf(so_snd->sb_wptr, "Error: Password required, log on with \"pass PASSWORD\"\r\n"); goto do_prompt; } cfg_quitting = 0; n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF); if (!cfg_quitting) { /* Register the printed data */ do_prompt: so_snd->sb_cc += n; so_snd->sb_wptr += n; /* Add prompt */ n = sprintf(so_snd->sb_wptr, "Slirp> "); so_snd->sb_cc += n; so_snd->sb_wptr += n; } /* Drop so_rcv data */ so_rcv->sb_cc = 0; so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data; tcp_output(sototcpcb(so)); /* Send the reply */ } num++; } return 0; } #endif case EMU_FTP: /* ftp */ *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { /* * Need to emulate the PORT command */ x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; n6 = ntohs(so->so_fport); n5 = (n6 >> 8) & 0xff; n6 &= 0xff; laddr = ntohl(so->so_faddr.s_addr); n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { /* * Need to emulate the PASV response */ x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", &n1, &n2, &n3, &n4, &n5, &n6, buff); if (x < 6) return 1; laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); lport = htons((n5 << 8) | (n6)); if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) return 1; n6 = ntohs(so->so_fport); n5 = (n6 >> 8) & 0xff; n6 &= 0xff; laddr = ntohl(so->so_faddr.s_addr); n1 = ((laddr >> 24) & 0xff); n2 = ((laddr >> 16) & 0xff); n3 = ((laddr >> 8) & 0xff); n4 = (laddr & 0xff); m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", n1, n2, n3, n4, n5, n6, x==7?buff:""); return 1; } return 1; case EMU_KSH: /* * The kshell (Kerberos rsh) and shell services both pass * a local port port number to carry signals to the server * and stderr to the client. It is passed at the beginning * of the connection as a NUL-terminated decimal ASCII string. */ so->so_emu = 0; for (lport = 0, i = 0; i < m->m_len-1; ++i) { if (m->m_data[i] < '0' || m->m_data[i] > '9') return 1; /* invalid number */ lport *= 10; lport += m->m_data[i] - '0'; } if (m->m_data[m->m_len-1] == '\0' && lport != 0 && (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; return 1; case EMU_IRC: /* * Need to emulate DCC CHAT, DCC SEND and DCC MOVE */ *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) return 1; /* The %256s is for the broken mIRC */ if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), 1); } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), n1, 1); } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) return 1; m->m_len = bptr - m->m_data; /* Adjust length */ m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", buff, (unsigned long)ntohl(so->so_faddr.s_addr), ntohs(so->so_fport), n1, 1); } return 1; case EMU_REALAUDIO: /* * RealAudio emulation - JP. We must try to parse the incoming * data and try to find the two characters that contain the * port number. Then we redirect an udp port and replace the * number with the real port we got. * * The 1.0 beta versions of the player are not supported * any more. * * A typical packet for player version 1.0 (release version): * * 0000:50 4E 41 00 05 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB * * Now the port number 0x1BD7 is found at offset 0x04 of the * Now the port number 0x1BD7 is found at offset 0x04 of the * second packet. This time we received five bytes first and * then the rest. You never know how many bytes you get. * * A typical packet for player version 2.0 (beta): * * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á. * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B * * Port number 0x1BC1 is found at offset 0x0d. * * This is just a horrible switch statement. Variable ra tells * us where we're going. */ bptr = m->m_data; while (bptr < m->m_data + m->m_len) { u_short p; static int ra = 0; char ra_tbl[4]; ra_tbl[0] = 0x50; ra_tbl[1] = 0x4e; ra_tbl[2] = 0x41; ra_tbl[3] = 0; switch (ra) { case 0: case 2: case 3: if (*bptr++ != ra_tbl[ra]) { ra = 0; continue; } break; case 1: /* * We may get 0x50 several times, ignore them */ if (*bptr == 0x50) { ra = 1; bptr++; continue; } else if (*bptr++ != ra_tbl[ra]) { ra = 0; continue; } break; case 4: /* * skip version number */ bptr++; break; case 5: /* * The difference between versions 1.0 and * 2.0 is here. For future versions of * the player this may need to be modified. */ if (*(bptr + 1) == 0x02) bptr += 8; else bptr += 4; break; case 6: /* This is the field containing the port * number that RA-player is listening to. */ lport = (((u_char*)bptr)[0] << 8) + ((u_char *)bptr)[1]; if (lport < 6970) lport += 256; /* don't know why */ if (lport < 6970 || lport > 7170) return 1; /* failed */ /* try to get udp port between 6970 - 7170 */ for (p = 6970; p < 7071; p++) { if (udp_listen( htons(p), so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) { break; } } if (p == 7071) p = 0; *(u_char *)bptr++ = (p >> 8) & 0xff; *(u_char *)bptr++ = p & 0xff; ra = 0; return 1; /* port redirected, we're done */ break; default: ra = 0; } ra++; } return 1; default: /* Ooops, not emulated, won't call tcp_emu again */ so->so_emu = 0; return 1; } } /* * Do misc. config of SLiRP while its running. * Return 0 if this connections is to be closed, 1 otherwise, * return 2 if this is a command-line connection */ int tcp_ctl(so) struct socket *so; { struct sbuf *sb = &so->so_snd; int command; struct ex_list *ex_ptr; int do_pty; // struct socket *tmpso; DEBUG_CALL("tcp_ctl"); DEBUG_ARG("so = %lx", (long )so); #if 0 /* * Check if they're authorised */ if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); sb->sb_wptr += sb->sb_cc; return 0; } #endif command = (ntohl(so->so_faddr.s_addr) & 0xff); switch(command) { default: /* Check for exec's */ /* * Check if it's pty_exec */ for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_fport == so->so_fport && command == ex_ptr->ex_addr) { do_pty = ex_ptr->ex_pty; goto do_exec; } } /* * Nothing bound.. */ /* tcp_fconnect(so); */ /* FALLTHROUGH */ case CTL_ALIAS: sb->sb_cc = sprintf(sb->sb_wptr, "Error: No application configured.\r\n"); sb->sb_wptr += sb->sb_cc; return(0); do_exec: DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); return(fork_exec(so, ex_ptr->ex_exec, do_pty)); #if 0 case CTL_CMD: for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { if (tmpso->so_emu == EMU_CTL && !(tmpso->so_tcpcb? (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) :0)) { /* Ooops, control connection already active */ sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n"); sb->sb_wptr += sb->sb_cc; return 0; } } so->so_emu = EMU_CTL; ctl_password_ok = 0; sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> "); sb->sb_wptr += sb->sb_cc; do_echo=-1; return(2); #endif } } BasiliskII/src/slirp/tcpip.h0000644000175000017500000000472111735673707016175 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp */ #ifndef _TCPIP_H_ #define _TCPIP_H_ /* * Tcp+ip header, after ip options removed. */ struct tcpiphdr { struct ipovly ti_i; /* overlaid ip structure */ struct tcphdr ti_t; /* tcp header */ }; #define ti_next ti_i.ih_next #define ti_prev ti_i.ih_prev #define ti_x1 ti_i.ih_x1 #define ti_pr ti_i.ih_pr #define ti_len ti_i.ih_len #define ti_src ti_i.ih_src #define ti_dst ti_i.ih_dst #define ti_sport ti_t.th_sport #define ti_dport ti_t.th_dport #define ti_seq ti_t.th_seq #define ti_ack ti_t.th_ack #define ti_x2 ti_t.th_x2 #define ti_off ti_t.th_off #define ti_flags ti_t.th_flags #define ti_win ti_t.th_win #define ti_sum ti_t.th_sum #define ti_urp ti_t.th_urp /* * Just a clean way to get to the first byte * of the packet */ struct tcpiphdr_2 { struct tcpiphdr dummy; char first_char; }; #endif BasiliskII/src/slirp/VERSION0000644000175000017500000000003010713121623015716 0ustar centriscentrisqemu 0.9.0 (2007/02/05) BasiliskII/src/slirp/main.h0000644000175000017500000000246510713053556015772 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifdef HAVE_SYS_SELECT_H #include #endif #define TOWRITEMAX 512 extern struct timeval tt; extern int link_up; extern int slirp_socket; extern int slirp_socket_unit; extern int slirp_socket_port; extern u_int32_t slirp_socket_addr; extern char *slirp_socket_passwd; extern int ctty_closed; /* * Get the difference in 2 times from updtim() * Allow for wraparound times, "just in case" * x is the greater of the 2 (current time) and y is * what it's being compared against. */ #define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) extern char *slirp_tty; extern char *exec_shell; extern u_int curtime; extern fd_set *global_readfds, *global_writefds, *global_xfds; extern struct in_addr ctl_addr; extern struct in_addr special_addr; extern struct in_addr alias_addr; extern struct in_addr our_addr; extern struct in_addr loopback_addr; extern struct in_addr dns_addr; extern char *username; extern char *socket_path; extern int towrite_max; extern int ppp_exit; extern int so_options; extern int tcp_keepintvl; extern uint8_t client_ethaddr[6]; #define PROTO_SLIP 0x1 #ifdef USE_PPP #define PROTO_PPP 0x2 #endif void if_encap(const uint8_t *ip_data, int ip_data_len); BasiliskII/src/slirp/mbuf.c0000644000175000017500000001122510555147310015760 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ /* * mbuf's in SLiRP are much simpler than the real mbufs in * FreeBSD. They are fixed size, determined by the MTU, * so that one whole packet can fit. Mbuf's cannot be * chained together. If there's more data than the mbuf * could hold, an external malloced buffer is pointed to * by m_ext (and the data pointers) and M_EXT is set in * the flags */ #include #include struct mbuf *mbutl; char *mclrefcnt; int mbuf_alloced = 0; struct mbuf m_freelist, m_usedlist; int mbuf_thresh = 30; int mbuf_max = 0; int msize; void m_init() { m_freelist.m_next = m_freelist.m_prev = &m_freelist; m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; msize_init(); } void msize_init() { /* * Find a nice value for msize * XXX if_maxlinkhdr already in mtu */ msize = (if_mtu>if_mru?if_mtu:if_mru) + if_maxlinkhdr + sizeof(struct m_hdr ) + 6; } /* * Get an mbuf from the free list, if there are none * malloc one * * Because fragmentation can occur if we alloc new mbufs and * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, * which tells m_free to actually free() it */ struct mbuf * m_get() { register struct mbuf *m; int flags = 0; DEBUG_CALL("m_get"); if (m_freelist.m_next == &m_freelist) { m = (struct mbuf *)malloc(msize); if (m == NULL) goto end_error; mbuf_alloced++; if (mbuf_alloced > mbuf_thresh) flags = M_DOFREE; if (mbuf_alloced > mbuf_max) mbuf_max = mbuf_alloced; } else { m = m_freelist.m_next; remque(m); } /* Insert it in the used list */ insque(m,&m_usedlist); m->m_flags = (flags | M_USEDLIST); /* Initialise it */ m->m_size = msize - sizeof(struct m_hdr); m->m_data = m->m_dat; m->m_len = 0; m->m_nextpkt = 0; m->m_prevpkt = 0; end_error: DEBUG_ARG("m = %lx", (long )m); return m; } void m_free(m) struct mbuf *m; { DEBUG_CALL("m_free"); DEBUG_ARG("m = %lx", (long )m); if(m) { /* Remove from m_usedlist */ if (m->m_flags & M_USEDLIST) remque(m); /* If it's M_EXT, free() it */ if (m->m_flags & M_EXT) free(m->m_ext); /* * Either free() it or put it on the free list */ if (m->m_flags & M_DOFREE) { free(m); mbuf_alloced--; } else if ((m->m_flags & M_FREELIST) == 0) { insque(m,&m_freelist); m->m_flags = M_FREELIST; /* Clobber other flags */ } } /* if(m) */ } /* * Copy data from one mbuf to the end of * the other.. if result is too big for one mbuf, malloc() * an M_EXT data segment */ void m_cat(m, n) register struct mbuf *m, *n; { /* * If there's no room, realloc */ if (M_FREEROOM(m) < n->m_len) m_inc(m,m->m_size+MINCSIZE); memcpy(m->m_data+m->m_len, n->m_data, n->m_len); m->m_len += n->m_len; m_free(n); } /* make m size bytes large */ void m_inc(m, size) struct mbuf *m; int size; { int datasize; /* some compiles throw up on gotos. This one we can fake. */ if(m->m_size>size) return; if (m->m_flags & M_EXT) { datasize = m->m_data - m->m_ext; m->m_ext = (char *)realloc(m->m_ext,size); /* if (m->m_ext == NULL) * return (struct mbuf *)NULL; */ m->m_data = m->m_ext + datasize; } else { char *dat; datasize = m->m_data - m->m_dat; dat = (char *)malloc(size); /* if (dat == NULL) * return (struct mbuf *)NULL; */ memcpy(dat, m->m_dat, m->m_size); m->m_ext = dat; m->m_data = m->m_ext + datasize; m->m_flags |= M_EXT; } m->m_size = size; } void m_adj(m, len) struct mbuf *m; int len; { if (m == NULL) return; if (len >= 0) { /* Trim from head */ m->m_data += len; m->m_len -= len; } else { /* Trim from tail */ len = -len; m->m_len -= len; } } /* * Copy len bytes from m, starting off bytes into n */ int m_copy(n, m, off, len) struct mbuf *n, *m; int off, len; { if (len > M_FREEROOM(n)) return -1; memcpy((n->m_data + n->m_len), (m->m_data + off), len); n->m_len += len; return 0; } /* * Given a pointer into an mbuf, return the mbuf * XXX This is a kludge, I should eliminate the need for it * Fortunately, it's not used often */ struct mbuf * dtom(dat) void *dat; { struct mbuf *m; DEBUG_CALL("dtom"); DEBUG_ARG("dat = %lx", (long )dat); /* bug corrected for M_EXT buffers */ for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { if (m->m_flags & M_EXT) { if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) return m; } else { if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) return m; } } DEBUG_ERROR((dfd, "dtom failed")); return (struct mbuf *)0; } BasiliskII/src/slirp/mbuf.h0000644000175000017500000001123011735673707016000 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp */ #ifndef _MBUF_H_ #define _MBUF_H_ #define m_freem m_free #define MINCSIZE 4096 /* Amount to increase mbuf if too small */ /* * Macros for type conversion * mtod(m,t) - convert mbuf pointer to data pointer of correct type * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) */ #define mtod(m,t) ((t)(m)->m_data) /* #define dtom(x) ((struct mbuf *)((int)(x) & ~(M_SIZE-1))) */ /* XXX About mbufs for slirp: * Only one mbuf is ever used in a chain, for each "cell" of data. * m_nextpkt points to the next packet, if fragmented. * If the data is too large, the M_EXT is used, and a larger block * is alloced. Therefore, m_free[m] must check for M_EXT and if set * free the m_ext. This is inefficient memory-wise, but who cares. */ /* XXX should union some of these! */ /* header at beginning of each mbuf: */ struct m_hdr { struct mbuf *mh_next; /* Linked list of mbufs */ struct mbuf *mh_prev; struct mbuf *mh_nextpkt; /* Next packet in queue/record */ struct mbuf *mh_prevpkt; /* Flags aren't used in the output queue */ int mh_flags; /* Misc flags */ int mh_size; /* Size of data */ struct socket *mh_so; caddr_t mh_data; /* Location of data */ int mh_len; /* Amount of data in this mbuf */ }; /* * How much room is in the mbuf, from m_data to the end of the mbuf */ #define M_ROOM(m) ((m->m_flags & M_EXT)? \ (((m)->m_ext + (m)->m_size) - (m)->m_data) \ : \ (((m)->m_dat + (m)->m_size) - (m)->m_data)) /* * How much free room there is */ #define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) #define M_TRAILINGSPACE M_FREEROOM struct mbuf { struct m_hdr m_hdr; union M_dat { char m_dat_[1]; /* ANSI don't like 0 sized arrays */ char *m_ext_; } M_dat; }; #define m_next m_hdr.mh_next #define m_prev m_hdr.mh_prev #define m_nextpkt m_hdr.mh_nextpkt #define m_prevpkt m_hdr.mh_prevpkt #define m_flags m_hdr.mh_flags #define m_len m_hdr.mh_len #define m_data m_hdr.mh_data #define m_size m_hdr.mh_size #define m_dat M_dat.m_dat_ #define m_ext M_dat.m_ext_ #define m_so m_hdr.mh_so #define ifq_prev m_prev #define ifq_next m_next #define ifs_prev m_prevpkt #define ifs_next m_nextpkt #define ifq_so m_so #define M_EXT 0x01 /* m_ext points to more (malloced) data */ #define M_FREELIST 0x02 /* mbuf is on free list */ #define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ #define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() * it rather than putting it on the free list */ /* * Mbuf statistics. XXX */ struct mbstat { int mbs_alloced; /* Number of mbufs allocated */ }; extern struct mbstat mbstat; extern int mbuf_alloced; extern struct mbuf m_freelist, m_usedlist; extern int mbuf_max; void m_init _P((void)); void msize_init _P((void)); struct mbuf * m_get _P((void)); void m_free _P((struct mbuf *)); void m_cat _P((register struct mbuf *, register struct mbuf *)); void m_inc _P((struct mbuf *, int)); void m_adj _P((struct mbuf *, int)); int m_copy _P((struct mbuf *, struct mbuf *, int, int)); struct mbuf * dtom _P((void *)); #endif BasiliskII/src/slirp/misc.c0000644000175000017500000004634310713053556015777 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define WANT_SYS_IOCTL_H #include #include u_int curtime, time_fasttimo, last_slowtimo, detach_time; u_int detach_wait = 600000; /* 10 minutes */ #if 0 int x_port = -1; int x_display = 0; int x_screen = 0; int show_x(buff, inso) char *buff; struct socket *inso; { if (x_port < 0) { lprint("X Redir: X not being redirected.\r\n"); } else { lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n", inet_ntoa(our_addr), x_port, x_screen); lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n", inet_ntoa(our_addr), x_port, x_screen); if (x_display) lprint("X Redir: Redirecting to display %d\r\n", x_display); } return CFG_OK; } /* * XXX Allow more than one X redirection? */ void redir_x(inaddr, start_port, display, screen) u_int32_t inaddr; int start_port; int display; int screen; { int i; if (x_port >= 0) { lprint("X Redir: X already being redirected.\r\n"); show_x(0, 0); } else { for (i = 6001 + (start_port-1); i <= 6100; i++) { if (solisten(htons(i), inaddr, htons(6000 + display), 0)) { /* Success */ x_port = i - 6000; x_display = display; x_screen = screen; show_x(0, 0); return; } } lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n"); } } #endif #ifndef HAVE_INET_ATON int inet_aton(cp, ia) const char *cp; struct in_addr *ia; { u_int32_t addr = inet_addr(cp); if (addr == 0xffffffff) return 0; ia->s_addr = addr; return 1; } #endif /* * Get our IP address and put it in our_addr */ void getouraddr() { char buff[256]; struct hostent *he = NULL; if (gethostname(buff,256) == 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; } #if SIZEOF_CHAR_P == 8 struct quehead_32 { u_int32_t qh_link; u_int32_t qh_rlink; }; inline void insque_32(a, b) void *a; void *b; { register struct quehead_32 *element = (struct quehead_32 *) a; register struct quehead_32 *head = (struct quehead_32 *) b; element->qh_link = head->qh_link; head->qh_link = (u_int32_t)element; element->qh_rlink = (u_int32_t)head; ((struct quehead_32 *)(element->qh_link))->qh_rlink = (u_int32_t)element; } inline void remque_32(a) void *a; { register struct quehead_32 *element = (struct quehead_32 *) a; ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; element->qh_rlink = 0; } #endif /* SIZEOF_CHAR_P == 8 */ struct quehead { struct quehead *qh_link; struct quehead *qh_rlink; }; void insque(a, b) void *a, *b; { register struct quehead *element = (struct quehead *) a; register struct quehead *head = (struct quehead *) b; element->qh_link = head->qh_link; head->qh_link = (struct quehead *)element; element->qh_rlink = (struct quehead *)head; ((struct quehead *)(element->qh_link))->qh_rlink = (struct quehead *)element; } void remque(a) void *a; { register struct quehead *element = (struct quehead *) a; ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; element->qh_rlink = NULL; /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ } /* #endif */ int add_exec(ex_ptr, do_pty, exec, addr, port) struct ex_list **ex_ptr; int do_pty; char *exec; int addr; int port; { struct ex_list *tmp_ptr; /* First, check if the port is "bound" */ for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) return -1; } tmp_ptr = *ex_ptr; *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); (*ex_ptr)->ex_fport = port; (*ex_ptr)->ex_addr = addr; (*ex_ptr)->ex_pty = do_pty; (*ex_ptr)->ex_exec = strdup(exec); (*ex_ptr)->ex_next = tmp_ptr; return 0; } #ifndef HAVE_STRERROR /* * For systems with no strerror */ extern int sys_nerr; extern char *sys_errlist[]; char * strerror(error) int error; { if (error < sys_nerr) return sys_errlist[error]; else return "Unknown error."; } #endif #ifdef _WIN32 int fork_exec(so, ex, do_pty) struct socket *so; char *ex; int do_pty; { /* not implemented */ return 0; } #else int slirp_openpty(amaster, aslave) int *amaster, *aslave; { register int master, slave; #ifdef HAVE_GRANTPT char *ptr; if ((master = open("/dev/ptmx", O_RDWR)) < 0 || grantpt(master) < 0 || unlockpt(master) < 0 || (ptr = ptsname(master)) == NULL) { close(master); return -1; } if ((slave = open(ptr, O_RDWR)) < 0 || ioctl(slave, I_PUSH, "ptem") < 0 || ioctl(slave, I_PUSH, "ldterm") < 0 || ioctl(slave, I_PUSH, "ttcompat") < 0) { close(master); close(slave); return -1; } *amaster = master; *aslave = slave; return 0; #else static char line[] = "/dev/ptyXX"; register const char *cp1, *cp2; for (cp1 = "pqrsPQRS"; *cp1; cp1++) { line[8] = *cp1; for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { line[9] = *cp2; if ((master = open(line, O_RDWR, 0)) == -1) { if (errno == ENOENT) return (-1); /* out of ptys */ } else { line[5] = 't'; /* These will fail */ (void) chown(line, getuid(), 0); (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); #ifdef HAVE_REVOKE (void) revoke(line); #endif if ((slave = open(line, O_RDWR, 0)) != -1) { *amaster = master; *aslave = slave; return 0; } (void) close(master); line[5] = 'p'; } } } errno = ENOENT; /* out of ptys */ return (-1); #endif } /* * XXX This is ugly * We create and bind a socket, then fork off to another * process, which connects to this socket, after which we * exec the wanted program. If something (strange) happens, * the accept() call could block us forever. * * do_pty = 0 Fork/exec inetd style * do_pty = 1 Fork/exec using slirp.telnetd * do_ptr = 2 Fork/exec using pty */ int fork_exec(so, ex, do_pty) struct socket *so; char *ex; int do_pty; { int s; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); int opt; int master; char *argv[256]; #if 0 char buff[256]; #endif /* don't want to clobber the original */ char *bptr; char *curarg; int c, i, ret; DEBUG_CALL("fork_exec"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("ex = %lx", (long)ex); DEBUG_ARG("do_pty = %lx", (long)do_pty); if (do_pty == 2) { if (slirp_openpty(&master, &s) == -1) { lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } } else { addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || listen(s, 1) < 0) { lprint("Error: inet socket: %s\n", strerror(errno)); closesocket(s); return 0; } } switch(fork()) { case -1: lprint("Error: fork failed: %s\n", strerror(errno)); close(s); if (do_pty == 2) close(master); return 0; case 0: /* Set the DISPLAY */ if (do_pty == 2) { (void) close(master); #ifdef TIOCSCTTY /* XXXXX */ (void) setsid(); ioctl(s, TIOCSCTTY, (char *)NULL); #endif } else { getsockname(s, (struct sockaddr *)&addr, &addrlen); close(s); /* * Connect to the socket * XXX If any of these fail, we're in trouble! */ s = socket(AF_INET, SOCK_STREAM, 0); addr.sin_addr = loopback_addr; do { ret = connect(s, (struct sockaddr *)&addr, addrlen); } while (ret < 0 && errno == EINTR); } #if 0 if (x_port >= 0) { #ifdef HAVE_SETENV sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); setenv("DISPLAY", buff, 1); #else sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); putenv(buff); #endif } #endif dup2(s, 0); dup2(s, 1); dup2(s, 2); for (s = 3; s <= 255; s++) close(s); i = 0; bptr = strdup(ex); /* No need to free() this */ if (do_pty == 1) { /* Setup "slirp.telnetd -x" */ argv[i++] = "slirp.telnetd"; argv[i++] = "-x"; argv[i++] = bptr; } else do { /* Change the string into argv[] */ curarg = bptr; while (*bptr != ' ' && *bptr != (char)0) bptr++; c = *bptr; *bptr++ = (char)0; argv[i++] = strdup(curarg); } while (c); argv[i] = 0; execvp(argv[0], argv); /* Ooops, failed, let's tell the user why */ { char buff[256]; sprintf(buff, "Error: execvp of %s failed: %s\n", argv[0], strerror(errno)); write(2, buff, strlen(buff)+1); } close(0); close(1); close(2); /* XXX */ exit(1); default: if (do_pty == 2) { close(s); so->s = master; } else { /* * XXX this could block us... * XXX Should set a timer here, and if accept() doesn't * return after X seconds, declare it a failure * The only reason this will block forever is if socket() * of connect() fail in the child process */ do { so->s = accept(s, (struct sockaddr *)&addr, &addrlen); } while (so->s < 0 && errno == EINTR); closesocket(s); opt = 1; setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); opt = 1; setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); } fd_nonblock(so->s); /* Append the telnet options now */ if (so->so_m != 0 && do_pty == 1) { sbappend(so, so->so_m); so->so_m = 0; } return 1; } } #endif #ifndef HAVE_STRDUP char * strdup(str) const char *str; { char *bptr; bptr = (char *)malloc(strlen(str)+1); strcpy(bptr, str); return bptr; } #endif #if 0 void snooze_hup(num) int num; { int s, ret; #ifndef NO_UNIX_SOCKETS struct sockaddr_un sock_un; #endif struct sockaddr_in sock_in; char buff[256]; ret = -1; if (slirp_socket_passwd) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) slirp_exit(1); sock_in.sin_family = AF_INET; sock_in.sin_addr.s_addr = slirp_socket_addr; sock_in.sin_port = htons(slirp_socket_port); if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) slirp_exit(1); /* just exit...*/ sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); write(s, buff, strlen(buff)+1); } #ifndef NO_UNIX_SOCKETS else { s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) slirp_exit(1); sock_un.sun_family = AF_UNIX; strcpy(sock_un.sun_path, socket_path); if (connect(s, (struct sockaddr *)&sock_un, sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) slirp_exit(1); sprintf(buff, "kill none:%d", slirp_socket_unit); write(s, buff, strlen(buff)+1); } #endif slirp_exit(0); } void snooze() { sigset_t s; int i; /* Don't need our data anymore */ /* XXX This makes SunOS barf */ /* brk(0); */ /* Close all fd's */ for (i = 255; i >= 0; i--) close(i); signal(SIGQUIT, slirp_exit); signal(SIGHUP, snooze_hup); sigemptyset(&s); /* Wait for any signal */ sigsuspend(&s); /* Just in case ... */ exit(255); } void relay(s) int s; { char buf[8192]; int n; fd_set readfds; struct ttys *ttyp; /* Don't need our data anymore */ /* XXX This makes SunOS barf */ /* brk(0); */ signal(SIGQUIT, slirp_exit); signal(SIGHUP, slirp_exit); signal(SIGINT, slirp_exit); signal(SIGTERM, slirp_exit); /* Fudge to get term_raw and term_restore to work */ if (NULL == (ttyp = tty_attach (0, slirp_tty))) { lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); slirp_exit (1); } ttyp->fd = 0; ttyp->flags |= TTY_CTTY; term_raw(ttyp); while (1) { FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(s, &readfds); n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); if (n <= 0) slirp_exit(0); if (FD_ISSET(0, &readfds)) { n = read(0, buf, 8192); if (n <= 0) slirp_exit(0); n = writen(s, buf, n); if (n <= 0) slirp_exit(0); } if (FD_ISSET(s, &readfds)) { n = read(s, buf, 8192); if (n <= 0) slirp_exit(0); n = writen(0, buf, n); if (n <= 0) slirp_exit(0); } } /* Just in case.... */ exit(1); } #endif int (*lprint_print) _P((void *, const char *, va_list)); char *lprint_ptr, *lprint_ptr2, **lprint_arg; void #ifdef __STDC__ lprint(const char *format, ...) #else lprint(va_alist) va_dcl #endif { va_list args; #ifdef __STDC__ va_start(args, format); #else char *format; va_start(args); format = va_arg(args, char *); #endif #if 0 /* If we're printing to an sbuf, make sure there's enough room */ /* XXX +100? */ if (lprint_sb) { if ((lprint_ptr - lprint_sb->sb_wptr) >= (lprint_sb->sb_datalen - (strlen(format) + 100))) { int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; int deltap = lprint_ptr - lprint_sb->sb_data; lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, lprint_sb->sb_datalen + TCP_SNDSPACE); /* Adjust all values */ lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; lprint_ptr = lprint_sb->sb_data + deltap; lprint_sb->sb_datalen += TCP_SNDSPACE; } } #endif if (lprint_print) lprint_ptr += (*lprint_print)(*lprint_arg, format, args); /* Check if they want output to be logged to file as well */ if (lfd) { /* * Remove \r's * otherwise you'll get ^M all over the file */ int len = strlen(format); char *bptr1, *bptr2; bptr1 = bptr2 = strdup(format); while (len--) { if (*bptr1 == '\r') memcpy(bptr1, bptr1+1, len+1); else bptr1++; } vfprintf(lfd, bptr2, args); free(bptr2); } va_end(args); } void add_emu(buff) char *buff; { u_int lport, fport; u_int8_t tos = 0, emu = 0; char buff1[256], buff2[256], buff4[128]; char *buff3 = buff4; struct emu_t *emup; struct socket *so; if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { lprint("Error: Bad arguments\r\n"); return; } if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { lport = 0; if (sscanf(buff1, "%d", &fport) != 1) { lprint("Error: Bad first argument\r\n"); return; } } if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { buff3 = 0; if (sscanf(buff2, "%256s", buff1) != 1) { lprint("Error: Bad second argument\r\n"); return; } } if (buff3) { if (strcmp(buff3, "lowdelay") == 0) tos = IPTOS_LOWDELAY; else if (strcmp(buff3, "throughput") == 0) tos = IPTOS_THROUGHPUT; else { lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); return; } } if (strcmp(buff1, "ftp") == 0) emu = EMU_FTP; else if (strcmp(buff1, "irc") == 0) emu = EMU_IRC; else if (strcmp(buff1, "none") == 0) emu = EMU_NONE; /* ie: no emulation */ else { lprint("Error: Unknown service\r\n"); return; } /* First, check that it isn't already emulated */ for (emup = tcpemu; emup; emup = emup->next) { if (emup->lport == lport && emup->fport == fport) { lprint("Error: port already emulated\r\n"); return; } } /* link it */ emup = (struct emu_t *)malloc(sizeof (struct emu_t)); emup->lport = (u_int16_t)lport; emup->fport = (u_int16_t)fport; emup->tos = tos; emup->emu = emu; emup->next = tcpemu; tcpemu = emup; /* And finally, mark all current sessions, if any, as being emulated */ for (so = tcb.so_next; so != &tcb; so = so->so_next) { if ((lport && lport == ntohs(so->so_lport)) || (fport && fport == ntohs(so->so_fport))) { if (emu) so->so_emu = emu; if (tos) so->so_iptos = tos; } } lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); } #ifdef BAD_SPRINTF #undef vsprintf #undef sprintf /* * Some BSD-derived systems have a sprintf which returns char * */ int vsprintf_len(string, format, args) char *string; const char *format; va_list args; { vsprintf(string, format, args); return strlen(string); } int #ifdef __STDC__ sprintf_len(char *string, const char *format, ...) #else sprintf_len(va_alist) va_dcl #endif { va_list args; #ifdef __STDC__ va_start(args, format); #else char *string; char *format; va_start(args); string = va_arg(args, char *); format = va_arg(args, char *); #endif vsprintf(string, format, args); return strlen(string); } #endif void u_sleep(usec) int usec; { struct timeval t; fd_set fdset; FD_ZERO(&fdset); t.tv_sec = 0; t.tv_usec = usec * 1000; select(0, &fdset, &fdset, &fdset, &t); } /* * Set fd blocking and non-blocking */ void fd_nonblock(fd) int fd; { #if defined USE_FIONBIO && defined FIONBIO ioctlsockopt_t opt = 1; ioctlsocket(fd, FIONBIO, &opt); #else int opt; opt = fcntl(fd, F_GETFL, 0); opt |= O_NONBLOCK; fcntl(fd, F_SETFL, opt); #endif } void fd_block(fd) int fd; { #if defined USE_FIONBIO && defined FIONBIO ioctlsockopt_t opt = 0; ioctlsocket(fd, FIONBIO, &opt); #else int opt; opt = fcntl(fd, F_GETFL, 0); opt &= ~O_NONBLOCK; fcntl(fd, F_SETFL, opt); #endif } #if 0 /* * invoke RSH */ int rsh_exec(so,ns, user, host, args) struct socket *so; struct socket *ns; char *user; char *host; char *args; { int fd[2]; int fd0[2]; int s; char buff[256]; DEBUG_CALL("rsh_exec"); DEBUG_ARG("so = %lx", (long)so); if (pipe(fd)<0) { lprint("Error: pipe failed: %s\n", strerror(errno)); return 0; } /* #ifdef HAVE_SOCKETPAIR */ #if 1 if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { close(fd[0]); close(fd[1]); lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } #else if (slirp_openpty(&fd0[0], &fd0[1]) == -1) { close(fd[0]); close(fd[1]); lprint("Error: openpty failed: %s\n", strerror(errno)); return 0; } #endif switch(fork()) { case -1: lprint("Error: fork failed: %s\n", strerror(errno)); close(fd[0]); close(fd[1]); close(fd0[0]); close(fd0[1]); return 0; case 0: close(fd[0]); close(fd0[0]); /* Set the DISPLAY */ if (x_port >= 0) { #ifdef HAVE_SETENV sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); setenv("DISPLAY", buff, 1); #else sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); putenv(buff); #endif } dup2(fd0[1], 0); dup2(fd0[1], 1); dup2(fd[1], 2); for (s = 3; s <= 255; s++) close(s); execlp("rsh","rsh","-l", user, host, args, NULL); /* Ooops, failed, let's tell the user why */ sprintf(buff, "Error: execlp of %s failed: %s\n", "rsh", strerror(errno)); write(2, buff, strlen(buff)+1); close(0); close(1); close(2); /* XXX */ exit(1); default: close(fd[1]); close(fd0[1]); ns->s=fd[0]; so->s=fd0[0]; return 1; } } #endif BasiliskII/src/slirp/misc.h0000644000175000017500000000371510344604726016001 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifndef _MISC_H_ #define _MISC_H_ struct ex_list { int ex_pty; /* Do we want a pty? */ int ex_addr; /* The last byte of the address */ int ex_fport; /* Port to telnet to */ char *ex_exec; /* Command line of what to exec */ struct ex_list *ex_next; }; extern struct ex_list *exec_list; extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; extern int (*lprint_print) _P((void *, const char *, va_list)); extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; extern struct sbuf *lprint_sb; #ifndef HAVE_STRDUP char *strdup _P((const char *)); #endif void do_wait _P((int)); #define EMU_NONE 0x0 /* TCP emulations */ #define EMU_CTL 0x1 #define EMU_FTP 0x2 #define EMU_KSH 0x3 #define EMU_IRC 0x4 #define EMU_REALAUDIO 0x5 #define EMU_RLOGIN 0x6 #define EMU_IDENT 0x7 #define EMU_RSH 0x8 #define EMU_NOCONNECT 0x10 /* Don't connect */ /* UDP emulations */ #define EMU_TALK 0x1 #define EMU_NTALK 0x2 #define EMU_CUSEEME 0x3 struct tos_t { u_int16_t lport; u_int16_t fport; u_int8_t tos; u_int8_t emu; }; struct emu_t { u_int16_t lport; u_int16_t fport; u_int8_t tos; u_int8_t emu; struct emu_t *next; }; extern struct emu_t *tcpemu; extern int x_port, x_server, x_display; int show_x _P((char *, struct socket *)); void redir_x _P((u_int32_t, int, int, int)); void getouraddr _P((void)); void slirp_insque _P((void *, void *)); void slirp_remque _P((void *)); int add_exec _P((struct ex_list **, int, char *, int, int)); int slirp_openpty _P((int *, int *)); int fork_exec _P((struct socket *, char *, int)); void snooze_hup _P((int)); void snooze _P((void)); void relay _P((int)); void add_emu _P((char *)); void u_sleep _P((int)); void fd_nonblock _P((int)); void fd_block _P((int)); int rsh_exec _P((struct socket *, struct socket *, char *, char *, char *)); #endif BasiliskII/src/slirp/tcp_timer.c0000644000175000017500000002227311735673707017041 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93 * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp */ #include int tcp_keepidle = TCPTV_KEEP_IDLE; int tcp_keepintvl = TCPTV_KEEPINTVL; int tcp_maxidle; int so_options = DO_KEEPALIVE; struct tcpstat tcpstat; /* tcp statistics */ u_int32_t tcp_now; /* for RFC 1323 timestamps */ /* * Fast timeout routine for processing delayed acks */ void tcp_fasttimo() { register struct socket *so; register struct tcpcb *tp; DEBUG_CALL("tcp_fasttimo"); so = tcb.so_next; if (so) for (; so != &tcb; so = so->so_next) if ((tp = (struct tcpcb *)so->so_tcpcb) && (tp->t_flags & TF_DELACK)) { tp->t_flags &= ~TF_DELACK; tp->t_flags |= TF_ACKNOW; tcpstat.tcps_delack++; (void) tcp_output(tp); } } /* * Tcp protocol timeout routine called every 500 ms. * Updates the timers in all active tcb's and * causes finite state machine actions if timers expire. */ void tcp_slowtimo() { register struct socket *ip, *ipnxt; register struct tcpcb *tp; register int i; DEBUG_CALL("tcp_slowtimo"); tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; /* * Search through tcb's and update active timers. */ ip = tcb.so_next; if (ip == 0) return; for (; ip != &tcb; ip = ipnxt) { ipnxt = ip->so_next; tp = sototcpcb(ip); if (tp == 0) continue; for (i = 0; i < TCPT_NTIMERS; i++) { if (tp->t_timer[i] && --tp->t_timer[i] == 0) { tcp_timers(tp,i); if (ipnxt->so_prev != ip) goto tpgone; } } tp->t_idle++; if (tp->t_rtt) tp->t_rtt++; tpgone: ; } tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ #ifdef TCP_COMPAT_42 if ((int)tcp_iss < 0) tcp_iss = 0; /* XXX */ #endif tcp_now++; /* for timestamps */ } /* * Cancel all timers for TCP tp. */ void tcp_canceltimers(tp) struct tcpcb *tp; { register int i; for (i = 0; i < TCPT_NTIMERS; i++) tp->t_timer[i] = 0; } int tcp_backoff[TCP_MAXRXTSHIFT + 1] = { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; /* * TCP timer processing. */ struct tcpcb * tcp_timers(tp, timer) register struct tcpcb *tp; int timer; { register int rexmt; DEBUG_CALL("tcp_timers"); switch (timer) { /* * 2 MSL timeout in shutdown went off. If we're closed but * still waiting for peer to close and connection has been idle * too long, or if 2MSL time is up from TIME_WAIT, delete connection * control block. Otherwise, check again in a bit. */ case TCPT_2MSL: if (tp->t_state != TCPS_TIME_WAIT && tp->t_idle <= tcp_maxidle) tp->t_timer[TCPT_2MSL] = tcp_keepintvl; else tp = tcp_close(tp); break; /* * Retransmission timer went off. Message has not * been acked within retransmit interval. Back off * to a longer retransmit interval and retransmit one segment. */ case TCPT_REXMT: /* * XXXXX If a packet has timed out, then remove all the queued * packets for that session. */ if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { /* * This is a hack to suit our terminal server here at the uni of canberra * since they have trouble with zeroes... It usually lets them through * unharmed, but under some conditions, it'll eat the zeros. If we * keep retransmitting it, it'll keep eating the zeroes, so we keep * retransmitting, and eventually the connection dies... * (this only happens on incoming data) * * So, if we were gonna drop the connection from too many retransmits, * don't... instead halve the t_maxseg, which might break up the NULLs and * let them through * * *sigh* */ tp->t_maxseg >>= 1; if (tp->t_maxseg < 32) { /* * We tried our best, now the connection must die! */ tp->t_rxtshift = TCP_MAXRXTSHIFT; tcpstat.tcps_timeoutdrop++; tp = tcp_drop(tp, tp->t_softerror); /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ return (tp); /* XXX */ } /* * Set rxtshift to 6, which is still at the maximum * backoff time */ tp->t_rxtshift = 6; } tcpstat.tcps_rexmttimeo++; rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; TCPT_RANGESET(tp->t_rxtcur, rexmt, (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; /* * If losing, let the lower level know and try for * a better route. Also, if we backed off this far, * our srtt estimate is probably bogus. Clobber it * so we'll take the next rtt measurement as our srtt; * move the current srtt into rttvar to keep the current * retransmit times until then. */ if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { /* in_losing(tp->t_inpcb); */ tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); tp->t_srtt = 0; } tp->snd_nxt = tp->snd_una; /* * If timing a segment in this window, stop the timer. */ tp->t_rtt = 0; /* * Close the congestion window down to one segment * (we'll open it by one segment for each ack we get). * Since we probably have a window's worth of unacked * data accumulated, this "slow start" keeps us from * dumping all that data as back-to-back packets (which * might overwhelm an intermediate gateway). * * There are two phases to the opening: Initially we * open by one mss on each ack. This makes the window * size increase exponentially with time. If the * window is larger than the path can handle, this * exponential growth results in dropped packet(s) * almost immediately. To get more time between * drops but still "push" the network to take advantage * of improving conditions, we switch from exponential * to linear window opening at some threshold size. * For a threshold, we use half the current window * size, truncated to a multiple of the mss. * * (the minimum cwnd that will give us exponential * growth is 2 mss. We don't allow the threshold * to go below this.) */ { u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; if (win < 2) win = 2; tp->snd_cwnd = tp->t_maxseg; tp->snd_ssthresh = win * tp->t_maxseg; tp->t_dupacks = 0; } (void) tcp_output(tp); break; /* * Persistence timer into zero window. * Force a byte to be output, if possible. */ case TCPT_PERSIST: tcpstat.tcps_persisttimeo++; tcp_setpersist(tp); tp->t_force = 1; (void) tcp_output(tp); tp->t_force = 0; break; /* * Keep-alive timer went off; send something * or drop connection if idle for too long. */ case TCPT_KEEP: tcpstat.tcps_keeptimeo++; if (tp->t_state < TCPS_ESTABLISHED) goto dropit; /* if (tp->t_socket->so_options & SO_KEEPALIVE && */ if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { if (tp->t_idle >= tcp_keepidle + tcp_maxidle) goto dropit; /* * Send a packet designed to force a response * if the peer is up and reachable: * either an ACK if the connection is still alive, * or an RST if the peer has closed the connection * due to timeout or reboot. * Using sequence number tp->snd_una-1 * causes the transmitted zero-length segment * to lie outside the receive window; * by the protocol spec, this requires the * correspondent TCP to respond. */ tcpstat.tcps_keepprobe++; #ifdef TCP_COMPAT_42 /* * The keepalive packet must have nonzero length * to get a 4.2 host to respond. */ tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt - 1, tp->snd_una - 1, 0); #else tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL, tp->rcv_nxt, tp->snd_una - 1, 0); #endif tp->t_timer[TCPT_KEEP] = tcp_keepintvl; } else tp->t_timer[TCPT_KEEP] = tcp_keepidle; break; dropit: tcpstat.tcps_keepdrops++; tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ break; } return (tp); } BasiliskII/src/slirp/tcp_timer.h0000644000175000017500000001336111735673707017044 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp */ #ifndef _TCP_TIMER_H_ #define _TCP_TIMER_H_ /* * Definitions of the TCP timers. These timers are counted * down PR_SLOWHZ times a second. */ #define TCPT_NTIMERS 4 #define TCPT_REXMT 0 /* retransmit */ #define TCPT_PERSIST 1 /* retransmit persistence */ #define TCPT_KEEP 2 /* keep alive */ #define TCPT_2MSL 3 /* 2*msl quiet time timer */ /* * The TCPT_REXMT timer is used to force retransmissions. * The TCP has the TCPT_REXMT timer set whenever segments * have been sent for which ACKs are expected but not yet * received. If an ACK is received which advances tp->snd_una, * then the retransmit timer is cleared (if there are no more * outstanding segments) or reset to the base value (if there * are more ACKs expected). Whenever the retransmit timer goes off, * we retransmit one unacknowledged segment, and do a backoff * on the retransmit timer. * * The TCPT_PERSIST timer is used to keep window size information * flowing even if the window goes shut. If all previous transmissions * have been acknowledged (so that there are no retransmissions in progress), * and the window is too small to bother sending anything, then we start * the TCPT_PERSIST timer. When it expires, if the window is nonzero, * we go to transmit state. Otherwise, at intervals send a single byte * into the peer's window to force him to update our window information. * We do this at most as often as TCPT_PERSMIN time intervals, * but no more frequently than the current estimate of round-trip * packet time. The TCPT_PERSIST timer is cleared whenever we receive * a window update from the peer. * * The TCPT_KEEP timer is used to keep connections alive. If an * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, * but not yet established, then we drop the connection. Once the connection * is established, if the connection is idle for TCPTV_KEEP_IDLE time * (and keepalives have been enabled on the socket), we begin to probe * the connection. We force the peer to send us a segment by sending: * * This segment is (deliberately) outside the window, and should elicit * an ack segment in response from the peer. If, despite the TCPT_KEEP * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE * amount of time probing, then we drop the connection. */ /* * Time constants. */ #define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ #define TCPTV_SRTTBASE 0 /* base roundtrip time; if 0, no idea yet */ #define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ #define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ #define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ #define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ #define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ #define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ #define TCPTV_KEEPCNT 8 /* max probes before drop */ #define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ /* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ #define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ #define TCP_LINGERTIME 120 /* linger at most 2 minutes */ #define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ #ifdef TCPTIMERS char *tcptimers[] = { "REXMT", "PERSIST", "KEEP", "2MSL" }; #endif /* * Force a time value to be in a certain range. */ #define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ (tv) = (value); \ if ((tv) < (tvmin)) \ (tv) = (tvmin); \ else if ((tv) > (tvmax)) \ (tv) = (tvmax); \ } extern int tcp_keepidle; /* time before keepalive probes begin */ extern int tcp_keepintvl; /* time between keepalive probes */ extern int tcp_maxidle; /* time to drop after starting probes */ extern int tcp_ttl; /* time to live for TCP segs */ extern int tcp_backoff[]; struct tcpcb; void tcp_fasttimo _P((void)); void tcp_slowtimo _P((void)); void tcp_canceltimers _P((struct tcpcb *)); struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); #endif BasiliskII/src/slirp/sbuf.c0000644000175000017500000001000410555147310015760 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include #include /* Done as a macro in socket.h */ /* int * sbspace(struct sockbuff *sb) * { * return SB_DATALEN - sb->sb_cc; * } */ void sbfree(sb) struct sbuf *sb; { free(sb->sb_data); } void sbdrop(sb, num) struct sbuf *sb; int num; { /* * We can only drop how much we have * This should never succeed */ if(num > sb->sb_cc) num = sb->sb_cc; sb->sb_cc -= num; sb->sb_rptr += num; if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) sb->sb_rptr -= sb->sb_datalen; } void sbreserve(sb, size) struct sbuf *sb; int size; { if (sb->sb_data) { /* Already alloced, realloc if necessary */ if (sb->sb_datalen != size) { sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size); sb->sb_cc = 0; if (sb->sb_wptr) sb->sb_datalen = size; else sb->sb_datalen = 0; } } else { sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size); sb->sb_cc = 0; if (sb->sb_wptr) sb->sb_datalen = size; else sb->sb_datalen = 0; } } /* * Try and write() to the socket, whatever doesn't get written * append to the buffer... for a host with a fast net connection, * this prevents an unnecessary copy of the data * (the socket is non-blocking, so we won't hang) */ void sbappend(so, m) struct socket *so; struct mbuf *m; { int ret = 0; DEBUG_CALL("sbappend"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m->m_len = %d", m->m_len); /* Shouldn't happen, but... e.g. foreign host closes connection */ if (m->m_len <= 0) { m_free(m); return; } /* * If there is urgent data, call sosendoob * if not all was sent, sowrite will take care of the rest * (The rest of this function is just an optimisation) */ if (so->so_urgc) { sbappendsb(&so->so_rcv, m); m_free(m); sosendoob(so); return; } /* * We only write if there's nothing in the buffer, * ottherwise it'll arrive out of order, and hence corrupt */ if (!so->so_rcv.sb_cc) ret = send(so->s, m->m_data, m->m_len, 0); if (ret <= 0) { /* * Nothing was written * It's possible that the socket has closed, but * we don't need to check because if it has closed, * it will be detected in the normal way by soread() */ sbappendsb(&so->so_rcv, m); } else if (ret != m->m_len) { /* * Something was written, but not everything.. * sbappendsb the rest */ m->m_len -= ret; m->m_data += ret; sbappendsb(&so->so_rcv, m); } /* else */ /* Whatever happened, we free the mbuf */ m_free(m); } /* * Copy the data from m into sb * The caller is responsible to make sure there's enough room */ void sbappendsb(sb, m) struct sbuf *sb; struct mbuf *m; { int len, n, nn; len = m->m_len; if (sb->sb_wptr < sb->sb_rptr) { n = sb->sb_rptr - sb->sb_wptr; if (n > len) n = len; memcpy(sb->sb_wptr, m->m_data, n); } else { /* Do the right edge first */ n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; if (n > len) n = len; memcpy(sb->sb_wptr, m->m_data, n); len -= n; if (len) { /* Now the left edge */ nn = sb->sb_rptr - sb->sb_data; if (nn > len) nn = len; memcpy(sb->sb_data,m->m_data+n,nn); n += nn; } } sb->sb_cc += n; sb->sb_wptr += n; if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) sb->sb_wptr -= sb->sb_datalen; } /* * Copy data from sbuf to a normal, straight buffer * Don't update the sbuf rptr, this will be * done in sbdrop when the data is acked */ void sbcopy(sb, off, len, to) struct sbuf *sb; int off; int len; char *to; { char *from; from = sb->sb_rptr + off; if (from >= sb->sb_data + sb->sb_datalen) from -= sb->sb_datalen; if (from < sb->sb_wptr) { if (len > sb->sb_cc) len = sb->sb_cc; memcpy(to,from,len); } else { /* re-use off */ off = (sb->sb_data + sb->sb_datalen) - from; if (off > len) off = len; memcpy(to,from,off); len -= off; if (len) memcpy(to+off,sb->sb_data,len); } } BasiliskII/src/slirp/sbuf.h0000644000175000017500000000157310241066313015773 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #ifndef _SBUF_H_ #define _SBUF_H_ #define sbflush(sb) sbdrop((sb),(sb)->sb_cc) #define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) struct sbuf { u_int sb_cc; /* actual chars in buffer */ u_int sb_datalen; /* Length of data */ char *sb_wptr; /* write pointer. points to where the next * bytes should be written in the sbuf */ char *sb_rptr; /* read pointer. points to where the next * byte should be read from the sbuf */ char *sb_data; /* Actual data */ }; void sbfree _P((struct sbuf *)); void sbdrop _P((struct sbuf *, int)); void sbreserve _P((struct sbuf *, int)); void sbappend _P((struct socket *, struct mbuf *)); void sbappendsb _P((struct sbuf *, struct mbuf *)); void sbcopy _P((struct sbuf *, int, int, char *)); #endif BasiliskII/src/slirp/tftp.c0000644000175000017500000001561010555570677016026 0ustar centriscentris/* * tftp.c - a simple, read-only tftp server for qemu * * Copyright (c) 2004 Magnus Damm * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include struct tftp_session { int in_use; char filename[TFTP_FILENAME_MAX]; struct in_addr client_ip; u_int16_t client_port; int timestamp; }; struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; const char *tftp_prefix; static void tftp_session_update(struct tftp_session *spt) { spt->timestamp = curtime; spt->in_use = 1; } static void tftp_session_terminate(struct tftp_session *spt) { spt->in_use = 0; } static int tftp_session_allocate(struct tftp_t *tp) { struct tftp_session *spt; int k; for (k = 0; k < TFTP_SESSIONS_MAX; k++) { spt = &tftp_sessions[k]; if (!spt->in_use) goto found; /* sessions time out after 5 inactive seconds */ if ((int)(curtime - spt->timestamp) > 5000) goto found; } return -1; found: memset(spt, 0, sizeof(*spt)); memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); spt->client_port = tp->udp.uh_sport; tftp_session_update(spt); return k; } static int tftp_session_find(struct tftp_t *tp) { struct tftp_session *spt; int k; for (k = 0; k < TFTP_SESSIONS_MAX; k++) { spt = &tftp_sessions[k]; if (spt->in_use) { if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { if (spt->client_port == tp->udp.uh_sport) { return k; } } } } return -1; } static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, u_int8_t *buf, int len) { int fd; int bytes_read = 0; fd = open(spt->filename, O_RDONLY | O_BINARY); if (fd < 0) { return -1; } if (len) { lseek(fd, block_nr * 512, SEEK_SET); bytes_read = read(fd, buf, len); } close(fd); return bytes_read; } static int tftp_send_error(struct tftp_session *spt, u_int16_t errorcode, const char *msg, struct tftp_t *recv_tp) { struct sockaddr_in saddr, daddr; struct mbuf *m; struct tftp_t *tp; int nobytes; m = m_get(); if (!m) { return -1; } memset(m->m_data, 0, m->m_size); m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); tp->tp_op = htons(TFTP_ERROR); tp->x.tp_error.tp_error_code = htons(errorcode); strncpy((char *)tp->x.tp_error.tp_msg, msg, sizeof(tp->x.tp_error.tp_msg)); tp->x.tp_error.tp_msg[sizeof(tp->x.tp_error.tp_msg)-1] = 0; saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; daddr.sin_addr = spt->client_ip; daddr.sin_port = spt->client_port; nobytes = 2; m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); tftp_session_terminate(spt); return 0; } static int tftp_send_data(struct tftp_session *spt, u_int16_t block_nr, struct tftp_t *recv_tp) { struct sockaddr_in saddr, daddr; struct mbuf *m; struct tftp_t *tp; int nobytes; if (block_nr < 1) { return -1; } m = m_get(); if (!m) { return -1; } memset(m->m_data, 0, m->m_size); m->m_data += if_maxlinkhdr; tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); tp->tp_op = htons(TFTP_DATA); tp->x.tp_data.tp_block_nr = htons(block_nr); saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; daddr.sin_addr = spt->client_ip; daddr.sin_port = spt->client_port; nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); if (nobytes < 0) { m_free(m); /* send "file not found" error back */ tftp_send_error(spt, 1, "File not found", tp); return -1; } m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); if (nobytes == 512) { tftp_session_update(spt); } else { tftp_session_terminate(spt); } return 0; } static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) { struct tftp_session *spt; int s, k, n; u_int8_t *src, *dst; s = tftp_session_allocate(tp); if (s < 0) { return; } spt = &tftp_sessions[s]; src = tp->x.tp_buf; dst = (u_int8_t *)spt->filename; n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); /* get name */ for (k = 0; k < n; k++) { if (k < TFTP_FILENAME_MAX) { dst[k] = src[k]; } else { return; } if (src[k] == '\0') { break; } } if (k >= n) { return; } k++; /* check mode */ if ((n - k) < 6) { return; } if (memcmp(&src[k], "octet\0", 6) != 0) { tftp_send_error(spt, 4, "Unsupported transfer mode", tp); return; } /* do sanity checks on the filename */ if ((spt->filename[0] != '/') || (spt->filename[strlen(spt->filename) - 1] == '/') || strstr(spt->filename, "/../")) { tftp_send_error(spt, 2, "Access violation", tp); return; } /* only allow exported prefixes */ if (!tftp_prefix || (strncmp(spt->filename, tftp_prefix, strlen(tftp_prefix)) != 0)) { tftp_send_error(spt, 2, "Access violation", tp); return; } /* check if the file exists */ if (tftp_read_data(spt, 0, (u_int8_t *)spt->filename, 0) < 0) { tftp_send_error(spt, 1, "File not found", tp); return; } tftp_send_data(spt, 1, tp); } static void tftp_handle_ack(struct tftp_t *tp, int pktlen) { int s; s = tftp_session_find(tp); if (s < 0) { return; } if (tftp_send_data(&tftp_sessions[s], ntohs(tp->x.tp_data.tp_block_nr) + 1, tp) < 0) { return; } } void tftp_input(struct mbuf *m) { struct tftp_t *tp = (struct tftp_t *)m->m_data; switch(ntohs(tp->tp_op)) { case TFTP_RRQ: tftp_handle_rrq(tp, m->m_len); break; case TFTP_ACK: tftp_handle_ack(tp, m->m_len); break; } } BasiliskII/src/slirp/tftp.h0000644000175000017500000000122510363257520016012 0ustar centriscentris/* tftp defines */ #define TFTP_SESSIONS_MAX 3 #define TFTP_SERVER 69 #define TFTP_RRQ 1 #define TFTP_WRQ 2 #define TFTP_DATA 3 #define TFTP_ACK 4 #define TFTP_ERROR 5 #define TFTP_FILENAME_MAX 512 #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct tftp_t { struct ip ip; struct udphdr udp; u_int16_t tp_op; union { struct { u_int16_t tp_block_nr; u_int8_t tp_buf[512]; } tp_data; struct { u_int16_t tp_error_code; u_int8_t tp_msg[512]; } tp_error; u_int8_t tp_buf[512 + 2]; } x; } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif void tftp_input(struct mbuf *m); BasiliskII/src/slirp/icmp_var.h0000644000175000017500000000500611735673707016653 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp */ #ifndef _NETINET_ICMP_VAR_H_ #define _NETINET_ICMP_VAR_H_ /* * Variables related to this implementation * of the internet control message protocol. */ struct icmpstat { /* statistics related to input messages processed */ u_long icps_received; /* #ICMP packets received */ u_long icps_tooshort; /* packet < ICMP_MINLEN */ u_long icps_checksum; /* bad checksum */ u_long icps_notsupp; /* #ICMP packets not supported */ u_long icps_badtype; /* #with bad type feild */ u_long icps_reflect; /* number of responses */ }; /* * Names for ICMP sysctl objects */ #define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ #define ICMPCTL_STATS 2 /* statistics (read-only) */ #define ICMPCTL_MAXID 3 #define ICMPCTL_NAMES { \ { 0, 0 }, \ { "maskrepl", CTLTYPE_INT }, \ { "stats", CTLTYPE_STRUCT }, \ } extern struct icmpstat icmpstat; #endif BasiliskII/src/slirp/bootp.c0000644000175000017500000001442510713053556016163 0ustar centriscentris/* * QEMU BOOTP/DHCP server * * Copyright (c) 2004 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include /* XXX: only DHCP is supported */ #define NB_ADDR 16 #define START_ADDR 15 #define LEASE_TIME (24 * 3600) typedef struct { uint8_t allocated; uint8_t macaddr[6]; } BOOTPClient; BOOTPClient bootp_clients[NB_ADDR]; static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; static BOOTPClient *get_new_addr(struct in_addr *paddr) { BOOTPClient *bc; int i; for(i = 0; i < NB_ADDR; i++) { if (!bootp_clients[i].allocated) goto found; } return NULL; found: bc = &bootp_clients[i]; bc->allocated = 1; paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); return bc; } static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) { BOOTPClient *bc; int i; for(i = 0; i < NB_ADDR; i++) { if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) goto found; } return NULL; found: bc = &bootp_clients[i]; bc->allocated = 1; paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); return bc; } static void dhcp_decode(const uint8_t *buf, int size, int *pmsg_type) { const uint8_t *p, *p_end; int len, tag; *pmsg_type = 0; p = buf; p_end = buf + size; if (size < 5) return; if (memcmp(p, rfc1533_cookie, 4) != 0) return; p += 4; while (p < p_end) { tag = p[0]; if (tag == RFC1533_PAD) { p++; } else if (tag == RFC1533_END) { break; } else { p++; if (p >= p_end) break; len = *p++; switch(tag) { case RFC2132_MSG_TYPE: if (len >= 1) *pmsg_type = p[0]; break; default: break; } p += len; } } } static void bootp_reply(struct bootp_t *bp) { BOOTPClient *bc; struct mbuf *m; struct bootp_t *rbp; struct sockaddr_in saddr, daddr; struct in_addr dns_addr; int dhcp_msg_type, val; uint8_t *q; /* extract exact DHCP msg type */ dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); if (dhcp_msg_type == 0) dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST) return; /* XXX: this is a hack to get the client mac address */ memcpy(client_ethaddr, bp->bp_hwaddr, 6); if ((m = m_get()) == NULL) return; m->m_data += if_maxlinkhdr; rbp = (struct bootp_t *)m->m_data; m->m_data += sizeof(struct udpiphdr); memset(rbp, 0, sizeof(struct bootp_t)); if (dhcp_msg_type == DHCPDISCOVER) { new_addr: bc = get_new_addr(&daddr.sin_addr); if (!bc) return; memcpy(bc->macaddr, client_ethaddr, 6); } else { bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); if (!bc) { /* if never assigned, behaves as if it was already assigned (windows fix because it remembers its address) */ goto new_addr; } } saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); saddr.sin_port = htons(BOOTP_SERVER); daddr.sin_port = htons(BOOTP_CLIENT); rbp->bp_op = BOOTP_REPLY; rbp->bp_xid = bp->bp_xid; rbp->bp_htype = 1; rbp->bp_hlen = 6; memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ q = rbp->bp_vend; memcpy(q, rfc1533_cookie, 4); q += 4; if (dhcp_msg_type == DHCPDISCOVER) { *q++ = RFC2132_MSG_TYPE; *q++ = 1; *q++ = DHCPOFFER; } else if (dhcp_msg_type == DHCPREQUEST) { *q++ = RFC2132_MSG_TYPE; *q++ = 1; *q++ = DHCPACK; } if (dhcp_msg_type == DHCPDISCOVER || dhcp_msg_type == DHCPREQUEST) { *q++ = RFC2132_SRV_ID; *q++ = 4; memcpy(q, &saddr.sin_addr, 4); q += 4; *q++ = RFC1533_NETMASK; *q++ = 4; *q++ = 0xff; *q++ = 0xff; *q++ = 0xff; *q++ = 0x00; *q++ = RFC1533_GATEWAY; *q++ = 4; memcpy(q, &saddr.sin_addr, 4); q += 4; *q++ = RFC1533_DNS; *q++ = 4; dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); memcpy(q, &dns_addr, 4); q += 4; *q++ = RFC2132_LEASE_TIME; *q++ = 4; val = htonl(LEASE_TIME); memcpy(q, &val, 4); q += 4; if (*slirp_hostname) { val = strlen(slirp_hostname); *q++ = RFC1533_HOSTNAME; *q++ = val; memcpy(q, slirp_hostname, val); q += val; } } *q++ = RFC1533_END; m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); } void bootp_input(struct mbuf *m) { struct bootp_t *bp = mtod(m, struct bootp_t *); if (bp->bp_op == BOOTP_REQUEST) { bootp_reply(bp); } } BasiliskII/src/slirp/bootp.h0000644000175000017500000000601310363257520016160 0ustar centriscentris/* bootp/dhcp defines */ #define BOOTP_SERVER 67 #define BOOTP_CLIENT 68 #define BOOTP_REQUEST 1 #define BOOTP_REPLY 2 #define RFC1533_COOKIE 99, 130, 83, 99 #define RFC1533_PAD 0 #define RFC1533_NETMASK 1 #define RFC1533_TIMEOFFSET 2 #define RFC1533_GATEWAY 3 #define RFC1533_TIMESERVER 4 #define RFC1533_IEN116NS 5 #define RFC1533_DNS 6 #define RFC1533_LOGSERVER 7 #define RFC1533_COOKIESERVER 8 #define RFC1533_LPRSERVER 9 #define RFC1533_IMPRESSSERVER 10 #define RFC1533_RESOURCESERVER 11 #define RFC1533_HOSTNAME 12 #define RFC1533_BOOTFILESIZE 13 #define RFC1533_MERITDUMPFILE 14 #define RFC1533_DOMAINNAME 15 #define RFC1533_SWAPSERVER 16 #define RFC1533_ROOTPATH 17 #define RFC1533_EXTENSIONPATH 18 #define RFC1533_IPFORWARDING 19 #define RFC1533_IPSOURCEROUTING 20 #define RFC1533_IPPOLICYFILTER 21 #define RFC1533_IPMAXREASSEMBLY 22 #define RFC1533_IPTTL 23 #define RFC1533_IPMTU 24 #define RFC1533_IPMTUPLATEAU 25 #define RFC1533_INTMTU 26 #define RFC1533_INTLOCALSUBNETS 27 #define RFC1533_INTBROADCAST 28 #define RFC1533_INTICMPDISCOVER 29 #define RFC1533_INTICMPRESPOND 30 #define RFC1533_INTROUTEDISCOVER 31 #define RFC1533_INTROUTESOLICIT 32 #define RFC1533_INTSTATICROUTES 33 #define RFC1533_LLTRAILERENCAP 34 #define RFC1533_LLARPCACHETMO 35 #define RFC1533_LLETHERNETENCAP 36 #define RFC1533_TCPTTL 37 #define RFC1533_TCPKEEPALIVETMO 38 #define RFC1533_TCPKEEPALIVEGB 39 #define RFC1533_NISDOMAIN 40 #define RFC1533_NISSERVER 41 #define RFC1533_NTPSERVER 42 #define RFC1533_VENDOR 43 #define RFC1533_NBNS 44 #define RFC1533_NBDD 45 #define RFC1533_NBNT 46 #define RFC1533_NBSCOPE 47 #define RFC1533_XFS 48 #define RFC1533_XDM 49 #define RFC2132_REQ_ADDR 50 #define RFC2132_LEASE_TIME 51 #define RFC2132_MSG_TYPE 53 #define RFC2132_SRV_ID 54 #define RFC2132_PARAM_LIST 55 #define RFC2132_MAX_SIZE 57 #define RFC2132_RENEWAL_TIME 58 #define RFC2132_REBIND_TIME 59 #define DHCPDISCOVER 1 #define DHCPOFFER 2 #define DHCPREQUEST 3 #define DHCPACK 5 #define RFC1533_VENDOR_MAJOR 0 #define RFC1533_VENDOR_MINOR 0 #define RFC1533_VENDOR_MAGIC 128 #define RFC1533_VENDOR_ADDPARM 129 #define RFC1533_VENDOR_ETHDEV 130 #define RFC1533_VENDOR_HOWTO 132 #define RFC1533_VENDOR_MNUOPTS 160 #define RFC1533_VENDOR_SELECTION 176 #define RFC1533_VENDOR_MOTD 184 #define RFC1533_VENDOR_NUMOFMOTD 8 #define RFC1533_VENDOR_IMG 192 #define RFC1533_VENDOR_NUMOFIMG 16 #define RFC1533_END 255 #define BOOTP_VENDOR_LEN 64 #define DHCP_OPT_LEN 312 #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(1) #endif struct bootp_t { struct ip ip; struct udphdr udp; uint8_t bp_op; uint8_t bp_htype; uint8_t bp_hlen; uint8_t bp_hops; uint32_t bp_xid; uint16_t bp_secs; uint16_t unused; struct in_addr bp_ciaddr; struct in_addr bp_yiaddr; struct in_addr bp_siaddr; struct in_addr bp_giaddr; uint8_t bp_hwaddr[16]; uint8_t bp_sname[64]; uint8_t bp_file[128]; uint8_t bp_vend[DHCP_OPT_LEN]; } PACKED__; #ifdef PRAGMA_PACK_SUPPORTED #pragma pack(0) #endif void bootp_input(struct mbuf *m); BasiliskII/src/slirp/tcp_output.c0000644000175000017500000004177611735673707017272 0ustar centriscentris/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp */ /* * Changes and additions relating to SLiRP * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #include /* * Since this is only used in "stats socket", we give meaning * names instead of the REAL names */ char *tcpstates[] = { /* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", }; u_char tcp_outflags[TCP_NSTATES] = { TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK, }; #define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ /* * Tcp output routine: figure out what should be sent and send it. */ int tcp_output(tp) register struct tcpcb *tp; { register struct socket *so = tp->t_socket; register long len, win; int off, flags, error; register struct mbuf *m; register struct tcpiphdr *ti; u_char opt[MAX_TCPOPTLEN]; unsigned optlen, hdrlen; int idle, sendalot; DEBUG_CALL("tcp_output"); DEBUG_ARG("tp = %lx", (long )tp); /* * Determine length of data that should be transmitted, * and flags that will be used. * If there is some data or critical controls (SYN, RST) * to send, then transmit; otherwise, investigate further. */ idle = (tp->snd_max == tp->snd_una); if (idle && tp->t_idle >= tp->t_rxtcur) /* * We have been idle for "a while" and no acks are * expected to clock out any data we send -- * slow start to get ack "clock" running again. */ tp->snd_cwnd = tp->t_maxseg; again: sendalot = 0; off = tp->snd_nxt - tp->snd_una; win = min(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); /* * If in persist timeout with window of 0, send 1 byte. * Otherwise, if window is small but nonzero * and timer expired, we will send what we can * and go to transmit state. */ if (tp->t_force) { if (win == 0) { /* * If we still have some data to send, then * clear the FIN bit. Usually this would * happen below when it realizes that we * aren't sending all the data. However, * if we have exactly 1 byte of unset data, * then it won't clear the FIN bit below, * and if we are in persist state, we wind * up sending the packet without recording * that we sent the FIN bit. * * We can't just blindly clear the FIN bit, * because if we don't have any more data * to send then the probe will be the FIN * itself. */ if (off < so->so_snd.sb_cc) flags &= ~TH_FIN; win = 1; } else { tp->t_timer[TCPT_PERSIST] = 0; tp->t_rxtshift = 0; } } len = min(so->so_snd.sb_cc, win) - off; if (len < 0) { /* * If FIN has been sent but not acked, * but we haven't been called to retransmit, * len will be -1. Otherwise, window shrank * after we sent into it. If window shrank to 0, * cancel pending retransmit and pull snd_nxt * back to (closed) window. We will enter persist * state below. If the window didn't close completely, * just wait for an ACK. */ len = 0; if (win == 0) { tp->t_timer[TCPT_REXMT] = 0; tp->snd_nxt = tp->snd_una; } } if (len > tp->t_maxseg) { len = tp->t_maxseg; sendalot = 1; } if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) flags &= ~TH_FIN; win = sbspace(&so->so_rcv); /* * Sender silly window avoidance. If connection is idle * and can send all data, a maximum segment, * at least a maximum default-size segment do it, * or are forced, do it; otherwise don't bother. * If peer's buffer is tiny, then send * when window is at least half open. * If retransmitting (possibly after persist timer forced us * to send into a small window), then must resend. */ if (len) { if (len == tp->t_maxseg) goto send; if ((1 || idle || tp->t_flags & TF_NODELAY) && len + off >= so->so_snd.sb_cc) goto send; if (tp->t_force) goto send; if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) goto send; if (SEQ_LT(tp->snd_nxt, tp->snd_max)) goto send; } /* * Compare available window to amount of window * known to peer (as advertised window less * next expected input). If the difference is at least two * max size segments, or at least 50% of the maximum possible * window, then want to send a window update to peer. */ if (win > 0) { /* * "adv" is the amount we can increase the window, * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. */ long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - (tp->rcv_adv - tp->rcv_nxt); if (adv >= (long) (2 * tp->t_maxseg)) goto send; if (2 * adv >= (long) so->so_rcv.sb_datalen) goto send; } /* * Send if we owe peer an ACK. */ if (tp->t_flags & TF_ACKNOW) goto send; if (flags & (TH_SYN|TH_RST)) goto send; if (SEQ_GT(tp->snd_up, tp->snd_una)) goto send; /* * If our state indicates that FIN should be sent * and we have not yet done so, or we're retransmitting the FIN, * then we need to send. */ if (flags & TH_FIN && ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) goto send; /* * TCP window updates are not reliable, rather a polling protocol * using ``persist'' packets is used to insure receipt of window * updates. The three ``states'' for the output side are: * idle not doing retransmits or persists * persisting to move a small or zero window * (re)transmitting and thereby not persisting * * tp->t_timer[TCPT_PERSIST] * is set when we are in persist state. * tp->t_force * is set when we are called to send a persist packet. * tp->t_timer[TCPT_REXMT] * is set when we are retransmitting * The output side is idle when both timers are zero. * * If send window is too small, there is data to transmit, and no * retransmit or persist is pending, then go to persist state. * If nothing happens soon, send when timer expires: * if window is nonzero, transmit what we can, * otherwise force out a byte. */ if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && tp->t_timer[TCPT_PERSIST] == 0) { tp->t_rxtshift = 0; tcp_setpersist(tp); } /* * No reason to send a segment, just return. */ tcpstat.tcps_didnuttin++; return (0); send: /* * Before ESTABLISHED, force sending of initial options * unless TCP set not to do any options. * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN */ optlen = 0; hdrlen = sizeof (struct tcpiphdr); if (flags & TH_SYN) { tp->snd_nxt = tp->iss; if ((tp->t_flags & TF_NOOPT) == 0) { u_int16_t mss; opt[0] = TCPOPT_MAXSEG; opt[1] = 4; mss = htons((u_int16_t) tcp_mss(tp, 0)); memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss)); optlen = 4; /* if ((tp->t_flags & TF_REQ_SCALE) && * ((flags & TH_ACK) == 0 || * (tp->t_flags & TF_RCVD_SCALE))) { * *((u_int32_t *) (opt + optlen)) = htonl( * TCPOPT_NOP << 24 | * TCPOPT_WINDOW << 16 | * TCPOLEN_WINDOW << 8 | * tp->request_r_scale); * optlen += 4; * } */ } } /* * Send a timestamp and echo-reply if this is a SYN and our side * wants to use timestamps (TF_REQ_TSTMP is set) or both our side * and our peer have sent timestamps in our SYN's. */ /* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && * (flags & TH_RST) == 0 && * ((flags & (TH_SYN|TH_ACK)) == TH_SYN || * (tp->t_flags & TF_RCVD_TSTMP))) { * u_int32_t *lp = (u_int32_t *)(opt + optlen); * * / * Form timestamp option as shown in appendix A of RFC 1323. * / * *lp++ = htonl(TCPOPT_TSTAMP_HDR); * *lp++ = htonl(tcp_now); * *lp = htonl(tp->ts_recent); * optlen += TCPOLEN_TSTAMP_APPA; * } */ hdrlen += optlen; /* * Adjust data length if insertion of options will * bump the packet length beyond the t_maxseg length. */ if (len > tp->t_maxseg - optlen) { len = tp->t_maxseg - optlen; sendalot = 1; } /* * Grab a header mbuf, attaching a copy of data to * be transmitted, and initialize the header from * the template for sends on this connection. */ if (len) { if (tp->t_force && len == 1) tcpstat.tcps_sndprobe++; else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { tcpstat.tcps_sndrexmitpack++; tcpstat.tcps_sndrexmitbyte += len; } else { tcpstat.tcps_sndpack++; tcpstat.tcps_sndbyte += len; } m = m_get(); if (m == NULL) { /* error = ENOBUFS; */ error = 1; goto out; } m->m_data += if_maxlinkhdr; m->m_len = hdrlen; /* * This will always succeed, since we make sure our mbufs * are big enough to hold one MSS packet + header + ... etc. */ /* if (len <= MHLEN - hdrlen - max_linkhdr) { */ sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen); m->m_len += len; /* } else { * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); * if (m->m_next == 0) * len = 0; * } */ /* * If we're sending everything we've got, set PUSH. * (This will keep happy those implementations which only * give data to the user when a buffer fills or * a PUSH comes in.) */ if (off + len == so->so_snd.sb_cc) flags |= TH_PUSH; } else { if (tp->t_flags & TF_ACKNOW) tcpstat.tcps_sndacks++; else if (flags & (TH_SYN|TH_FIN|TH_RST)) tcpstat.tcps_sndctrl++; else if (SEQ_GT(tp->snd_up, tp->snd_una)) tcpstat.tcps_sndurg++; else tcpstat.tcps_sndwinup++; m = m_get(); if (m == NULL) { /* error = ENOBUFS; */ error = 1; goto out; } m->m_data += if_maxlinkhdr; m->m_len = hdrlen; } ti = mtod(m, struct tcpiphdr *); memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); /* * Fill in fields, remembering maximum advertised * window for use in delaying messages about window sizes. * If resending a FIN, be sure not to use a new sequence number. */ if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && tp->snd_nxt == tp->snd_max) tp->snd_nxt--; /* * If we are doing retransmissions, then snd_nxt will * not reflect the first unsent octet. For ACK only * packets, we do not want the sequence number of the * retransmitted packet, we want the sequence number * of the next unsent octet. So, if there is no data * (and no SYN or FIN), use snd_max instead of snd_nxt * when filling in ti_seq. But if we are in persist * state, snd_max might reflect one byte beyond the * right edge of the window, so use snd_nxt in that * case, since we know we aren't doing a retransmission. * (retransmit and persist are mutually exclusive...) */ if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) ti->ti_seq = htonl(tp->snd_nxt); else ti->ti_seq = htonl(tp->snd_max); ti->ti_ack = htonl(tp->rcv_nxt); if (optlen) { memcpy((caddr_t)(ti + 1), (caddr_t)opt, optlen); ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; } ti->ti_flags = flags; /* * Calculate receive window. Don't shrink window, * but avoid silly window syndrome. */ if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) win = 0; if (win > (long)TCP_MAXWIN << tp->rcv_scale) win = (long)TCP_MAXWIN << tp->rcv_scale; if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) win = (long)(tp->rcv_adv - tp->rcv_nxt); ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); if (SEQ_GT(tp->snd_up, tp->snd_una)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); #ifdef notdef if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); #endif ti->ti_flags |= TH_URG; } else /* * If no urgent pointer to send, then we pull * the urgent pointer to the left edge of the send window * so that it doesn't drift into the send window on sequence * number wraparound. */ tp->snd_up = tp->snd_una; /* drag it along */ /* * Put TCP length in extended header, and then * checksum extended header and data. */ if (len + optlen) ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + optlen + len)); ti->ti_sum = cksum(m, (int)(hdrlen + len)); /* * In transmit state, time the transmission and arrange for * the retransmit. In persist state, just set snd_max. */ if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { tcp_seq startseq = tp->snd_nxt; /* * Advance snd_nxt over sequence space of this segment. */ if (flags & (TH_SYN|TH_FIN)) { if (flags & TH_SYN) tp->snd_nxt++; if (flags & TH_FIN) { tp->snd_nxt++; tp->t_flags |= TF_SENTFIN; } } tp->snd_nxt += len; if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { tp->snd_max = tp->snd_nxt; /* * Time this transmission if not a retransmission and * not currently timing anything. */ if (tp->t_rtt == 0) { tp->t_rtt = 1; tp->t_rtseq = startseq; tcpstat.tcps_segstimed++; } } /* * Set retransmit timer if not currently set, * and not doing an ack or a keep-alive probe. * Initial value for retransmit timer is smoothed * round-trip time + 2 * round-trip time variance. * Initialize shift counter which is used for backoff * of retransmit time. */ if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; if (tp->t_timer[TCPT_PERSIST]) { tp->t_timer[TCPT_PERSIST] = 0; tp->t_rxtshift = 0; } } } else if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) tp->snd_max = tp->snd_nxt + len; /* * Fill in IP length and desired time to live and * send to IP level. There should be a better way * to handle ttl and tos; we could keep them in * the template, but need a way to checksum without them. */ m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ { ((struct ip *)ti)->ip_len = m->m_len; ((struct ip *)ti)->ip_ttl = ip_defttl; ((struct ip *)ti)->ip_tos = so->so_iptos; /* #if BSD >= 43 */ /* Don't do IP options... */ /* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, * so->so_options & SO_DONTROUTE, 0); */ error = ip_output(so, m); /* #else * error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, * so->so_options & SO_DONTROUTE); * #endif */ } if (error) { out: /* if (error == ENOBUFS) { * tcp_quench(tp->t_inpcb, 0); * return (0); * } */ /* if ((error == EHOSTUNREACH || error == ENETDOWN) * && TCPS_HAVERCVDSYN(tp->t_state)) { * tp->t_softerror = error; * return (0); * } */ return (error); } tcpstat.tcps_sndtotal++; /* * Data sent (as far as we can tell). * If this advertises a larger window than any other segment, * then remember the size of the advertised window. * Any pending ACK has now been sent. */ if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) tp->rcv_adv = tp->rcv_nxt + win; tp->last_ack_sent = tp->rcv_nxt; tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); if (sendalot) goto again; return (0); } void tcp_setpersist(tp) register struct tcpcb *tp; { int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; /* if (tp->t_timer[TCPT_REXMT]) * panic("tcp_output REXMT"); */ /* * Start/restart persistence timer. */ TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], t * tcp_backoff[tp->t_rxtshift], TCPTV_PERSMIN, TCPTV_PERSMAX); if (tp->t_rxtshift < TCP_MAXRXTSHIFT) tp->t_rxtshift++; } BasiliskII/src/slirp/COPYRIGHT0000644000175000017500000000570410241066313016156 0ustar centriscentrisSlirp was written by Danny Gasparovski. Copyright (c), 1995,1996 All Rights Reserved. Slirp is maintained by Kelly Price Slirp is free software; "free" as in you don't have to pay for it, and you are free to do whatever you want with it. I do not accept any donations, monetary or otherwise, for Slirp. Instead, I would ask you to pass this potential donation to your favorite charity. In fact, I encourage *everyone* who finds Slirp useful to make a small donation to their favorite charity (for example, GreenPeace). This is not a requirement, but a suggestion from someone who highly values the service they provide. The copyright terms and conditions: ---BEGIN--- Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. All advertising materials mentioning features or use of this software must display the following acknowledgment: This product includes software developed by Danny Gasparovski. THIS SOFTWARE IS PROVIDED ``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 DANNY GASPAROVSKI OR CONTRIBUTORS 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. ---END--- This basically means you can do anything you want with the software, except 1) call it your own, and 2) claim warranty on it. There is no warranty for this software. None. Nada. If you lose a million dollars while using Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. If these conditions cannot be met due to legal restrictions (E.g. where it is against the law to give out Software without warranty), you must cease using the software and delete all copies you have. Slirp uses code that is copyrighted by the following people/organizations: Juha Pirkola. Gregory M. Christy. The Regents of the University of California. Carnegie Mellon University. The Australian National University. RSA Data Security, Inc. Please read the top of each source file for the details on the various copyrights. BasiliskII/src/slirp/socket.c0000644000175000017500000004122510713053556016326 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ #define WANT_SYS_IOCTL_H #include #include #include "ip_icmp.h" #include "main.h" #ifdef __sun__ #include #endif void so_init() { /* Nothing yet */ } struct socket * solookup(head, laddr, lport, faddr, fport) struct socket *head; struct in_addr laddr; u_int lport; struct in_addr faddr; u_int fport; { struct socket *so; for (so = head->so_next; so != head; so = so->so_next) { if (so->so_lport == lport && so->so_laddr.s_addr == laddr.s_addr && so->so_faddr.s_addr == faddr.s_addr && so->so_fport == fport) break; } if (so == head) return (struct socket *)NULL; return so; } /* * Create a new socket, initialise the fields * It is the responsibility of the caller to * insque() it into the correct linked-list */ struct socket * socreate() { struct socket *so; so = (struct socket *)malloc(sizeof(struct socket)); if(so) { memset(so, 0, sizeof(struct socket)); so->so_state = SS_NOFDREF; so->s = -1; } return(so); } /* * remque and free a socket, clobber cache */ void sofree(so) struct socket *so; { if (so->so_emu==EMU_RSH && so->extra) { sofree(so->extra); so->extra=NULL; } if (so == tcp_last_so) tcp_last_so = &tcb; else if (so == udp_last_so) udp_last_so = &udb; m_free(so->so_m); if(so->so_next && so->so_prev) remque(so); /* crashes if so is not in a queue */ free(so); } /* * Read from so's socket into sb_snd, updating all relevant sbuf fields * NOTE: This will only be called if it is select()ed for reading, so * a read() of 0 (or less) means it's disconnected */ int soread(so) struct socket *so; { int n, nn, lss, total; struct sbuf *sb = &so->so_snd; int len = sb->sb_datalen - sb->sb_cc; struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; DEBUG_CALL("soread"); DEBUG_ARG("so = %lx", (long )so); /* * No need to check if there's enough room to read. * soread wouldn't have been called if there weren't */ len = sb->sb_datalen - sb->sb_cc; iov[0].iov_base = sb->sb_wptr; if (sb->sb_wptr < sb->sb_rptr) { iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; len -= iov[0].iov_len; if (len) { iov[1].iov_base = sb->sb_data; iov[1].iov_len = sb->sb_rptr - sb->sb_data; if(iov[1].iov_len > len) iov[1].iov_len = len; total = iov[0].iov_len + iov[1].iov_len; if (total > mss) { lss = total%mss; if (iov[1].iov_len > lss) { iov[1].iov_len -= lss; n = 2; } else { lss -= iov[1].iov_len; iov[0].iov_len -= lss; n = 1; } } else n = 2; } else { if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } } #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #else nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); #endif if (nn <= 0) { if (nn < 0 && (errno == EINTR || errno == EAGAIN)) return 0; else { DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); sofcantrcvmore(so); tcp_sockclosed(sototcpcb(so)); return -1; } } #ifndef HAVE_READV /* * If there was no error, try and read the second time round * We read again if n = 2 (ie, there's another part of the buffer) * and we read as much as we could in the first read * We don't test for <= 0 this time, because there legitimately * might not be any more data (since the socket is non-blocking), * a close will be detected on next iteration. * A return of -1 wont (shouldn't) happen, since it didn't happen above */ if (n == 2 && nn == iov[0].iov_len) { int ret; ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); if (ret > 0) nn += ret; } DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #endif /* Update fields */ sb->sb_cc += nn; sb->sb_wptr += nn; if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_wptr -= sb->sb_datalen; return nn; } /* * Get urgent data * * When the socket is created, we set it SO_OOBINLINE, * so when OOB data arrives, we soread() it and everything * in the send buffer is sent as urgent data */ void sorecvoob(so) struct socket *so; { struct tcpcb *tp = sototcpcb(so); DEBUG_CALL("sorecvoob"); DEBUG_ARG("so = %lx", (long)so); /* * We take a guess at how much urgent data has arrived. * In most situations, when urgent data arrives, the next * read() should get all the urgent data. This guess will * be wrong however if more data arrives just after the * urgent data, or the read() doesn't return all the * urgent data. */ soread(so); tp->snd_up = tp->snd_una + so->so_snd.sb_cc; tp->t_force = 1; tcp_output(tp); tp->t_force = 0; } /* * Send urgent data * There's a lot duplicated code here, but... */ int sosendoob(so) struct socket *so; { struct sbuf *sb = &so->so_rcv; char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ int n, len; DEBUG_CALL("sosendoob"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); if (so->so_urgc > 2048) so->so_urgc = 2048; /* XXXX */ if (sb->sb_rptr < sb->sb_wptr) { /* We can send it directly */ n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ so->so_urgc -= n; DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } else { /* * Since there's no sendv or sendtov like writev, * we must copy all data to a linear buffer then * send it all */ len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; if (len > so->so_urgc) len = so->so_urgc; memcpy(buff, sb->sb_rptr, len); so->so_urgc -= len; if (so->so_urgc) { n = sb->sb_wptr - sb->sb_data; if (n > so->so_urgc) n = so->so_urgc; memcpy((buff + len), sb->sb_data, n); so->so_urgc -= n; len += n; } n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ #ifdef DEBUG if (n != len) DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); #endif DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); } sb->sb_cc -= n; sb->sb_rptr += n; if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_rptr -= sb->sb_datalen; return n; } /* * Write data from so_rcv to so's socket, * updating all sbuf field as necessary */ int sowrite(so) struct socket *so; { int n,nn; struct sbuf *sb = &so->so_rcv; int len = sb->sb_cc; struct iovec iov[2]; DEBUG_CALL("sowrite"); DEBUG_ARG("so = %lx", (long)so); if (so->so_urgc) { sosendoob(so); if (sb->sb_cc == 0) return 0; } /* * No need to check if there's something to write, * sowrite wouldn't have been called otherwise */ len = sb->sb_cc; iov[0].iov_base = sb->sb_rptr; if (sb->sb_rptr < sb->sb_wptr) { iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; if (iov[0].iov_len > len) iov[0].iov_len = len; len -= iov[0].iov_len; if (len) { iov[1].iov_base = sb->sb_data; iov[1].iov_len = sb->sb_wptr - sb->sb_data; if (iov[1].iov_len > len) iov[1].iov_len = len; n = 2; } else n = 1; } /* Check if there's urgent data to send, and if so, send it */ #ifdef HAVE_READV nn = writev(so->s, (const struct iovec *)iov, n); DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #else nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); #endif /* This should never happen, but people tell me it does *shrug* */ if (nn < 0 && (errno == EAGAIN || errno == EINTR)) return 0; if (nn <= 0) { DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", so->so_state, errno)); sofcantsendmore(so); tcp_sockclosed(sototcpcb(so)); return -1; } #ifndef HAVE_READV if (n == 2 && nn == iov[0].iov_len) { int ret; ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); if (ret > 0) nn += ret; } DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #endif /* Update sbuf */ sb->sb_cc -= nn; sb->sb_rptr += nn; if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_rptr -= sb->sb_datalen; /* * If in DRAIN mode, and there's no more data, set * it CANTSENDMORE */ if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) sofcantsendmore(so); return nn; } /* * recvfrom() a UDP socket */ void sorecvfrom(so) struct socket *so; { struct sockaddr_in addr; socklen_t addrlen = sizeof(struct sockaddr_in); DEBUG_CALL("sorecvfrom"); DEBUG_ARG("so = %lx", (long)so); if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ char buff[256]; int len; len = recvfrom(so->s, buff, 256, 0, (struct sockaddr *)&addr, &addrlen); /* XXX Check if reply is "correct"? */ if(len == -1 || len == 0) { u_char code=ICMP_UNREACH_PORT; if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", errno,strerror(errno))); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); } else { icmp_reflect(so->so_m); so->so_m = 0; /* Don't m_free() it again! */ } /* No need for this socket anymore, udp_detach it */ udp_detach(so); } else { /* A "normal" UDP packet */ struct mbuf *m; int len; ioctlsockopt_t n; if (!(m = m_get())) return; m->m_data += if_maxlinkhdr; /* * XXX Shouldn't FIONREAD packets destined for port 53, * but I don't know the max packet size for DNS lookups */ len = M_FREEROOM(m); /* if (so->so_fport != htons(53)) { */ ioctlsocket(so->s, FIONREAD, &n); if (n > len) { n = (m->m_data - m->m_dat) + m->m_len + n + 1; m_inc(m, n); len = M_FREEROOM(m); } /* } */ m->m_len = recvfrom(so->s, m->m_data, len, 0, (struct sockaddr *)&addr, &addrlen); DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", m->m_len, errno,strerror(errno))); if(m->m_len<0) { u_char code=ICMP_UNREACH_PORT; if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); m_free(m); } else { /* * Hack: domain name lookup will be used the most for UDP, * and since they'll only be used once there's no need * for the 4 minute (or whatever) timeout... So we time them * out much quicker (10 seconds for now...) */ if (so->so_expire) { if (so->so_fport == htons(53)) so->so_expire = curtime + SO_EXPIREFAST; else so->so_expire = curtime + SO_EXPIRE; } /* if (m->m_len == len) { * m_inc(m, MINCSIZE); * m->m_len = 0; * } */ /* * If this packet was destined for CTL_ADDR, * make it look like that's where it came from, done by udp_output */ udp_output(so, m, &addr); } /* rx error */ } /* if ping packet */ } /* * sendto() a socket */ int sosendto(so, m) struct socket *so; struct mbuf *m; { int ret; struct sockaddr_in addr; DEBUG_CALL("sosendto"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); addr.sin_family = AF_INET; if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { /* It's an alias */ switch(ntohl(so->so_faddr.s_addr) & 0xff) { case CTL_DNS: addr.sin_addr = dns_addr; break; case CTL_ALIAS: default: addr.sin_addr = loopback_addr; break; } } else addr.sin_addr = so->so_faddr; addr.sin_port = so->so_fport; DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); /* Don't care what port we get */ ret = sendto(so->s, m->m_data, m->m_len, 0, (struct sockaddr *)&addr, sizeof (struct sockaddr)); if (ret < 0) return -1; /* * Kill the socket if there's no reply in 4 minutes, * but only if it's an expirable socket */ if (so->so_expire) so->so_expire = curtime + SO_EXPIRE; so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ return 0; } /* * XXX This should really be tcp_listen */ struct socket * solisten(port, laddr, lport, flags) u_int port; u_int32_t laddr; u_int lport; int flags; { struct sockaddr_in addr; struct socket *so; int s; socklen_t addrlen = sizeof(addr); int opt = 1; DEBUG_CALL("solisten"); DEBUG_ARG("port = %d", port); DEBUG_ARG("laddr = %x", laddr); DEBUG_ARG("lport = %d", lport); DEBUG_ARG("flags = %x", flags); if ((so = socreate()) == NULL) { /* free(so); Not sofree() ??? free(NULL) == NOP */ return NULL; } /* Don't tcp_attach... we don't need so_snd nor so_rcv */ if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { free(so); return NULL; } insque(so,&tcb); /* * SS_FACCEPTONCE sockets must time out. */ if (flags & SS_FACCEPTONCE) so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; so->so_state = (SS_FACCEPTCONN|flags); so->so_lport = lport; /* Kept in network format */ so->so_laddr.s_addr = laddr; /* Ditto */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = port; if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { int tmperrno = errno; /* Don't clobber the real reason we failed */ close(s); sofree(so); /* Restore the real errno */ #ifdef _WIN32 WSASetLastError(tmperrno); #else errno = tmperrno; #endif return NULL; } setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); getsockname(s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = alias_addr; else so->so_faddr = addr.sin_addr; so->s = s; return so; } /* * Data is available in so_rcv * Just write() the data to the socket * XXX not yet... */ void sorwakeup(so) struct socket *so; { /* sowrite(so); */ /* FD_CLR(so->s,&writefds); */ } /* * Data has been freed in so_snd * We have room for a read() if we want to * For now, don't read, it'll be done in the main loop */ void sowwakeup(so) struct socket *so; { /* Nothing, yet */ } /* * Various session state calls * XXX Should be #define's * The socket state stuff needs work, these often get call 2 or 3 * times each when only 1 was needed */ void soisfconnecting(so) register struct socket *so; { so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| SS_FCANTSENDMORE|SS_FWDRAIN); so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ } void soisfconnected(so) register struct socket *so; { so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ } void sofcantrcvmore(so) struct socket *so; { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,0); if(global_writefds) { FD_CLR(so->s,global_writefds); } } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTSENDMORE) so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */ else so->so_state |= SS_FCANTRCVMORE; } void sofcantsendmore(so) struct socket *so; { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,1); /* send FIN to fhost */ if (global_readfds) { FD_CLR(so->s,global_readfds); } if (global_xfds) { FD_CLR(so->s,global_xfds); } } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTRCVMORE) so->so_state = SS_NOFDREF; /* as above */ else so->so_state |= SS_FCANTSENDMORE; } void soisfdisconnected(so) struct socket *so; { /* so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */ /* close(so->s); */ /* so->so_state = SS_ISFDISCONNECTED; */ /* * XXX Do nothing ... ? */ } /* * Set write drain mode * Set CANTSENDMORE once all data has been write()n */ void sofwdrain(so) struct socket *so; { if (so->so_rcv.sb_cc) so->so_state |= SS_FWDRAIN; else sofcantsendmore(so); } BasiliskII/src/slirp/socket.h0000644000175000017500000000675410241066313016332 0ustar centriscentris/* * Copyright (c) 1995 Danny Gasparovski. * * Please read the file COPYRIGHT for the * terms and conditions of the copyright. */ /* MINE */ #ifndef _SLIRP_SOCKET_H_ #define _SLIRP_SOCKET_H_ #define SO_EXPIRE 240000 #define SO_EXPIREFAST 10000 /* * Our socket structure */ struct socket { struct socket *so_next,*so_prev; /* For a linked list of sockets */ int s; /* The actual socket */ /* XXX union these with not-yet-used sbuf params */ struct mbuf *so_m; /* Pointer to the original SYN packet, * for non-blocking connect()'s, and * PING reply's */ struct tcpiphdr *so_ti; /* Pointer to the original ti within * so_mconn, for non-blocking connections */ int so_urgc; struct in_addr so_faddr; /* foreign host table entry */ struct in_addr so_laddr; /* local host table entry */ u_int16_t so_fport; /* foreign port */ u_int16_t so_lport; /* local port */ u_int8_t so_iptos; /* Type of service */ u_int8_t so_emu; /* Is the socket emulated? */ u_char so_type; /* Type of socket, UDP or TCP */ int so_state; /* internal state flags SS_*, below */ struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ u_int so_expire; /* When the socket will expire */ int so_queued; /* Number of packets queued from this socket */ int so_nqueued; /* Number of packets queued in a row * Used to determine when to "downgrade" a session * from fastq to batchq */ struct sbuf so_rcv; /* Receive buffer */ struct sbuf so_snd; /* Send buffer */ void * extra; /* Extra pointer */ }; /* * Socket state bits. (peer means the host on the Internet, * local host means the host on the other end of the modem) */ #define SS_NOFDREF 0x001 /* No fd reference */ #define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ #define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ #define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ #define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ /* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ #define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ #define SS_CTL 0x080 #define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ #define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ extern struct socket tcb; #if defined(DECLARE_IOVEC) && !defined(HAVE_READV) struct iovec { char *iov_base; size_t iov_len; }; #endif void so_init _P((void)); struct socket * solookup _P((struct socket *, struct in_addr, u_int, struct in_addr, u_int)); struct socket * socreate _P((void)); void sofree _P((struct socket *)); int soread _P((struct socket *)); void sorecvoob _P((struct socket *)); int sosendoob _P((struct socket *)); int sowrite _P((struct socket *)); void sorecvfrom _P((struct socket *)); int sosendto _P((struct socket *, struct mbuf *)); struct socket * solisten _P((u_int, u_int32_t, u_int, int)); void sorwakeup _P((struct socket *)); void sowwakeup _P((struct socket *)); void soisfconnecting _P((register struct socket *)); void soisfconnected _P((register struct socket *)); void sofcantrcvmore _P((struct socket *)); void sofcantsendmore _P((struct socket *)); void soisfdisconnected _P((struct socket *)); void sofwdrain _P((struct socket *)); #endif /* _SOCKET_H_ */ BasiliskII/src/slirp/cksum.c0000644000175000017500000000750111735673706016171 0ustar centriscentris/* * Copyright (c) 1988, 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. * * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp */ #include /* * Checksum routine for Internet Protocol family headers (Portable Version). * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. * * XXX Since we will never span more than 1 mbuf, we can optimise this */ #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) #define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} int cksum(struct mbuf *m, int len) { register u_int16_t *w; register int sum = 0; register int mlen = 0; int byte_swapped = 0; union { u_int8_t c[2]; u_int16_t s; } s_util; union { u_int16_t s[2]; u_int32_t l; } l_util; if (m->m_len == 0) goto cont; w = mtod(m, u_int16_t *); mlen = m->m_len; if (len < mlen) mlen = len; len -= mlen; /* * Force to even boundary. */ if ((1 & (long) w) && (mlen > 0)) { REDUCE; sum <<= 8; s_util.c[0] = *(u_int8_t *)w; w = (u_int16_t *)((int8_t *)w + 1); mlen--; byte_swapped = 1; } /* * Unroll the loop to make overhead from * branches &c small. */ while ((mlen -= 32) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; w += 16; } mlen += 32; while ((mlen -= 8) >= 0) { sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; w += 4; } mlen += 8; if (mlen == 0 && byte_swapped == 0) goto cont; REDUCE; while ((mlen -= 2) >= 0) { sum += *w++; } if (byte_swapped) { REDUCE; sum <<= 8; byte_swapped = 0; if (mlen == -1) { s_util.c[1] = *(u_int8_t *)w; sum += s_util.s; mlen = 0; } else mlen = -1; } else if (mlen == -1) s_util.c[0] = *(u_int8_t *)w; cont: #ifdef DEBUG if (len) { DEBUG_ERROR((dfd, "cksum: out of data\n")); DEBUG_ERROR((dfd, " len = %d\n", len)); } #endif if (mlen == -1) { /* The last mbuf has odd # of bytes. Follow the standard (the odd byte may be shifted left by 8 bits or not as determined by endian-ness of the machine) */ s_util.c[1] = 0; sum += s_util.s; } REDUCE; return (~sum & 0xffff); } BasiliskII/src/Windows/0000755000175000017500000000000011735674751015202 5ustar centriscentrisBasiliskII/src/Windows/kernel_windows.cpp0000755000175000017500000000612010736405221020722 0ustar centriscentris/* * kernel_windows.cpp * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "prefs.h" #include "kernel_windows.h" // From main_windows.cpp extern DWORD win_os; extern DWORD win_os_major; static HMODULE hKernel32 = 0; static HMODULE hUser32 = 0; static HMODULE hB2Win32 = 0; UINT (WINAPI *pfnGetWriteWatch) (DWORD,PVOID,SIZE_T,PVOID *,LPDWORD,LPDWORD) = 0; BOOL (WINAPI *pfnInitializeCriticalSectionAndSpinCount) (LPCRITICAL_SECTION,DWORD) = 0; BOOL (WINAPI *pfnCancelIo) (HANDLE) = 0; BOOL (WINAPI *pfnGETCDSECTORS) (BYTE,DWORD,WORD,LPBYTE) = 0; UINT (WINAPI *pfnSendInput) (UINT,LPVOID,int) = 0; BOOL (WINAPI *pfnGetDiskFreeSpaceEx) (LPCSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER) = 0; void KernelInit( void ) { hKernel32 = LoadLibrary( "kernel32.dll" ); hUser32 = LoadLibrary( "user32.dll" ); if(hKernel32) { if(win_os == VER_PLATFORM_WIN32_WINDOWS) { // NT5 RC2 Kernel exports GetWriteWatch(), but VirtualAlloc(MEM_WRITE_WATCH) fails pfnGetWriteWatch = (UINT (WINAPI *)(DWORD,PVOID,SIZE_T,PVOID *,LPDWORD,LPDWORD))GetProcAddress( hKernel32, "GetWriteWatch" ); } pfnInitializeCriticalSectionAndSpinCount = (BOOL (WINAPI *)(LPCRITICAL_SECTION,DWORD))GetProcAddress( hKernel32, "InitializeCriticalSectionAndSpinCount" ); pfnCancelIo = (BOOL (WINAPI *)(HANDLE))GetProcAddress( hKernel32, "CancelIo" ); pfnGetDiskFreeSpaceEx = (BOOL (WINAPI *)(LPCSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER))GetProcAddress( hKernel32, "GetDiskFreeSpaceExA" ); } if(hUser32) { // Win98 has this one too. // if(win_os == VER_PLATFORM_WIN32_NT) { pfnSendInput = (UINT (WINAPI *)(UINT,LPVOID,int))GetProcAddress( hUser32, "SendInput" ); // } } if(win_os == VER_PLATFORM_WIN32_WINDOWS) { hB2Win32 = LoadLibrary( "B2Win32.dll" ); if(hB2Win32) { pfnGETCDSECTORS = (BOOL (WINAPI *)(BYTE,DWORD,WORD,LPBYTE))GetProcAddress( hB2Win32, "GETCDSECTORS" ); } } } void KernelExit( void ) { if(hKernel32) { FreeLibrary( hKernel32 ); hKernel32 = 0; } if(hUser32) { FreeLibrary( hUser32 ); hUser32 = 0; } if(hB2Win32) { FreeLibrary( hB2Win32 ); hB2Win32 = 0; } pfnGetWriteWatch = 0; pfnInitializeCriticalSectionAndSpinCount = 0; pfnCancelIo = 0; pfnSendInput = 0; pfnGETCDSECTORS = 0; } BasiliskII/src/Windows/serial_windows.cpp0000755000175000017500000007447410736405222020743 0ustar centriscentris/* * serial_windows.cpp - Serial device driver for Win32 * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ // TODO: serial i/o threads should have high priority. #include "sysdeps.h" #include #include #include "main.h" #include "macos_util.h" #include "prefs.h" #include "serial.h" #include "serial_defs.h" #include "cpu_emulation.h" // This must be always on. #define DEBUG 1 #undef OutputDebugString #define OutputDebugString serial_log_write static void serial_log_write( char *s ); #define SERIAL_LOG_FILE_NAME "serial.log" #include "debug.h" #undef D #define D(x) if(debug_serial != DB_SERIAL_NONE) (x); enum { DB_SERIAL_NONE=0, DB_SERIAL_NORMAL, DB_SERIAL_LOUD }; static int16 debug_serial = DB_SERIAL_NONE; static HANDLE serial_log_file = INVALID_HANDLE_VALUE; static void serial_log_open( char *path ) { if(debug_serial == DB_SERIAL_NONE) return; DeleteFile( path ); serial_log_file = CreateFile( path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL ); if( serial_log_file == INVALID_HANDLE_VALUE ) { ErrorAlert( "Could not create the serial log file." ); } } static void serial_log_close( void ) { if(debug_serial == DB_SERIAL_NONE) return; if( serial_log_file != INVALID_HANDLE_VALUE ) { CloseHandle( serial_log_file ); serial_log_file = INVALID_HANDLE_VALUE; } } static void serial_log_write( char *s ) { DWORD bytes_written; // should have been checked already. if(debug_serial == DB_SERIAL_NONE) return; if( serial_log_file != INVALID_HANDLE_VALUE ) { DWORD count = strlen(s); if (0 == WriteFile(serial_log_file, s, count, &bytes_written, NULL) || (int)bytes_written != count) { serial_log_close(); ErrorAlert( "serial log file write error (out of disk space?). Log closed." ); } else { FlushFileBuffers( serial_log_file ); } } } // Driver private variables class XSERDPort : public SERDPort { public: XSERDPort(const char *dev, const char *suffix) { D(bug("XSERDPort constructor %s\r\n", dev)); // device_name = (char *)dev; read_pending = write_pending = false; if(dev) strcpy( device_name, (char *)dev ); else *device_name = 0; strupr(device_name); is_parallel = (strncmp(device_name,"LPT",3) == 0); is_file = (strncmp(device_name,"FILE",4) == 0); if(is_file) { char entry_name[20]; wsprintf( entry_name, "portfile%s", suffix ); const char *path = PrefsFindString(entry_name); if(path) { strcpy( output_file_name, path ); } else { strcpy( output_file_name, "C:\\B2TEMP.OUT" ); } } is_serial = !is_parallel && !is_file; fd = INVALID_HANDLE_VALUE; input_thread_active = output_thread_active = NULL; } virtual ~XSERDPort() { D(bug("XSERDPort destructor \r\n")); if (input_thread_active) { D(bug("WARNING: brute TerminateThread(input)\r\n")); TerminateThread(input_thread_active,0); CloseHandle(input_signal); input_thread_active = NULL; } if (output_thread_active) { D(bug("WARNING: brute TerminateThread(output)\r\n")); TerminateThread(output_thread_active,0); CloseHandle(output_signal); output_thread_active = NULL; } } virtual int16 open(uint16 config); virtual int16 prime_in(uint32 pb, uint32 dce); virtual int16 prime_out(uint32 pb, uint32 dce); virtual int16 control(uint32 pb, uint32 dce, uint16 code); virtual int16 status(uint32 pb, uint32 dce, uint16 code); virtual int16 close(void); private: bool configure(uint16 config); void set_handshake(uint32 s, bool with_dtr); static WINAPI unsigned int input_func(void *arg); static WINAPI unsigned int output_func(void *arg); static int acknowledge_error(HANDLE h, bool is_read); bool set_timeouts(int bauds, int parity_bits, int stop_bits); char device_name[256]; HANDLE fd; bool io_killed; // Flag: KillIO called, I/O threads must not call deferred tasks bool quitting; // Flag: Quit threads HANDLE input_thread_active; // Handle: Input thread installed (was a bool) unsigned int input_thread_id; HANDLE input_signal; // Signal for input thread: execute command uint32 input_pb, input_dce; // Command parameters for input thread HANDLE output_thread_active; // Handle: Output thread installed (was a bool) unsigned int output_thread_id; HANDLE output_signal; // Signal for output thread: execute command uint32 output_pb, output_dce; // Command parameters for output thread DCB mode; // Terminal configuration bool is_serial; bool is_parallel; // true if LPTx bool is_file; // true if FILE char output_file_name[256]; }; /* * Initialization */ void SerialInit(void) { const char *port; debug_serial = PrefsFindInt32("debugserial"); serial_log_open( SERIAL_LOG_FILE_NAME ); // Read serial preferences and create structs for both ports port = PrefsFindString("seriala"); if(port) { D(bug("SerialInit seriala=%s\r\n",port)); } the_serd_port[0] = new XSERDPort(port,"0"); port = PrefsFindString("serialb"); if(port) { D(bug("SerialInit serialb=%s\r\n",port)); } the_serd_port[1] = new XSERDPort(port,"1"); } /* * Deinitialization */ void SerialExit(void) { D(bug("SerialExit\r\n")); if(the_serd_port[0]) delete (XSERDPort *)the_serd_port[0]; if(the_serd_port[1]) delete (XSERDPort *)the_serd_port[1]; D(bug("SerialExit done\r\n")); serial_log_close(); } /* * Open serial port */ int16 XSERDPort::open(uint16 config) { // Don't open NULL name devices if (!device_name || !*device_name) return openErr; D(bug("XSERDPort::open device=%s,config=0x%X\r\n",device_name,(int)config)); // Init variables io_killed = false; quitting = false; // Open port if(is_file) { DeleteFile( output_file_name ); fd = CreateFile( output_file_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); } else { fd = CreateFile( device_name, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0 ); } if(fd == INVALID_HANDLE_VALUE) { goto open_error; D(bug("XSERDPort::open failed to open port %s\r\n",device_name)); } if(is_serial) { // Configure port for raw mode memset( &mode, 0, sizeof(DCB) ); mode.DCBlength = sizeof(mode); if(!GetCommState( fd, &mode )) goto open_error; mode.fBinary = TRUE; if(!configure(config)) { D(bug("XSERDPort::configure failed\r\n")); goto open_error; } } // Start input/output threads input_signal = CreateSemaphore( 0, 0, 1, NULL); if(!input_signal) goto open_error; output_signal = CreateSemaphore( 0, 0, 1, NULL); if(!output_signal) goto open_error; D(bug("Semaphores created\r\n")); input_thread_active = (HANDLE)_beginthreadex( 0, 0, input_func, (LPVOID)this, 0, &input_thread_id ); output_thread_active = (HANDLE)_beginthreadex( 0, 0, output_func, (LPVOID)this, 0, &output_thread_id ); if (!input_thread_active || !output_thread_active) goto open_error; D(bug("Threads created, Open returns success\r\n")); return noErr; open_error: D(bug("Open cleanup after failure\r\n")); if (input_thread_active) { TerminateThread(input_thread_active,0); CloseHandle(input_signal); input_thread_active = false; } if (output_thread_active) { TerminateThread(output_thread_active,0); CloseHandle(output_signal); output_thread_active = false; } if(fd != INVALID_HANDLE_VALUE) { CloseHandle(fd); fd = 0; } return openErr; } /* * Read data from port */ int16 XSERDPort::prime_in(uint32 pb, uint32 dce) { D(bug("XSERDPort::prime_in\r\n")); // Send input command to input_thread read_done = false; read_pending = true; input_pb = pb; input_dce = dce; ReleaseSemaphore(input_signal,1,NULL); return 1; // Command in progress } /* * Write data to port */ int16 XSERDPort::prime_out(uint32 pb, uint32 dce) { D(bug("XSERDPort::prime_out\r\n")); // Send output command to output_thread write_done = false; write_pending = true; output_pb = pb; output_dce = dce; ReleaseSemaphore(output_signal,1,NULL); return 1; // Command in progress } static DWORD get_comm_output_buf_size( HANDLE h ) { DWORD size = 0; COMMPROP cp; if(GetCommProperties(h,&cp)) { size = cp.dwCurrentTxQueue; } return size; } /* * Control calls */ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code) { D(bug("XSERDPort::control code=%d\r\n",(int)code)); switch (code) { case kSERDClockMIDI: /* http://til.info.apple.com/techinfo.nsf/artnum/n2425 A MIDI interface operates at 31.25 Kbaud (+/- 1%) [== 31400] asynchronously, using a data format of one start bit, eight data bits, and one stop bit. This makes a total of 10 bits for each 320 microsecond period per serial byte. */ D(bug("kSERDClockMIDI setting 38400,n,8,1\n")); return noErr; /* mode.BaudRate = 38400; mode.ByteSize = 8; mode.StopBits = ONESTOPBIT; mode.Parity = NOPARITY; if(!SetCommState( fd, &mode )) { D(bug("kSERDClockMIDI SetCommState() failed\n")); return controlErr; } else { if(!set_timeouts(38400,0,2)) { D(bug("kSERDClockMIDI set_timeouts() failed\n")); return controlErr; } D(bug("kSERDClockMIDI OK\n")); return noErr; } */ case 1: // KillIO io_killed = true; if(is_serial) { // Make sure we won't hang waiting. There is something wrong // in how read_pending & write_pending are handled. DWORD endtime = GetTickCount() + 1000; while ( (read_pending || write_pending) && (GetTickCount() < endtime) ) { Sleep(20); } if(read_pending || write_pending) { D(bug("Warning (KillIO): read_pending=%d, write_pending=%d\n", read_pending, write_pending)); read_pending = write_pending = false; } // | PURGE_TXABORT | PURGE_RXABORT not needed, no overlapped i/o PurgeComm(fd,PURGE_TXCLEAR|PURGE_RXCLEAR); FlushFileBuffers(fd); } io_killed = false; D(bug("KillIO done\n")); return noErr; case kSERDConfiguration: if (configure((uint16)ReadMacInt16(pb + csParam))) return noErr; else return paramErr; case kSERDInputBuffer: if(is_serial) { // SetupComm() wants both values, so we need to know the output size. DWORD osize = get_comm_output_buf_size(fd); DWORD isize = ReadMacInt16(pb + csParam + 4) & 0xffffffc0; // 1k minimum // Was this something Amiga specific -- do I need to do this? if (isize < 1024) isize = 1024; if(isize > 0 && osize > 0) { if(SetupComm( fd, isize, osize )) { D(bug(" buffer size is now %08lx\n", isize)); return noErr; } else { D(bug(" SetupComm(%d,%d) failed, error = %08lx\n", isize, osize, GetLastError())); } } } // Always return ok. return noErr; case kSERDSerHShake: set_handshake(pb + csParam, false); return noErr; case kSERDSetBreak: if(is_serial) { if(!SetCommBreak(fd)) return controlErr; } return noErr; case kSERDClearBreak: if(is_serial) { if(!ClearCommBreak(fd)) return controlErr; } return noErr; case kSERDBaudRate: { if (is_serial) { uint16 rate = (uint16)ReadMacInt16(pb + csParam); int baud_rate; if (rate <= 50) { rate = 50; baud_rate = CBR_110; } else if (rate <= 75) { rate = 75; baud_rate = CBR_110; } else if (rate <= 110) { rate = 110; baud_rate = CBR_110; } else if (rate <= 134) { rate = 134; baud_rate = CBR_110; } else if (rate <= 150) { rate = 150; baud_rate = CBR_110; } else if (rate <= 200) { rate = 200; baud_rate = CBR_300; } else if (rate <= 300) { rate = 300; baud_rate = CBR_300; } else if (rate <= 600) { rate = 600; baud_rate = CBR_600; } else if (rate <= 1200) { rate = 1200; baud_rate = CBR_1200; } else if (rate <= 1800) { rate = 1800; baud_rate = CBR_2400; } else if (rate <= 2400) { rate = 2400; baud_rate = CBR_2400; } else if (rate <= 4800) { rate = 4800; baud_rate = CBR_4800; } else if (rate <= 9600) { rate = 9600; baud_rate = CBR_9600; } else if (rate <= 19200) { rate = 19200; baud_rate = CBR_19200; } else if (rate <= 38400) { rate = 38400; baud_rate = CBR_38400; } else if (rate <= 57600) { rate = 57600; baud_rate = CBR_57600; } else { rate = 57600; baud_rate = CBR_57600; } WriteMacInt16(pb + csParam, rate); mode.BaudRate = baud_rate; if(!SetCommState( fd, &mode )) return controlErr; // TODO: save parity/stop values and use here (not critical) if(!set_timeouts(rate,0,1)) return controlErr; } return noErr; } case kSERDHandshake: case kSERDHandshakeRS232: set_handshake(pb + csParam, true); return noErr; case kSERDMiscOptions: if (ReadMacInt8(pb + csParam) & kOptionPreserveDTR) mode.fDtrControl = DTR_CONTROL_ENABLE; // correct? else mode.fDtrControl = DTR_CONTROL_DISABLE; // correct? if(is_serial) { if(!SetCommState( fd, &mode )) return controlErr; } return noErr; case kSERDAssertDTR: { if (is_serial) { if(!EscapeCommFunction(fd,SETDTR)) return controlErr; } return noErr; } case kSERDNegateDTR: { if (is_serial) { if(!EscapeCommFunction(fd,CLRDTR)) return controlErr; } return noErr; } case kSERDSetPEChar: case kSERDSetPEAltChar: { uint16 errChar = (uint16)ReadMacInt16(pb + csParam); mode.fErrorChar = TRUE; mode.ErrorChar = (char)errChar; return noErr; } case kSERDResetChannel: if (is_serial) { // | PURGE_TXABORT | PURGE_RXABORT not needed, no overlapped i/o PurgeComm(fd,PURGE_TXCLEAR|PURGE_RXCLEAR); FlushFileBuffers(fd); } return noErr; case kSERDAssertRTS: { if (is_serial) { if(!EscapeCommFunction(fd,SETRTS)) return controlErr; } return noErr; } case kSERDNegateRTS: { if (is_serial) { if(!EscapeCommFunction(fd,CLRRTS)) return controlErr; } return noErr; } case kSERD115KBaud: if (is_serial) { mode.BaudRate = CBR_115200; if(!SetCommState( fd, &mode )) return controlErr; } return noErr; case kSERD230KBaud: case kSERDSetHighSpeed: if (is_serial) { mode.BaudRate = CBR_256000; if(!SetCommState( fd, &mode )) return controlErr; } return noErr; default: D(bug("WARNING: SerialControl(): unimplemented control code %d\r\n", code)); return controlErr; } } /* * Status calls */ int16 XSERDPort::status(uint32 pb, uint32 dce, uint16 code) { // D(bug("XSERDPort::status code=%d\r\n",(int)code)); DWORD error_state; COMSTAT comstat; switch (code) { case kSERDInputCount: { uint32 num = 0; if (is_serial) { if(!ClearCommError(fd,&error_state,&comstat)) return statusErr; num = comstat.cbInQue; } WriteMacInt32(pb + csParam, num); return noErr; } case kSERDStatus: { uint32 p = pb + csParam; WriteMacInt8(p + staCumErrs, cum_errors); cum_errors = 0; DWORD status; if(is_serial) { if(!GetCommModemStatus(fd,&status)) return statusErr; } else { status = MS_CTS_ON | MS_DSR_ON | MS_RLSD_ON; D(bug("kSERDStatus: faking status for LPT port or FILE\r\n")); } WriteMacInt8(p + staXOffSent, 0); WriteMacInt8(p + staXOffHold, 0); WriteMacInt8(p + staRdPend, read_pending); WriteMacInt8(p + staWrPend, write_pending); WriteMacInt8(p + staCtsHold, status & MS_CTS_ON ? 0 : 1); WriteMacInt8(p + staDsrHold, status & MS_DSR_ON ? 0 : 1); WriteMacInt8(p + staModemStatus, (status & MS_DSR_ON ? dsrEvent : 0) | (status & MS_RING_ON ? riEvent : 0) | (status & MS_RLSD_ON ? dcdEvent : 0) // is this carrier detect? | (status & MS_CTS_ON ? ctsEvent : 0)); return noErr; } default: D(bug("WARNING: SerialStatus(): unimplemented status code %d\r\n", code)); return statusErr; } } /* * Close serial port */ int16 XSERDPort::close() { D(bug("XSERDPort::close\r\n")); // Kill threads if (input_thread_active) { quitting = true; ReleaseSemaphore(input_signal,1,NULL); input_thread_active = false; CloseHandle(input_signal); } if (output_thread_active) { quitting = true; ReleaseSemaphore(output_signal,1,NULL); output_thread_active = false; // bugfix: was: CloseHandle(&output_signal); CloseHandle(output_signal); } // Close port if(fd != INVALID_HANDLE_VALUE) { CloseHandle(fd); fd = 0; } return noErr; } bool XSERDPort::set_timeouts( int bauds, int parity_bits, int stop_bits ) { COMMTIMEOUTS timeouts; uint32 bytes_per_sec; uint32 msecs_per_ch; bool result = false; // Should already been checked if (!is_serial) return true; bytes_per_sec = bauds / (mode.ByteSize + parity_bits + stop_bits); // 75% bytes_per_sec // bytes_per_sec = (bytes_per_sec+bytes_per_sec+bytes_per_sec) >> 2; // 50% bytes_per_sec bytes_per_sec = bytes_per_sec >> 1; msecs_per_ch = 1000 / bytes_per_sec; if(msecs_per_ch == 0) msecs_per_ch = 1; if(GetCommTimeouts(fd,&timeouts)) { D(bug("old timeout values: %ld %ld %ld %ld %ld\r\n", timeouts.ReadIntervalTimeout, timeouts.ReadTotalTimeoutMultiplier, timeouts.ReadTotalTimeoutConstant, timeouts.WriteTotalTimeoutMultiplier, timeouts.WriteTotalTimeoutConstant )); timeouts.WriteTotalTimeoutMultiplier = msecs_per_ch; timeouts.WriteTotalTimeoutConstant = 10; /* timeouts.ReadIntervalTimeout = msecs_per_ch; timeouts.ReadTotalTimeoutMultiplier = msecs_per_ch; timeouts.ReadTotalTimeoutConstant = 10; */ timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; if(!SetCommTimeouts(fd,&timeouts)) { D(bug("SetCommTimeouts() failed in configure()\r\n")); } else { D(bug("new timeout values: %ld %ld %ld %ld %ld\r\n", timeouts.ReadIntervalTimeout, timeouts.ReadTotalTimeoutMultiplier, timeouts.ReadTotalTimeoutConstant, timeouts.WriteTotalTimeoutMultiplier, timeouts.WriteTotalTimeoutConstant )); result = true; } } else { D(bug("GetCommTimeouts() failed in set_timeouts()\r\n")); } return(result); } /* * Configure serial port with MacOS config word */ bool XSERDPort::configure(uint16 config) { D(bug("XSERDPort::configure, config=%d\r\n",(int)config)); if (!is_serial) return true; // needed to calculate optimal timeouts uint32 bauds = 57600; uint32 stop_bits = 1; uint32 parity_bits = 0; // Not all of these can be set here anyway. /* mode.fOutxCtsFlow = TRUE; mode.fOutxDsrFlow = FALSE; mode.fDtrControl = DTR_CONTROL_ENABLE; // DTR_CONTROL_HANDSHAKE? mode.fDsrSensitivity = FALSE; // ??? mode.fOutX = FALSE; mode.fInX = FALSE; mode.fTXContinueOnXoff = FALSE; mode.fErrorChar = FALSE; mode.ErrorChar = 0; mode.fNull = FALSE; mode.fRtsControl = 2; // ??? mode.fAbortOnError = FALSE; mode.XonLim = 0x800; mode.XoffLim = 0x200; mode.XonChar = 0x11; mode.XoffChar = 0x13; mode.EofChar = 0; mode.EvtChar = '\0'; */ // Set baud rate switch (config & 0x03ff) { // no baud1800, CBR_14400, CBR_56000, CBR_115200, CBR_128000, CBR_256000 case baud150: mode.BaudRate = CBR_110; bauds = 110; break; case baud300: mode.BaudRate = CBR_300; bauds = 300; break; case baud600: mode.BaudRate = CBR_600; bauds = 600; break; case baud1200: mode.BaudRate = CBR_1200; bauds = 1200; break; case baud1800: return false; case baud2400: mode.BaudRate = CBR_2400; bauds = 2400; break; case baud4800: mode.BaudRate = CBR_4800; bauds = 4800; break; case baud9600: mode.BaudRate = CBR_9600; bauds = 9600; break; case baud19200: mode.BaudRate = CBR_19200; bauds = 19200; break; case baud38400: mode.BaudRate = CBR_38400; bauds = 38400; break; case baud57600: mode.BaudRate = CBR_57600; bauds = 57600; break; default: return false; } // Set number of stop bits switch (config & 0xc000) { case stop10: mode.StopBits = ONESTOPBIT; stop_bits = 1; break; case stop15: mode.StopBits = ONE5STOPBITS; stop_bits = 2; break; case stop20: mode.StopBits = TWOSTOPBITS; stop_bits = 2; break; default: return false; } // Set parity mode switch (config & 0x3000) { case noParity: mode.Parity = NOPARITY; mode.fParity = FALSE; parity_bits = 0; break; case oddParity: mode.Parity = ODDPARITY; mode.fParity = TRUE; parity_bits = 1; break; case evenParity: mode.Parity = EVENPARITY; mode.fParity = TRUE; parity_bits = 1; break; // No MARKPARITY, SPACEPARITY default: return false; } // Set number of data bits switch (config & 0x0c00) { // No data4 case data5: mode.ByteSize = 5; break; case data6: mode.ByteSize = 6; break; case data7: mode.ByteSize = 7; break; case data8: mode.ByteSize = 8; break; default: return false; } D(bug("Interpreted configuration: %d,%d,%d,%d\r\n", bauds, mode.ByteSize, stop_bits, parity_bits )); if(!SetCommState( fd, &mode )) { D(bug("SetCommState failed in configure()\r\n")); return false; } if(!set_timeouts(bauds,parity_bits,stop_bits)) return false; return true; } /* * Set serial handshaking */ void XSERDPort::set_handshake(uint32 s, bool with_dtr) { D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\r\n", ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3), ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7))); if (!is_serial) return; if (with_dtr) { mode.fDtrControl = DTR_CONTROL_ENABLE; if (ReadMacInt8(s + shkFCTS) || ReadMacInt8(s + shkFDTR)) mode.fOutxCtsFlow = TRUE; else mode.fOutxCtsFlow = FALSE; } else { mode.fDtrControl = DTR_CONTROL_DISABLE; if (ReadMacInt8(s + shkFCTS)) mode.fOutxCtsFlow = TRUE; else mode.fOutxCtsFlow = FALSE; } // MIDI: set_handshake 00 00 f4 f5 21 00 00 00 // shkFXOn = 0 // shkFCTS = 0 // shkXOn = f4 // shkXOff = f5 // shkErrs = 21 // shkEvts = 0 // shkFInX = 0 // shkFDTR = 0 if (ReadMacInt8(s + shkXOn) && ReadMacInt8(s + shkXOn)) { mode.fOutX = 1; mode.fInX = 1; mode.XonChar = ReadMacInt8(s + shkXOn); mode.XoffChar = ReadMacInt8(s + shkXOff); } else { mode.fOutX = 0; mode.fInX = 0; } if (ReadMacInt8(s + shkErrs)) { mode.ErrorChar = ReadMacInt8(s + shkErrs); mode.fErrorChar = 1; } else { mode.fErrorChar = 0; } (void)SetCommState( fd, &mode ); // D(bug(" %sware flow control\r\n", mode.c_cflag & CRTSCTS ? "hard" : "soft")); // tcsetattr(fd, TCSANOW, &mode); } /* if mode.fAbortOnError is TRUE, ClearCommError() *MUST* be called after any read or write errors. Otherwise no i/o will occur again These error codes should be translated but the Mac Device Manager error code mnemonics are too cryptic to me. */ int XSERDPort::acknowledge_error(HANDLE h, bool is_read) { DWORD error_state; COMSTAT comstat; int err; // default error code if cannot map correctly err = is_read ? readErr : writErr; if(ClearCommError(h,&error_state,&comstat)) { D(bug("A %s error 0x%X occured.\r\n", is_read ? "read" : "write", error_state)); D(bug("There was %d bytes in input buffer and %d bytes in output buffer.\r\n",(int)comstat.cbInQue,(int)comstat.cbOutQue)); if(error_state & CE_MODE) { D(bug("The requested mode is not supported.\r\n")); } else { if(error_state & CE_BREAK) { D(bug("The hardware detected a break condition.\r\n")); } if(error_state & CE_FRAME) { D(bug("The hardware detected a framing error.\r\n")); } if(error_state & CE_IOE) { D(bug("An I/O error occurred during communications with the device.\r\n")); } if(error_state & CE_RXOVER) { D(bug("An input buffer overflow has occurred.\r\n")); } if(error_state & CE_RXPARITY) { D(bug("The hardware detected a parity error.\r\n")); err = badDCksum; } if(error_state & CE_TXFULL) { D(bug("The application tried to transmit a character, but the output buffer was full.\r\n")); } // Win95 specific errors if(error_state & CE_OVERRUN) { D(bug("A character-buffer overrun has occurred. The next character is lost.\r\n")); if(!is_read) err = wrUnderrun; } // Win95 parallel devices really. if(error_state & CE_DNS) { D(bug("A parallel device is not selected (Windows 95).\r\n")); } if(error_state & CE_OOP) { D(bug("A parallel device signaled that it is out of paper (Windows 95 only).\r\n")); err = unitEmptyErr; } if(error_state & CE_PTO) { D(bug("A time-out occurred on a parallel device (Windows 95).\r\n")); } } } else { D(bug("Failed to resume after %s operation.\r\n",is_read ? "read" : "write")); } return(err); } #if DEBUG static void dump_dirst_bytes( BYTE *buf, int32 actual ) { if(debug_serial != DB_SERIAL_LOUD) return; BYTE b[256]; int32 i, bytes = min(actual,sizeof(b)-3); for (i=0; idevice_name)); for (;;) { // Wait for commands WaitForSingleObject(s->input_signal,INFINITE); if (s->quitting) break; // Execute command void *buf = Mac2HostAddr(ReadMacInt32(s->input_pb + ioBuffer)); uint32 length = ReadMacInt32(s->input_pb + ioReqCount); D(bug("input_func waiting for %ld bytes of data...\r\n", length)); if(length & 0xFFFF0000) { length &= 0x0000FFFF; D(bug("byte count fixed to be %ld...\r\n", length)); } int32 actual; if(s->is_file) { actual = -1; error_code = readErr; } else if(!ReadFile(s->fd, buf, length, (LPDWORD)&actual, 0)) { actual = -1; if(s->is_serial) error_code = acknowledge_error(s->fd,true); else error_code = readErr; } D(bug(" %ld bytes received\r\n", actual)); if(actual > 0) { dump_dirst_bytes( (BYTE*)buf, actual ); } // KillIO called? Then simply return if (s->io_killed) { WriteMacInt16(s->input_pb + ioResult, abortErr); WriteMacInt32(s->input_pb + ioActCount, 0); s->read_pending = s->read_done = false; } else { // Set error code if (actual >= 0) { WriteMacInt32(s->input_pb + ioActCount, actual); WriteMacInt32(s->input_dt + serdtResult, noErr); } else { WriteMacInt32(s->input_pb + ioActCount, 0); WriteMacInt32(s->input_dt + serdtResult, error_code); } // Trigger serial interrupt D(bug(" triggering serial interrupt\r\n")); WriteMacInt32(s->input_dt + serdtDCE, s->input_dce); s->read_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } D(bug("XSERDPort::input_func terminating gracefully\r\n")); _endthreadex( 0 ); return(0); } /* * Data output thread */ unsigned int XSERDPort::output_func(void *arg) { XSERDPort *s = (XSERDPort *)arg; int error_code; #if 0 SetThreadPriority( GetCurrentThread(), threads[THREAD_SERIAL_OUT].priority_running ); SetThreadAffinityMask( GetCurrentThread(), threads[THREAD_SERIAL_OUT].affinity_mask ); set_desktop(); #endif D(bug("XSERDPort::output_func started for device %s\r\n",s->device_name)); for (;;) { // Wait for commands WaitForSingleObject(s->output_signal,INFINITE); if (s->quitting) break; // Execute command void *buf = Mac2HostAddr(ReadMacInt32(s->output_pb + ioBuffer)); uint32 length = ReadMacInt32(s->output_pb + ioReqCount); D(bug("output_func transmitting %ld bytes of data...\r\n", length)); if(length & 0xFFFF0000) { length &= 0x0000FFFF; D(bug("byte count fixed to be %ld...\r\n", length)); } int32 actual; if(!WriteFile(s->fd, buf, length, (LPDWORD)&actual, 0)) { actual = -1; if(s->is_serial) error_code = acknowledge_error(s->fd,false); else error_code = writErr; } D(bug(" %ld bytes transmitted\r\n", actual)); if(actual > 0) { dump_dirst_bytes( (BYTE*)buf, actual ); } // KillIO called? Then simply return if (s->io_killed) { WriteMacInt16(s->output_pb + ioResult, abortErr); WriteMacInt32(s->output_pb + ioActCount, 0); s->write_pending = s->write_done = false; } else { // Set error code if (actual >= 0) { WriteMacInt32(s->output_pb + ioActCount, actual); WriteMacInt32(s->output_dt + serdtResult, noErr); } else { WriteMacInt32(s->output_pb + ioActCount, 0); WriteMacInt32(s->output_dt + serdtResult, error_code); } // Trigger serial interrupt D(bug(" triggering serial interrupt\r\n")); WriteMacInt32(s->output_dt + serdtDCE, s->output_dce); s->write_done = true; SetInterruptFlag(INTFLAG_SERIAL); TriggerInterrupt(); } } D(bug("XSERDPort::output_func terminating gracefully\r\n")); _endthreadex( 0 ); return(0); } BasiliskII/src/Windows/extfs_windows.cpp0000755000175000017500000002651510736405221020605 0ustar centriscentris/* * extfs_windows.cpp - MacOS file system for access native file system access, Windows specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include "sysdeps.h" #include "extfs.h" #include "extfs_defs.h" #include "posix_emu.h" #define DEBUG 0 #include "debug.h" // Constants #define HOST_DIRSEP_CHAR '\\' #define HOST_DIRSEP_STR "\\" // Default Finder flags const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; /* * Initialization */ void extfs_init(void) { init_posix_emu(); } /* * Deinitialization */ void extfs_exit(void) { final_posix_emu(); } /* * Add component to path name */ void add_path_component(char *path, const char *component) { int l = strlen(path); if (l < MAX_PATH_LENGTH-1 && path[l-1] != HOST_DIRSEP_CHAR) { path[l] = HOST_DIRSEP_CHAR; path[l+1] = 0; } strncat(path, component, MAX_PATH_LENGTH-1); } /* * Finder info and resource forks are kept in helper files * * Finder info: * /path/.finf/file * Resource fork: * /path/.rsrc/file * * The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo * (16+16 bytes) */ static void make_helper_path(const char *src, char *dest, const char *add, bool only_dir = false) { dest[0] = 0; // Get pointer to last component of path const char *last_part = strrchr(src, HOST_DIRSEP_CHAR); if (last_part) last_part++; else last_part = src; // Copy everything before strncpy(dest, src, last_part-src); dest[last_part-src] = 0; // Add additional component strncat(dest, add, MAX_PATH_LENGTH-1); // Add last component if (!only_dir) strncat(dest, last_part, MAX_PATH_LENGTH-1); } static int create_helper_dir(const char *path, const char *add) { char helper_dir[MAX_PATH_LENGTH]; make_helper_path(path, helper_dir, add, true); if (helper_dir[strlen(helper_dir) - 1] == HOST_DIRSEP_CHAR) // Remove trailing "\" helper_dir[strlen(helper_dir) - 1] = 0; return mkdir(helper_dir, 0777); } static int open_helper(const char *path, const char *add, int flag) { char helper_path[MAX_PATH_LENGTH]; make_helper_path(path, helper_path, add); if ((flag & O_ACCMODE) == O_RDWR || (flag & O_ACCMODE) == O_WRONLY) flag |= O_CREAT; int fd = open(helper_path, flag, 0666); if (fd < 0) { if (/*errno == ENOENT &&*/ (flag & O_CREAT)) { // One path component was missing, probably the helper // directory. Try to create it and re-open the file. int ret = create_helper_dir(path, add); if (ret < 0) return ret; fd = open(helper_path, flag, 0666); } } return fd; } static int open_finf(const char *path, int flag) { return open_helper(path, ".finf" HOST_DIRSEP_STR, flag); } static int open_rsrc(const char *path, int flag) { return open_helper(path, ".rsrc" HOST_DIRSEP_STR, flag); } /* * Get/set finder info for file/directory specified by full path */ struct ext2type { const char *ext; uint32 type; uint32 creator; }; static const ext2type e2t_translation[] = { {".Z", FOURCC('Z','I','V','M'), FOURCC('L','Z','I','V')}, {".gz", FOURCC('G','z','i','p'), FOURCC('G','z','i','p')}, {".hqx", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".bin", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".pdf", FOURCC('P','D','F',' '), FOURCC('C','A','R','O')}, {".ps", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".sit", FOURCC('S','I','T','!'), FOURCC('S','I','T','x')}, {".tar", FOURCC('T','A','R','F'), FOURCC('T','A','R',' ')}, {".uu", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".uue", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')}, {".zip", FOURCC('Z','I','P',' '), FOURCC('Z','I','P',' ')}, {".8svx", FOURCC('8','S','V','X'), FOURCC('S','N','D','M')}, {".aifc", FOURCC('A','I','F','C'), FOURCC('T','V','O','D')}, {".aiff", FOURCC('A','I','F','F'), FOURCC('T','V','O','D')}, {".au", FOURCC('U','L','A','W'), FOURCC('T','V','O','D')}, {".mid", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".midi", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')}, {".mp2", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".mp3", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')}, {".wav", FOURCC('W','A','V','E'), FOURCC('T','V','O','D')}, {".bmp", FOURCC('B','M','P','f'), FOURCC('o','g','l','e')}, {".gif", FOURCC('G','I','F','f'), FOURCC('o','g','l','e')}, {".lbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".ilbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')}, {".jpg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".jpeg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')}, {".pict", FOURCC('P','I','C','T'), FOURCC('o','g','l','e')}, {".png", FOURCC('P','N','G','f'), FOURCC('o','g','l','e')}, {".sgi", FOURCC('.','S','G','I'), FOURCC('o','g','l','e')}, {".tga", FOURCC('T','P','I','C'), FOURCC('o','g','l','e')}, {".tif", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".tiff", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')}, {".htm", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".html", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')}, {".txt", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')}, {".rtf", FOURCC('T','E','X','T'), FOURCC('M','S','W','D')}, {".c", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".C", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cc", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".cxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".h", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hh", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".hxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".s", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".S", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".i", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')}, {".mpg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mpeg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')}, {".mov", FOURCC('M','o','o','V'), FOURCC('T','V','O','D')}, {".fli", FOURCC('F','L','I',' '), FOURCC('T','V','O','D')}, {".avi", FOURCC('V','f','W',' '), FOURCC('T','V','O','D')}, {".qxd", FOURCC('X','D','O','C'), FOURCC('X','P','R','3')}, {".hfv", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".dsk", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')}, {".img", FOURCC('r','o','h','d'), FOURCC('d','d','s','k')}, {NULL, 0, 0} // End marker }; void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Read Finder info file int fd = open_finf(path, O_RDONLY); if (fd >= 0) { ssize_t actual = read(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) actual += read(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); if (actual >= SIZEOF_FInfo) return; } // No Finder info file, translate file name extension to MacOS type/creator if (!is_dir) { int path_len = strlen(path); for (int i=0; e2t_translation[i].ext; i++) { int ext_len = strlen(e2t_translation[i].ext); if (path_len < ext_len) continue; if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) { WriteMacInt32(finfo + fdType, e2t_translation[i].type); WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator); break; } } } } void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Open Finder info file int fd = open_finf(path, O_RDWR); if (fd < 0) return; // Write file write(fd, Mac2HostAddr(finfo), SIZEOF_FInfo); if (fxinfo) write(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo); close(fd); } /* * Resource fork emulation functions */ uint32 get_rfork_size(const char *path) { // Open resource file int fd = open_rsrc(path, O_RDONLY); if (fd < 0) return 0; // Get size off_t size = lseek(fd, 0, SEEK_END); // Close file and return size close(fd); return size < 0 ? 0 : size; } int open_rfork(const char *path, int flag) { return open_rsrc(path, flag); } void close_rfork(const char *path, int fd) { if (fd >= 0) close(fd); } /* * Read "length" bytes from file to "buffer", * returns number of bytes read (or -1 on error) */ ssize_t extfs_read(int fd, void *buffer, size_t length) { return read(fd, buffer, length); } /* * Write "length" bytes from "buffer" to file, * returns number of bytes written (or -1 on error) */ ssize_t extfs_write(int fd, void *buffer, size_t length) { return write(fd, buffer, length); } /* * Remove file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_remove(const char *path) { // Remove helpers first, don't complain if this fails char helper_path[MAX_PATH_LENGTH]; make_helper_path(path, helper_path, ".finf" HOST_DIRSEP_STR, false); remove(helper_path); make_helper_path(path, helper_path, ".rsrc" HOST_DIRSEP_STR, false); remove(helper_path); // Now remove file or directory (and helper directories in the directory) if (remove(path) < 0) { if (errno == EISDIR || errno == ENOTEMPTY) { helper_path[0] = 0; strncpy(helper_path, path, MAX_PATH_LENGTH-1); add_path_component(helper_path, ".finf"); rmdir(helper_path); helper_path[0] = 0; strncpy(helper_path, path, MAX_PATH_LENGTH-1); add_path_component(helper_path, ".rsrc"); rmdir(helper_path); return rmdir(path) == 0; } else return false; } return true; } /* * Rename/move file/directory (and associated helper files), * returns false on error (and sets errno) */ bool extfs_rename(const char *old_path, const char *new_path) { // Rename helpers first, don't complain if this fails char old_helper_path[MAX_PATH_LENGTH], new_helper_path[MAX_PATH_LENGTH]; make_helper_path(old_path, old_helper_path, ".finf" HOST_DIRSEP_STR, false); make_helper_path(new_path, new_helper_path, ".finf" HOST_DIRSEP_STR, false); create_helper_dir(new_path, ".finf" HOST_DIRSEP_STR); rename(old_helper_path, new_helper_path); make_helper_path(old_path, old_helper_path, ".rsrc" HOST_DIRSEP_STR, false); make_helper_path(new_path, new_helper_path, ".rsrc" HOST_DIRSEP_STR, false); create_helper_dir(new_path, ".rsrc" HOST_DIRSEP_STR); rename(old_helper_path, new_helper_path); // Now rename file return rename(old_path, new_path) == 0; } // Convert from the host OS filename encoding to MacRoman const char *host_encoding_to_macroman(const char *filename) { return filename; } // Convert from MacRoman to host OS filename encoding const char *macroman_to_host_encoding(const char *filename) { return filename; } BasiliskII/src/Windows/util_windows.h0000755000175000017500000000354010736405222020070 0ustar centriscentris/* * util_windows.h - Miscellaneous utilities for Win32 * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _UTIL_WINDOWS_H #define _UTIL_WINDOWS_H BOOL exists( const char *path ); int32 get_file_size( const char *path ); BOOL create_file( const char *path, DWORD size ); bool check_drivers(void); // Thread wrappers extern HANDLE create_thread(LPTHREAD_START_ROUTINE start_routine, void *arg = NULL); extern void wait_thread(HANDLE thread); extern void kill_thread(HANDLE thread); // Mutex wrappers class mutex_t { CRITICAL_SECTION cs; public: mutex_t() { InitializeCriticalSection(&cs); } ~mutex_t() { DeleteCriticalSection(&cs); } void lock() { EnterCriticalSection(&cs); } void unlock() { LeaveCriticalSection(&cs); } }; // Network control panel helpers extern const char *ether_name_to_guid(const char *name); extern const char *ether_guid_to_name(const char *guid); // Get TAP-Win32 devices (caller free()s returned buffer) extern const char *ether_tap_devices(void); #endif // _UTIL_WINDOWS_H BasiliskII/src/Windows/BasiliskII.ico0000755000175000017500000000566610145767212017666 0ustar centriscentris è& ¨( @€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿr8ˆˆˆ083p`13303313x&3ˆ33301x20‚ƒ33r888ƒ"ƒ33x#bˆ333r3ƒ 333331s&(€ˆ3ƒˆ31xh3ƒˆ33r3bˆ330x"03ˆˆˆ31r3033ˆˆ33s# ƒƒ3ˆˆƒ1r283ˆˆ3xhƒs8x(10r8ƒ31xhˆƒ1s30x(1ˆr0€80s#08r8ƒ0ˆxhˆx8ˆ0s#23ˆ3ƒ8xxpr8ƒƒ€ˆsx7ƒˆ8€s#23(ˆ€€xˆƒ‡€r2332xq77€ƒxˆpx(#8ˆˆ3ss‡7ˆˆ7pwwwwwwwwwwwwwwww( @€€€€€€€€€€ÀÀÀÀÜÀðʦ """)))UUUMMMBBB999€|ÿPPÿ“ÖÿìÌÆÖïÖçç©­3f™Ì3333f3™3Ì3ÿff3fff™fÌfÿ™™3™f™™™Ì™ÿÌÌ3ÌfÌ™ÌÌÌÿÿfÿ™ÿÌ3333f3™3Ì3ÿ3333333f33™33Ì33ÿ3f3f33ff3f™3fÌ3fÿ3™3™33™f3™™3™Ì3™ÿ3Ì3Ì33Ìf3Ì™3ÌÌ3Ìÿ3ÿ33ÿf3ÿ™3ÿÌ3ÿÿff3fff™fÌfÿf3f33f3ff3™f3Ìf3ÿffff3fffff™ffÌf™f™3f™ff™™f™Ìf™ÿfÌfÌ3fÌ™fÌÌfÌÿfÿfÿ3fÿ™fÿÌÌÿÿÌ™™™3™™™™Ì™™33™f™3Ì™ÿ™f™f3™3f™f™™fÌ™3ÿ™™3™™f™™™™™Ì™™ÿ™Ì™Ì3fÌf™Ì™™ÌÌ™Ìÿ™ÿ™ÿ3™Ìf™ÿ™™ÿÌ™ÿÿÌ™3ÌfÌ™ÌÌ™3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌfÌf3™ffÌf™ÌfÌ™fÿ̙̙3Ì™fÌ™™Ì™ÌÌ™ÿÌÌÌÌ3ÌÌfÌÌ™ÌÌÌÌÌÿÌÿÌÿ3™ÿfÌÿ™ÌÿÌÌÿÿÌ3ÿfÿ™Ì3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿfÿf3Ìffÿf™ÿfÌÌfÿÿ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿÌÿÌ3ÿÌfÿÌ™ÿÌÌÿÌÿÿÿ3Ìÿfÿÿ™ÿÿÌffÿfÿffÿÿÿffÿfÿÿÿf!¥___www†††–––ËË˲²²×××ÝÝÝãããêêêñññøøøðûÿ¤  €€€ÿÿÿÿÿÿÿÿÿÿÿÿ íI ")êêêêêê#)#)) " H)$KC))*#*$ ) ëHk)Që"))#*  íP("D(P$  # OPJ) mP.P*   ì.qOrìJ### O/rP. )** P.OOrrëQQë$ ìqqPC êQ$"êìì OPq!ëE#êìì" ì./! êQKëmëìì$  O// êëììì " P..!Jëëìììë$  O/.! êEë$Eëììë  ìqrmE"mìQ$  QPë )" D"  ì.r ##  " # O/ë **   ìqë Knn))  QP EE"    ì.P" )"  # m O/    "C)P.) "  "" mJ O/P")  **  )ëì ìqëmë C#  mm #JììJQOPO))Jê))) mQ)íì÷ìO/PëP$íë*QëìQsìJssQììQëìP..(ëEmëìEìCíëCìíìëìQë÷ìO/..ìì÷EKsQìmmìQììì÷ì.P.QërììQsQQëìD#íìëììQCï÷ï÷ïïïïïïíïïïï’BasiliskII/src/Windows/timer_windows.cpp0000755000175000017500000001253710736405222020574 0ustar centriscentris/* * timer_windows.cpp - Time Manager emulation, Windows specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #define WIN32_LEAN_AND_MEAN #include #include "main.h" #include "macos_util.h" #include "timer.h" #define DEBUG 0 #include "debug.h" // Helper time functions #define MSECS2TICKS(MSECS) (((uint64)(MSECS) * frequency) / 1000) #define USECS2TICKS(USECS) (((uint64)(USECS) * frequency) / 1000000) #define TICKS2USECS(TICKS) (((uint64)(TICKS) * 1000000) / frequency) // From main_windows.cpp extern HANDLE emul_thread; // Global variables static uint32 frequency; // CPU frequency in Hz (< 4 GHz) static tm_time_t mac_boot_ticks; static tm_time_t mac_1904_ticks; static tm_time_t mac_now_diff; /* * Initialize native Windows timers */ void timer_init(void) { D(bug("SysTimerInit\n")); LARGE_INTEGER tt; if (!QueryPerformanceFrequency(&tt)) { ErrorAlert("No high resolution timers available\n"); QuitEmulator(); } frequency = tt.LowPart; D(bug(" frequency %d\n", frequency)); // mac_boot_ticks is 1.18 us since Basilisk II was started QueryPerformanceCounter(&tt); mac_boot_ticks = tt.QuadPart; // mac_1904_ticks is 1.18 us since Mac time started 1904 mac_1904_ticks = time(NULL) * frequency; mac_now_diff = mac_1904_ticks - mac_boot_ticks; } /* * Return microseconds since boot (64 bit) */ void Microseconds(uint32 &hi, uint32 &lo) { D(bug("Microseconds\n")); LARGE_INTEGER tt; QueryPerformanceCounter(&tt); tt.QuadPart = TICKS2USECS(tt.QuadPart - mac_boot_ticks); hi = tt.HighPart; lo = tt.LowPart; } /* * Return local date/time in Mac format (seconds since 1.1.1904) */ uint32 TimerDateTime(void) { return TimeToMacTime(time(NULL)); } /* * Get current time */ void timer_current_time(tm_time_t &t) { LARGE_INTEGER tt; QueryPerformanceCounter(&tt); t = tt.QuadPart + mac_now_diff; } /* * Add times */ void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b) { res = a + b; } /* * Subtract times */ void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b) { res = a - b; } /* * Compare times (<0: a < b, =0: a = b, >0: a > b) */ int timer_cmp_time(tm_time_t a, tm_time_t b) { tm_time_t r = a - b; return r < 0 ? -1 : (r > 0 ? 1 : 0); } /* * Convert Mac time value (>0: microseconds, <0: microseconds) to tm_time_t */ void timer_mac2host_time(tm_time_t &res, int32 mactime) { if (mactime > 0) { // Time in milliseconds res = MSECS2TICKS(mactime); } else { // Time in negative microseconds res = USECS2TICKS(-mactime); } } /* * Convert positive tm_time_t to Mac time value (>0: microseconds, <0: microseconds) * A negative input value for hosttime results in a zero return value * As long as the microseconds value fits in 32 bit, it must not be converted to milliseconds! */ int32 timer_host2mac_time(tm_time_t hosttime) { if (hosttime < 0) return 0; else { uint64 t = TICKS2USECS(hosttime); if (t > 0x7fffffff) return t / 1000; // Time in milliseconds else return -t; // Time in negative microseconds } } /* * Get current value of microsecond timer */ uint64 GetTicks_usec(void) { LARGE_INTEGER tt; QueryPerformanceCounter(&tt); return TICKS2USECS(tt.QuadPart - mac_boot_ticks); } /* * Delay by specified number of microseconds (<1 second) */ void Delay_usec(uint32 usec) { // FIXME: fortunately, Delay_usec() is generally used with // millisecond resolution anyway Sleep(usec / 1000); } /* * Suspend emulator thread, virtual CPU in idle mode */ struct idle_sentinel { idle_sentinel(); ~idle_sentinel(); }; static idle_sentinel idle_sentinel; static int idle_sem_ok = -1; static HANDLE idle_sem = NULL; static HANDLE idle_lock = NULL; #define LOCK_IDLE WaitForSingleObject(idle_lock, INFINITE) #define UNLOCK_IDLE ReleaseMutex(idle_lock) idle_sentinel::idle_sentinel() { idle_sem_ok = 1; if ((idle_sem = CreateSemaphore(0, 0, 1, NULL)) == NULL) idle_sem_ok = 0; if ((idle_lock = CreateMutex(NULL, FALSE, NULL)) == NULL) idle_sem_ok = 0; } idle_sentinel::~idle_sentinel() { if (idle_lock) { ReleaseMutex(idle_lock); CloseHandle(idle_lock); } if (idle_sem) { ReleaseSemaphore(idle_sem, 1, NULL); CloseHandle(idle_sem); } } void idle_wait(void) { LOCK_IDLE; if (idle_sem_ok > 0) { idle_sem_ok++; UNLOCK_IDLE; WaitForSingleObject(idle_sem, INFINITE); return; } UNLOCK_IDLE; // Fallback: sleep 10 ms (this should not happen though) Delay_usec(10000); } /* * Resume execution of emulator thread, events just arrived */ void idle_resume(void) { LOCK_IDLE; if (idle_sem_ok > 1) { idle_sem_ok--; UNLOCK_IDLE; ReleaseSemaphore(idle_sem, 1, NULL); return; } UNLOCK_IDLE; } BasiliskII/src/Windows/b2ether/0000755000175000017500000000000011735674761016536 5ustar centriscentrisBasiliskII/src/Windows/b2ether/inc/0000755000175000017500000000000011735675027017303 5ustar centriscentrisBasiliskII/src/Windows/b2ether/inc/b2ether_hl.h0000755000175000017500000000545110736405222021466 0ustar centriscentris/* * b2ether_hl.h - Win32 ethernet driver high-level interface * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _B2_ETHER_HL_ #define _B2_ETHER_HL_ #ifdef __cplusplus extern "C" { #endif #define ETH_802_3_ADDRESS_LENGTH 6 #define MAX_LINK_NAME_LENGTH 124 typedef struct _ADAPTER { HANDLE hFile; TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; } ADAPTER, *LPADAPTER; typedef struct _PACKET { OVERLAPPED OverLapped; PVOID Buffer; UINT Length; ULONG BytesReceived; BOOL bIoComplete; BOOL free; struct _PACKET *next; } PACKET, *LPPACKET; BOOLEAN StartPacketDriver( LPTSTR ServiceName ); LPADAPTER PacketOpenAdapter( LPCSTR AdapterName, int16 mode ); VOID PacketCloseAdapter( LPADAPTER lpAdapter ); LPPACKET PacketAllocatePacket( LPADAPTER AdapterObject, UINT Length ); VOID PacketFreePacket( LPPACKET lpPacket ); BOOLEAN PacketSendPacket( LPADAPTER AdapterObject, LPPACKET lpPacket, BOOLEAN Sync, BOOLEAN RecyclingAllowed ); BOOLEAN PacketGetAddress( LPADAPTER AdapterObject, PUCHAR AddressBuffer, PUINT Length ); BOOLEAN PacketReceivePacket( LPADAPTER AdapterObject, LPPACKET lpPacket, BOOLEAN Sync ); BOOLEAN PacketSetFilter( LPADAPTER AdapterObject, ULONG Filter ); BOOLEAN PacketGetMAC( LPADAPTER AdapterObject, LPBYTE address, BOOL permanent ); BOOLEAN PacketAddMulticast( LPADAPTER AdapterObject, LPBYTE address ); BOOLEAN PacketDelMulticast( LPADAPTER AdapterObject, LPBYTE address ); ULONG PacketGetAdapterNames( LPADAPTER lpAdapter, PTSTR pStr, PULONG BufferSize ); ULONG PacketSelectAdapterByName( LPADAPTER AdapterObject, LPCSTR name ); // callbacks void recycle_write_packet( LPPACKET Packet ); VOID CALLBACK packet_read_completion( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ); #ifdef __cplusplus } #endif #endif // _B2_ETHER_HL_ BasiliskII/src/Windows/b2ether/inc/ntddpack.h0000755000175000017500000000234710154636221021240 0ustar centriscentris// #include #ifndef __NTDDPACKET #define __NTDDPACKET 1 // #include #define MAX_LINK_NAME_LENGTH 124 #pragma pack(1) typedef struct _PACKET_OID_DATA { ULONG Oid; ULONG Length; UCHAR Data[1]; } ATTRIBUTE_PACKED PACKET_OID_DATA, *PPACKET_OID_DATA; #pragma pack() #define FILE_DEVICE_PROTOCOL 0x8000 #define IOCTL_PROTOCOL_SET_OID CTL_CODE(FILE_DEVICE_PROTOCOL, 0 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_PROTOCOL_QUERY_OID CTL_CODE(FILE_DEVICE_PROTOCOL, 1 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_PROTOCOL_RESET CTL_CODE(FILE_DEVICE_PROTOCOL, 2 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_PROTOCOL_READ CTL_CODE(FILE_DEVICE_PROTOCOL, 3 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_PROTOCOL_WRITE CTL_CODE(FILE_DEVICE_PROTOCOL, 4 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_PROTOCOL_MACNAME CTL_CODE(FILE_DEVICE_PROTOCOL, 5 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_PROTOCOL_SELECT_BY_NAME CTL_CODE(FILE_DEVICE_PROTOCOL, 6 , METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_ENUM_ADAPTERS CTL_CODE(FILE_DEVICE_PROTOCOL, 7 , METHOD_BUFFERED, FILE_ANY_ACCESS) #endif BasiliskII/src/Windows/b2ether/multiopt.h0000755000175000017500000000171710736405222020555 0ustar centriscentris/* * multiopt.h * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ enum { ETHER_MULTICAST_MAC, ETHER_MULTICAST_ALL, ETHER_MULTICAST_PROMISCUOUS }; BasiliskII/src/Windows/b2ether/packet32.cpp0000755000175000017500000005056410736405222020653 0ustar centriscentris/* * packet32.cpp * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include #include #include #include "cpu_emulation.h" typedef unsigned long ULONG_PTR, *PULONG_PTR; // VC6 does not have this, Platform SDK has. // In case of errors, try to comment out, the needed // definitions are below (#ifndef _NTDDNDIS_) // Most people don't have the Platform SDK, so I take this one out. // #include #include "inc/ntddpack.h" #include "ether.h" #include "ether_defs.h" #include "b2ether/multiopt.h" #include "b2ether/inc/b2ether_hl.h" #ifndef _NTDDNDIS_ #define NDIS_PACKET_TYPE_DIRECTED 0x00000001 #define NDIS_PACKET_TYPE_MULTICAST 0x00000002 #define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 #define NDIS_PACKET_TYPE_BROADCAST 0x00000008 #define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 #define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 #define OID_802_3_PERMANENT_ADDRESS 0x01010101 #define OID_802_3_CURRENT_ADDRESS 0x01010102 #define OID_802_3_MULTICAST_LIST 0x01010103 #define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E #endif #define DEBUG_PACKETS 0 #define DEBUG 0 #include "debug.h" #ifdef __cplusplus extern "C" { #endif #if DEBUG #pragma optimize("",off) #endif #define MAX_MULTICAST 100 #define MAX_MULTICAST_SZ (20*ETH_802_3_ADDRESS_LENGTH) static int os = VER_PLATFORM_WIN32_WINDOWS; static ULONG packet_filter = 0; LPADAPTER PacketOpenAdapter( LPCSTR AdapterName, int16 mode ) { LPADAPTER lpAdapter; BOOLEAN Result = TRUE; OSVERSIONINFO osv; D(bug("Packet32: PacketOpenAdapter\n")); osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(GetVersionEx( &osv )) os = osv.dwPlatformId; if(os == VER_PLATFORM_WIN32_NT) { // May fail if user is not an Administrator. StartPacketDriver( "B2ether" ); } lpAdapter = (LPADAPTER)GlobalAllocPtr( GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(ADAPTER) ); if (lpAdapter==NULL) { D(bug("Packet32: PacketOpenAdapter GlobalAlloc Failed\n")); return NULL; } if(os == VER_PLATFORM_WIN32_NT) { char device_name[256]; wsprintf( lpAdapter->SymbolicLink, "\\\\.\\B2ether_%s", AdapterName ); wsprintf( device_name, "\\Device\\B2ether_%s", AdapterName ); // Work around one subtle NT4 bug. DefineDosDevice( DDD_REMOVE_DEFINITION, &lpAdapter->SymbolicLink[4], NULL ); DefineDosDevice( DDD_RAW_TARGET_PATH, &lpAdapter->SymbolicLink[4], device_name ); } else { wsprintf( lpAdapter->SymbolicLink, "\\\\.\\B2ether" ); } packet_filter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST | NDIS_PACKET_TYPE_BROADCAST; if(mode == ETHER_MULTICAST_ALL) packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; if(mode == ETHER_MULTICAST_PROMISCUOUS) packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS; if (Result) { lpAdapter->hFile = CreateFile(lpAdapter->SymbolicLink, GENERIC_WRITE | GENERIC_READ, 0, NULL, // (os == VER_PLATFORM_WIN32_NT) ? CREATE_ALWAYS : OPEN_EXISTING, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0 ); if (lpAdapter->hFile != INVALID_HANDLE_VALUE) { if(*AdapterName && strcmp(AdapterName,"") != 0) { if(os == VER_PLATFORM_WIN32_WINDOWS) { PacketSelectAdapterByName( lpAdapter, AdapterName ); } PacketSetFilter( lpAdapter, packet_filter ); } return lpAdapter; } } D(bug("Packet32: PacketOpenAdapter Could not open adapter\n")); GlobalFreePtr( lpAdapter ); return NULL; } VOID PacketCloseAdapter( LPADAPTER lpAdapter ) { D(bug("Packet32: PacketCloseAdapter\n")); if(lpAdapter) { if(lpAdapter->hFile) { CloseHandle(lpAdapter->hFile); } GlobalFreePtr(lpAdapter); } } LPPACKET PacketAllocatePacket( LPADAPTER AdapterObject, UINT Length ) { LPPACKET lpPacket; lpPacket = (LPPACKET)GlobalAllocPtr( GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(PACKET) ); if(lpPacket==NULL) { D(bug("Packet32: PacketAllocatePacket: GlobalAlloc Failed\n")); return NULL; } lpPacket->OverLapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); if(!lpPacket->OverLapped.hEvent) { D(bug("Packet32: PacketAllocatePacket: CreateEvent Failed\n")); GlobalFreePtr(lpPacket); return NULL; } lpPacket->Buffer = GlobalAllocPtr(GMEM_MOVEABLE,2048); // 1514 if(!lpPacket->Buffer) { D(bug("Packet32: PacketAllocatePacket: GlobalAllocPtr Failed\n")); if(lpPacket->OverLapped.hEvent) CloseHandle(lpPacket->OverLapped.hEvent); GlobalFreePtr(lpPacket); return NULL; } lpPacket->OverLapped.Offset = 0; lpPacket->OverLapped.OffsetHigh = 0; lpPacket->Length = Length; lpPacket->BytesReceived = 0; lpPacket->bIoComplete = FALSE; lpPacket->free = TRUE; return lpPacket; } VOID PacketFreePacket( LPPACKET lpPacket ) { if(lpPacket) { if(lpPacket->Buffer) GlobalFreePtr(lpPacket->Buffer); if(lpPacket->OverLapped.hEvent) CloseHandle(lpPacket->OverLapped.hEvent); GlobalFreePtr(lpPacket); } } BOOLEAN PacketDeviceIoControl( LPADAPTER lpAdapterObject, LPPACKET lpPacket, ULONG ulIoctl, BOOLEAN bSync ) { BOOLEAN Result; lpPacket->OverLapped.Offset = 0; lpPacket->OverLapped.OffsetHigh = 0; lpPacket->BytesReceived = 0; if ( !ResetEvent( lpPacket->OverLapped.hEvent ) ) { lpPacket->bIoComplete = FALSE; D(bug( "Packet32: PacketDeviceIoControl failed to reset event\r\n", GetLastError() )); return FALSE; } Result = DeviceIoControl( lpAdapterObject->hFile, ulIoctl, lpPacket->Buffer, lpPacket->Length, lpPacket->Buffer, lpPacket->Length, &(lpPacket->BytesReceived), &(lpPacket->OverLapped) ); if( !Result && bSync ) { if (GetLastError() == ERROR_IO_PENDING) { Result = GetOverlappedResult( lpAdapterObject->hFile, &(lpPacket->OverLapped), &(lpPacket->BytesReceived), TRUE ); } else { D(bug( "Packet32: unsupported API call returned error 0x%x\r\n", GetLastError() )); } } lpPacket->bIoComplete = Result; return Result; } VOID CALLBACK PacketSendCompletionRoutine( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { LPPACKET lpPacket = CONTAINING_RECORD(lpOverlapped,PACKET,OverLapped); #if DEBUG_PACKETS D(bug("PacketSendCompletionRoutine %d\n",dwNumberOfBytesTransfered)); #endif lpPacket->bIoComplete = TRUE; // lpPacket->free = TRUE; // PacketFreePacket(lpPacket); recycle_write_packet(lpPacket); } BOOLEAN PacketSendPacket( LPADAPTER AdapterObject, LPPACKET lpPacket, BOOLEAN Sync, BOOLEAN RecyclingAllowed ) { BOOLEAN Result; #if DEBUG_PACKETS D(bug("Packet32: PacketSendPacket bytes=%d, sync=%d\n",lpPacket->Length,Sync)); #endif if(os == VER_PLATFORM_WIN32_NT) { lpPacket->OverLapped.Offset = 0; lpPacket->OverLapped.OffsetHigh = 0; lpPacket->bIoComplete = FALSE; if(Sync) { Result = WriteFile( AdapterObject->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->BytesReceived, &lpPacket->OverLapped ); if(Result) { Result = GetOverlappedResult( AdapterObject->hFile, &lpPacket->OverLapped, &lpPacket->BytesReceived, TRUE ); } else { D(bug("Packet32: PacketSendPacket WriteFile failed, err=%d\n",(int)GetLastError())); } lpPacket->bIoComplete = TRUE; if(RecyclingAllowed) PacketFreePacket(lpPacket); #if DEBUG_PACKETS D(bug("Packet32: PacketSendPacket result=%d, bytes=%d\n",(int)Result,(int)lpPacket->BytesReceived)); #endif } else { // don't care about the result Result = WriteFileEx( AdapterObject->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->OverLapped, PacketSendCompletionRoutine ); #if DEBUG_PACKETS D(bug("Packet32: PacketSendPacket result=%d\n",(int)Result)); #endif if(!Result && RecyclingAllowed) { recycle_write_packet(lpPacket); } } } else { // Now: make writes always synchronous under Win9x Sync = TRUE; Result = PacketDeviceIoControl( AdapterObject, lpPacket, IOCTL_PROTOCOL_WRITE, Sync ); if(RecyclingAllowed) recycle_write_packet(lpPacket); } return Result; } BOOLEAN PacketReceivePacket( LPADAPTER AdapterObject, LPPACKET lpPacket, BOOLEAN Sync ) { BOOLEAN Result; if(os == VER_PLATFORM_WIN32_NT) { lpPacket->OverLapped.Offset=0; lpPacket->OverLapped.OffsetHigh=0; lpPacket->bIoComplete = FALSE; #if DEBUG_PACKETS D(bug("Packet32: PacketReceivePacket\n")); #endif if (Sync) { Result = ReadFile( AdapterObject->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->BytesReceived, &lpPacket->OverLapped ); if(Result) { Result = GetOverlappedResult( AdapterObject->hFile, &lpPacket->OverLapped, &lpPacket->BytesReceived, TRUE ); if(Result) lpPacket->bIoComplete = TRUE; else lpPacket->free = TRUE; } } else { Result = ReadFileEx( AdapterObject->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->OverLapped, packet_read_completion ); } if(!Result) lpPacket->BytesReceived = 0; } else { Result = PacketDeviceIoControl( AdapterObject, lpPacket, IOCTL_PROTOCOL_READ, Sync ); if( !Result && !Sync ) { if (GetLastError() == ERROR_IO_PENDING) { Result = TRUE; } } } #if DEBUG_PACKETS D(bug("Packet32: PacketReceivePacket got %d bytes, result=%d\n",lpPacket->BytesReceived,(int)Result)); #endif return Result; } BOOLEAN PacketRequest( LPADAPTER lpAdapterObject, LPPACKET lpPacket, BOOLEAN bSet ) { BOOLEAN Result = FALSE; Result = PacketDeviceIoControl( lpAdapterObject, lpPacket, (ULONG) ((bSet) ? IOCTL_PROTOCOL_SET_OID : IOCTL_PROTOCOL_QUERY_OID), TRUE ); if ( lpPacket->BytesReceived == 0 ) { D(bug( "Packet32: Ndis returned error to OID\r\n")); Result = FALSE; } return Result; } LPPACKET PacketQueryOid( LPADAPTER lpAdapter, ULONG ulOid, ULONG ulLength ) { ULONG ioctl; LPPACKET lpPacket; #define pOidData ((PPACKET_OID_DATA)(lpPacket->Buffer)) lpPacket = PacketAllocatePacket( lpAdapter, sizeof(PACKET_OID_DATA)-1+ulLength ); if( lpPacket ) { ioctl = IOCTL_PROTOCOL_QUERY_OID; pOidData->Oid = ulOid; pOidData->Length = ulLength; if (PacketRequest( lpAdapter, lpPacket, FALSE )) { return lpPacket; } PacketFreePacket( lpPacket ); } #undef pOidData return 0; } BOOLEAN PacketGetMAC( LPADAPTER AdapterObject, LPBYTE address, BOOL permanent ) { BOOLEAN Status; LPPACKET lpPacket; lpPacket = PacketQueryOid( AdapterObject, permanent ? OID_802_3_PERMANENT_ADDRESS : OID_802_3_CURRENT_ADDRESS, ETH_802_3_ADDRESS_LENGTH ); if(lpPacket) { memcpy( address, ((BYTE *)(lpPacket->Buffer)) + sizeof(PACKET_OID_DATA) - 1, ETH_802_3_ADDRESS_LENGTH ); PacketFreePacket( lpPacket ); Status = TRUE; } else { Status = FALSE; } return Status; } // There are other ways to do this. BOOLEAN PacketAddMulticast( LPADAPTER AdapterObject, LPBYTE address ) { BOOLEAN Status = FALSE; LPBYTE p; int i, count; LPPACKET lpPacket; D(bug("PacketAddMulticast\n")); /* if(packet_filter & (NDIS_PACKET_TYPE_ALL_MULTICAST|NDIS_PACKET_TYPE_PROMISCUOUS)) { D(bug("PacketAddMulticast: already listening for all multicast\n")); return TRUE; } */ lpPacket = PacketQueryOid( AdapterObject, OID_802_3_MULTICAST_LIST, MAX_MULTICAST_SZ ); #define OidData ((PPACKET_OID_DATA)(lpPacket->Buffer)) if(lpPacket) { count = OidData->Length / ETH_802_3_ADDRESS_LENGTH; D(bug("PacketAddMulticast: %d old addresses\n",count)); p = (LPBYTE)OidData->Data; for( i=0; i= MAX_MULTICAST) { D(bug("PacketAddMulticast: too many addresses\n")); Status = FALSE; } else { D(bug("PacketAddMulticast: adding a new address\n")); // ULONG IoCtlBufferLength = (sizeof(PACKET_OID_DATA)+ETH_802_3_ADDRESS_LENGTH*1-1); ULONG IoCtlBufferLength = (sizeof(PACKET_OID_DATA)+ETH_802_3_ADDRESS_LENGTH*(count+1)-1); LPPACKET lpPacket2 = PacketAllocatePacket( AdapterObject, IoCtlBufferLength ); #define OidData2 ((PPACKET_OID_DATA)(lpPacket2->Buffer)) if ( lpPacket2 ) { OidData2->Oid = OID_802_3_MULTICAST_LIST; // OidData2->Length = ETH_802_3_ADDRESS_LENGTH*1; // memcpy( OidData2->Data, address, ETH_802_3_ADDRESS_LENGTH ); memcpy( OidData2->Data, OidData->Data, ETH_802_3_ADDRESS_LENGTH*count ); memcpy( OidData2->Data+ETH_802_3_ADDRESS_LENGTH*count, address, ETH_802_3_ADDRESS_LENGTH ); OidData2->Length = ETH_802_3_ADDRESS_LENGTH*(count+1); Status = PacketRequest( AdapterObject, lpPacket2, TRUE ); PacketFreePacket( lpPacket2 ); } #undef OidData2 } } PacketFreePacket( lpPacket ); } #undef OidData // return Status; return TRUE; } // It seems that the last multicast address is never deleted. Why? // Don't know the reason, but luckily this is not fatal. // Hard to examine return codes. See NE2000 sources, always returns ok. BOOLEAN PacketDelMulticast( LPADAPTER AdapterObject, LPBYTE address ) { BOOLEAN Status = FALSE; LPBYTE p; int i, count; LPPACKET lpPacket, lpPacket2; D(bug("PacketDelMulticast\n")); if(packet_filter & (NDIS_PACKET_TYPE_ALL_MULTICAST|NDIS_PACKET_TYPE_PROMISCUOUS)) { D(bug("PacketDelMulticast: already listening for all multicast\n")); return TRUE; } lpPacket = PacketQueryOid( AdapterObject, OID_802_3_MULTICAST_LIST, MAX_MULTICAST_SZ ); #define OidData ((PPACKET_OID_DATA)(lpPacket->Buffer)) if(lpPacket) { count = OidData->Length / ETH_802_3_ADDRESS_LENGTH; D(bug("PacketDelMulticast: %d old addresses\n",count)); Status = FALSE; p = (LPBYTE)OidData->Data; for( i=0; iBuffer)) if ( lpPacket2 ) { OidData2->Oid = OID_802_3_MULTICAST_LIST; OidData2->Length = ETH_802_3_ADDRESS_LENGTH*(count-1); tail_len = ETH_802_3_ADDRESS_LENGTH * (count-i-1); if(tail_len) memmove( p, p+ETH_802_3_ADDRESS_LENGTH, tail_len ); if(OidData2->Length) memcpy( OidData2->Data, OidData->Data, OidData2->Length ); if(count == 1) memset( OidData2->Data, 0, ETH_802_3_ADDRESS_LENGTH ); // eh... Status = PacketRequest( AdapterObject, lpPacket2, TRUE ); PacketFreePacket( lpPacket2 ); D(bug("PacketDelMulticast: PacketRequest returned status 0x%X, last error = 0x%X\n",Status,GetLastError())); } break; #undef OidData2 } p += ETH_802_3_ADDRESS_LENGTH; } if( i == count ) { D(bug("PacketDelMulticast: cannot delete, was not defined\n")); } PacketFreePacket( lpPacket ); #undef OidData } // return Status; return TRUE; } BOOLEAN PacketSetFilter( LPADAPTER AdapterObject, ULONG Filter ) { BOOLEAN Status; ULONG IoCtlBufferLength = (sizeof(PACKET_OID_DATA)+sizeof(ULONG)-1); LPPACKET lpPacket; lpPacket = PacketAllocatePacket( AdapterObject, IoCtlBufferLength ); #define lpOidData ((PPACKET_OID_DATA)(lpPacket->Buffer)) if ( lpPacket ) { lpOidData->Oid = OID_GEN_CURRENT_PACKET_FILTER; lpOidData->Length = sizeof(ULONG); *((PULONG)lpOidData->Data) = Filter; Status = PacketRequest( AdapterObject, lpPacket, TRUE ); PacketFreePacket( lpPacket ); } else { Status = FALSE; } #undef lpOidData return Status; } BOOLEAN StartPacketDriver( LPTSTR ServiceName ) { BOOLEAN Status = FALSE; SC_HANDLE SCManagerHandle; SC_HANDLE SCServiceHandle; SCManagerHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS); if(SCManagerHandle == NULL) { D(bug("Could not open Service Control Manager\r\n")); } else { SCServiceHandle = OpenService(SCManagerHandle,ServiceName,SERVICE_START); if (SCServiceHandle == NULL) { D(bug("Could not open service %s\r\n",ServiceName)); } else { Status = StartService( SCServiceHandle, 0, NULL ); if(!Status) { if (GetLastError()==ERROR_SERVICE_ALREADY_RUNNING) { Status = TRUE; } } BOOL waiting = TRUE; // loop until the service is fully started. while (waiting) { SERVICE_STATUS ServiceStatus; if (QueryServiceStatus(SCServiceHandle, &ServiceStatus)) { switch(ServiceStatus.dwCurrentState) { case SERVICE_RUNNING: waiting = FALSE; Status = TRUE; break; case SERVICE_START_PENDING: Sleep(500); break; default: waiting = FALSE; break; } } else { waiting = FALSE; } } CloseServiceHandle(SCServiceHandle); } CloseServiceHandle(SCManagerHandle); } return Status; } ULONG PacketGetAdapterNames( LPADAPTER lpAdapter, PTSTR pStr, PULONG BufferSize ) { LONG Status; if(os == VER_PLATFORM_WIN32_NT) { HKEY hKey; DWORD RegType; Status = RegOpenKey( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\B2Ether\\Linkage", &hKey ); if( Status == ERROR_SUCCESS ) { Status = RegQueryValueEx( hKey, "Export", NULL, &RegType, (LPBYTE)pStr, BufferSize ); RegCloseKey(hKey); } } else { if (lpAdapter && lpAdapter->hFile != INVALID_HANDLE_VALUE) { LPPACKET Packet = PacketAllocatePacket( lpAdapter, *BufferSize ); if(Packet) { memset( pStr, 0, *BufferSize ); Packet->Buffer = (PVOID)pStr; Packet->Length = *BufferSize; Status = PacketDeviceIoControl( lpAdapter, Packet, (ULONG)IOCTL_PROTOCOL_MACNAME, TRUE ); if(Status) { while(*pStr) { if(*pStr == '|' || *pStr == ' ') *pStr = 0; pStr++; } *(++pStr) = 0; Status = ERROR_SUCCESS; } else { Status = ERROR_ACCESS_DENIED; } *BufferSize = Packet->BytesReceived; PacketFreePacket(Packet); } } } return Status; } ULONG PacketSelectAdapterByName( LPADAPTER lpAdapter, LPCSTR name ) { ULONG Status = 0; if(os == VER_PLATFORM_WIN32_WINDOWS) { int len = strlen(name) + 1; LPPACKET Packet = PacketAllocatePacket( lpAdapter, len ); if(Packet) { Packet->Buffer = (PVOID)name; Packet->Length = len; Status = PacketDeviceIoControl( lpAdapter, Packet, (ULONG)IOCTL_PROTOCOL_SELECT_BY_NAME, TRUE ); if(Status) { Status = ERROR_SUCCESS; } else { Status = ERROR_ACCESS_DENIED; } PacketFreePacket(Packet); } } return Status; } #ifdef __cplusplus } #endif #if DEBUG #pragma optimize("",on) #endif BasiliskII/src/Windows/sysdeps.h0000755000175000017500000002016210736405222017032 0ustar centriscentris/* * sysdeps.h - System dependent definitions for Windows * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SYSDEPS_H #define SYSDEPS_H #ifndef __STDC__ #error "Your compiler is not ANSI. Get a real one." #endif #include "config.h" #include "user_strings_windows.h" #ifndef STDC_HEADERS #error "You don't have ANSI C header files." #endif #ifndef WIN32 #define WIN32 #endif #include #include #include #include #include #ifdef __WIN32__ #include #endif #include /* Mac and host address space are distinct */ #ifndef REAL_ADDRESSING #define REAL_ADDRESSING 0 #endif #if REAL_ADDRESSING #error "Real Addressing mode can't work without proper kernel support" #endif /* Using 68k emulator */ #define EMULATED_68K 1 /* The m68k emulator uses a prefetch buffer ? */ #define USE_PREFETCH_BUFFER 0 /* Mac ROM is write protected when banked memory is used */ #if REAL_ADDRESSING || DIRECT_ADDRESSING # define ROM_IS_WRITE_PROTECTED 0 # define USE_SCRATCHMEM_SUBTERFUGE 1 #else # define ROM_IS_WRITE_PROTECTED 1 #endif /* Direct Addressing requires Video on SEGV signals in plain X11 mode */ #if DIRECT_ADDRESSING && (!ENABLE_VOSF && !USE_SDL_VIDEO) # undef ENABLE_VOSF # define ENABLE_VOSF 1 #endif /* ExtFS is supported */ #define SUPPORTS_EXTFS 1 /* Data types */ typedef unsigned char uint8; typedef signed char int8; #if SIZEOF_SHORT == 2 typedef unsigned short uint16; typedef short int16; #elif SIZEOF_INT == 2 typedef unsigned int uint16; typedef int int16; #else #error "No 2 byte type, you lose." #endif #if SIZEOF_INT == 4 typedef unsigned int uint32; typedef int int32; #elif SIZEOF_LONG == 4 typedef unsigned long uint32; typedef long int32; #else #error "No 4 byte type, you lose." #endif #if SIZEOF_LONG == 8 typedef unsigned long uint64; typedef long int64; #define VAL64(a) (a ## l) #define UVAL64(a) (a ## ul) #elif SIZEOF_LONG_LONG == 8 typedef unsigned long long uint64; typedef long long int64; #define VAL64(a) (a ## LL) #define UVAL64(a) (a ## uLL) #else #error "No 8 byte type, you lose." #endif #if SIZEOF_VOID_P == 4 typedef uint32 uintptr; typedef int32 intptr; #elif SIZEOF_VOID_P == 8 typedef uint64 uintptr; typedef int64 intptr; #else #error "Unsupported size of pointer" #endif #ifdef __WIN32__ typedef int64 loff_t; #endif #ifndef HAVE_CADDR_T typedef char * caddr_t; #endif /* Time data type for Time Manager emulation */ typedef int64 tm_time_t; /* Define codes for all the float formats that we know of. * Though we only handle IEEE format. */ #define UNKNOWN_FLOAT_FORMAT 0 #define IEEE_FLOAT_FORMAT 1 #define VAX_FLOAT_FORMAT 2 #define IBM_FLOAT_FORMAT 3 #define C4X_FLOAT_FORMAT 4 /* UAE CPU data types */ #define uae_s8 int8 #define uae_u8 uint8 #define uae_s16 int16 #define uae_u16 uint16 #define uae_s32 int32 #define uae_u32 uint32 #define uae_s64 int64 #define uae_u64 uint64 typedef uae_u32 uaecptr; /* Timing functions */ extern void timer_init(void); extern uint64 GetTicks_usec(void); extern void Delay_usec(uint32 usec); /* Spinlocks */ #ifdef __GNUC__ #define HAVE_TEST_AND_SET 1 static inline int testandset(volatile int *p) { long int ret; /* Note: the "xchg" instruction does not need a "lock" prefix */ __asm__ __volatile__("xchgl %k0, %1" : "=r" (ret), "=m" (*p) : "0" (1), "m" (*p) : "memory"); return ret; } #endif /* __GNUC__ */ typedef volatile int spinlock_t; static const spinlock_t SPIN_LOCK_UNLOCKED = 0; #if HAVE_TEST_AND_SET #define HAVE_SPINLOCKS 1 static inline void spin_lock(spinlock_t *lock) { while (testandset(lock)); } static inline void spin_unlock(spinlock_t *lock) { *lock = 0; } static inline int spin_trylock(spinlock_t *lock) { return !testandset(lock); } #else static inline void spin_lock(spinlock_t *lock) { } static inline void spin_unlock(spinlock_t *lock) { } static inline int spin_trylock(spinlock_t *lock) { return 1; } #endif /* Intel x86 */ #define X86_PPRO_OPT static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 retval; __asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc"); return retval;} #ifdef X86_PPRO_OPT static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswapl %k0\n" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #else static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc"); return retval;} #endif #define HAVE_GET_WORD_UNSWAPPED #define do_get_mem_word_unswapped(a) ((uae_u32)*((uae_u16 *)(a))) static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #ifdef X86_PPRO_OPT static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); *a = v;} #else static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); *a = v;} #endif #define HAVE_OPTIMIZED_BYTESWAP_32 /* bswap doesn't affect condition codes */ static inline uae_u32 do_byteswap_32_g(uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v)); return v;} #define HAVE_OPTIMIZED_BYTESWAP_16 #ifdef X86_PPRO_OPT static inline uae_u32 do_byteswap_16_g(uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); return v;} #else static inline uae_u32 do_byteswap_16_g(uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); return v;} #endif #ifndef HAVE_OPTIMIZED_BYTESWAP_32 static inline uae_u32 do_byteswap_32_g(uae_u32 v) { return (((v >> 24) & 0xff) | ((v >> 8) & 0xff00) | ((v & 0xff) << 24) | ((v & 0xff00) << 8)); } #endif #ifndef HAVE_OPTIMIZED_BYTESWAP_16 static inline uae_u32 do_byteswap_16_g(uae_u32 v) { return (((v >> 8) & 0xff) | ((v & 0xff) << 8)); } #endif #define do_byteswap_16_c(x) \ ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) #define do_byteswap_32_c(x) \ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) #if defined(__GNUC__) #define do_byteswap_16(x) \ (__extension__ \ ({ register uint16 __v, __x = (x); \ if (__builtin_constant_p(__x)) \ __v = do_byteswap_16_c(__x); \ else \ __v = do_byteswap_16_g(__x); \ __v; })) #define do_byteswap_32(x) \ (__extension__ \ ({ register uint32 __v, __x = (x); \ if (__builtin_constant_p(__x)) \ __v = do_byteswap_32_c(__x); \ else \ __v = do_byteswap_32_g(__x); \ __v; })) #else #define do_byteswap_16(x) do_byteswap_16_g(x) #define do_byteswap_32(x) do_byteswap_32_g(x) #endif /* Byte-swapping routines */ #if defined(__i386__) || defined(__x86_64__) #define ntohl(x) do_byteswap_32(x) #define ntohs(x) do_byteswap_16(x) #define htonl(x) do_byteswap_32(x) #define htons(x) do_byteswap_16(x) #endif #define do_get_mem_byte(a) ((uae_u32)*((uae_u8 *)(a))) #define do_put_mem_byte(a, v) (*(uae_u8 *)(a) = (v)) #define call_mem_get_func(func, addr) ((*func)(addr)) #define call_mem_put_func(func, addr, v) ((*func)(addr, v)) #define __inline__ inline #define CPU_EMU_SIZE 0 #undef NO_INLINE_MEMORY_ACCESS #undef MD_HAVE_MEM_1_FUNCS #define ENUMDECL typedef enum #define ENUMNAME(name) name #define write_log printf #define ATTRIBUTE_PACKED __attribute__((packed)) #if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY) #define ASM_SYM_FOR_FUNC(a) __asm__(a) #else #define ASM_SYM_FOR_FUNC(a) #endif #ifndef REGPARAM # define REGPARAM #endif #define REGPARAM2 #endif BasiliskII/src/Windows/user_strings_windows.cpp0000755000175000017500000001226610736405222022202 0ustar centriscentris/* * user_strings_windows.cpp - Windows-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "user_strings.h" #define WIN32_LEAN_AND_MEAN #include // Platform-specific string definitions user_string_def platform_strings[] = { // Common strings that have a platform-specific variant {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under Unix. Basilisk II will try to unmount it."}, {STR_EXTFS_VOLUME_NAME, "My Computer"}, // Purely platform-specific strings {STR_NO_XVISUAL_ERR, "Cannot obtain appropriate X visual."}, {STR_VOSF_INIT_ERR, "Cannot initialize Video on SEGV signals."}, {STR_SIG_INSTALL_ERR, "Cannot install %s handler (%s)."}, {STR_TICK_THREAD_ERR, "Cannot create 60Hz thread (%s)."}, {STR_SLIRP_NO_DNS_FOUND_WARN, "Cannot get DNS address. Ethernet will not be available."}, {STR_NO_AUDIO_WARN, "No audio device found, audio output will be disabled."}, {STR_KEYCODE_FILE_WARN, "Cannot open keycode translation file %s (%s)."}, {STR_KEYCODE_VENDOR_WARN, "Cannot find vendor '%s' in keycode translation file %s."}, {STR_WINDOW_TITLE_GRABBED, "Basilisk II (mouse grabbed, press Ctrl-F5 to release)"}, {STR_NO_WIN32_NT_4, "Basilisk II does not run on Windows NT versions less than 4.0"}, {STR_PREFS_MENU_FILE_GTK, "/_File"}, {STR_PREFS_ITEM_START_GTK, "/File/_Start Basilisk II"}, {STR_PREFS_ITEM_ZAP_PRAM_GTK, "/File/_Zap PRAM File"}, {STR_PREFS_ITEM_SEPL_GTK, "/File/sepl"}, {STR_PREFS_ITEM_QUIT_GTK, "/File/_Quit Basilisk II"}, {STR_HELP_MENU_GTK, "/_Help"}, {STR_HELP_ITEM_ABOUT_GTK, "/Help/_About Basilisk II"}, {STR_ABOUT_BUTTON, "About"}, {STR_FILE_CTRL, "File"}, {STR_BROWSE_TITLE, "Browse file"}, {STR_BROWSE_CTRL, "Browse..."}, {STR_SERIAL_PANE_TITLE, "Serial"}, {STR_NETWORK_PANE_TITLE, "Network"}, {STR_INPUT_PANE_TITLE, "Keyboard/Mouse"}, {STR_KEYCODES_CTRL, "Use Raw Keycodes"}, {STR_KEYCODE_FILE_CTRL, "Keycode Translation File"}, {STR_MOUSEWHEELMODE_CTRL, "Mouse Wheel Function"}, {STR_MOUSEWHEELMODE_PAGE_LAB, "Page Up/Down"}, {STR_MOUSEWHEELMODE_CURSOR_LAB, "Cursor Up/Down"}, {STR_MOUSEWHEELLINES_CTRL, "Lines To Scroll"}, {STR_POLLMEDIA_CTRL, "Try to automatically detect new removable media (enable polling)"}, {STR_EXTFS_ENABLE_CTRL, "Enable \"My Computer\" icon on your Mac desktop (external file system)"}, {STR_EXTFS_DRIVES_CTRL, "Mount drives"}, {STR_ETHER_FTP_PORT_LIST_CTRL, "FTP ports"}, {STR_ETHER_TCP_PORT_LIST_CTRL, "Server ports"}, {STR_IGNORESEGV_CTRL, "Ignore Illegal Memory Accesses"}, {-1, NULL} // End marker }; /* * Search for main volume name */ static const char *get_volume_name(void) { HKEY hHelpKey; DWORD key_type, cbData; static char volume[256]; memset(volume, 0, sizeof(volume)); // Try Windows 2000 key first if (ERROR_SUCCESS == RegOpenKey( HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}", &hHelpKey)) { cbData = sizeof(volume); RegQueryValueEx( hHelpKey, 0, NULL, &key_type, (unsigned char *)volume, &cbData ); RegCloseKey(hHelpKey); } if (volume[0] == 0 && ERROR_SUCCESS == RegOpenKey( HKEY_CURRENT_USER, "Software\\Classes\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}", &hHelpKey)) { cbData = sizeof(volume); RegQueryValueEx( hHelpKey, 0, NULL, &key_type, (unsigned char *)volume, &cbData ); RegCloseKey(hHelpKey); } if (volume[0] == 0 && ERROR_SUCCESS == RegOpenKey( HKEY_CLASSES_ROOT, "CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}", &hHelpKey)) { cbData = sizeof(volume); RegQueryValueEx( hHelpKey, 0, NULL, &key_type, (unsigned char *)volume, &cbData ); RegCloseKey(hHelpKey); } // Fix the error that some "tweak" apps do. if (stricmp(volume, "%USERNAME% on %COMPUTER%") == 0) volume[0] = '\0'; // No volume name found, default to "My Computer" if (volume[0] == 0) strcpy(volume, "My Computer"); return volume; } /* * Fetch pointer to string, given the string number */ const char *GetString(int num) { // First, search for platform-specific variable string switch (num) { case STR_EXTFS_VOLUME_NAME: return get_volume_name(); } // Next, search for platform-specific constant string int i = 0; while (platform_strings[i].num >= 0) { if (platform_strings[i].num == num) return platform_strings[i].str; i++; } // Not found, search for common string i = 0; while (common_strings[i].num >= 0) { if (common_strings[i].num == num) return common_strings[i].str; i++; } return NULL; } BasiliskII/src/Windows/clip_windows.cpp0000755000175000017500000001630211171124357020376 0ustar centriscentris/* * clip_windows.cpp - Clipboard handling, Windows implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #define WIN32_LEAN_AND_MEAN #include #include "macos_util.h" #include "clip.h" #include "prefs.h" #include "cpu_emulation.h" #include "main.h" #include "emul_op.h" #define DEBUG 0 #include "debug.h" #ifndef NO_STD_NAMESPACE using std::vector; #endif // Conversion tables static const uint8 mac2iso[0x80] = { 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, 0x2b, 0xb0, 0xa2, 0xa3, 0xa7, 0xb7, 0xb6, 0xdf, 0xae, 0xa9, 0x20, 0xb4, 0xa8, 0x23, 0xc6, 0xd8, 0x20, 0xb1, 0x3c, 0x3e, 0xa5, 0xb5, 0xf0, 0x53, 0x50, 0x70, 0x2f, 0xaa, 0xba, 0x4f, 0xe6, 0xf8, 0xbf, 0xa1, 0xac, 0x2f, 0x66, 0x7e, 0x44, 0xab, 0xbb, 0x2e, 0x20, 0xc0, 0xc3, 0xd5, 0x4f, 0x6f, 0x2d, 0x2d, 0x22, 0x22, 0x60, 0x27, 0xf7, 0x20, 0xff, 0x59, 0x2f, 0xa4, 0x3c, 0x3e, 0x66, 0x66, 0x23, 0xb7, 0x2c, 0x22, 0x25, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, 0x20, 0xd2, 0xda, 0xdb, 0xd9, 0x69, 0x5e, 0x7e, 0xaf, 0x20, 0xb7, 0xb0, 0xb8, 0x22, 0xb8, 0x20 }; static const uint8 iso2mac[0x80] = { 0xad, 0xb0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0, 0xf6, 0xe4, 0xde, 0xdc, 0xce, 0xb2, 0xb3, 0xb6, 0xb7, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1, 0xf7, 0xaa, 0xdf, 0xdd, 0xcf, 0xba, 0xfd, 0xd9, 0xca, 0xc1, 0xa2, 0xa3, 0xdb, 0xb4, 0xbd, 0xa4, 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xf0, 0xa8, 0xf8, 0xa1, 0xb1, 0xc3, 0xc5, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0xc6, 0xbc, 0xc8, 0xf9, 0xda, 0xd7, 0xc0, 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, 0xf5, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xfb, 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xfa, 0xb8, 0xa7, 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, 0xfe, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xff, 0xb9, 0xd8 }; // Flag: Don't convert clipboard text static bool no_clip_conversion; // Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Windows side static bool we_put_this_data = false; // Define a byte array (rewrite if it's a bottleneck) struct ByteArray : public vector { uint8 *data() { return &(*this)[0]; } }; // Prototypes static void do_putscrap(uint32 type, void *scrap, int32 length); static void do_getscrap(void **handle, uint32 type, int32 offset); // From main_windows.cpp extern HWND GetMainWindowHandle(void); /* * Initialization */ void ClipInit(void) { no_clip_conversion = PrefsFindBool("noclipconversion"); } /* * Deinitialization */ void ClipExit(void) { } /* * Mac application wrote to clipboard */ void PutScrap(uint32 type, void *scrap, int32 length) { D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length)); if (we_put_this_data) { we_put_this_data = false; return; } if (length <= 0) return; do_putscrap(type, scrap, length); } static void do_putscrap(uint32 type, void *scrap, int32 length) { ByteArray clip_data; UINT uFormat = 0; switch (type) { case FOURCC('T','E','X','T'): { D(bug(" clipping TEXT\n")); // Convert text from Mac charset to ISO-Latin1 uint8 *p = (uint8 *)scrap; for (int i=0; i CR/LF clip_data.push_back(c); c = 10; } } else if (!no_clip_conversion) c = mac2iso[c & 0x7f]; clip_data.push_back(c); } clip_data.push_back(0); uFormat = CF_TEXT; break; } } if (uFormat != CF_TEXT) // 'TEXT' only return; // Transfer data to the native clipboard HWND hMainWindow = GetMainWindowHandle(); if (!hMainWindow ||!OpenClipboard(hMainWindow)) return; EmptyClipboard(); HANDLE hData = GlobalAlloc(GMEM_DDESHARE, clip_data.size()); if (hData) { uint8 *data = (uint8 *)GlobalLock(hData); memcpy(data, clip_data.data(), clip_data.size()); GlobalUnlock(hData); if (!SetClipboardData(uFormat, hData)) GlobalFree(hData); } CloseClipboard(); } /* * Mac application reads clipboard */ void GetScrap(void **handle, uint32 type, int32 offset) { D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); do_getscrap(handle, type, offset); } static void do_getscrap(void **handle, uint32 type, int32 offset) { // Get appropriate format for requested data UINT uFormat = 0; switch (type) { case FOURCC('T','E','X','T'): uFormat = CF_TEXT; break; } if (uFormat != CF_TEXT) // 'TEXT' only return; // Get the native clipboard data HWND hMainWindow = GetMainWindowHandle(); if (!hMainWindow || !OpenClipboard(hMainWindow)) return; HANDLE hData = GetClipboardData(uFormat); if (hData) { uint8 *data = (uint8 *)GlobalLock(hData); if (data) { uint32 length = GlobalSize(hData); if (length) { int32 out_length = 0; // Allocate space for new scrap in MacOS side M68kRegisters r; r.d[0] = length; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 scrap_area = r.a[0]; if (scrap_area) { switch (type) { case FOURCC('T','E','X','T'): D(bug(" clipping TEXT\n")); // Convert text from ISO-Latin1 to Mac charset uint8 *p = Mac2HostAddr(scrap_area); for (int i = 0; i < length; i++) { uint8 c = data[i]; if (c < 0x80) { if (c == 0) break; if (c == 13 && i < length - 1 && data[i + 1] == 10) { // CR/LF -> CR c = 13; i++; } } else if (!no_clip_conversion) c = iso2mac[c & 0x7f]; *p++ = c; out_length++; } break; } // Add new data to clipboard static uint8 proc[] = { 0x59, 0x8f, // subq.l #4,sp 0xa9, 0xfc, // ZeroScrap() 0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp) 0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp) 0xa9, 0xfe, // PutScrap() 0x58, 0x8f, // addq.l #4,sp M68K_RTS >> 8, M68K_RTS }; uint32 proc_area = Host2MacAddr(proc); WriteMacInt32(proc_area + 6, out_length); WriteMacInt32(proc_area + 12, type); WriteMacInt32(proc_area + 18, scrap_area); we_put_this_data = true; Execute68k(proc_area, &r); // We are done with scratch memory r.a[0] = scrap_area; Execute68kTrap(0xa01f, &r); // DisposePtr } } GlobalUnlock(hData); } } CloseClipboard(); } BasiliskII/src/Windows/BasiliskIIGUI.ico0000755000175000017500000000206610340133071020205 0ustar centriscentris è&(( @€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwpwwwwwwwwwwpwwwwwwwwwwpwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwpwwwwpwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwpwwwwwwwwpwpwwwwwwwwpwpwwwwwwpwpwwpwwwwpwpwwwwwwwwpwpwwwpwwwpwpwwwwwwwpwpwwwwwwwpwpwwwwwpwpwwwwwpwpwwwwwwwwpwpwwwwwwwwpwpwwwwwwwwpwwwwwwwwwwwwwwwwwwwwwwwwpøøøøðððððððððððððððððððððððððððø( À€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwppwwppwwwwwppppwwwpppwppppwppppwpwpppppppppwwwppppwwwwwpÀÀ€€€€€€€€€€€€€ÀBasiliskII/src/Windows/prefs_editor_gtk.cpp0000644000175000017500000014552311232133661021230 0ustar centriscentris/* * prefs_editor_gtk.cpp - Preferences editor, Unix implementation using GTK+ * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include "user_strings.h" #include "version.h" #include "cdrom.h" #include "xpram.h" #include "prefs.h" #include "prefs_editor.h" #include "util_windows.h" #include "b2ether/inc/b2ether_hl.h" // Global variables static GtkWidget *win; // Preferences window static bool start_clicked = true; // Return value of PrefsEditor() function // Prototypes static void create_volumes_pane(GtkWidget *top); static void create_scsi_pane(GtkWidget *top); static void create_graphics_pane(GtkWidget *top); static void create_input_pane(GtkWidget *top); static void create_serial_pane(GtkWidget *top); static void create_ethernet_pane(GtkWidget *top); static void create_memory_pane(GtkWidget *top); static void create_jit_pane(GtkWidget *top); static void read_settings(void); /* * SheepShaver glue */ #ifdef SHEEPSHAVER #define DISABLE_SCSI 1 #define PROGRAM_NAME "SheepShaver" enum { STR_WINDOW_LAB = STR_WINDOW_CTRL, STR_FULLSCREEN_LAB = STR_FULLSCREEN_CTRL, STR_SERIALA_CTRL = STR_SERPORTA_CTRL, STR_SERIALB_CTRL = STR_SERPORTB_CTRL, }; #else #define DISABLE_SCSI 1 /* XXX merge code from original Basilisk II for Windows */ #define PROGRAM_NAME "BasiliskII" #endif /* * Utility functions */ struct opt_desc { int label_id; GtkSignalFunc func; }; struct combo_desc { int label_id; }; struct file_req_assoc { file_req_assoc(GtkWidget *r, GtkWidget *e) : req(r), entry(e) {} GtkWidget *req; GtkWidget *entry; }; static void cb_browse_ok(GtkWidget *button, file_req_assoc *assoc) { gchar *file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); gtk_entry_set_text(GTK_ENTRY(assoc->entry), file); gtk_widget_destroy(assoc->req); delete assoc; } static void cb_browse(GtkWidget *widget, void *user_data) { GtkWidget *req = gtk_file_selection_new(GetString(STR_BROWSE_TITLE)); gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(cb_browse_ok), new file_req_assoc(req, (GtkWidget *)user_data)); gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_widget_show(req); } static GtkWidget *make_browse_button(GtkWidget *entry) { GtkWidget *button; button = gtk_button_new_with_label(GetString(STR_BROWSE_CTRL)); gtk_widget_show(button); gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)cb_browse, (void *)entry); return button; } static void add_menu_item(GtkWidget *menu, const char *label, GtkSignalFunc func, gpointer data = NULL) { GtkWidget *item = gtk_menu_item_new_with_label(label); gtk_widget_show(item); gtk_signal_connect(GTK_OBJECT(item), "activate", func, data); gtk_menu_append(GTK_MENU(menu), item); } static void add_menu_item(GtkWidget *menu, int label_id, GtkSignalFunc func) { add_menu_item(menu, GetString(label_id), func, NULL); } static GtkWidget *make_pane(GtkWidget *notebook, int title_id) { GtkWidget *frame, *label, *box; frame = gtk_frame_new(NULL); gtk_widget_show(frame); gtk_container_border_width(GTK_CONTAINER(frame), 4); label = gtk_label_new(GetString(title_id)); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); box = gtk_vbox_new(FALSE, 4); gtk_widget_show(box); gtk_container_set_border_width(GTK_CONTAINER(box), 4); gtk_container_add(GTK_CONTAINER(frame), box); return box; } static GtkWidget *make_button_box(GtkWidget *top, int border, const opt_desc *buttons) { GtkWidget *bb, *button; bb = gtk_hbutton_box_new(); gtk_widget_show(bb); gtk_container_set_border_width(GTK_CONTAINER(bb), border); gtk_button_box_set_layout(GTK_BUTTON_BOX(bb), GTK_BUTTONBOX_DEFAULT_STYLE); gtk_button_box_set_spacing(GTK_BUTTON_BOX(bb), 4); gtk_box_pack_start(GTK_BOX(top), bb, FALSE, FALSE, 0); while (buttons->label_id) { button = gtk_button_new_with_label(GetString(buttons->label_id)); gtk_widget_show(button); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", buttons->func, NULL); gtk_box_pack_start(GTK_BOX(bb), button, TRUE, TRUE, 0); buttons++; } return bb; } static GtkWidget *make_separator(GtkWidget *top) { GtkWidget *sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(top), sep, FALSE, FALSE, 0); gtk_widget_show(sep); return sep; } static GtkWidget *make_table(GtkWidget *top, int x, int y) { GtkWidget *table = gtk_table_new(x, y, FALSE); gtk_widget_show(table); gtk_box_pack_start(GTK_BOX(top), table, FALSE, FALSE, 0); return table; } static GtkWidget *table_make_option_menu(GtkWidget *table, int row, int label_id, const opt_desc *options, int active) { GtkWidget *label, *opt, *menu; label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); opt = gtk_option_menu_new(); gtk_widget_show(opt); menu = gtk_menu_new(); while (options->label_id) { add_menu_item(menu, options->label_id, options->func); options++; } gtk_menu_set_active(GTK_MENU(menu), active); gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); gtk_table_attach(GTK_TABLE(table), opt, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); return menu; } static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, GList *glist) { GtkWidget *label, *combo; char str[32]; label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); combo = gtk_combo_new(); gtk_widget_show(combo); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); return combo; } static GtkWidget *table_make_combobox(GtkWidget *table, int row, int label_id, const char *default_value, const combo_desc *options) { GList *glist = NULL; while (options->label_id) { glist = g_list_append(glist, (void *)GetString(options->label_id)); options++; } return table_make_combobox(table, row, label_id, default_value, glist); } static GtkWidget *table_make_file_entry(GtkWidget *table, int row, int label_id, const char *prefs_item, bool only_dirs = false) { GtkWidget *box, *label, *entry, *button; label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); const char *str = PrefsFindString(prefs_item); if (str == NULL) str = ""; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_table_attach(GTK_TABLE(table), box, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), str); gtk_widget_show(entry); gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); button = make_browse_button(entry); gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0); g_object_set_data(G_OBJECT(entry), "chooser_button", button); return entry; } static GtkWidget *make_option_menu(GtkWidget *top, int label_id, const opt_desc *options, int active) { GtkWidget *box, *label, *opt, *menu; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); opt = gtk_option_menu_new(); gtk_widget_show(opt); menu = gtk_menu_new(); while (options->label_id) { add_menu_item(menu, options->label_id, options->func); options++; } gtk_menu_set_active(GTK_MENU(menu), active); gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); gtk_box_pack_start(GTK_BOX(box), opt, FALSE, FALSE, 0); return menu; } static GtkWidget *make_file_entry(GtkWidget *top, int label_id, const char *prefs_item, bool only_dirs = false) { GtkWidget *box, *label, *entry; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); const char *str = PrefsFindString(prefs_item); if (str == NULL) str = ""; entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(entry), str); gtk_widget_show(entry); gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); return entry; } static const gchar *get_file_entry_path(GtkWidget *entry) { return gtk_entry_get_text(GTK_ENTRY(entry)); } static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func) { GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id)); gtk_widget_show(button); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), PrefsFindBool(prefs_item)); gtk_signal_connect(GTK_OBJECT(button), "toggled", func, button); gtk_box_pack_start(GTK_BOX(top), button, FALSE, FALSE, 0); return button; } static GtkWidget *make_combobox(GtkWidget *top, int label_id, const char *default_value, GList *glist) { GtkWidget *box, *label, *combo; box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); gtk_box_pack_start(GTK_BOX(top), box, FALSE, FALSE, 0); label = gtk_label_new(GetString(label_id)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); combo = gtk_combo_new(); gtk_widget_show(combo); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), default_value); gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0); return combo; } static GtkWidget *make_combobox(GtkWidget *top, int label_id, const char *default_value, const combo_desc *options) { GList *glist = NULL; while (options->label_id) { glist = g_list_append(glist, (void *)GetString(options->label_id)); options++; } return make_combobox(top, label_id, default_value, glist); } /* * Show preferences editor * Returns true when user clicked on "Start", false otherwise */ // Window closed static gint window_closed(void) { return FALSE; } // Window destroyed static void window_destroyed(void) { gtk_main_quit(); } // "Start" button clicked static void cb_start(...) { start_clicked = true; read_settings(); SavePrefs(); gtk_widget_destroy(win); } // "Zap PRAM" button clicked static void cb_zap_pram(...) { ZapPRAM(); } // "Quit" button clicked static void cb_quit(...) { start_clicked = false; gtk_widget_destroy(win); } // "OK" button of "About" dialog clicked static void dl_quit(GtkWidget *dialog) { gtk_widget_destroy(dialog); } // "About" button clicked static void cb_about(...) { GtkWidget *dialog; GtkWidget *label, *button; char str[512]; sprintf(str, PROGRAM_NAME "\nVersion %d.%d\n\n" "Copyright (C) 1997-2008 Christian Bauer et al.\n" "E-mail: cb@cebix.net\n" #ifdef SHEEPSHAVER "http://sheepshaver.cebix.net/\n\n" #else "http://basilisk.cebix.net/\n\n" #endif PROGRAM_NAME " comes with ABSOLUTELY NO\n" "WARRANTY. This is free software, and\n" "you are welcome to redistribute it\n" "under the terms of the GNU General\n" "Public License.\n", VERSION_MAJOR, VERSION_MINOR ); dialog = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dialog), GetString(STR_ABOUT_TITLE)); gtk_container_border_width(GTK_CONTAINER(dialog), 5); gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150); label = gtk_label_new(str); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0); button = gtk_button_new_with_label(GetString(STR_OK_BUTTON)); gtk_widget_show(button); gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog)); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_grab_default(button); gtk_widget_show(dialog); } // Menu item descriptions static GtkItemFactoryEntry menu_items[] = { {(gchar *)GetString(STR_PREFS_MENU_FILE_GTK), NULL, NULL, 0, ""}, {(gchar *)GetString(STR_PREFS_ITEM_START_GTK), "S", GTK_SIGNAL_FUNC(cb_start), 0, NULL}, {(gchar *)GetString(STR_PREFS_ITEM_ZAP_PRAM_GTK), NULL, GTK_SIGNAL_FUNC(cb_zap_pram), 0, NULL}, {(gchar *)GetString(STR_PREFS_ITEM_SEPL_GTK), NULL, NULL, 0, ""}, {(gchar *)GetString(STR_PREFS_ITEM_QUIT_GTK), "Q", GTK_SIGNAL_FUNC(cb_quit), 0, NULL}, {(gchar *)GetString(STR_HELP_MENU_GTK), NULL, NULL, 0, ""}, {(gchar *)GetString(STR_HELP_ITEM_ABOUT_GTK), "H", GTK_SIGNAL_FUNC(cb_about), 0, NULL} }; void PrefsMigrate(void) { // Ethernet const char *ether = PrefsFindString("ether"); if (ether && ether[0] == '{') { PrefsReplaceString("etherguid", ether); PrefsReplaceString("ether", "b2ether"); } if (PrefsFindBool("routerenabled")) { PrefsRemoveItem("etherguid"); PrefsReplaceString("ether", "router"); } } bool PrefsEditor(void) { // Create window win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(win), GetString(STR_PREFS_TITLE)); gtk_signal_connect(GTK_OBJECT(win), "delete_event", GTK_SIGNAL_FUNC(window_closed), NULL); gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(window_destroyed), NULL); // Create window contents GtkWidget *box = gtk_vbox_new(FALSE, 4); gtk_widget_show(box); gtk_container_add(GTK_CONTAINER(win), box); GtkAccelGroup *accel_group = gtk_accel_group_new(); GtkItemFactory *item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "
", accel_group); gtk_item_factory_create_items(item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL); #if GTK_CHECK_VERSION(1,3,15) gtk_window_add_accel_group(GTK_WINDOW(win), accel_group); #else gtk_accel_group_attach(accel_group, GTK_OBJECT(win)); #endif GtkWidget *menu_bar = gtk_item_factory_get_widget(item_factory, "
"); gtk_widget_show(menu_bar); gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, TRUE, 0); GtkWidget *notebook = gtk_notebook_new(); gtk_widget_show(notebook); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP); gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE); gtk_box_pack_start(GTK_BOX(box), notebook, TRUE, TRUE, 0); create_volumes_pane(notebook); #ifndef DISABLE_SCSI create_scsi_pane(notebook); #endif create_graphics_pane(notebook); create_input_pane(notebook); create_serial_pane(notebook); create_ethernet_pane(notebook); create_memory_pane(notebook); create_jit_pane(notebook); static const opt_desc buttons[] = { {STR_START_BUTTON, GTK_SIGNAL_FUNC(cb_start)}, {STR_QUIT_BUTTON, GTK_SIGNAL_FUNC(cb_quit)}, {0, NULL} }; make_button_box(box, 4, buttons); // Show window and enter main loop gtk_widget_show(win); gtk_main(); return start_clicked; } /* * "Volumes" pane */ static GtkWidget *w_enableextfs, *w_extdrives, *w_cdrom_drive; static GtkWidget *volume_list; static int selected_volume; // Set sensitivity of widgets static void set_volumes_sensitive(void) { const bool enable_extfs = PrefsFindBool("enableextfs"); gtk_widget_set_sensitive(w_extdrives, enable_extfs); const bool no_cdrom = PrefsFindBool("nocdrom"); gtk_widget_set_sensitive(w_cdrom_drive, !no_cdrom); } // Volume in list selected static void cl_selected(GtkWidget *list, int row, int column) { selected_volume = row; } // Volume selected for addition static void add_volume_ok(GtkWidget *button, file_req_assoc *assoc) { gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); gtk_clist_append(GTK_CLIST(volume_list), &file); gtk_widget_destroy(assoc->req); delete assoc; } // Volume selected for creation static void create_volume_ok(GtkWidget *button, file_req_assoc *assoc) { gchar *file = (gchar *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(assoc->req)); const gchar *str = gtk_entry_get_text(GTK_ENTRY(assoc->entry)); size_t size = atoi(str) << 20; int fd = _open(file, _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC, _S_IREAD | _S_IWRITE); if (fd >= 0) { if (_chsize(fd, size) == 0) gtk_clist_append(GTK_CLIST(volume_list), &file); _close(fd); } gtk_widget_destroy(GTK_WIDGET(assoc->req)); delete assoc; } // "Add Volume" button clicked static void cb_add_volume(...) { GtkWidget *req = gtk_file_selection_new(GetString(STR_ADD_VOLUME_TITLE)); gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(add_volume_ok), new file_req_assoc(req, NULL)); gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_widget_show(req); } // "Create Hardfile" button clicked static void cb_create_volume(...) { GtkWidget *req = gtk_file_selection_new(GetString(STR_CREATE_VOLUME_TITLE)); GtkWidget *box = gtk_hbox_new(FALSE, 4); gtk_widget_show(box); GtkWidget *label = gtk_label_new(GetString(STR_HARDFILE_SIZE_CTRL)); gtk_widget_show(label); GtkWidget *entry = gtk_entry_new(); gtk_widget_show(entry); char str[32]; sprintf(str, "%d", 40); gtk_entry_set_text(GTK_ENTRY(entry), str); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(box), entry, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(req)->main_vbox), box, FALSE, FALSE, 0); gtk_signal_connect_object(GTK_OBJECT(req), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(req)->ok_button), "clicked", GTK_SIGNAL_FUNC(create_volume_ok), new file_req_assoc(req, entry)); gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(req)->cancel_button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(req)); gtk_widget_show(req); } // "Remove Volume" button clicked static void cb_remove_volume(...) { gtk_clist_remove(GTK_CLIST(volume_list), selected_volume); } // "Boot From" selected static void mn_boot_any(...) {PrefsReplaceInt32("bootdriver", 0);} static void mn_boot_cdrom(...) {PrefsReplaceInt32("bootdriver", CDROMRefNum);} // "Enable external file system" button toggled static void tb_enableextfs(GtkWidget *widget) { PrefsReplaceBool("enableextfs", GTK_TOGGLE_BUTTON(widget)->active); set_volumes_sensitive(); } // "No CD-ROM Driver" button toggled static void tb_nocdrom(GtkWidget *widget) { PrefsReplaceBool("nocdrom", GTK_TOGGLE_BUTTON(widget)->active); set_volumes_sensitive(); } // Add names of CD-ROM devices static GList *add_cdrom_names(void) { GList *glist = NULL; char rootdir[4] = "X:\\"; for (char letter = 'C'; letter <= 'Z'; letter++) { rootdir[0] = letter; if (GetDriveType(rootdir) == DRIVE_CDROM) glist = g_list_append(glist, strdup(rootdir)); } return glist; } // "Enable polling" button toggled static void tb_pollmedia(GtkWidget *widget) { PrefsReplaceBool("pollmedia", GTK_TOGGLE_BUTTON(widget)->active); } // Read settings from widgets and set preferences static void read_volumes_settings(void) { while (PrefsFindString("disk")) PrefsRemoveItem("disk"); for (int i=0; irows; i++) { char *str; gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str); PrefsAddString("disk", str); } const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_cdrom_drive)->entry)); if (str && strlen(str)) PrefsReplaceString("cdrom", str); else PrefsRemoveItem("cdrom"); PrefsReplaceString("extdrives", get_file_entry_path(w_extdrives)); } // Create "Volumes" pane static void create_volumes_pane(GtkWidget *top) { GtkWidget *box, *scroll, *menu; box = make_pane(top, STR_VOLUMES_PANE_TITLE); scroll = gtk_scrolled_window_new(NULL, NULL); gtk_widget_show(scroll); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); volume_list = gtk_clist_new(1); gtk_widget_show(volume_list); gtk_clist_set_selection_mode(GTK_CLIST(volume_list), GTK_SELECTION_SINGLE); gtk_clist_set_shadow_type(GTK_CLIST(volume_list), GTK_SHADOW_NONE); gtk_clist_set_reorderable(GTK_CLIST(volume_list), true); gtk_signal_connect(GTK_OBJECT(volume_list), "select_row", GTK_SIGNAL_FUNC(cl_selected), NULL); char *str; int32 index = 0; while ((str = const_cast(PrefsFindString("disk", index++))) != NULL) gtk_clist_append(GTK_CLIST(volume_list), &str); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), volume_list); gtk_box_pack_start(GTK_BOX(box), scroll, TRUE, TRUE, 0); selected_volume = 0; static const opt_desc buttons[] = { {STR_ADD_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_add_volume)}, {STR_CREATE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_create_volume)}, {STR_REMOVE_VOLUME_BUTTON, GTK_SIGNAL_FUNC(cb_remove_volume)}, {0, NULL}, }; make_button_box(box, 0, buttons); make_separator(box); static const opt_desc options[] = { {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)}, {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)}, {0, NULL} }; int bootdriver = PrefsFindInt32("bootdriver"), active = 0; switch (bootdriver) { case 0: active = 0; break; case CDROMRefNum: active = 1; break; } menu = make_option_menu(box, STR_BOOTDRIVER_CTRL, options, active); make_checkbox(box, STR_NOCDROM_CTRL, "nocdrom", GTK_SIGNAL_FUNC(tb_nocdrom)); GList *glist = add_cdrom_names(); str = const_cast(PrefsFindString("cdrom")); if (str == NULL) str = ""; w_cdrom_drive = make_combobox(box, STR_CDROM_DRIVE_CTRL, str, glist); make_checkbox(box, STR_POLLMEDIA_CTRL, "pollmedia", GTK_SIGNAL_FUNC(tb_pollmedia)); make_separator(box); w_enableextfs = make_checkbox(box, STR_EXTFS_ENABLE_CTRL, "enableextfs", GTK_SIGNAL_FUNC(tb_enableextfs)); w_extdrives = make_file_entry(box, STR_EXTFS_DRIVES_CTRL, "extdrives", true); set_volumes_sensitive(); } /* * "JIT Compiler" pane */ #ifndef SHEEPSHAVER static GtkWidget *w_jit_fpu; static GtkWidget *w_jit_atraps; static GtkWidget *w_jit_cache_size; static GtkWidget *w_jit_lazy_flush; static GtkWidget *w_jit_follow_const_jumps; #endif // Set sensitivity of widgets static void set_jit_sensitive(void) { #ifndef SHEEPSHAVER const bool jit_enabled = PrefsFindBool("jit"); gtk_widget_set_sensitive(w_jit_fpu, jit_enabled); gtk_widget_set_sensitive(w_jit_cache_size, jit_enabled); gtk_widget_set_sensitive(w_jit_lazy_flush, jit_enabled); gtk_widget_set_sensitive(w_jit_follow_const_jumps, jit_enabled); #endif } // "Use JIT Compiler" button toggled static void tb_jit(GtkWidget *widget) { PrefsReplaceBool("jit", GTK_TOGGLE_BUTTON(widget)->active); set_jit_sensitive(); } // "Compile FPU Instructions" button toggled #ifndef SHEEPSHAVER static void tb_jit_fpu(GtkWidget *widget) { PrefsReplaceBool("jitfpu", GTK_TOGGLE_BUTTON(widget)->active); } #endif // "Lazy translation cache invalidation" button toggled #ifndef SHEEPSHAVER static void tb_jit_lazy_flush(GtkWidget *widget) { PrefsReplaceBool("jitlazyflush", GTK_TOGGLE_BUTTON(widget)->active); } #endif // "Translate through constant jumps (inline blocks)" button toggled #ifndef SHEEPSHAVER static void tb_jit_follow_const_jumps(GtkWidget *widget) { PrefsReplaceBool("jitinline", GTK_TOGGLE_BUTTON(widget)->active); } #endif // Read settings from widgets and set preferences static void read_jit_settings(void) { #if USE_JIT bool jit_enabled = PrefsFindBool("jit"); if (jit_enabled) { #ifndef SHEEPSHAVER const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_jit_cache_size)->entry)); PrefsReplaceInt32("jitcachesize", atoi(str)); #endif } #endif } // "Use built-in 68k DR emulator" button toggled #ifdef SHEEPSHAVER static void tb_jit_68k(GtkWidget *widget) { PrefsReplaceBool("jit68k", GTK_TOGGLE_BUTTON(widget)->active); } #endif // Create "JIT Compiler" pane static void create_jit_pane(GtkWidget *top) { #if USE_JIT GtkWidget *box, *table, *label, *menu; char str[32]; box = make_pane(top, STR_JIT_PANE_TITLE); make_checkbox(box, STR_JIT_CTRL, "jit", GTK_SIGNAL_FUNC(tb_jit)); #ifndef SHEEPSHAVER w_jit_fpu = make_checkbox(box, STR_JIT_FPU_CTRL, "jitfpu", GTK_SIGNAL_FUNC(tb_jit_fpu)); // Translation cache size static const combo_desc options[] = { STR_JIT_CACHE_SIZE_2MB_LAB, STR_JIT_CACHE_SIZE_4MB_LAB, STR_JIT_CACHE_SIZE_8MB_LAB, STR_JIT_CACHE_SIZE_16MB_LAB, 0 }; sprintf(str, "%d", PrefsFindInt32("jitcachesize")); w_jit_cache_size = make_combobox(box, STR_JIT_CACHE_SIZE_CTRL, str, options); // Lazy translation cache invalidation w_jit_lazy_flush = make_checkbox(box, STR_JIT_LAZY_CINV_CTRL, "jitlazyflush", GTK_SIGNAL_FUNC(tb_jit_lazy_flush)); // Follow constant jumps (inline basic blocks) w_jit_follow_const_jumps = make_checkbox(box, STR_JIT_FOLLOW_CONST_JUMPS, "jitinline", GTK_SIGNAL_FUNC(tb_jit_follow_const_jumps)); #endif set_jit_sensitive(); #endif #ifdef SHEEPSHAVER make_checkbox(box, STR_JIT_68K_CTRL, "jit68k", GTK_SIGNAL_FUNC(tb_jit_68k)); #endif } /* * "SCSI" pane */ static GtkWidget *w_scsi[7]; // Read settings from widgets and set preferences static void read_scsi_settings(void) { #ifndef DISABLE_SCSI for (int id=0; id<7; id++) { char prefs_name[32]; sprintf(prefs_name, "scsi%d", id); const char *str = get_file_entry_path(w_scsi[id]); if (str && strlen(str)) PrefsReplaceString(prefs_name, str); else PrefsRemoveItem(prefs_name); } #endif } // Create "SCSI" pane static void create_scsi_pane(GtkWidget *top) { #ifndef DISABLE_SCSI GtkWidget *box; box = make_pane(top, STR_SCSI_PANE_TITLE); for (int id=0; id<7; id++) { char prefs_name[32]; sprintf(prefs_name, "scsi%d", id); w_scsi[id] = make_file_entry(box, STR_SCSI_ID_0 + id, prefs_name); } #endif } /* * "Graphics/Sound" pane */ // Display types enum { DISPLAY_WINDOW, DISPLAY_SCREEN }; static GtkWidget *w_frameskip, *w_display_x, *w_display_y; static GtkWidget *l_frameskip, *l_display_x, *l_display_y; static int display_type; static int dis_width, dis_height; // Hide/show graphics widgets static void hide_show_graphics_widgets(void) { switch (display_type) { case DISPLAY_WINDOW: gtk_widget_show(w_frameskip); gtk_widget_show(l_frameskip); break; case DISPLAY_SCREEN: gtk_widget_hide(w_frameskip); gtk_widget_hide(l_frameskip); break; } } // "Window" video type selected static void mn_window(...) { display_type = DISPLAY_WINDOW; hide_show_graphics_widgets(); } // "Fullscreen" video type selected static void mn_fullscreen(...) { display_type = DISPLAY_SCREEN; hide_show_graphics_widgets(); PrefsReplaceInt32("frameskip", 1); } // "5 Hz".."60Hz" selected static void mn_5hz(...) {PrefsReplaceInt32("frameskip", 12);} static void mn_7hz(...) {PrefsReplaceInt32("frameskip", 8);} static void mn_10hz(...) {PrefsReplaceInt32("frameskip", 6);} static void mn_15hz(...) {PrefsReplaceInt32("frameskip", 4);} static void mn_30hz(...) {PrefsReplaceInt32("frameskip", 2);} static void mn_60hz(...) {PrefsReplaceInt32("frameskip", 1);} static void mn_dynamic(...) {PrefsReplaceInt32("frameskip", 0);} // QuickDraw acceleration #ifdef SHEEPSHAVER static void tb_gfxaccel(GtkWidget *widget) { PrefsReplaceBool("gfxaccel", GTK_TOGGLE_BUTTON(widget)->active); } #endif // Set sensitivity of widgets static void set_graphics_sensitive(void) { const bool sound_enabled = !PrefsFindBool("nosound"); } // "Disable Sound Output" button toggled static void tb_nosound(GtkWidget *widget) { PrefsReplaceBool("nosound", GTK_TOGGLE_BUTTON(widget)->active); set_graphics_sensitive(); } // Read graphics preferences static void parse_graphics_prefs(void) { display_type = DISPLAY_WINDOW; #ifdef SHEEPSHAVER dis_width = 640; dis_height = 480; #else dis_width = 512; dis_height = 384; #endif const char *str = PrefsFindString("screen"); if (str) { if (sscanf(str, "win/%d/%d", &dis_width, &dis_height) == 2) display_type = DISPLAY_WINDOW; else if (sscanf(str, "dga/%d/%d", &dis_width, &dis_height) == 2) display_type = DISPLAY_SCREEN; } } // Read settings from widgets and set preferences static void read_graphics_settings(void) { const char *str; str = gtk_entry_get_text(GTK_ENTRY(w_display_x)); dis_width = atoi(str); str = gtk_entry_get_text(GTK_ENTRY(w_display_y)); dis_height = atoi(str); char pref[256]; switch (display_type) { case DISPLAY_WINDOW: sprintf(pref, "win/%d/%d", dis_width, dis_height); break; case DISPLAY_SCREEN: sprintf(pref, "dga/%d/%d", dis_width, dis_height); break; default: PrefsRemoveItem("screen"); return; } PrefsReplaceString("screen", pref); } // Create "Graphics/Sound" pane static void create_graphics_pane(GtkWidget *top) { GtkWidget *box, *table, *label, *opt, *menu, *combo; char str[32]; parse_graphics_prefs(); box = make_pane(top, STR_GRAPHICS_SOUND_PANE_TITLE); table = make_table(box, 2, 5); label = gtk_label_new(GetString(STR_VIDEO_TYPE_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); opt = gtk_option_menu_new(); gtk_widget_show(opt); menu = gtk_menu_new(); add_menu_item(menu, STR_WINDOW_LAB, GTK_SIGNAL_FUNC(mn_window)); add_menu_item(menu, STR_FULLSCREEN_LAB, GTK_SIGNAL_FUNC(mn_fullscreen)); switch (display_type) { case DISPLAY_WINDOW: gtk_menu_set_active(GTK_MENU(menu), 0); break; case DISPLAY_SCREEN: gtk_menu_set_active(GTK_MENU(menu), 1); break; } gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); l_frameskip = gtk_label_new(GetString(STR_FRAMESKIP_CTRL)); gtk_widget_show(l_frameskip); gtk_table_attach(GTK_TABLE(table), l_frameskip, 0, 1, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); w_frameskip = gtk_option_menu_new(); gtk_widget_show(w_frameskip); menu = gtk_menu_new(); add_menu_item(menu, STR_REF_5HZ_LAB, GTK_SIGNAL_FUNC(mn_5hz)); add_menu_item(menu, STR_REF_7_5HZ_LAB, GTK_SIGNAL_FUNC(mn_7hz)); add_menu_item(menu, STR_REF_10HZ_LAB, GTK_SIGNAL_FUNC(mn_10hz)); add_menu_item(menu, STR_REF_15HZ_LAB, GTK_SIGNAL_FUNC(mn_15hz)); add_menu_item(menu, STR_REF_30HZ_LAB, GTK_SIGNAL_FUNC(mn_30hz)); add_menu_item(menu, STR_REF_60HZ_LAB, GTK_SIGNAL_FUNC(mn_60hz)); add_menu_item(menu, STR_REF_DYNAMIC_LAB, GTK_SIGNAL_FUNC(mn_dynamic)); int frameskip = PrefsFindInt32("frameskip"); int item = -1; switch (frameskip) { case 12: item = 0; break; case 8: item = 1; break; case 6: item = 2; break; case 4: item = 3; break; case 2: item = 4; break; case 1: item = 5; break; case 0: item = 6; break; } if (item >= 0) gtk_menu_set_active(GTK_MENU(menu), item); gtk_option_menu_set_menu(GTK_OPTION_MENU(w_frameskip), menu); gtk_table_attach(GTK_TABLE(table), w_frameskip, 1, 2, 1, 2, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); l_display_x = gtk_label_new(GetString(STR_DISPLAY_X_CTRL)); gtk_widget_show(l_display_x); gtk_table_attach(GTK_TABLE(table), l_display_x, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); combo = gtk_combo_new(); gtk_widget_show(combo); GList *glist1 = NULL; glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_512_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_640_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_800_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_1024_LAB)); glist1 = g_list_append(glist1, (void *)GetString(STR_SIZE_MAX_LAB)); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist1); if (dis_width) sprintf(str, "%d", dis_width); else strcpy(str, GetString(STR_SIZE_MAX_LAB)); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 2, 3, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); w_display_x = GTK_COMBO(combo)->entry; l_display_y = gtk_label_new(GetString(STR_DISPLAY_Y_CTRL)); gtk_widget_show(l_display_y); gtk_table_attach(GTK_TABLE(table), l_display_y, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); combo = gtk_combo_new(); gtk_widget_show(combo); GList *glist2 = NULL; glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_384_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_480_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_600_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_768_LAB)); glist2 = g_list_append(glist2, (void *)GetString(STR_SIZE_MAX_LAB)); gtk_combo_set_popdown_strings(GTK_COMBO(combo), glist2); if (dis_height) sprintf(str, "%d", dis_height); else strcpy(str, GetString(STR_SIZE_MAX_LAB)); gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), str); gtk_table_attach(GTK_TABLE(table), combo, 1, 2, 3, 4, (GtkAttachOptions)GTK_FILL, (GtkAttachOptions)0, 4, 4); w_display_y = GTK_COMBO(combo)->entry; #ifdef SHEEPSHAVER make_checkbox(box, STR_GFXACCEL_CTRL, "gfxaccel", GTK_SIGNAL_FUNC(tb_gfxaccel)); #endif make_separator(box); make_checkbox(box, STR_NOSOUND_CTRL, "nosound", GTK_SIGNAL_FUNC(tb_nosound)); set_graphics_sensitive(); hide_show_graphics_widgets(); } /* * "Input" pane */ static GtkWidget *w_keycode_file; static GtkWidget *w_mouse_wheel_lines; // Set sensitivity of widgets static void set_input_sensitive(void) { const bool use_keycodes = PrefsFindBool("keycodes"); gtk_widget_set_sensitive(w_keycode_file, use_keycodes); gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_keycode_file), "chooser_button")), use_keycodes); gtk_widget_set_sensitive(w_mouse_wheel_lines, PrefsFindInt32("mousewheelmode") == 1); } // "Use Raw Keycodes" button toggled static void tb_keycodes(GtkWidget *widget) { PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active); set_input_sensitive(); } // "Mouse Wheel Mode" selected static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();} static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();} // Read settings from widgets and set preferences static void read_input_settings(void) { const char *str = get_file_entry_path(w_keycode_file); if (str && strlen(str)) PrefsReplaceString("keycodefile", str); else PrefsRemoveItem("keycodefile"); PrefsReplaceInt32("mousewheellines", gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w_mouse_wheel_lines))); } // Create "Input" pane static void create_input_pane(GtkWidget *top) { GtkWidget *box, *hbox, *menu, *label, *button; GtkObject *adj; box = make_pane(top, STR_INPUT_PANE_TITLE); make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes)); hbox = gtk_hbox_new(FALSE, 4); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); label = gtk_label_new(GetString(STR_KEYCODES_CTRL)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); const char *str = PrefsFindString("keycodefile"); if (str == NULL) str = ""; w_keycode_file = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(w_keycode_file), str); gtk_widget_show(w_keycode_file); gtk_box_pack_start(GTK_BOX(hbox), w_keycode_file, TRUE, TRUE, 0); button = make_browse_button(w_keycode_file); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button); make_separator(box); static const opt_desc options[] = { {STR_MOUSEWHEELMODE_PAGE_LAB, GTK_SIGNAL_FUNC(mn_wheel_page)}, {STR_MOUSEWHEELMODE_CURSOR_LAB, GTK_SIGNAL_FUNC(mn_wheel_cursor)}, {0, NULL} }; int wheelmode = PrefsFindInt32("mousewheelmode"), active = 0; switch (wheelmode) { case 0: active = 0; break; case 1: active = 1; break; } menu = make_option_menu(box, STR_MOUSEWHEELMODE_CTRL, options, active); hbox = gtk_hbox_new(FALSE, 4); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0); label = gtk_label_new(GetString(STR_MOUSEWHEELLINES_CTRL)); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); adj = gtk_adjustment_new(PrefsFindInt32("mousewheellines"), 1, 1000, 1, 5, 0); w_mouse_wheel_lines = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.0, 0); gtk_widget_show(w_mouse_wheel_lines); gtk_box_pack_start(GTK_BOX(hbox), w_mouse_wheel_lines, FALSE, FALSE, 0); set_input_sensitive(); } /* * "Serial" pane */ static GtkWidget *w_seriala, *w_portfile0; static GtkWidget *w_serialb, *w_portfile1; // Set sensitivity of widgets static void set_serial_sensitive(void) { const char *str; bool is_file; str = gtk_entry_get_text(GTK_ENTRY(w_seriala)); is_file = strcmp(str, "FILE") == 0; gtk_widget_set_sensitive(w_portfile0, is_file); gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile0), "chooser_button")), is_file); str = gtk_entry_get_text(GTK_ENTRY(w_serialb)); is_file = strcmp(str, "FILE") == 0; gtk_widget_set_sensitive(w_portfile1, is_file); gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(w_portfile1), "chooser_button")), is_file); } // Read settings from widgets and set preferences static void read_serial_settings(void) { const char *str; str = gtk_entry_get_text(GTK_ENTRY(w_seriala)); PrefsReplaceString("seriala", str); str = gtk_entry_get_text(GTK_ENTRY(w_serialb)); PrefsReplaceString("serialb", str); str = gtk_entry_get_text(GTK_ENTRY(w_portfile0)); PrefsReplaceString("portfile0", str); str = gtk_entry_get_text(GTK_ENTRY(w_portfile1)); PrefsReplaceString("portfile1", str); } // Port changed in combo static void cb_serial_port_changed(...) { set_serial_sensitive(); } // Add names of serial devices static GList *add_serial_names(void) { GList *glist = NULL; static const char *port_names[] = { "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "FILE", NULL }; for (int i = 0; port_names[i] != NULL; i++) glist = g_list_append(glist, (void *)port_names[i]); return glist; } // Create "Serial" pane static void create_serial_pane(GtkWidget *top) { GtkWidget *box, *hbox, *table, *label, *combo, *sep, *entry; GtkObject *adj; box = make_pane(top, STR_SERIAL_PANE_TITLE); table = make_table(box, 2, 5); GList *glist = add_serial_names(); const char *str = PrefsFindString("seriala"); combo = table_make_combobox(table, 0, STR_SERIALA_CTRL, str, glist); w_seriala = GTK_COMBO(combo)->entry; gtk_signal_connect(GTK_OBJECT(w_seriala), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL); w_portfile0 = table_make_file_entry(table, 1, STR_FILE_CTRL, "portfile0"); sep = gtk_hseparator_new(); gtk_widget_show(sep); gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); str = PrefsFindString("serialb"); combo = table_make_combobox(table, 3, STR_SERIALB_CTRL, str, glist); w_serialb = GTK_COMBO(combo)->entry; gtk_signal_connect(GTK_OBJECT(w_serialb), "changed", GTK_SIGNAL_FUNC(cb_serial_port_changed), NULL); w_portfile1 = table_make_file_entry(table, 4, STR_FILE_CTRL, "portfile1"); set_serial_sensitive(); } /* * "Ethernet" pane */ static GtkWidget *w_ftp_port_list, *w_tcp_port_list; // Set sensitivity of widgets static void set_ethernet_sensitive(void) { const char *str = PrefsFindString("ether"); bool is_router = str && strcmp(str, "router") == 0; gtk_widget_set_sensitive(w_ftp_port_list, is_router); gtk_widget_set_sensitive(w_tcp_port_list, is_router); } // Read settings from widgets and set preferences static void read_ethernet_settings(void) { const char *str = PrefsFindString("ether"); bool is_router = str && strcmp(str, "router") == 0; if (is_router) { str = gtk_entry_get_text(GTK_ENTRY(w_ftp_port_list)); PrefsReplaceString("ftp_port_list", str); str = gtk_entry_get_text(GTK_ENTRY(w_tcp_port_list)); PrefsReplaceString("tcp_port", str); } } // Ethernet emulation type changed in menulist static void cb_ether_changed(...) { set_ethernet_sensitive(); } // Ethernet option "None" selected static void mn_ether_none(void) { PrefsRemoveItem("ether"); PrefsRemoveItem("etherguid"); } // Ethernet option "Basilisk II Router" selected static void mn_ether_router(void) { PrefsReplaceString("ether", "router"); PrefsRemoveItem("etherguid"); } // Ethernet option "Basilisk II Slirp" selected static void mn_ether_slirp(void) { PrefsReplaceString("ether", "slirp"); PrefsRemoveItem("etherguid"); } // Ethernet option for Basilisk II driver selected static void mn_ether_b2ether(GtkWidget *, const char *guid) { PrefsReplaceString("ether", "b2ether"); PrefsReplaceString("etherguid", guid); } // Ethernet option for Basilisk II driver selected static void mn_ether_tap(GtkWidget *, const char *guid) { PrefsReplaceString("ether", "tap"); PrefsReplaceString("etherguid", guid); } // Create ethernet interfaces menu static int create_ether_menu(GtkWidget *menu) { int active = -1; int n_items = 0; const char *ether = PrefsFindString("ether"); const char *etherguid = PrefsFindString("etherguid"); // No Ethernet add_menu_item(menu, STR_NONE_LAB, (GtkSignalFunc)mn_ether_none); if (ether == NULL) active = n_items; n_items++; // Basilisk II Router add_menu_item(menu, "Basilisk II Router", (GtkSignalFunc)mn_ether_router); if (ether && strcmp(ether, "router") == 0) active = n_items; n_items++; // Basilisk II Slirp add_menu_item(menu, "Basilisk II Slirp", (GtkSignalFunc)mn_ether_slirp); if (ether && strcmp(ether, "slirp") == 0) active = n_items; n_items++; // Basilisk II Ethernet Adapter PacketOpenAdapter("", 0); { ULONG sz; char names[1024]; sz = sizeof(names); if (PacketGetAdapterNames(NULL, names, &sz) == ERROR_SUCCESS) { char *p = names; while (*p) { const char DEVICE_HEADER[] = "\\Device\\B2ether_"; if (strnicmp(p, DEVICE_HEADER, sizeof(DEVICE_HEADER) - 1) == 0) { LPADAPTER fd = PacketOpenAdapter(p + sizeof(DEVICE_HEADER) - 1, 0); if (fd) { char guid[256]; sprintf(guid, "%s", p + sizeof(DEVICE_HEADER) - 1); const char *name = ether_guid_to_name(guid); if (name && (name = g_locale_to_utf8(name, -1, NULL, NULL, NULL))) { add_menu_item(menu, name, (GtkSignalFunc)mn_ether_b2ether, strdup(guid)); if (etherguid && strcmp(guid, etherguid) == 0 && ether && strcmp(ether, "b2ether") == 0) active = n_items; n_items++; } PacketCloseAdapter(fd); } } p += strlen(p) + 1; } } } PacketCloseAdapter(NULL); // TAP-Win32 const char *tap_devices; if ((tap_devices = ether_tap_devices()) != NULL) { const char *guid = tap_devices; while (*guid) { const char *name = ether_guid_to_name(guid); if (name && (name = g_locale_to_utf8(name, -1, NULL, NULL, NULL))) { add_menu_item(menu, name, (GtkSignalFunc)mn_ether_tap, strdup(guid)); if (etherguid && strcmp(guid, etherguid) == 0 && ether && strcmp(ether, "tap") == 0) active = n_items; n_items++; } guid += strlen(guid) + 1; } free((char *)tap_devices); } return active; } // Create "Ethernet" pane static void create_ethernet_pane(GtkWidget *top) { GtkWidget *box, *hbox, *table, *label, *sep, *entry, *opt, *menu, *item; box = make_pane(top, STR_NETWORK_PANE_TITLE); table = make_table(box, 2, 5); label = gtk_label_new(GetString(STR_ETHERNET_IF_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); opt = gtk_option_menu_new(); gtk_widget_show(opt); menu = gtk_menu_new(); int active = create_ether_menu(menu); if (active >= 0) gtk_menu_set_active(GTK_MENU(menu), active); gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); gtk_table_attach(GTK_TABLE(table), opt, 1, 2, 0, 1, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); gtk_signal_connect(GTK_OBJECT(opt), "changed", GTK_SIGNAL_FUNC(cb_ether_changed), NULL); sep = gtk_hseparator_new(); gtk_widget_show(sep); gtk_table_attach(GTK_TABLE(table), sep, 0, 2, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); label = gtk_label_new(GetString(STR_ETHER_FTP_PORT_LIST_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); entry = gtk_entry_new(); const char *str = PrefsFindString("ftp_port_list"); if (str == NULL) str = ""; gtk_entry_set_text(GTK_ENTRY(entry), str); gtk_widget_show(entry); gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 2, 3, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); w_ftp_port_list = entry; label = gtk_label_new(GetString(STR_ETHER_TCP_PORT_LIST_CTRL)); gtk_widget_show(label); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, (GtkAttachOptions)0, (GtkAttachOptions)0, 4, 4); entry = gtk_entry_new(); str = PrefsFindString("tcp_port"); if (str == NULL) str = ""; gtk_entry_set_text(GTK_ENTRY(entry), str); gtk_widget_show(entry); gtk_table_attach(GTK_TABLE(table), entry, 1, 2, 3, 4, (GtkAttachOptions)(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 4, 4); w_tcp_port_list = entry; set_ethernet_sensitive(); } /* * "Memory/Misc" pane */ static GtkWidget *w_ramsize; static GtkWidget *w_rom_file; // Don't use CPU when idle? static void tb_idlewait(GtkWidget *widget) { PrefsReplaceBool("idlewait", GTK_TOGGLE_BUTTON(widget)->active); } // "Ignore SEGV" button toggled #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION static void tb_ignoresegv(GtkWidget *widget) { PrefsReplaceBool("ignoresegv", GTK_TOGGLE_BUTTON(widget)->active); } #endif // Model ID selected static void mn_modelid_5(...) {PrefsReplaceInt32("modelid", 5);} static void mn_modelid_14(...) {PrefsReplaceInt32("modelid", 14);} // CPU/FPU type static void mn_cpu_68020(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", false);} static void mn_cpu_68020_fpu(...) {PrefsReplaceInt32("cpu", 2); PrefsReplaceBool("fpu", true);} static void mn_cpu_68030(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", false);} static void mn_cpu_68030_fpu(...) {PrefsReplaceInt32("cpu", 3); PrefsReplaceBool("fpu", true);} static void mn_cpu_68040(...) {PrefsReplaceInt32("cpu", 4); PrefsReplaceBool("fpu", true);} // Read settings from widgets and set preferences static void read_memory_settings(void) { const char *str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(w_ramsize)->entry)); PrefsReplaceInt32("ramsize", atoi(str) << 20); str = get_file_entry_path(w_rom_file); if (str && strlen(str)) PrefsReplaceString("rom", str); else PrefsRemoveItem("rom"); } // Create "Memory/Misc" pane static void create_memory_pane(GtkWidget *top) { GtkWidget *box, *hbox, *table, *label, *scale, *menu; box = make_pane(top, STR_MEMORY_MISC_PANE_TITLE); table = make_table(box, 2, 5); static const combo_desc options[] = { #ifndef SHEEPSHAVER STR_RAMSIZE_2MB_LAB, #endif STR_RAMSIZE_4MB_LAB, STR_RAMSIZE_8MB_LAB, STR_RAMSIZE_16MB_LAB, STR_RAMSIZE_32MB_LAB, STR_RAMSIZE_64MB_LAB, STR_RAMSIZE_128MB_LAB, STR_RAMSIZE_256MB_LAB, STR_RAMSIZE_512MB_LAB, STR_RAMSIZE_1024MB_LAB, 0 }; char default_ramsize[16]; sprintf(default_ramsize, "%d", PrefsFindInt32("ramsize") >> 20); w_ramsize = table_make_combobox(table, 0, STR_RAMSIZE_CTRL, default_ramsize, options); #ifndef SHEEPSHAVER static const opt_desc model_options[] = { {STR_MODELID_5_LAB, GTK_SIGNAL_FUNC(mn_modelid_5)}, {STR_MODELID_14_LAB, GTK_SIGNAL_FUNC(mn_modelid_14)}, {0, NULL} }; int modelid = PrefsFindInt32("modelid"), active = 0; switch (modelid) { case 5: active = 0; break; case 14: active = 1; break; } table_make_option_menu(table, 2, STR_MODELID_CTRL, model_options, active); #endif #if EMULATED_68K static const opt_desc cpu_options[] = { {STR_CPU_68020_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020)}, {STR_CPU_68020_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68020_fpu)}, {STR_CPU_68030_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030)}, {STR_CPU_68030_FPU_LAB, GTK_SIGNAL_FUNC(mn_cpu_68030_fpu)}, {STR_CPU_68040_LAB, GTK_SIGNAL_FUNC(mn_cpu_68040)}, {0, NULL} }; int cpu = PrefsFindInt32("cpu"); bool fpu = PrefsFindBool("fpu"); active = 0; switch (cpu) { case 2: active = fpu ? 1 : 0; break; case 3: active = fpu ? 3 : 2; break; case 4: active = 4; } table_make_option_menu(table, 3, STR_CPU_CTRL, cpu_options, active); #endif w_rom_file = table_make_file_entry(table, 4, STR_ROM_FILE_CTRL, "rom"); make_checkbox(box, STR_IDLEWAIT_CTRL, "idlewait", GTK_SIGNAL_FUNC(tb_idlewait)); #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION make_checkbox(box, STR_IGNORESEGV_CTRL, "ignoresegv", GTK_SIGNAL_FUNC(tb_ignoresegv)); #endif } /* * Read settings from widgets and set preferences */ static void read_settings(void) { read_volumes_settings(); read_scsi_settings(); read_graphics_settings(); read_input_settings(); read_serial_settings(); read_ethernet_settings(); read_memory_settings(); read_jit_settings(); } /* * Fake unused data and functions */ uint8 XPRAM[XPRAM_SIZE]; void MountVolume(void *fh) { } void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { } void recycle_write_packet(LPPACKET) { } VOID CALLBACK packet_read_completion(DWORD, DWORD, LPOVERLAPPED) { } /* * Add default serial prefs (must be added, even if no ports present) */ void SysAddSerialPrefs(void) { PrefsAddString("seriala", "COM1"); PrefsAddString("serialb", "COM2"); } /* * Display alerts */ static void display_alert(int title_id, const char *text, int flags) { MessageBox(NULL, text, GetString(title_id), MB_OK | flags); } void ErrorAlert(const char *text) { display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP); } void WarningAlert(const char *text) { display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONSTOP); } /* * Start standalone GUI */ int main(int argc, char *argv[]) { // Init GTK gtk_set_locale(); gtk_init(&argc, &argv); // Read preferences PrefsInit(NULL, argc, argv); // Migrate preferences PrefsMigrate(); // Show preferences editor bool start = PrefsEditor(); // Exit preferences PrefsExit(); // Transfer control to the executable if (start) { char path[_MAX_PATH]; bool ok = GetModuleFileName(NULL, path, sizeof(path)) != 0; if (ok) { char b2_path[_MAX_PATH]; char *p = strrchr(path, '\\'); *++p = '\0'; SetCurrentDirectory(path); strcpy(b2_path, path); strcat(b2_path, PROGRAM_NAME); strcat(b2_path, ".exe"); HINSTANCE h = ShellExecute(GetDesktopWindow(), "open", b2_path, "", path, SW_SHOWNORMAL); if ((int)h <= 32) ok = false; } if (!ok) { ErrorAlert("Coult not start " PROGRAM_NAME " executable"); return 1; } } return 0; } BasiliskII/src/Windows/posix_emu.cpp0000755000175000017500000011211310736405221017700 0ustar centriscentris/* * posix_emu.cpp -- posix and virtual desktop * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ // TODO: UNC names. Customizable "Virtual Desktop" location. #include "sysdeps.h" #define NO_POSIX_API_HOOK #include "posix_emu.h" #include "user_strings.h" #include "util_windows.h" #include "main.h" #include "extfs_defs.h" #include "prefs.h" #include #define DEBUG_EXTFS 0 #if DEBUG_EXTFS // This must be always on. #define DEBUG 1 #undef OutputDebugString #define OutputDebugString extfs_log_write extern void extfs_log_write( char *s ); #define EXTFS_LOG_FILE_NAME "extfs.log" #include "debug.h" enum { DB_EXTFS_NONE=0, DB_EXTFS_NORMAL, DB_EXTFS_LOUD }; static int16 debug_extfs = DB_EXTFS_NONE; static HANDLE extfs_log_file = INVALID_HANDLE_VALUE; static void extfs_log_open( char *path ) { if(debug_extfs == DB_EXTFS_NONE) return; DeleteFile( path ); extfs_log_file = CreateFile( path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, // FILE_FLAG_WRITE_THROUGH|FILE_FLAG_NO_BUFFERING, FILE_FLAG_WRITE_THROUGH, NULL ); if( extfs_log_file == INVALID_HANDLE_VALUE ) { ErrorAlert( "Could not create the EXTFS log file." ); } } static void extfs_log_close( void ) { if(debug_extfs == DB_EXTFS_NONE) return; if( extfs_log_file != INVALID_HANDLE_VALUE ) { CloseHandle( extfs_log_file ); extfs_log_file = INVALID_HANDLE_VALUE; } } static void extfs_log_write( char *s ) { DWORD bytes_written; // should have been checked already. if(debug_extfs == DB_EXTFS_NONE) return; if( extfs_log_file != INVALID_HANDLE_VALUE ) { DWORD count = strlen(s); if (0 == WriteFile(extfs_log_file, s, count, &bytes_written, NULL) || (int)bytes_written != count) { extfs_log_close(); ErrorAlert( "extfs log file write error (out of disk space?). Log closed." ); } else { FlushFileBuffers( extfs_log_file ); } } } #else #define DEBUG 0 #include "debug.h" #endif // DEBUG_EXTFS int my_errno = 0; #define VIRTUAL_ROOT_ID ((HANDLE)0xFFFFFFFE) static const char *desktop_name = "Virtual Desktop"; static const char *custom_icon_name = "Icon\r"; #define my_computer GetString(STR_EXTFS_VOLUME_NAME) static char lb1[MAX_PATH_LENGTH]; static char lb2[MAX_PATH_LENGTH]; #define MRP(path) translate(path,lb1) #define MRP2(path) translate(path,lb2) #define DISABLE_ERRORS UINT prevmode = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS) #define RESTORE_ERRORS SetErrorMode(prevmode); static char host_drive_list[512]; static char virtual_root[248]; // Not _MAX_PATH const uint8 my_comp_icon[2670] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0xD8, 0x00, 0x00, 0x08, 0xD8, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x79, 0x79, 0x79, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xC0, 0xCC, 0xCC, 0xCC, 0xCC, 0xD7, 0x97, 0x97, 0x97, 0x97, 0x97, 0xC0, 0xC0, 0xC0, 0xC0, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD, 0xDB, 0xD9, 0x79, 0x79, 0x7E, 0x79, 0x0C, 0xDD, 0xCD, 0xDD, 0xCD, 0xCD, 0xDC, 0xDD, 0xCD, 0xCC, 0xED, 0xED, 0x97, 0x97, 0x97, 0x97, 0x0C, 0xE7, 0x78, 0x77, 0x97, 0x97, 0x97, 0x97, 0x97, 0xDC, 0xED, 0xDE, 0x79, 0x79, 0x79, 0x99, 0x0C, 0xD9, 0x7E, 0x5E, 0x65, 0x5E, 0x65, 0xD9, 0x79, 0xCD, 0xDE, 0xDD, 0x97, 0xE7, 0x9E, 0x77, 0xC0, 0x97, 0x9D, 0xCD, 0xCC, 0xC7, 0xCC, 0xE7, 0x97, 0xCC, 0xED, 0xEE, 0x79, 0x79, 0x79, 0x7E, 0xCC, 0x57, 0xD5, 0xD7, 0xD5, 0xDD, 0x5D, 0xD9, 0x7E, 0xCD, 0xDE, 0xDE, 0x79, 0x97, 0x97, 0x99, 0x0C, 0x87, 0xCD, 0x75, 0xC7, 0x5C, 0x7D, 0xD9, 0x79, 0xCD, 0xDD, 0xED, 0xE7, 0x7E, 0x79, 0x77, 0xCC, 0xE7, 0xB0, 0x00, 0xC0, 0x0C, 0xCD, 0xE7, 0x97, 0xDC, 0xED, 0xEE, 0x79, 0x97, 0x86, 0x79, 0xC0, 0xE7, 0xD0, 0x2C, 0xC1, 0xC2, 0xCD, 0xD9, 0x79, 0xCD, 0xDE, 0xDD, 0x97, 0x99, 0x79, 0x97, 0x0C, 0xE7, 0xB0, 0xD0, 0xDC, 0xCC, 0xCD, 0xD6, 0x87, 0xDD, 0xDE, 0xED, 0x79, 0x77, 0xE7, 0x79, 0x0C, 0x58, 0xDC, 0x0C, 0x0C, 0xCC, 0xCD, 0xE9, 0x79, 0xCD, 0xDD, 0xD5, 0x99, 0x97, 0x99, 0x79, 0xC0, 0x87, 0xD0, 0xC0, 0xC0, 0xC0, 0xCD, 0xD7, 0xE7, 0xDD, 0xDE, 0xD7, 0x97, 0x79, 0x77, 0xE7, 0x0C, 0xE7, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x79, 0x79, 0xCD, 0xDE, 0xD9, 0x79, 0x97, 0xE9, 0x79, 0x0C, 0x97, 0x79, 0x79, 0x79, 0x79, 0x79, 0x97, 0x97, 0xDC, 0xED, 0xE7, 0x97, 0x79, 0x97, 0x97, 0x0C, 0xCD, 0xD7, 0xD7, 0xD7, 0xE7, 0xE7, 0x7E, 0x79, 0xCD, 0xDE, 0x79, 0x79, 0x97, 0x7E, 0x79, 0xC0, 0xCC, 0xCC, 0x0C, 0xCC, 0x0D, 0xCC, 0xDC, 0xDC, 0xDC, 0xED, 0x97, 0x97, 0x77, 0x99, 0x79, 0xCC, 0xCC, 0xCC, 0xDC, 0xCC, 0xDC, 0xCC, 0xCC, 0x8D, 0xCD, 0xDE, 0x79, 0x79, 0x96, 0x77, 0x97, 0x97, 0x97, 0x90, 0xCC, 0xCD, 0xCD, 0xDD, 0xDD, 0xCC, 0xDD, 0xD9, 0x76, 0x87, 0x97, 0x99, 0x7E, 0x7C, 0x0C, 0xCC, 0xDD, 0xDD, 0xED, 0xDE, 0xDD, 0xEE, 0xDE, 0xD5, 0xBD, 0xDE, 0x79, 0x79, 0x9C, 0xC0, 0xCC, 0xDD, 0xDD, 0xDD, 0xDE, 0xDD, 0xED, 0xDE, 0xDE, 0xDD, 0xDE, 0xDE, 0x79, 0x79, 0x70, 0xCD, 0xCC, 0xCC, 0xCC, 0xCC, 0xDC, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xED, 0xED, 0x97, 0x97, 0x90, 0xCC, 0x8D, 0xCC, 0xDC, 0xCD, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xEE, 0xDE, 0xDE, 0x79, 0x7E, 0x70, 0xCC, 0x88, 0xDC, 0xCC, 0xCC, 0xCD, 0xDD, 0xDD, 0xDC, 0xCD, 0xDD, 0xED, 0xED, 0x97, 0x97, 0xEC, 0xCC, 0xCC, 0xCC, 0xDC, 0xCC, 0xCD, 0xDD, 0xED, 0xDD, 0xDC, 0xED, 0xED, 0xEE, 0x79, 0x79, 0xDC, 0x0D, 0xCC, 0xDC, 0xCC, 0xCD, 0xCC, 0xCC, 0xCC, 0x0C, 0xDC, 0xDE, 0xDE, 0xED, 0x97, 0xDC, 0xCC, 0xDC, 0xCD, 0xCC, 0xDC, 0xCD, 0xCC, 0xCC, 0xCD, 0xCC, 0xCC, 0xED, 0xED, 0x79, 0xDD, 0xC0, 0xCD, 0xCC, 0xDC, 0xCD, 0xCC, 0xDC, 0xCC, 0xDC, 0xDD, 0xCD, 0xCD, 0xED, 0x97, 0x97, 0xDD, 0xCC, 0xCC, 0x00, 0xC0, 0xDD, 0xCD, 0xCC, 0xCC, 0xCD, 0xD0, 0xDC, 0xDD, 0xF7, 0x99, 0x79, 0x97, 0x9D, 0xDD, 0xDD, 0xCC, 0xC0, 0xCC, 0x0C, 0xDC, 0xDC, 0xCD, 0xCD, 0xDF, 0x79, 0x77, 0x97, 0x79, 0x79, 0x79, 0x79, 0xDD, 0xDE, 0xDC, 0xCC, 0xCC, 0xC0, 0xC0, 0xDD, 0xE9, 0x79, 0x97, 0x99, 0x97, 0xE7, 0xE7, 0x97, 0x97, 0x9D, 0x79, 0xDD, 0xDD, 0xDD, 0xCD, 0xDE, 0x79, 0x79, 0x7E, 0x77, 0x00, 0x00, 0x04, 0x00, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF9, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF7, 0xF7, 0xF7, 0xF7, 0xF8, 0x81, 0xFA, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0xF7, 0xF8, 0x81, 0x81, 0x81, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0xF8, 0x81, 0xFA, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xC2, 0xFB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xFB, 0xC2, 0xC2, 0xC2, 0xF7, 0xF8, 0x81, 0x81, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0x2B, 0xA5, 0xC2, 0xC2, 0xFB, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x81, 0xC2, 0xC2, 0xC2, 0xF7, 0xF8, 0x81, 0x81, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0x2B, 0xA5, 0xC2, 0xF9, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF9, 0xFB, 0xC2, 0xC2, 0xC2, 0xF7, 0xF8, 0x81, 0x81, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xF9, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xF9, 0x81, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0xFA, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xF9, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0xF9, 0xFB, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0x81, 0x81, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xF9, 0xF5, 0x0A, 0xF6, 0x2B, 0x0A, 0xF6, 0x0A, 0x2B, 0xF9, 0x81, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0x81, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xF9, 0xF5, 0xF8, 0xF6, 0x56, 0xF7, 0xF7, 0xF8, 0x2B, 0xF9, 0x81, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0x81, 0x81, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xF9, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0x2B, 0xF9, 0xFB, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0xFA, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xF9, 0xF6, 0xF6, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0x2B, 0xF9, 0x81, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0x81, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xA5, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0x81, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7, 0x56, 0xF8, 0x7A, 0x7A, 0x9E, 0x9E, 0x9E, 0x9E, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0x56, 0x81, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0x56, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0x56, 0xB9, 0xF8, 0xF8, 0x56, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0x2B, 0x2B, 0xF7, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0xF8, 0xF8, 0x56, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xF6, 0xF6, 0x2B, 0xF8, 0x56, 0xFA, 0xF9, 0x81, 0x81, 0x81, 0xFA, 0x81, 0x81, 0x81, 0xFB, 0x81, 0xFB, 0xFB, 0xFB, 0x81, 0xFA, 0xFA, 0xFA, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xF6, 0xF6, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFB, 0x81, 0xFB, 0xF9, 0xFA, 0xFA, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7, 0xF8, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF8, 0xF8, 0x56, 0x56, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0x81, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7, 0x93, 0xA0, 0xF7, 0xF7, 0xF8, 0xF7, 0xF7, 0xF8, 0xF7, 0xF7, 0xF7, 0xF7, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x81, 0xFB, 0x81, 0xFB, 0xFB, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7, 0xA0, 0xA0, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0x56, 0x56, 0xF9, 0xF9, 0xF9, 0xF8, 0xF7, 0xF7, 0xF7, 0xFB, 0xFB, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF5, 0x2B, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF9, 0xF9, 0xFB, 0xFB, 0xFB, 0xF8, 0xF9, 0xF9, 0xF7, 0x81, 0xFB, 0xFB, 0x81, 0xFB, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0x2B, 0x2B, 0x56, 0x2B, 0x2B, 0xF9, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF8, 0xF8, 0xF7, 0xFB, 0xFB, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xF8, 0xF8, 0xF6, 0xF6, 0xF9, 0xF8, 0x2B, 0xF9, 0xF8, 0x2B, 0xF9, 0x2B, 0x2B, 0xF9, 0x2B, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0x81, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xF9, 0xF8, 0xF6, 0xF6, 0xF7, 0xF9, 0xF8, 0x2B, 0xF9, 0xF8, 0xF6, 0xF9, 0xF8, 0xF6, 0xF9, 0xF8, 0xF6, 0x2B, 0xF9, 0x2B, 0xF9, 0x56, 0x2B, 0xF9, 0x2B, 0xF9, 0xAC, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xFA, 0xF9, 0xF8, 0x2B, 0x2B, 0x2B, 0xF5, 0xF5, 0xF5, 0xF5, 0xF9, 0xF8, 0xF6, 0xF9, 0xF8, 0xF6, 0x2B, 0xF8, 0x2B, 0xF9, 0x56, 0x2B, 0x56, 0x2B, 0x56, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xFA, 0xFA, 0xFA, 0xF9, 0xF8, 0xF8, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF5, 0x2B, 0xF9, 0xF6, 0xF9, 0xF8, 0xF7, 0xF9, 0x2B, 0xF9, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xFA, 0xFA, 0xFA, 0xFA, 0xF9, 0xF8, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0xF5, 0xF5, 0xF5, 0x56, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xFA, 0xF9, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, 0xF8, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0x00, 0x00, 0x01, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x02, 0x00, 0x00, 0x38, 0x02, 0xFF, 0xFF, 0x3C, 0x02, 0xFF, 0xFF, 0x3C, 0x02, 0xFF, 0xFF, 0x3C, 0x02, 0xF0, 0x0F, 0x3C, 0x02, 0xFF, 0xFF, 0x3C, 0x02, 0xFF, 0xFF, 0x7C, 0x02, 0xE0, 0x1F, 0x7C, 0x02, 0xE0, 0x1F, 0x7C, 0x02, 0xE0, 0x1F, 0x7C, 0x02, 0xE0, 0x1F, 0x7C, 0x02, 0xE0, 0x1F, 0x78, 0x02, 0xFF, 0xFF, 0x78, 0x02, 0xFF, 0xFF, 0x78, 0x02, 0x1F, 0xFF, 0x70, 0x02, 0x00, 0x00, 0x70, 0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x1F, 0xFF, 0xFF, 0x02, 0x00, 0x3F, 0xFF, 0x02, 0x40, 0x00, 0x3F, 0x02, 0xC0, 0x7C, 0x3F, 0x02, 0x00, 0x7D, 0xBF, 0x0F, 0x20, 0x00, 0x3F, 0x32, 0x49, 0x00, 0x3C, 0xC4, 0x92, 0x2D, 0x70, 0xE0, 0x24, 0x1A, 0xE0, 0x1F, 0x00, 0xA5, 0xC0, 0x00, 0xFC, 0x03, 0x80, 0x00, 0x03, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0xFC, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x06, 0x10, 0x04, 0x1F, 0xFC, 0x0F, 0xFE, 0x0F, 0xFF, 0x18, 0x67, 0x34, 0x06, 0x69, 0x64, 0x72, 0xC8, 0x3F, 0xF0, 0x1F, 0xFC, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x1F, 0xFC, 0x1F, 0xFC, 0x07, 0xFF, 0x1F, 0xFF, 0x3F, 0xFF, 0x3F, 0xFF, 0x7F, 0xFE, 0xFF, 0xFC, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x80, 0x79, 0x7C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCD, 0x97, 0x97, 0x90, 0xE7, 0x97, 0x97, 0x97, 0xDD, 0xD9, 0x79, 0x7C, 0xE7, 0xD5, 0x5E, 0x58, 0xCE, 0xD7, 0x97, 0x9C, 0xDD, 0x5D, 0x7D, 0xB7, 0xDD, 0x59, 0x79, 0x7C, 0x9D, 0x10, 0x1D, 0xD9, 0xCE, 0xD7, 0x97, 0x9C, 0xDD, 0x0C, 0xCC, 0xE7, 0xDD, 0xD9, 0x79, 0x7C, 0xED, 0xDD, 0xDD, 0x79, 0xCE, 0xE7, 0xE7, 0x90, 0xE7, 0x77, 0x97, 0x97, 0xDD, 0x79, 0x79, 0x7C, 0xCC, 0xDC, 0xCD, 0xC8, 0xDD, 0x97, 0x97, 0x99, 0x7C, 0xDD, 0xDD, 0xDE, 0xDE, 0xDE, 0x7E, 0x7C, 0xCC, 0xCC, 0xCD, 0xCD, 0xDD, 0xDE, 0x99, 0x0C, 0x8C, 0xCC, 0xCC, 0xCC, 0xCD, 0xED, 0x77, 0xCC, 0xCC, 0xCD, 0xDD, 0xED, 0xCE, 0xDE, 0x9C, 0xCD, 0xCD, 0xCD, 0x0D, 0xCC, 0xCE, 0xE7, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xCC, 0xDE, 0x99, 0x97, 0x97, 0x9D, 0xDD, 0xDD, 0xDE, 0xE9, 0x77, 0x00, 0x00, 0x01, 0x00, 0xC2, 0xC2, 0xC2, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0x2B, 0x2B, 0x2B, 0xF7, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF8, 0x81, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xC2, 0x81, 0xAA, 0xAA, 0xAA, 0xFB, 0xC2, 0xF8, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0x7F, 0x7F, 0x7F, 0x56, 0x81, 0xC2, 0xF8, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0x0A, 0xF6, 0x0A, 0x56, 0xFB, 0xC2, 0xF8, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0xF6, 0xF6, 0xF6, 0x56, 0x81, 0xC2, 0x56, 0x81, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xC2, 0xC2, 0xF8, 0x81, 0xFB, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0xA5, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0x56, 0xFA, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0x2B, 0x2B, 0x2B, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xB9, 0x56, 0x81, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF6, 0x56, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0x81, 0xFA, 0x81, 0xC2, 0xC2, 0xC2, 0xF6, 0xF6, 0xF7, 0x2B, 0x2B, 0x2B, 0xF8, 0xF8, 0xF8, 0xF9, 0xFA, 0x81, 0xFB, 0xC2, 0xC2, 0xF5, 0xF7, 0x93, 0xF7, 0xF7, 0xF7, 0xF7, 0x2B, 0x2B, 0x2B, 0x2B, 0xFB, 0x81, 0xFB, 0xC2, 0xC2, 0xF5, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF9, 0xFB, 0xFB, 0xF9, 0xF7, 0xFB, 0x81, 0xFB, 0xC2, 0xF6, 0xF8, 0xF9, 0x2B, 0xF9, 0x2B, 0xF9, 0xF6, 0xF8, 0x2B, 0xF8, 0xF7, 0xFB, 0xFB, 0xC2, 0xF9, 0xF7, 0xF9, 0xF7, 0xF9, 0xF7, 0xF9, 0x2B, 0xF9, 0x2B, 0xF8, 0x2B, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0x81, 0xAC, 0xC2, 0xC2, 0xC2, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0xD8, 0x00, 0x00, 0x08, 0xD8, 0x00, 0x00, 0x00, 0x96, 0x02, 0x1C, 0xC1, 0xC4, 0x18, 0x9C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x96, 0x00, 0x05, 0x69, 0x63, 0x6C, 0x34, 0x00, 0x00, 0x00, 0x32, 0x69, 0x63, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x3E, 0x49, 0x43, 0x4E, 0x23, 0x00, 0x00, 0x00, 0x4A, 0x69, 0x63, 0x73, 0x23, 0x00, 0x00, 0x00, 0x56, 0x69, 0x63, 0x73, 0x34, 0x00, 0x00, 0x00, 0x62, 0x69, 0x63, 0x73, 0x38, 0x00, 0x00, 0x00, 0x6E, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xE2, 0x10, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x04, 0x02, 0x1C, 0xE1, 0xAC, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x06, 0x08, 0x02, 0x1C, 0xE1, 0xA4, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0x0C, 0x02, 0x1C, 0xE1, 0xF8, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0x50, 0x02, 0x1C, 0xE1, 0xDC, 0xBF, 0xB9, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xD4, 0x02, 0x1C, 0xE1, 0xD0 }; static bool use_streams[ 'Z'-'A'+1 ]; static bool is_ntfs_volume( char *rootdir ) { bool ret = false; char tst_file[_MAX_PATH], tst_stream[_MAX_PATH]; sprintf( tst_file, "%sb2query.tmp", rootdir ); sprintf( tst_stream, "%s:AFP_AfpInfo", tst_file ); if(!exists(tst_file)) { if(create_file( tst_file, 0 )) { if(create_file( tst_stream, 0 )) { ret = true; } DeleteFile( tst_file ); } } return ret; } // !!UNC void init_posix_emu(void) { if(!validate_stat_struct) { ErrorAlert( "Invalid struct my_stat -- edit posix_emu.h" ); QuitEmulator(); } #if DEBUG_EXTFS debug_extfs = PrefsFindInt16("debugextfs"); debug_extfs = DB_EXTFS_LOUD; if(debug_extfs != DB_EXTFS_NONE) { extfs_log_open( EXTFS_LOG_FILE_NAME ); } #endif // We cannot use ExtFS "RootPath" because of the virtual desktop. if(PrefsFindBool("enableextfs")) { PrefsReplaceString("extfs", ""); } else { PrefsRemoveItem("extfs"); D(bug("extfs disabled by user\n")); #if DEBUG_EXTFS extfs_log_close(); #endif return; } const char *extdrives = PrefsFindString("extdrives"); // Set up drive list. int outinx = 0; for( char letter = 'A'; letter <= 'Z'; letter++ ) { if(extdrives && !strchr(extdrives,letter)) continue; int i = (int)( letter - 'A' ); char rootdir[20]; wsprintf( rootdir, "%c:\\", letter ); use_streams[ letter - 'A' ] = false; switch(GetDriveType(rootdir)) { case DRIVE_FIXED: case DRIVE_REMOTE: case DRIVE_RAMDISK: // TODO: NTFS AFP? // fall case DRIVE_REMOVABLE: case DRIVE_CDROM: if(outinx < sizeof(host_drive_list)) { host_drive_list[outinx] = letter; outinx += 2; } } } // Set up virtual desktop root. // TODO: this should be customizable. GetModuleFileName( NULL, virtual_root, sizeof(virtual_root) ); char *p = strrchr( virtual_root, '\\' ); if(p) { *(++p) = 0; strcat( virtual_root, desktop_name ); } else { // should never happen sprintf( virtual_root, "C:\\%s", desktop_name ); } CreateDirectory( virtual_root, 0 ); // Set up an icon looking like "My Computer" // Can be overwritten just like any other folder custom icon. if(my_access(custom_icon_name,0) != 0) { int fd = my_creat( custom_icon_name, 0 ); if(fd >= 0) { my_close(fd); fd = open_rfork( custom_icon_name, O_RDWR|O_CREAT ); if(fd >= 0) { my_write( fd, my_comp_icon, sizeof(my_comp_icon) ); my_close(fd); static uint8 host_finfo[SIZEOF_FInfo]; uint32 finfo = Host2MacAddr(host_finfo); get_finfo(custom_icon_name, finfo, 0, false); WriteMacInt16(finfo + fdFlags, kIsInvisible); set_finfo(custom_icon_name, finfo, 0, false); get_finfo(my_computer, finfo, 0, true); WriteMacInt16(finfo + fdFlags, ReadMacInt16(finfo + fdFlags) | kHasCustomIcon); set_finfo(my_computer, finfo, 0, true); } else { my_remove(custom_icon_name); } } } } void final_posix_emu(void) { #if DEBUG_EXTFS extfs_log_close(); #endif } static void charset_host2mac( char *s ) { int i, len=strlen(s), code; for( i=len-3; i>=0; i-- ) { if( s[i] == '%' && isxdigit(s[i+1]) && isxdigit(s[i+2]) ) { sscanf( &s[i], "%%%02X", &code ); memmove( &s[i], &s[i+2], strlen(&s[i+2])+1 ); s[i] = code; } } } static void charset_mac2host( char *s ) { int i, convert, len = strlen(s); D(bug("charset_mac2host(%s)...\n", s)); for( i=len-1; i>=0; i-- ) { convert = 0; switch( (unsigned char)s[i] ) { // case '\r': // handled by "default" // case '\n': // case '\t': case '/': // case '\\': // Backslash is tricky -- "s" is a full path! // case ':': case '*': case '?': case '"': case '<': case '>': case '|': case '%': convert = 1; break; default: if((unsigned char)s[i] < ' ') convert = 1; break; } if(convert) { char sml[10]; sprintf( sml, "%%%02X", s[i] ); memmove( &s[i+2], &s[i], strlen(&s[i])+1 ); memmove( &s[i], sml, 3 ); } } D(bug("charset_mac2host = %s\n", s)); } static void make_mask( char *mask, const char *dir, const char *a1, const char *a2 ) { strcpy( mask, dir ); int len = strlen(mask); if( len && mask[len-1] != '\\' ) strcat( mask, "\\" ); if( a1 ) strcat( mask, a1 ); if( a2 ) strcat( mask, a2 ); } // !!UNC static char *translate( const char *path, char *buffer ) { char *l = host_drive_list; char *p = (char *)path; while(*l) { if(toupper(p[1]) == toupper(*l)) break; l += strlen(l) + 1; } if(p[0] == '\\' && *l && (p[2] == 0 || p[2] == ':' || p[2] == '\\')) { p += 2; if(*p == ':') p++; if(*p == '\\') p++; sprintf( buffer, "%c:\\%s", *l, p ); } else { if(*path == '\\') { sprintf( buffer, "%s%s", virtual_root, path ); } else { int len = strlen(path); if(len == 0 || path[len-1] == '\\') { make_mask( buffer, virtual_root, path, my_computer ); } else { make_mask( buffer, virtual_root, path, 0 ); } } } charset_mac2host( buffer ); return buffer; } // helpers static void strip_trailing_bs( char *path ) { int len = strlen(path); if(len > 0 && path[len-1] == '\\') path[len-1] = 0; } #if 0 /* defined is util_windows.cpp */ static int exists( const char *p ) { WIN32_FIND_DATA fdata; int result = 0; HANDLE h = FindFirstFile( p, &fdata ); if(h != INVALID_HANDLE_VALUE) { result = 1; FindClose( h ); } D(bug("exists(%s) = %d\n", p, result)); return result; } #endif static int is_dir( char *p ) { WIN32_FIND_DATA fdata; int result = 0; HANDLE h = FindFirstFile( p, &fdata ); if(h != INVALID_HANDLE_VALUE) { result = (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; FindClose( h ); } return result; } static int myRemoveDirectory( const char *source ) { HANDLE fh; WIN32_FIND_DATA FindFileData; int ok, result = 1; char mask[_MAX_PATH]; D(bug("removing folder %s\n", source)); make_mask( mask, source, "*.*", 0 ); fh = FindFirstFile( mask, &FindFileData ); ok = fh != INVALID_HANDLE_VALUE; while(ok) { make_mask( mask, source, FindFileData.cFileName, 0 ); D(bug("removing item %s\n", mask)); int isdir = (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; if(isdir) { // must delete ".finf", ".rsrc" but not ".", ".." if(strcmp(FindFileData.cFileName,".") && strcmp(FindFileData.cFileName,"..")) { result = myRemoveDirectory( mask ); if(!result) break; } } else { D(bug("DeleteFile %s\n", mask)); result = DeleteFile( mask ); if(!result) break; } ok = FindNextFile( fh, &FindFileData ); } if(fh != INVALID_HANDLE_VALUE) FindClose( fh ); if(result) { D(bug("RemoveDirectory %s\n", source)); result = RemoveDirectory( source ); } return result; } static void make_folders( char *path ) { char local_path[_MAX_PATH], *p; strcpy( local_path, path ); p = strrchr( local_path, '\\' ); if(p) { *p = 0; if(strlen(local_path) > 3) { make_folders(local_path); mkdir(local_path); } } } // !!UNC static bool is_same_drive( char *p1, char *p2 ) { return toupper(*p1) == toupper(*p2); } // Used when the drives are known to be different. // Can't use MoveFileEx() etc because of the Win9x limitations. // It would simulate CopyFile*() -- DeleteFile*() anyway int file_move_copy( char *src, char *dst, bool delete_old ) { int result = 0; my_errno = 0; D(bug("file_copy %s -> %s\n", src, dst)); // Fail if exists -- it's up to MacOS to move things to Trash if(CopyFile(src,dst,TRUE)) { if(delete_old && !DeleteFile(src)) { result = -1; my_errno = EACCES; } } else { result = -1; if(exists(src)) my_errno = EACCES; else my_errno = ENOENT; } return result; } int file_move( char *src, char *dst ) { return file_move_copy( src, dst, true ); } int file_copy( char *src, char *dst ) { return file_move_copy( src, dst, false ); } int folder_copy( char *folder_src, char *folder_dst ) { HANDLE fh; WIN32_FIND_DATA FindFileData; int ok, result = 0; char mask[_MAX_PATH]; D(bug("copying folder %s -> \n", folder_src, folder_dst)); my_errno = 0; if(!CreateDirectory( folder_dst, 0 )) { my_errno = EACCES; return -1; } make_mask( mask, folder_src, "*.*", 0 ); fh = FindFirstFile( mask, &FindFileData ); ok = fh != INVALID_HANDLE_VALUE; while(ok) { make_mask( mask, folder_src, FindFileData.cFileName, 0 ); int isdir = (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; char target[_MAX_PATH]; make_mask( target, folder_dst, FindFileData.cFileName, 0 ); D(bug("copying item %s -> %s\n", mask, target)); if(isdir) { if(strcmp(FindFileData.cFileName,".") && strcmp(FindFileData.cFileName,"..")) { result = folder_copy( mask, target ); if(result < 0) break; } } else { result = file_copy( mask, target ); if(result < 0) break; } ok = FindNextFile( fh, &FindFileData ); } if(fh != INVALID_HANDLE_VALUE) FindClose( fh ); return result; } // dir enumeration void closedir( struct DIR *d ) { DISABLE_ERRORS; if(d) { if(d->h != INVALID_HANDLE_VALUE && d->h != VIRTUAL_ROOT_ID) { FindClose( d->h ); } delete d; } RESTORE_ERRORS; } static int make_dentry( struct DIR *d ) { int ok = 0; memset( &d->de, 0, sizeof(d->de) ); if(d->h != INVALID_HANDLE_VALUE) { if( (d->FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 && *d->FindFileData.cFileName == '.') { ok = 0; } else { strncpy( d->de.d_name, d->FindFileData.cFileName, sizeof(d->de.d_name)-1 ); d->de.d_name[sizeof(d->de.d_name)-1] = 0; charset_host2mac( d->de.d_name ); ok = 1; } } return ok; } struct dirent *readdir( struct DIR *d ) { DISABLE_ERRORS; dirent *de = 0; if(d) { if(d->h != INVALID_HANDLE_VALUE) { if(d->h == VIRTUAL_ROOT_ID) { make_dentry(d); de = &d->de; d->vname_list += strlen(d->vname_list) + 1; if(*d->vname_list) { strcpy( d->FindFileData.cFileName, d->vname_list ); d->FindFileData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; } else { // Out of static drive entries. Continue with other stuff. char mask[MAX_PATH_LENGTH]; make_mask( mask, virtual_root, "*.*", 0 ); d->h = FindFirstFile( mask, &d->FindFileData ); } } else { int done = 0; do { if(make_dentry(d)) { de = &d->de; done = 1; } if(!FindNextFile( d->h, &d->FindFileData )) { FindClose( d->h ); d->h = INVALID_HANDLE_VALUE; done = 1; } } while(!done); } } } if(de) { D(bug("readdir found %s\n", de->d_name)); } RESTORE_ERRORS; return de; } struct DIR *opendir( const char *path ) { DISABLE_ERRORS; DIR *d = new DIR; if(d) { memset( d, 0, sizeof(DIR) ); if(*path == 0) { d->vname_list = host_drive_list; if(d->vname_list) { d->h = VIRTUAL_ROOT_ID; strcpy( d->FindFileData.cFileName, d->vname_list ); d->FindFileData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; } else { d->h = INVALID_HANDLE_VALUE; } } else { char mask[MAX_PATH_LENGTH]; make_mask( mask, MRP(path), "*.*", 0 ); D(bug("opendir path=%s, mask=%s\n", path, mask)); d->h = FindFirstFile( mask, &d->FindFileData ); if(d->h == INVALID_HANDLE_VALUE) { delete d; d = 0; } } } D(bug("opendir(%s,%s) = %08x\n", path, MRP(path), d)); RESTORE_ERRORS; return d; } static void dump_stat( const struct my_stat *st ) { D(bug("stat: size = %ld, mode = %ld, a = %ld, m = %ld, c = %ld\n", st->st_size, st->st_mode, st->st_atime, st->st_mtime, st->st_ctime)); } // Exported hook functions int my_stat( const char *path, struct my_stat *st ) { DISABLE_ERRORS; int result; if(*path == 0) { /// virtual root memset( st, 0, sizeof(struct my_stat) ); st->st_mode = _S_IFDIR; result = 0; my_errno = 0; } else { result = stat( MRP(path), (struct stat *)st ); if(result < 0) { my_errno = errno; } else { my_errno = 0; } } D(bug("stat(%s,%s) = %d\n", path, MRP(path), result)); if(result >= 0) dump_stat( st ); RESTORE_ERRORS; return result; } int my_fstat( int fd, struct my_stat *st ) { DISABLE_ERRORS; int result = fstat( fd, (struct stat *)st ); if(result < 0) { my_errno = errno; } else { my_errno = 0; } D(bug("fstat(%d) = %d\n", fd, result)); if(result >= 0) dump_stat( st ); RESTORE_ERRORS; return result; } int my_open( const char *path, int mode, ... ) { DISABLE_ERRORS; int result; char *p = MRP(path); // Windows "open" does not handle _O_CREAT and _O_BINARY as it should if(mode & _O_CREAT) { if(exists(p)) { result = open( p, mode & ~_O_CREAT ); D(bug("open-nocreat(%s,%s,%d) = %d\n", path, p, mode, result)); } else { result = creat( p, _S_IWRITE|_S_IREAD ); if(result < 0) { make_folders(p); result = creat( p, _S_IWRITE|_S_IREAD ); } D(bug("open-creat(%s,%s,%d) = %d\n", path, p, mode, result)); } } else { result = open( p, mode ); D(bug("open(%s,%s,%d) = %d\n", path, p, mode, result)); } if(result < 0) { my_errno = errno; } else { setmode(result, _O_BINARY); my_errno = 0; } RESTORE_ERRORS; return result; } int my_rename( const char *old_path, const char *new_path ) { DISABLE_ERRORS; int result = -1; char *p_old = MRP(old_path); char *p_new = MRP2(new_path); result = my_access(old_path,0); if(result < 0) { // my_errno already set } else { if(is_same_drive(p_old,p_new)) { result = rename( p_old, p_new ); if(result != 0) { // by definition, rename may also return a positive value to indicate an error my_errno = errno; } else { my_errno = 0; } } else { if(is_dir(p_old)) { result = folder_copy( p_old, p_new ); // my_errno already set if(result >= 0) { if(myRemoveDirectory( p_old )) { my_errno = 0; result = 0; } else { // there is no proper error code for this failure. my_errno = EACCES; result = -1; } } } else { result = file_move( p_old, p_new ); // my_errno already set } } } D(bug("rename(%s,%s,%s,%s) = %d\n", old_path, p_old, new_path, p_new, result)); RESTORE_ERRORS; return result; } int my_access( const char *path, int mode ) { DISABLE_ERRORS; char *p = MRP(path); WIN32_FIND_DATA fdata; int result; if(is_dir(p)) { // access does not work for folders. HANDLE h = FindFirstFile( p, &fdata ); if(h != INVALID_HANDLE_VALUE) { FindClose( h ); if(mode == W_OK) { if( (fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0 ) { result = 0; my_errno = 0; } else { result = -1; my_errno = EACCES; } } else { result = 0; my_errno = 0; } } else { result = -1; my_errno = ENOENT; } } else { // W_OK, F_OK are ok. result = access(p,mode); if(result < 0) { my_errno = errno; } else { my_errno = 0; } } D(bug("access(%s,%s,%d) = %d\n", path, MRP(path), mode, result)); RESTORE_ERRORS; return result; } int my_mkdir( const char *path, int mode ) { DISABLE_ERRORS; char *p = MRP(path); strip_trailing_bs(p); int result = mkdir( p ); if(result < 0) { make_folders(p); result = mkdir( p ); } if(result < 0) { my_errno = errno; } else { my_errno = 0; } D(bug("mkdir(%s,%s,%d) = %d\n", path, p, mode, result)); RESTORE_ERRORS; return result; } int my_remove( const char *path ) { DISABLE_ERRORS; char *p = MRP(path); strip_trailing_bs(p); int result; if(is_dir(p)) { result = myRemoveDirectory( p ); } else { D(bug("DeleteFile %s\n", p)); result = DeleteFile( p ); } if(result) { result = 0; my_errno = 0; } else { result = -1; if(exists(p)) { my_errno = EACCES; } else { my_errno = ENOENT; } } D(bug("remove(%s,%s) = %d\n", path, p, result)); RESTORE_ERRORS; return result; } int my_creat( const char *path, int mode ) { DISABLE_ERRORS; char *p = MRP(path); int result = creat( p, _S_IWRITE|_S_IREAD ); // note mode if(result < 0) { make_folders(p); result = creat( p, _S_IWRITE|_S_IREAD ); // note mode } if(result < 0) { my_errno = errno; } else { setmode(result, _O_BINARY); my_errno = 0; } D(bug("creat(%s,%s,%d) = %d\n", path, p, mode,result)); RESTORE_ERRORS; return result; } int my_chsize( int fd, size_t sz ) { DISABLE_ERRORS; int result = chsize(fd,sz); if(result < 0) { my_errno = errno; } else { my_errno = 0; } RESTORE_ERRORS; return result; } int my_close( int fd ) { DISABLE_ERRORS; int result = close(fd); if(result < 0) { my_errno = errno; } else { my_errno = 0; } RESTORE_ERRORS; D(bug("close(%d) = %d\n", fd, result)); return result; } long my_lseek( int fd, long offset, int origin ) { DISABLE_ERRORS; int result = lseek( fd, offset, origin ); if(result < 0) { my_errno = errno; } else { my_errno = 0; } RESTORE_ERRORS; return result; } int my_read( int fd, void *buffer, unsigned int count ) { DISABLE_ERRORS; int result = read( fd, buffer, count ); if(result < 0) { my_errno = errno; } else { my_errno = 0; } RESTORE_ERRORS; D(bug("read(%ld,%08x,%ld) = %d\n", fd, buffer, count, result)); return result; } int my_write( int fd, const void *buffer, unsigned int count ) { DISABLE_ERRORS; int result = write( fd, buffer, count ); if(result < 0) { my_errno = errno; } else { my_errno = 0; } RESTORE_ERRORS; D(bug("write(%ld,%08x,%ld) = %d\n", fd, buffer, count, result)); return result; } BasiliskII/src/Windows/configure.ac0000755000175000017500000004431010552221452017453 0ustar centriscentrisdnl Process this file with autoconf to produce a configure script. dnl Written in 2002 by Christian Bauer et al. AC_INIT([Basilisk II], 1.0, [Christian.Bauer@uni-mainz.de], BasiliskII) AC_CONFIG_SRCDIR(main_windows.cpp) AC_CONFIG_AUX_DIR(../Unix) AC_PREREQ(2.52) AC_CONFIG_HEADER(config.h) dnl Aliases for PACKAGE and VERSION macros. AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE_NAME", [Define this program name.]) AC_DEFINE_UNQUOTED(VERSION, "$PACKAGE_VERSION", [Define this program version.]) dnl SDL options. AC_ARG_ENABLE(sdl-static, [ --enable-sdl-static use SDL static libraries for linking [default=no]], [WANT_SDL_STATIC=$enableval], [WANT_SDL_STATIC=no]) dnl JIT compiler options. AC_ARG_ENABLE(jit-compiler, [ --enable-jit-compiler enable JIT compiler [default=yes]], [WANT_JIT=$enableval], [WANT_JIT=yes]) AC_ARG_ENABLE(jit-debug, [ --enable-jit-debug activate native code disassemblers [default=no]], [WANT_JIT_DEBUG=$enableval], [WANT_JIT_DEBUG=no]) dnl FPU emulation core. AC_ARG_ENABLE(fpe, [ --enable-fpe=FPE specify which fpu emulator to use [default=auto]], [ case "$enableval" in dnl default is always ieee, if architecture has this fp format auto) FPE_CORE_TEST_ORDER="ieee uae";; ieee) FPE_CORE_TEST_ORDER="ieee";; uae) FPE_CORE_TEST_ORDER="uae";; x86) FPE_CORE_TEST_ORDER="x86";; *) AC_MSG_ERROR([--enable-fpe takes only one of the following values: auto, x86, ieee, uae]);; esac ], [ FPE_CORE_TEST_ORDER="ieee uae" ]) dnl External packages. AC_ARG_WITH(gtk, [ --with-gtk use GTK user interface [default=yes]], [WANT_GTK=$withval], [WANT_GTK=yes]) dnl Addressing modes. AC_ARG_ENABLE(addressing, [ --enable-addressing=AM specify the addressing mode to use [default=fastest]], [ case "$enableval" in direct) ADDRESSING_TEST_ORDER="direct";; banks) ADDRESSING_TEST_ORDER="banks";; fastest)ADDRESSING_TEST_ORDER="direct banks";; *) AC_MSG_ERROR([--enable-addressing takes only one of the following values: fastest, direct, banks]);; esac ], [ ADDRESSING_TEST_ORDER="direct banks" ]) dnl Canonical system information. AC_CANONICAL_HOST AC_CANONICAL_TARGET dnl Target CPU type. HAVE_I386=no HAVE_POWERPC=no HAVE_X86_64=no case "$target_cpu" in i386* | i486* | i586* | i686* | i786* ) HAVE_I386=yes;; powerpc* ) HAVE_POWERPC=yes;; x86_64* ) HAVE_X86_64=yes;; esac dnl Checks for programs. AC_PROG_CC AC_PROG_CC_C_O AC_PROG_CPP AC_PROG_CXX AC_PROG_MAKE_SET AC_PROG_EGREP AC_PROG_LN_S AC_CHECK_TOOL(WINDRES, windres) dnl We use GTK+ if possible. if [[ "x$WANT_GTK" = "xyes" ]]; then AM_PATH_GTK_2_0(1.3.15, [], [ AC_MSG_WARN([Could not find GTK+ 2.0, disabling user interface.]) WANT_GTK=no ]) fi AC_SUBST(WANT_GTK) dnl We use 64-bit file size support if possible. AC_SYS_LARGEFILE dnl Checks for header files. AC_HEADER_STDC dnl Checks for typedefs, structures, and compiler characteristics. AC_C_BIGENDIAN AC_C_CONST AC_C_INLINE AC_CHECK_SIZEOF(short, 2) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(long, 4) AC_CHECK_SIZEOF(long long, 8) AC_CHECK_SIZEOF(float, 4) AC_CHECK_SIZEOF(double, 8) AC_CHECK_SIZEOF(long double, 12) AC_CHECK_SIZEOF(void *, 4) AC_TYPE_OFF_T AC_CHECK_TYPES(loff_t) AC_CHECK_TYPES(caddr_t) AC_TYPE_SIZE_T dnl Checks for library functions. AC_CHECK_FUNCS(strdup strerror) dnl Define a macro that translates a yesno-variable into a C macro definition dnl to be put into the config.h file dnl $1 -- the macro to define dnl $2 -- the value to translate dnl $3 -- template name AC_DEFUN([AC_TRANSLATE_DEFINE], [ if [[ "x$2" = "xyes" -o "x$2" = "xguessing yes" ]]; then AC_DEFINE($1, 1, $3) fi ]) dnl Check that VirtualAlloc(), VirtualProtect() work AC_CACHE_CHECK([whether VirtualProtect works], ac_cv_VirtualProtect_works, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS ac_cv_VirtualProtect_works=yes dnl First the tests that should segfault for test_def in NONE_READ NONE_WRITE READ_WRITE; do AC_TRY_RUN([ #define HAVE_WIN32_VM 1 #define CONFIGURE_TEST_VM_MAP #define TEST_VM_PROT_$test_def #include "../Unix/vm_alloc.cpp" ], ac_cv_VirtualProtect_works=no, rm -f core, dnl When cross-compiling, assume it works ac_cv_VirtualProtect_works="yes" ) done AC_TRY_RUN([ #define HAVE_WIN32_VM 1 #define CONFIGURE_TEST_VM_MAP #define TEST_VM_PROT_RDWR_WRITE #include "../Unix/vm_alloc.cpp" ], , ac_cv_VirtualProtect_works=no, dnl When cross-compiling, assume it works ac_cv_VirtualProtect_works="yes" ) AC_LANG_RESTORE ] ) if [[ "x$ac_cv_VirtualProtect_works" = "xyes" ]]; then AC_DEFINE(HAVE_WIN32_VM, 1, [Define if your system has a working Win32-based memory allocator.]) else AC_MSG_ERROR([Sorry, Windows VM functions don't work as expected on your system.]) fi dnl Check if Windows exceptions are supported. AC_CACHE_CHECK([whether your system supports Windows exceptions], ac_cv_have_win32_exceptions, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_WIN32_EXCEPTIONS 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "../Unix/vm_alloc.cpp" #include "../Unix/sigsegv.cpp" ], ac_cv_have_win32_exceptions=yes, ac_cv_have_win32_exceptions=no, dnl When cross-compiling, assume it works ac_cv_have_win32_exceptions="yes" ) AC_LANG_RESTORE ] ) if [[ "x$ac_cv_have_win32_exceptions" = "xyes" ]]; then AC_DEFINE(HAVE_WIN32_EXCEPTIONS, 1, [Define if your system supports Windows exceptions.]) else AC_MSG_ERROR([Sorry, Windows exceptions don't work as expected on your system.]) fi dnl Check if we can ignore the fault (instruction skipping in SIGSEGV handler) AC_CACHE_CHECK([whether we can skip instruction in SIGSEGV handler], ac_cv_have_skip_instruction, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_TRY_RUN([ #define HAVE_SIGSEGV_SKIP_INSTRUCTION 1 #define CONFIGURE_TEST_SIGSEGV_RECOVERY #include "../Unix/vm_alloc.cpp" #include "../Unix/sigsegv.cpp" ], ac_cv_have_skip_instruction=yes, ac_cv_have_skip_instruction=no, dnl When cross-compiling, do not assume anything. ac_cv_have_skip_instruction=no ) AC_LANG_RESTORE ] ) AC_TRANSLATE_DEFINE(HAVE_SIGSEGV_SKIP_INSTRUCTION, "$ac_cv_have_skip_instruction", [Define if we can ignore the fault (instruction skipping in SIGSEGV handler).]) dnl We really want VOSF (Video on SEGV Signals) screen updates acceleration AC_DEFINE(ENABLE_VOSF, 1, [Define if using video enabled on SEGV signals.]) dnl Determine the addressing mode to use ADDRESSING_MODE="" AC_MSG_CHECKING([for the addressing mode to use]) for am in $ADDRESSING_TEST_ORDER; do case $am in direct) dnl Direct addressing mode (constant offset) ADDRESSING_MODE="direct" DEFINES="$DEFINES -DDIRECT_ADDRESSING" break ;; banks) dnl Default addressing mode ADDRESSING_MODE="memory banks" break ;; *) AC_MSG_ERROR([Internal configure.ac script error for $am addressing mode]) esac done AC_MSG_RESULT($ADDRESSING_MODE) if [[ "x$ADDRESSING_MODE" = "x" ]]; then AC_MSG_WARN([Sorry, no suitable addressing mode in $ADDRESSING_TEST_ORDER]) ADDRESSING_MODE="memory banks" fi dnl Banked Memory Addressing mode is not supported by the JIT compiler if [[ "x$WANT_JIT" = "xyes" -a "x$ADDRESSING_MODE" = "xmemory banks" ]]; then AC_MSG_ERROR([Sorry, the JIT Compiler requires Direct Addressing, at least]) fi dnl Check for GAS. HAVE_GAS=no AC_MSG_CHECKING(for GAS .p2align feature) cat >conftest.S << EOF .text .p2align 5 EOF if $CC conftest.S -c -o conftest.o >/dev/null 2>&1 ; then HAVE_GAS=yes; fi AC_MSG_RESULT($HAVE_GAS) dnl Check for GCC 2.7 or higher. HAVE_GCC27=no AC_MSG_CHECKING(for GCC 2.7 or higher) AC_EGREP_CPP(xyes, [#if __GNUC__ - 1 > 1 || __GNUC_MINOR__ - 1 > 5 xyes #endif ], [AC_MSG_RESULT(yes); HAVE_GCC27=yes], AC_MSG_RESULT(no)) dnl Check for GCC 3.0 or higher. HAVE_GCC30=no AC_MSG_CHECKING(for GCC 3.0 or higher) AC_EGREP_CPP(xyes, [#if __GNUC__ >= 3 xyes #endif ], [AC_MSG_RESULT(yes); HAVE_GCC30=yes], AC_MSG_RESULT(no)) dnl Add -fno-strict-aliasing for slirp sources if [[ "x$HAVE_GCC30" = "xyes" ]]; then SAVED_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-strict-aliasing" AC_CACHE_CHECK([whether the compiler supports -fno-strict-aliasing], ac_cv_gcc_no_strict_aliasing, [ AC_TRY_COMPILE([],[], [ac_cv_gcc_no_strict_aliasing=yes; AC_SUBST(SLIRP_CFLAGS, "-fno-strict-aliasing")], [ac_cv_gcc_no_strict_aliasing=no]) ]) CFLAGS="$SAVED_CFLAGS" fi dnl Select appropriate CPU source and REGPARAM define. ASM_OPTIMIZATIONS=none CPUSRCS="cpuemu1.cpp cpuemu2.cpp cpuemu3.cpp cpuemu4.cpp cpuemu5.cpp cpuemu6.cpp cpuemu7.cpp cpuemu8.cpp" dnl JITSRCS will be emptied later if the JIT is not available dnl Other platforms should define their own set of noflags file variants CAN_JIT=no JITSRCS="compemu1.cpp compemu2.cpp compemu3.cpp compemu4.cpp compemu5.cpp compemu6.cpp compemu7.cpp compemu8.cpp" if [[ "x$HAVE_GCC27" = "xyes" -a "x$HAVE_I386" = "xyes" ]]; then dnl i386 CPU DEFINES="$DEFINES -DUNALIGNED_PROFITABLE -DREGPARAM=\"__attribute__((regparm(3)))\"" if [[ "x$HAVE_GAS" = "xyes" ]]; then ASM_OPTIMIZATIONS=i386 DEFINES="$DEFINES -DX86_ASSEMBLY -DOPTIMIZED_FLAGS -DSAHF_SETO_PROFITABLE" JITSRCS="cpuemu1_nf.cpp cpuemu2_nf.cpp cpuemu3_nf.cpp cpuemu4_nf.cpp cpuemu5_nf.cpp cpuemu6_nf.cpp cpuemu7_nf.cpp cpuemu8_nf.cpp $JITSRCS" CAN_JIT=yes fi elif [[ "x$HAVE_GCC30" = "xyes" -a "x$HAVE_X86_64" = "xyes" ]]; then dnl x86-64 CPU DEFINES="$DEFINES -DUNALIGNED_PROFITABLE" if [[ "x$HAVE_GAS" = "xyes" ]]; then ASM_OPTIMIZATIONS="x86-64" DEFINES="$DEFINES -DX86_64_ASSEMBLY -DOPTIMIZED_FLAGS" JITSRCS="cpuemu1_nf.cpp cpuemu2_nf.cpp cpuemu3_nf.cpp cpuemu4_nf.cpp cpuemu5_nf.cpp cpuemu6_nf.cpp cpuemu7_nf.cpp cpuemu8_nf.cpp $JITSRCS" CAN_JIT=yes fi fi dnl Enable JIT compiler, if possible. if [[ "x$WANT_JIT" = "xyes" -a "x$CAN_JIT" ]]; then JITSRCS="$JITSRCS ../uae_cpu/compiler/compemu_support.cpp ../uae_cpu/compiler/compemu_fpp.cpp compstbl.o cpustbl_nf.o" DEFINES="$DEFINES -DUSE_JIT -DUSE_JIT_FPU" if [[ "x$WANT_JIT_DEBUG" = "xyes" ]]; then if [[ "x$WANT_MON" = "xyes" ]]; then DEFINES="$DEFINES -DJIT_DEBUG=1" else AC_MSG_WARN([cxmon not found, ignoring --enable-jit-debug]) WANT_JIT_DEBUG=no fi fi dnl IEEE core is the only FPU emulator to use with the JIT compiler case $FPE_CORE_TEST_ORDER in ieee*) ;; *) AC_MSG_WARN([Forcing use of the IEEE FPU core, as the JIT compiler supports only this one.]) ;; esac FPE_CORE_TEST_ORDER="ieee" else WANT_JIT=no WANT_JIT_DEBUG=no JITSRCS="" fi dnl Utility macro used by next two tests. dnl AC_EXAMINE_OBJECT(C source code, dnl commands examining object file, dnl [commands to run if compile failed]): dnl dnl Compile the source code to an object file; then convert it into a dnl printable representation. All unprintable characters and dnl asterisks (*) are replaced by dots (.). All white space is dnl deleted. Newlines (ASCII 0x10) in the input are preserved in the dnl output, but runs of newlines are compressed to a single newline. dnl Finally, line breaks are forcibly inserted so that no line is dnl longer than 80 columns and the file ends with a newline. The dnl result of all this processing is in the file conftest.dmp, which dnl may be examined by the commands in the second argument. dnl AC_DEFUN([gcc_AC_EXAMINE_OBJECT], [AC_LANG_SAVE AC_LANG_C dnl Next bit cribbed from AC_TRY_COMPILE. cat > conftest.$ac_ext < conftest.dmp $2 ifelse($3, , , else $3 )dnl fi rm -rf conftest* AC_LANG_RESTORE]) dnl Floating point format probe. dnl The basic concept is the same as the above: grep the object dnl file for an interesting string. We have to watch out for dnl rounding changing the values in the object, however; this is dnl handled by ignoring the least significant byte of the float. dnl dnl Does not know about VAX G-float or C4x idiosyncratic format. dnl It does know about PDP-10 idiosyncratic format, but this is dnl not presently supported by GCC. S/390 "binary floating point" dnl is in fact IEEE (but maybe we should have that in EBCDIC as well dnl as ASCII?) dnl AC_DEFUN([gcc_AC_C_FLOAT_FORMAT], [AC_CACHE_CHECK(floating point format, ac_cv_c_float_format, [gcc_AC_EXAMINE_OBJECT( [/* This will not work unless sizeof(double) == 8. */ extern char sizeof_double_must_be_8 [sizeof(double) == 8 ? 1 : -1]; /* This structure must have no internal padding. */ struct possibility { char prefix[8]; double candidate; char postfix[8]; }; #define C(cand) { "\nformat:", cand, ":tamrof\n" } struct possibility table [] = { C( 3.25724264705901305206e+01), /* @@IEEEFP - IEEE 754 */ C( 3.53802595280598432000e+18), /* D__float - VAX */ C( 5.32201830133125317057e-19), /* D.PDP-10 - PDP-10 - the dot is 0x13a */ C( 1.77977764695171661377e+10), /* IBMHEXFP - s/390 format, ascii */ C(-5.22995989424860458374e+10) /* IBMHEXFP - s/390 format, EBCDIC */ };], [if grep 'format:.@IEEEF.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (big-endian)' elif grep 'format:.I@@PFE.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (big-endian)' elif grep 'format:.FEEEI@.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (little-endian)' elif grep 'format:.EFP@@I.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IEEE (little-endian)' elif grep 'format:.__floa.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='VAX D-float' elif grep 'format:..PDP-1.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='PDP-10' elif grep 'format:.BMHEXF.:tamrof' conftest.dmp >/dev/null 2>&1; then ac_cv_c_float_format='IBM 370 hex' else AC_MSG_ERROR(Unknown floating point format) fi], [AC_MSG_ERROR(compile failed)]) ]) # IEEE is the default format. If the float endianness isn't the same # as the integer endianness, we have to set FLOAT_WORDS_BIG_ENDIAN # (which is a tristate: yes, no, default). This is only an issue with # IEEE; the other formats are only supported by a few machines each, # all with the same endianness. format=IEEE_FLOAT_FORMAT fbigend= case $ac_cv_c_float_format in 'IEEE (big-endian)' ) if test $ac_cv_c_bigendian = no; then fbigend=1 fi ;; 'IEEE (little-endian)' ) if test $ac_cv_c_bigendian = yes; then fbigend=0 fi ;; 'VAX D-float' ) format=VAX_FLOAT_FORMAT ;; 'PDP-10' ) format=PDP10_FLOAT_FORMAT ;; 'IBM 370 hex' ) format=IBM_FLOAT_FORMAT ;; esac AC_DEFINE_UNQUOTED(HOST_FLOAT_FORMAT, $format, [Define to the floating point format of the host machine.]) if test -n "$fbigend"; then AC_DEFINE_UNQUOTED(HOST_FLOAT_WORDS_BIG_ENDIAN, $fbigend, [Define to 1 if the host machine stores floating point numbers in memory with the word containing the sign bit at the lowest address, or to 0 if it does it the other way around. This macro should not be defined if the ordering is the same as for multi-word integers.]) fi ]) dnl Select appropriate FPU source. gcc_AC_C_FLOAT_FORMAT AC_CHECK_HEADERS(ieee754.h ieeefp.h floatingpoint.h nan.h) for fpe in $FPE_CORE_TEST_ORDER; do case $fpe in ieee) case $ac_cv_c_float_format in IEEE*) FPE_CORE="IEEE fpu core" DEFINES="$DEFINES -DFPU_IEEE" FPUSRCS="../uae_cpu/fpu/fpu_ieee.cpp" dnl Math functions not mandated by C99 standard AC_CHECK_FUNCS(isnanl isinfl) dnl Math functions required by C99 standard, but probably not dnl implemented everywhere. In that case, we fall back to the dnl regular variant for doubles. AC_CHECK_FUNCS(logl log10l expl powl fabsl sqrtl) AC_CHECK_FUNCS(sinl cosl tanl sinhl coshl tanhl) AC_CHECK_FUNCS(asinl acosl atanl asinhl acoshl atanhl) AC_CHECK_FUNCS(floorl ceill) break ;; esac ;; x86) if [[ ":$HAVE_GCC27:$HAVE_I386:$HAVE_GAS:" = ":yes:yes:yes:" ]]; then FPE_CORE="i387 fpu core" DEFINES="$DEFINES -DFPU_X86" FPUSRCS="../uae_cpu/fpu/fpu_x86.cpp" break fi ;; uae) FPE_CORE="uae fpu core" DEFINES="$DEFINES -DFPU_UAE" FPUSRCS="../uae_cpu/fpu/fpu_uae.cpp" break ;; *) AC_MSG_ERROR([Internal configure.in script error for $fpe fpu core]) ;; esac done if [[ "x$FPE_CORE" = "x" ]]; then AC_MSG_ERROR([Sorry, no suitable FPU core found in $FPE_CORE_TEST_ORDER]) fi dnl Check for certain math functions AC_CHECK_FUNCS(atanh) AC_CHECK_FUNCS(isnan isinf finite isnormal signbit) dnl UAE CPU sources for all non-m68k-native architectures. CPUINCLUDES="-I../uae_cpu" CPUSRCS="../uae_cpu/basilisk_glue.cpp ../uae_cpu/memory.cpp ../uae_cpu/newcpu.cpp ../uae_cpu/readcpu.cpp $FPUSRCS cpustbl.cpp cpudefs.cpp $CPUSRCS $JITSRCS" dnl We really want SDL for now AC_CHECK_TOOL(sdl_config, sdl-config, [AC_MSG_ERROR([Sorry, you currently need SDL for this port])]) SDL_CFLAGS=`$sdl_config --cflags` AC_SUBST(SDL_CFLAGS) if [[ "x$WANT_SDL_STATIC" = "xyes" ]]; then SDL_LIBS=`$sdl_config --static-libs` sdl_prefix=`$sdl_config --exec-prefix` if [[ -n "$sdl_prefix" ]]; then SDL_LIBS=`echo "$SDL_LIBS" | sed -e "s,-l\(SDLmain\|SDL\),$sdl_prefix/lib/lib\1.a,g"` fi SDL_LIBS="$SDL_LIBS -lwinmm" else SDL_LIBS=`$sdl_config --libs` fi AC_SUBST(SDL_LIBS) AC_DEFINE(USE_SDL, 1, [Define to enble SDL support]) AC_DEFINE(USE_SDL_VIDEO, 1, [Define to enable SDL video graphics support]) AC_DEFINE(USE_SDL_AUDIO, 1, [Define to enable SDL audio support]) dnl Remove the "-g" option if set for GCC. if [[ "x$HAVE_GCC27" = "xyes" ]]; then CFLAGS=`echo $CFLAGS | sed -e 's/-g\b//g'` CXXFLAGS=`echo $CXXFLAGS | sed -e 's/-g\b//g'` fi dnl Generate Makefile. AC_SUBST(DEFINES) AC_SUBST(CPUINCLUDES) AC_SUBST(CPUSRCS) AC_CONFIG_FILES([Makefile]) AC_OUTPUT dnl Print summary. echo echo Basilisk II configuration summary: echo echo Use JIT compiler ....................... : $WANT_JIT echo JIT debug mode ......................... : $WANT_JIT_DEBUG echo Floating-Point emulation core .......... : $FPE_CORE echo Assembly optimizations ................. : $ASM_OPTIMIZATIONS echo Addressing mode ........................ : $ADDRESSING_MODE echo GTK user interface ..................... : $WANT_GTK echo echo "Configuration done. Now type \"make\" (or \"gmake\")." BasiliskII/src/Windows/util_windows.cpp0000755000175000017500000001750410736405222020430 0ustar centriscentris/* * util_windows.cpp - Miscellaneous utilities for Win32 * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "util_windows.h" #include "main.h" #include using std::list; #include using std::string; BOOL exists( const char *path ) { HFILE h; bool ret = false; h = _lopen( path, OF_READ ); if(h != HFILE_ERROR) { ret = true; _lclose(h); } return(ret); } BOOL create_file( const char *path, DWORD size ) { HANDLE h; bool ok = false; h = CreateFile( path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); if(h != INVALID_HANDLE_VALUE) { if(size == 0) { ok = true; } else if(SetFilePointer( h, size, NULL, FILE_BEGIN) != 0xFFFFFFFF) { if(SetEndOfFile(h)) { ok = true; if(SetFilePointer( h, 0, NULL, FILE_BEGIN) != 0xFFFFFFFF) { DWORD written; DWORD zeroed_size = size; if (zeroed_size > 1024*1024) zeroed_size = 1024*1024; char *b = (char *)malloc(zeroed_size); if(b) { memset( b, 0, zeroed_size ); WriteFile( h, b, zeroed_size, &written, NULL ); free(b); } } } } CloseHandle(h); } if(!ok) DeleteFile(path); return(ok); } int32 get_file_size( const char *path ) { HANDLE h; DWORD size = 0; h = CreateFile( path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if(h != INVALID_HANDLE_VALUE) { size = GetFileSize( h, NULL ); CloseHandle(h); } return(size); } /* * Thread wrappers */ HANDLE create_thread(LPTHREAD_START_ROUTINE start_routine, void *arg) { DWORD dwThreadId; return CreateThread(NULL, 0, start_routine, arg, 0, &dwThreadId); } void wait_thread(HANDLE thread) { WaitForSingleObject(thread, INFINITE); CloseHandle(thread); } void kill_thread(HANDLE thread) { TerminateThread(thread, 0); } /* * Check that drivers are installed */ bool check_drivers(void) { char path[_MAX_PATH]; GetSystemDirectory(path, sizeof(path)); strcat(path, "\\drivers\\cdenable.sys"); if (exists(path)) { int32 size = get_file_size(path); if (size != 6112) { char str[256]; sprintf(str, "The CD-ROM driver file \"%s\" is too old or corrupted.", path); ErrorAlert(str); return false; } } else { char str[256]; sprintf(str, "The CD-ROM driver file \"%s\" is missing.", path); WarningAlert(str); } return true; } /* * Network control panel helpers */ struct panel_reg { string name; string guid; }; static list network_registry; typedef list::const_iterator network_registry_iterator; #define NETWORK_CONNECTIONS_KEY \ "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" static void get_network_registry(void) { LONG status; HKEY network_connections_key; DWORD len; int i = 0; if (network_registry.size() > 0) return; status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &network_connections_key); if (status != ERROR_SUCCESS) return; while (true) { char enum_name[256]; char connection_string[256]; HKEY connection_key; char name_data[256]; DWORD name_type; const char name_string[] = "Name"; len = sizeof (enum_name); status = RegEnumKeyEx( network_connections_key, i, enum_name, &len, NULL, NULL, NULL, NULL); if (status != ERROR_SUCCESS) break; snprintf (connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name); status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connection_key); if (status == ERROR_SUCCESS) { len = sizeof (name_data); status = RegQueryValueEx( connection_key, name_string, NULL, &name_type, (BYTE *)name_data, &len); if (status == ERROR_SUCCESS && name_type == REG_SZ) { panel_reg pr; pr.name = name_data; pr.guid = enum_name; network_registry.push_back(pr); } RegCloseKey (connection_key); } ++i; } RegCloseKey (network_connections_key); } const char *ether_name_to_guid(const char *name) { get_network_registry(); for (network_registry_iterator it = network_registry.begin(); it != network_registry.end(); it++) { if (strcmp((*it).name.c_str(), name) == 0) return (*it).guid.c_str(); } return NULL; } const char *ether_guid_to_name(const char *guid) { get_network_registry(); for (network_registry_iterator it = network_registry.begin(); it != network_registry.end(); it++) { if (strcmp((*it).guid.c_str(), guid) == 0) return (*it).name.c_str(); } return NULL; } /* * Get TAP-Win32 adapters */ #define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" #define TAP_COMPONENT_ID "tap0801" const char *ether_tap_devices(void) { HKEY adapter_key; LONG status; DWORD len; int i = 0; status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &adapter_key); if (status != ERROR_SUCCESS) return NULL; list devices; while (true) { char enum_name[256]; char unit_string[256]; HKEY unit_key; char component_id_string[] = "ComponentId"; char component_id[256]; char net_cfg_instance_id_string[] = "NetCfgInstanceId"; char net_cfg_instance_id[256]; DWORD data_type; len = sizeof (enum_name); status = RegEnumKeyEx( adapter_key, i, enum_name, &len, NULL, NULL, NULL, NULL); if (status != ERROR_SUCCESS) break; snprintf (unit_string, sizeof(unit_string), "%s\\%s", ADAPTER_KEY, enum_name); status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key); if (status == ERROR_SUCCESS) { len = sizeof (component_id); status = RegQueryValueEx( unit_key, component_id_string, NULL, &data_type, (BYTE *)component_id, &len); if (status == ERROR_SUCCESS && data_type == REG_SZ) { len = sizeof (net_cfg_instance_id); status = RegQueryValueEx( unit_key, net_cfg_instance_id_string, NULL, &data_type, (BYTE *)net_cfg_instance_id, &len); if (status == ERROR_SUCCESS && data_type == REG_SZ) { if (!strcmp (component_id, TAP_COMPONENT_ID)) devices.push_back(net_cfg_instance_id); } } RegCloseKey (unit_key); } ++i; } RegCloseKey (adapter_key); if (devices.empty()) return NULL; // The result is a '\0' separated list of strings list::const_iterator it; len = 0; for (it = devices.begin(); it != devices.end(); it++) len += (*it).length() + 1; char *names = (char *)malloc(len); if (names) { char *p = names; for (it = devices.begin(); it != devices.end(); it++) { len = (*it).length(); strcpy(p, (*it).c_str()); p[len] = '\0'; p += len + 1; } } return names; } BasiliskII/src/Windows/ether_windows.cpp0000755000175000017500000011176610736405221020566 0ustar centriscentris/* * ether_windows.cpp - Ethernet device driver * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include #include #include #include #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "ether.h" #include "ether_defs.h" #include "b2ether/multiopt.h" #include "b2ether/inc/b2ether_hl.h" #include "ether_windows.h" #include "router/router.h" #include "kernel_windows.h" #include "libslirp.h" // Define to let the slirp library determine the right timeout for select() #define USE_SLIRP_TIMEOUT 1 #define DEBUG 0 #define MONITOR 0 #if DEBUG #pragma optimize("",off) #endif #include "debug.h" // Ethernet device types enum { NET_IF_B2ETHER, NET_IF_ROUTER, NET_IF_SLIRP, NET_IF_TAP, NET_IF_FAKE, }; // TAP-Win32 constants #define TAP_VERSION_MIN_MAJOR 7 #define TAP_VERSION_MIN_MINOR 1 #define TAP_CONTROL_CODE(request, method) \ CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) #define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) #define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) #define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) #define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) #define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) #define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) #define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) #define OLD_TAP_CONTROL_CODE(request, method) \ CTL_CODE (FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS) #define OLD_TAP_IOCTL_GET_VERSION OLD_TAP_CONTROL_CODE (3, METHOD_BUFFERED) // Options bool ether_use_permanent = true; static int16 ether_multi_mode = ETHER_MULTICAST_MAC; // Global variables HANDLE ether_th; unsigned int ether_tid; HANDLE ether_th1; HANDLE ether_th2; static int net_if_type = -1; // Ethernet device type #ifdef SHEEPSHAVER static bool net_open = false; // Flag: initialization succeeded, network device open uint8 ether_addr[6]; // Our Ethernet address #endif // These are protected by queue_csection // Controls transfer for read thread to feed thread static CRITICAL_SECTION queue_csection; typedef struct _win_queue_t { uint8 *buf; int sz; } win_queue_t; #define MAX_QUEUE_ITEMS 1024 static win_queue_t queue[MAX_QUEUE_ITEMS]; static int queue_head = 0; static int queue_inx = 0; static bool wait_request = true; // Read thread protected packet pool static CRITICAL_SECTION fetch_csection; // Some people use pools as large as 64. #define PACKET_POOL_COUNT 10 static LPPACKET packets[PACKET_POOL_COUNT]; static bool wait_request2 = false; // Write thread packet queue static CRITICAL_SECTION send_csection; static LPPACKET send_queue = 0; // Write thread free packet pool static CRITICAL_SECTION wpool_csection; static LPPACKET write_packet_pool = 0; // Try to deal with echos. Protected by fetch_csection. // The code should be moved to the driver. No need to lift // the echo packets to the application level. // MAX_ECHO must be a power of two. #define MAX_ECHO (1<<2) static int echo_count = 0; typedef uint8 echo_t[1514]; static echo_t pending_packet[MAX_ECHO]; static int pending_packet_sz[MAX_ECHO]; // List of attached protocols struct NetProtocol { NetProtocol *next; uint16 type; uint32 handler; }; static NetProtocol *prot_list = NULL; static LPADAPTER fd = 0; static bool thread_active = false; static bool thread_active_1 = false; static bool thread_active_2 = false; static bool thread_active_3 = false; static HANDLE int_ack = 0; static HANDLE int_sig = 0; static HANDLE int_sig2 = 0; static HANDLE int_send_now = 0; // Prototypes static LPADAPTER tap_open_adapter(const char *dev_name); static void tap_close_adapter(LPADAPTER fd); static bool tap_check_version(LPADAPTER fd); static bool tap_set_status(LPADAPTER fd, ULONG status); static bool tap_get_mac(LPADAPTER fd, LPBYTE addr); static bool tap_receive_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync); static bool tap_send_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync, BOOLEAN recycle); static WINAPI unsigned int slirp_receive_func(void *arg); static WINAPI unsigned int ether_thread_feed_int(void *arg); static WINAPI unsigned int ether_thread_get_packets_nt(void *arg); static WINAPI unsigned int ether_thread_write_packets(void *arg); static void init_queue(void); static void final_queue(void); static bool allocate_read_packets(void); static void free_read_packets(void); static void free_write_packets(void); static int16 ether_do_add_multicast(uint8 *addr); static int16 ether_do_del_multicast(uint8 *addr); static int16 ether_do_write(uint32 arg); static void ether_do_interrupt(void); /* * Find protocol in list */ static NetProtocol *find_protocol(uint16 type) { // All 802.2 types are the same if (type <= 1500) type = 0; // Search list (we could use hashing here but there are usually only three // handlers installed: 0x0000 for AppleTalk and 0x0800/0x0806 for TCP/IP) NetProtocol *p = prot_list; while (p) { if (p->type == type) return p; p = p->next; } return NULL; } /* * Initialization */ bool ether_init(void) { char str[256]; // Do nothing if no Ethernet device specified const char *name = PrefsFindString("ether"); if (name == NULL) return false; ether_multi_mode = PrefsFindInt32("ethermulticastmode"); ether_use_permanent = PrefsFindBool("etherpermanentaddress"); // Determine Ethernet device type net_if_type = -1; if (PrefsFindBool("routerenabled") || strcmp(name, "router") == 0) net_if_type = NET_IF_ROUTER; else if (strcmp(name, "slirp") == 0) net_if_type = NET_IF_SLIRP; else if (strcmp(name, "tap") == 0) net_if_type = NET_IF_TAP; else net_if_type = NET_IF_B2ETHER; // Initialize NAT-Router if (net_if_type == NET_IF_ROUTER) { if (!router_init()) net_if_type = NET_IF_FAKE; } // Initialize slirp library if (net_if_type == NET_IF_SLIRP) { if (slirp_init() < 0) { sprintf(str, GetString(STR_SLIRP_NO_DNS_FOUND_WARN)); WarningAlert(str); return false; } } // Open ethernet device const char *dev_name; switch (net_if_type) { case NET_IF_B2ETHER: dev_name = PrefsFindString("etherguid"); if (dev_name == NULL || strcmp(name, "b2ether") != 0) dev_name = name; break; case NET_IF_TAP: dev_name = PrefsFindString("etherguid"); break; } if (net_if_type == NET_IF_B2ETHER) { if (dev_name == NULL) { WarningAlert("No ethernet device GUID specified. Ethernet is not available."); goto open_error; } fd = PacketOpenAdapter( dev_name, ether_multi_mode ); if (!fd) { sprintf(str, "Could not open ethernet adapter %s.", dev_name); WarningAlert(str); goto open_error; } // Get Ethernet address if(!PacketGetMAC(fd,ether_addr,ether_use_permanent)) { sprintf(str, "Could not get hardware address of device %s. Ethernet is not available.", dev_name); WarningAlert(str); goto open_error; } D(bug("Real ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); const char *ether_fake_address; ether_fake_address = PrefsFindString("etherfakeaddress"); if(ether_fake_address && strlen(ether_fake_address) == 12) { char sm[10]; strcpy( sm, "0x00" ); for( int i=0; i<6; i++ ) { sm[2] = ether_fake_address[i*2]; sm[3] = ether_fake_address[i*2+1]; ether_addr[i] = (uint8)strtoul(sm,0,0); } D(bug("Fake ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); } } else if (net_if_type == NET_IF_TAP) { if (dev_name == NULL) { WarningAlert("No ethernet device GUID specified. Ethernet is not available."); goto open_error; } fd = tap_open_adapter(dev_name); if (!fd) { sprintf(str, "Could not open ethernet adapter %s.", dev_name); WarningAlert(str); goto open_error; } if (!tap_check_version(fd)) { sprintf(str, "Minimal TAP-Win32 version supported is %d.%d.", TAP_VERSION_MIN_MAJOR, TAP_VERSION_MIN_MINOR); WarningAlert(str); goto open_error; } if (!tap_set_status(fd, true)) { sprintf(str, "Could not set media status to connected."); WarningAlert(str); goto open_error; } if (!tap_get_mac(fd, ether_addr)) { sprintf(str, "Could not get hardware address of device %s. Ethernet is not available.", dev_name); WarningAlert(str); goto open_error; } D(bug("Real ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); const char *ether_fake_address; ether_fake_address = PrefsFindString("etherfakeaddress"); if (ether_fake_address && strlen(ether_fake_address) == 12) { char sm[10]; strcpy( sm, "0x00" ); for( int i=0; i<6; i++ ) { sm[2] = ether_fake_address[i*2]; sm[3] = ether_fake_address[i*2+1]; ether_addr[i] = (uint8)strtoul(sm,0,0); } } #if 1 /* If we bridge the underlying ethernet connection and the TAP device altogether, we have to use a fake address. */ else { ether_addr[0] = 0x52; ether_addr[1] = 0x54; ether_addr[2] = 0x00; } #endif D(bug("Fake ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); } else if (net_if_type == NET_IF_SLIRP) { ether_addr[0] = 0x52; ether_addr[1] = 0x54; ether_addr[2] = 0x00; ether_addr[3] = 0x12; ether_addr[4] = 0x34; ether_addr[5] = 0x56; D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); } else { memcpy( ether_addr, router_mac_addr, 6 ); D(bug("Fake ethernet address (same as router) %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); } // Start packet reception thread int_ack = CreateSemaphore( 0, 0, 1, NULL); if(!int_ack) { WarningAlert("WARNING: Cannot create int_ack semaphore"); goto open_error; } // nonsignaled int_sig = CreateSemaphore( 0, 0, 1, NULL); if(!int_sig) { WarningAlert("WARNING: Cannot create int_sig semaphore"); goto open_error; } int_sig2 = CreateSemaphore( 0, 0, 1, NULL); if(!int_sig2) { WarningAlert("WARNING: Cannot create int_sig2 semaphore"); goto open_error; } int_send_now = CreateSemaphore( 0, 0, 1, NULL); if(!int_send_now) { WarningAlert("WARNING: Cannot create int_send_now semaphore"); goto open_error; } init_queue(); if(!allocate_read_packets()) goto open_error; // No need to enter wait state if we can avoid it. // These all terminate fast. if(pfnInitializeCriticalSectionAndSpinCount) { pfnInitializeCriticalSectionAndSpinCount( &fetch_csection, 5000 ); } else { InitializeCriticalSection( &fetch_csection ); } if(pfnInitializeCriticalSectionAndSpinCount) { pfnInitializeCriticalSectionAndSpinCount( &queue_csection, 5000 ); } else { InitializeCriticalSection( &queue_csection ); } if(pfnInitializeCriticalSectionAndSpinCount) { pfnInitializeCriticalSectionAndSpinCount( &send_csection, 5000 ); } else { InitializeCriticalSection( &send_csection ); } if(pfnInitializeCriticalSectionAndSpinCount) { pfnInitializeCriticalSectionAndSpinCount( &wpool_csection, 5000 ); } else { InitializeCriticalSection( &wpool_csection ); } ether_th = (HANDLE)_beginthreadex( 0, 0, ether_thread_feed_int, 0, 0, ðer_tid ); if (!ether_th) { D(bug("Failed to create ethernet thread\n")); goto open_error; } thread_active = true; unsigned int dummy; unsigned int (WINAPI *receive_func)(void *); switch (net_if_type) { case NET_IF_SLIRP: receive_func = slirp_receive_func; break; default: receive_func = ether_thread_get_packets_nt; break; } ether_th2 = (HANDLE)_beginthreadex( 0, 0, receive_func, 0, 0, &dummy ); ether_th1 = (HANDLE)_beginthreadex( 0, 0, ether_thread_write_packets, 0, 0, &dummy ); // Everything OK return true; open_error: if (thread_active) { TerminateThread(ether_th,0); ether_th = 0; if (int_ack) CloseHandle(int_ack); int_ack = 0; if(int_sig) CloseHandle(int_sig); int_sig = 0; if(int_sig2) CloseHandle(int_sig2); int_sig2 = 0; if(int_send_now) CloseHandle(int_send_now); int_send_now = 0; thread_active = false; } if (fd) { switch (net_if_type) { case NET_IF_B2ETHER: PacketCloseAdapter(fd); break; case NET_IF_TAP: tap_close_adapter(fd); break; } fd = 0; } return false; } /* * Deinitialization */ void ether_exit(void) { D(bug("EtherExit\n")); // Stop reception thread thread_active = false; if(int_ack) ReleaseSemaphore(int_ack,1,NULL); if(int_sig) ReleaseSemaphore(int_sig,1,NULL); if(int_sig2) ReleaseSemaphore(int_sig2,1,NULL); if(int_send_now) ReleaseSemaphore(int_send_now,1,NULL); D(bug("CancelIO if needed\n")); if (fd && fd->hFile && pfnCancelIo) pfnCancelIo(fd->hFile); // Wait max 2 secs to shut down pending io. After that, kill them. D(bug("Wait delay\n")); for( int i=0; i<10; i++ ) { if(!thread_active_1 && !thread_active_2 && !thread_active_3) break; Sleep(200); } if(thread_active_1) { D(bug("Ether killing ether_th1\n")); if(ether_th1) TerminateThread(ether_th1,0); thread_active_1 = false; } if(thread_active_2) { D(bug("Ether killing ether_th2\n")); if(ether_th2) TerminateThread(ether_th2,0); thread_active_2 = false; } if(thread_active_3) { D(bug("Ether killing thread\n")); if(ether_th) TerminateThread(ether_th,0); thread_active_3 = false; } ether_th1 = 0; ether_th2 = 0; ether_th = 0; D(bug("Closing semaphores\n")); if(int_ack) { CloseHandle(int_ack); int_ack = 0; } if(int_sig) { CloseHandle(int_sig); int_sig = 0; } if(int_sig2) { CloseHandle(int_sig2); int_sig2 = 0; } if(int_send_now) { CloseHandle(int_send_now); int_send_now = 0; } // Close ethernet device if (fd) { switch (net_if_type) { case NET_IF_B2ETHER: PacketCloseAdapter(fd); break; case NET_IF_TAP: tap_close_adapter(fd); break; } fd = 0; } // Remove all protocols D(bug("Removing protocols\n")); NetProtocol *p = prot_list; while (p) { NetProtocol *next = p->next; delete p; p = next; } prot_list = 0; D(bug("Deleting sections\n")); DeleteCriticalSection( &fetch_csection ); DeleteCriticalSection( &queue_csection ); DeleteCriticalSection( &send_csection ); DeleteCriticalSection( &wpool_csection ); D(bug("Freeing read packets\n")); free_read_packets(); D(bug("Freeing write packets\n")); free_write_packets(); D(bug("Finalizing queue\n")); final_queue(); if (net_if_type == NET_IF_ROUTER) { D(bug("Stopping router\n")); router_final(); } D(bug("EtherExit done\n")); } /* * Glue around low-level implementation */ #ifdef SHEEPSHAVER // Error codes enum { eMultiErr = -91, eLenErr = -92, lapProtErr = -94, excessCollsns = -95 }; // Initialize ethernet void EtherInit(void) { net_open = false; // Do nothing if the user disabled the network if (PrefsFindBool("nonet")) return; net_open = ether_init(); } // Exit ethernet void EtherExit(void) { ether_exit(); net_open = false; } // Get ethernet hardware address void AO_get_ethernet_address(uint32 arg) { uint8 *addr = Mac2HostAddr(arg); if (net_open) OTCopy48BitAddress(ether_addr, addr); else { addr[0] = 0x12; addr[1] = 0x34; addr[2] = 0x56; addr[3] = 0x78; addr[4] = 0x9a; addr[5] = 0xbc; } D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5])); } // Add multicast address void AO_enable_multicast(uint32 addr) { if (net_open) ether_do_add_multicast(Mac2HostAddr(addr)); } // Disable multicast address void AO_disable_multicast(uint32 addr) { if (net_open) ether_do_del_multicast(Mac2HostAddr(addr)); } // Transmit one packet void AO_transmit_packet(uint32 mp) { if (net_open) { switch (ether_do_write(mp)) { case noErr: num_tx_packets++; break; case excessCollsns: num_tx_buffer_full++; break; } } } // Copy packet data from message block to linear buffer static inline int ether_arg_to_buffer(uint32 mp, uint8 *p) { return ether_msgb_to_buffer(mp, p); } // Ethernet interrupt void EtherIRQ(void) { D(bug("EtherIRQ\n")); num_ether_irq++; OTEnterInterrupt(); ether_do_interrupt(); OTLeaveInterrupt(); // Acknowledge interrupt to reception thread D(bug(" EtherIRQ done\n")); ReleaseSemaphore(int_ack,1,NULL); } #else // Add multicast address int16 ether_add_multicast(uint32 pb) { return ether_do_add_multicast(Mac2HostAddr(pb + eMultiAddr)); } // Disable multicast address int16 ether_del_multicast(uint32 pb) { return ether_do_del_multicast(Mac2HostAddr(pb + eMultiAddr)); } // Transmit one packet int16 ether_write(uint32 wds) { return ether_do_write(wds); } // Copy packet data from WDS to linear buffer static inline int ether_arg_to_buffer(uint32 wds, uint8 *p) { return ether_wds_to_buffer(wds, p); } // Dispatch packet to protocol handler static void ether_dispatch_packet(uint32 packet, uint32 length) { // Get packet type uint16 type = ReadMacInt16(packet + 12); // Look for protocol NetProtocol *prot = find_protocol(type); if (prot == NULL) return; // No default handler if (prot->handler == 0) return; // Copy header to RHA Mac2Mac_memcpy(ether_data + ed_RHA, packet, 14); D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12))); // Call protocol handler M68kRegisters r; r.d[0] = type; // Packet type r.d[1] = length - 14; // Remaining packet length (without header, for ReadPacket) r.a[0] = packet + 14; // Pointer to packet (Mac address, for ReadPacket) r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", prot->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4])); Execute68k(prot->handler, &r); } // Ethernet interrupt void EtherInterrupt(void) { D(bug("EtherIRQ\n")); ether_do_interrupt(); // Acknowledge interrupt to reception thread D(bug(" EtherIRQ done\n")); ReleaseSemaphore(int_ack,1,NULL); } #endif /* * Reset */ void ether_reset(void) { D(bug("EtherReset\n")); // Remove all protocols NetProtocol *p = prot_list; while (p) { NetProtocol *next = p->next; delete p; p = next; } prot_list = NULL; } /* * Add multicast address */ static int16 ether_do_add_multicast(uint8 *addr) { D(bug("ether_add_multicast\n")); // We wouldn't need to do this // if(ether_multi_mode != ETHER_MULTICAST_MAC) return noErr; switch (net_if_type) { case NET_IF_B2ETHER: if (!PacketAddMulticast( fd, addr)) { D(bug("WARNING: couldn't enable multicast address\n")); return eMultiErr; } default: D(bug("ether_add_multicast: noErr\n")); return noErr; } } /* * Delete multicast address */ int16 ether_do_del_multicast(uint8 *addr) { D(bug("ether_del_multicast\n")); // We wouldn't need to do this // if(ether_multi_mode != ETHER_MULTICAST_MAC) return noErr; switch (net_if_type) { case NET_IF_B2ETHER: if (!PacketDelMulticast( fd, addr)) { D(bug("WARNING: couldn't disable multicast address\n")); return eMultiErr; } default: return noErr; } } /* * Attach protocol handler */ int16 ether_attach_ph(uint16 type, uint32 handler) { D(bug("ether_attach_ph type=0x%x, handler=0x%x\n",(int)type,handler)); // Already attached? NetProtocol *p = find_protocol(type); if (p != NULL) { D(bug("ether_attach_ph: lapProtErr\n")); return lapProtErr; } else { // No, create and attach p = new NetProtocol; p->next = prot_list; p->type = type; p->handler = handler; prot_list = p; D(bug("ether_attach_ph: noErr\n")); return noErr; } } /* * Detach protocol handler */ int16 ether_detach_ph(uint16 type) { D(bug("ether_detach_ph type=%08lx\n",(int)type)); NetProtocol *p = find_protocol(type); if (p != NULL) { NetProtocol *previous = 0; NetProtocol *q = prot_list; while(q) { if (q == p) { if(previous) { previous->next = q->next; } else { prot_list = q->next; } delete p; return noErr; } previous = q; q = q->next; } } return lapProtErr; } #if MONITOR static void dump_packet( uint8 *packet, int length ) { char buf[1000], sm[10]; *buf = 0; if(length > 256) length = 256; for (int i=0; inext = 0; if(send_queue) { LPPACKET p = send_queue; // The queue is short. It would be larger overhead to double-link it. while(p->next) p = p->next; p->next = Packet; } else { send_queue = Packet; } LeaveCriticalSection( &send_csection ); } static LPPACKET get_send_head( void ) { LPPACKET Packet = 0; EnterCriticalSection( &send_csection ); if(send_queue) { Packet = send_queue; send_queue = send_queue->next; } LeaveCriticalSection( &send_csection ); return Packet; } static int get_write_packet_pool_sz( void ) { LPPACKET t = write_packet_pool; int sz = 0; while(t) { t = t->next; sz++; } return(sz); } static void free_write_packets( void ) { LPPACKET next; int i = 0; while(write_packet_pool) { next = write_packet_pool->next; D(bug("Freeing write packet %ld\n",++i)); PacketFreePacket(write_packet_pool); write_packet_pool = next; } } void recycle_write_packet( LPPACKET Packet ) { EnterCriticalSection( &wpool_csection ); Packet->next = write_packet_pool; write_packet_pool = Packet; D(bug("Pool size after recycling = %ld\n",get_write_packet_pool_sz())); LeaveCriticalSection( &wpool_csection ); } static LPPACKET get_write_packet( UINT len ) { LPPACKET Packet = 0; EnterCriticalSection( &wpool_csection ); if(write_packet_pool) { Packet = write_packet_pool; write_packet_pool = write_packet_pool->next; Packet->OverLapped.Offset = 0; Packet->OverLapped.OffsetHigh = 0; Packet->Length = len; Packet->BytesReceived = 0; Packet->bIoComplete = FALSE; Packet->free = TRUE; Packet->next = 0; // actually an auto-reset event. if(Packet->OverLapped.hEvent) ResetEvent(Packet->OverLapped.hEvent); } else { Packet = PacketAllocatePacket(fd,len); } D(bug("Pool size after get wr packet = %ld\n",get_write_packet_pool_sz())); LeaveCriticalSection( &wpool_csection ); return Packet; } static unsigned int ether_thread_write_packets(void *arg) { LPPACKET Packet; thread_active_1 = true; D(bug("ether_thread_write_packets start\n")); while(thread_active) { // must be alertable, otherwise write completion is never called WaitForSingleObjectEx(int_send_now,INFINITE,TRUE); while( thread_active && (Packet = get_send_head()) != 0 ) { switch (net_if_type) { case NET_IF_ROUTER: if(router_write_packet((uint8 *)Packet->Buffer, Packet->Length)) { Packet->bIoComplete = TRUE; recycle_write_packet(Packet); } break; case NET_IF_FAKE: Packet->bIoComplete = TRUE; recycle_write_packet(Packet); break; case NET_IF_B2ETHER: if(!PacketSendPacket( fd, Packet, FALSE, TRUE )) { // already recycled if async } break; case NET_IF_TAP: if (!tap_send_packet(fd, Packet, FALSE, TRUE)) { // already recycled if async } break; case NET_IF_SLIRP: slirp_input((uint8 *)Packet->Buffer, Packet->Length); Packet->bIoComplete = TRUE; recycle_write_packet(Packet); break; } } } D(bug("ether_thread_write_packets exit\n")); thread_active_1 = false; return(0); } static BOOL write_packet( uint8 *packet, int len ) { LPPACKET Packet; D(bug("write_packet\n")); Packet = get_write_packet(len); if(Packet) { memcpy( Packet->Buffer, packet, len ); EnterCriticalSection( &fetch_csection ); pending_packet_sz[echo_count] = min(sizeof(pending_packet),len); memcpy( pending_packet[echo_count], packet, pending_packet_sz[echo_count] ); echo_count = (echo_count+1) & (~(MAX_ECHO-1)); LeaveCriticalSection( &fetch_csection ); insert_send_queue( Packet ); ReleaseSemaphore(int_send_now,1,NULL); return(TRUE); } else { return(FALSE); } } static int16 ether_do_write(uint32 arg) { D(bug("ether_write\n")); // Copy packet to buffer uint8 packet[1514], *p = packet; int len = ether_arg_to_buffer(arg, p); if(len > 1514) { D(bug("illegal packet length: %d\n",len)); return eLenErr; } else { #if MONITOR bug("Sending Ethernet packet (%d bytes):\n",(int)len); dump_packet( packet, len ); #endif } // Transmit packet if (!write_packet(packet, len)) { D(bug("WARNING: couldn't transmit packet\n")); return excessCollsns; } else { // It's up to the protocol drivers to do the error checking. Even if the // i/o completion routine returns ok, there can be errors, so there is // no point to wait for write completion and try to make some sense of the // possible error codes. return noErr; } } static void init_queue(void) { queue_inx = 0; queue_head = 0; for( int i=0; i 0) { D(bug("ethernet queue full, packet dropped\n")); } else { if(sz > 1514) sz = 1514; queue[queue_inx].sz = sz; memcpy( queue[queue_inx].buf, buf, sz ); queue_inx++; if(queue_inx >= MAX_QUEUE_ITEMS) queue_inx = 0; if(wait_request) { wait_request = false; ReleaseSemaphore(int_sig,1,NULL); } } LeaveCriticalSection( &queue_csection ); } static int dequeue_packet( uint8 *buf ) { int sz; if(!thread_active) return(0); EnterCriticalSection( &queue_csection ); sz = queue[queue_head].sz; if(sz > 0) { memcpy( buf, queue[queue_head].buf, sz ); queue[queue_head].sz = 0; queue_head++; if(queue_head >= MAX_QUEUE_ITEMS) queue_head = 0; } LeaveCriticalSection( &queue_csection ); return(sz); } static void trigger_queue(void) { EnterCriticalSection( &queue_csection ); if( queue[queue_head].sz > 0 ) { D(bug(" packet received, triggering Ethernet interrupt\n")); SetInterruptFlag(INTFLAG_ETHER); TriggerInterrupt(); // of course can't wait here. } LeaveCriticalSection( &queue_csection ); } static bool set_wait_request(void) { bool result; EnterCriticalSection( &queue_csection ); if(queue[queue_head].sz) { result = true; } else { result = false; wait_request = true; } LeaveCriticalSection( &queue_csection ); return(result); } /* * TAP-Win32 glue */ static LPADAPTER tap_open_adapter(const char *dev_name) { fd = (LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*fd)); if (fd == NULL) return NULL; char dev_path[MAX_PATH]; snprintf(dev_path, sizeof(dev_path), "\\\\.\\Global\\%s.tap", dev_name); HANDLE handle = CreateFile( dev_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL); if (handle == NULL || handle == INVALID_HANDLE_VALUE) return NULL; fd->hFile = handle; return fd; } static void tap_close_adapter(LPADAPTER fd) { if (fd) { if (fd->hFile) { tap_set_status(fd, false); CloseHandle(fd->hFile); } GlobalFreePtr(fd); } } static bool tap_check_version(LPADAPTER fd) { ULONG len; ULONG info[3] = { 0, }; if (!DeviceIoControl(fd->hFile, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info), &len, NULL) && !DeviceIoControl(fd->hFile, OLD_TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info), &len, NULL)) return false; if (info[0] > TAP_VERSION_MIN_MAJOR) return true; if (info[0] == TAP_VERSION_MIN_MAJOR && info[1] >= TAP_VERSION_MIN_MINOR) return true; return false; } static bool tap_set_status(LPADAPTER fd, ULONG status) { DWORD len = 0; return DeviceIoControl(fd->hFile, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof (status), &status, sizeof (status), &len, NULL); } static bool tap_get_mac(LPADAPTER fd, LPBYTE addr) { DWORD len = 0; return DeviceIoControl(fd->hFile, TAP_IOCTL_GET_MAC, addr, 6, addr, 6, &len, NULL); } static VOID CALLBACK tap_write_completion( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverLapped ) { LPPACKET lpPacket = CONTAINING_RECORD(lpOverLapped, PACKET, OverLapped); lpPacket->bIoComplete = TRUE; recycle_write_packet(lpPacket); } static bool tap_send_packet( LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync, BOOLEAN RecyclingAllowed) { BOOLEAN Result; lpPacket->OverLapped.Offset = 0; lpPacket->OverLapped.OffsetHigh = 0; lpPacket->bIoComplete = FALSE; if (Sync) { Result = WriteFile(fd->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->BytesReceived, &lpPacket->OverLapped); if (Result) { GetOverlappedResult(fd->hFile, &lpPacket->OverLapped, &lpPacket->BytesReceived, TRUE); } lpPacket->bIoComplete = TRUE; if (RecyclingAllowed) PacketFreePacket(lpPacket); } else { Result = WriteFileEx(fd->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->OverLapped, tap_write_completion); if (!Result && RecyclingAllowed) recycle_write_packet(lpPacket); } return Result; } static bool tap_receive_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync) { BOOLEAN Result; lpPacket->OverLapped.Offset = 0; lpPacket->OverLapped.OffsetHigh = 0; lpPacket->bIoComplete = FALSE; if (Sync) { Result = ReadFile(fd->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->BytesReceived, &lpPacket->OverLapped); if (Result) { Result = GetOverlappedResult(fd->hFile, &lpPacket->OverLapped, &lpPacket->BytesReceived, TRUE); if (Result) lpPacket->bIoComplete = TRUE; else lpPacket->free = TRUE; } } else { Result = ReadFileEx(fd->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->OverLapped, packet_read_completion); if (!Result) lpPacket->BytesReceived = 0; } return Result; } /* * SLIRP output buffer glue */ int slirp_can_output(void) { return 1; } void slirp_output(const uint8 *packet, int len) { enqueue_packet(packet, len); } static unsigned int slirp_receive_func(void *arg) { D(bug("slirp_receive_func\n")); thread_active_2 = true; while (thread_active) { // Wait for packets to arrive fd_set rfds, wfds, xfds; int nfds, ret, timeout; // ... in the output queue nfds = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); timeout = slirp_select_fill(&nfds, &rfds, &wfds, &xfds); #if ! USE_SLIRP_TIMEOUT timeout = 10000; #endif if (nfds < 0) { /* Windows does not honour the timeout if there is not descriptor to wait for */ Delay_usec(timeout); ret = 0; } else { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = timeout; ret = select(0, &rfds, &wfds, &xfds, &tv); } if (ret >= 0) slirp_select_poll(&rfds, &wfds, &xfds); } D(bug("slirp_receive_func exit\n")); thread_active_2 = false; return 0; } /* * Packet reception threads */ VOID CALLBACK packet_read_completion( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped ) { EnterCriticalSection( &fetch_csection ); LPPACKET lpPacket = CONTAINING_RECORD(lpOverlapped,PACKET,OverLapped); D(bug("packet_read_completion bytes=%d, error code=%d\n",dwNumberOfBytesTransfered,dwErrorCode)); if(thread_active && !dwErrorCode) { int count = min(dwNumberOfBytesTransfered,1514); if(count) { int j = echo_count; for(int i=MAX_ECHO; i; i--) { j--; if(j < 0) j = MAX_ECHO-1; if(count == pending_packet_sz[j] && memcmp(pending_packet[j],lpPacket->Buffer,count) == 0) { D(bug("packet_read_completion discarding own packet.\n")); dwNumberOfBytesTransfered = 0; j = (j+1) & (~(MAX_ECHO-1)); if(j != echo_count) { D(bug("Wow, this fix made some good after all...\n")); } break; } } // XXX drop packets that are not for us if (net_if_type == NET_IF_TAP) { if (memcmp((LPBYTE)lpPacket->Buffer, ether_addr, 6) != 0) dwNumberOfBytesTransfered = 0; } if(dwNumberOfBytesTransfered) { if(net_if_type != NET_IF_ROUTER || !router_read_packet((uint8 *)lpPacket->Buffer, dwNumberOfBytesTransfered)) { enqueue_packet( (LPBYTE)lpPacket->Buffer, dwNumberOfBytesTransfered ); } } } } // actually an auto-reset event. if(lpPacket->OverLapped.hEvent) ResetEvent(lpPacket->OverLapped.hEvent); lpPacket->free = TRUE; lpPacket->bIoComplete = TRUE; if(wait_request2) { wait_request2 = false; ReleaseSemaphore(int_sig2,1,NULL); } LeaveCriticalSection( &fetch_csection ); } static BOOL has_no_completed_io(void) { BOOL result = TRUE; EnterCriticalSection( &fetch_csection ); for( int i=0; ibIoComplete) { result = FALSE; break; } } if(result) wait_request2 = true; LeaveCriticalSection( &fetch_csection ); return(result); } static bool allocate_read_packets(void) { for( int i=0; ifree) { packets[i]->free = FALSE; BOOLEAN Result; switch (net_if_type) { case NET_IF_B2ETHER: Result = PacketReceivePacket(fd, packets[i], FALSE); break; case NET_IF_TAP: Result = tap_receive_packet(fd, packets[i], FALSE); break; } if (Result) { if(packets[i]->bIoComplete) { D(bug("Early io completion...\n")); packet_read_completion( ERROR_SUCCESS, packets[i]->BytesReceived, &packets[i]->OverLapped ); } } else { packets[i]->free = TRUE; } } } } if(thread_active && has_no_completed_io()) { D(bug("Waiting for int_sig2\n")); // "problem": awakens twice in a row. Fix if you increase the pool size. WaitForSingleObjectEx(int_sig2,INFINITE,TRUE); } } D(bug("ether_thread_get_packets_nt exit\n")); thread_active_2 = false; return 0; } static unsigned int ether_thread_feed_int(void *arg) { bool looping; thread_active_3 = true; D(bug("ether_thread_feed_int start\n")); while(thread_active) { D(bug("Waiting for int_sig\n")); WaitForSingleObject(int_sig,INFINITE); // Looping this way to avoid a race condition. D(bug("Triggering\n")); looping = true; while(thread_active && looping) { trigger_queue(); // Wait for interrupt acknowledge by EtherInterrupt() WaitForSingleObject(int_ack,INFINITE); if(thread_active) looping = set_wait_request(); } D(bug("Queue empty.\n")); } D(bug("ether_thread_feed_int exit\n")); thread_active_3 = false; return 0; } /* * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers */ static void ether_do_interrupt(void) { // Call protocol handler for received packets EthernetPacket ether_packet; uint32 packet = ether_packet.addr(); ssize_t length; for (;;) { // Read packet from Ethernet device length = dequeue_packet(Mac2HostAddr(packet)); if (length < 14) break; #if MONITOR bug("Receiving Ethernet packet (%d bytes):\n",(int)length); dump_packet( Mac2HostAddr(packet), length ); #endif // Dispatch packet ether_dispatch_packet(packet, length); } } #if DEBUG #pragma optimize("",on) #endif BasiliskII/src/Windows/xpram_windows.cpp0000755000175000017500000000445011232133661020573 0ustar centriscentris/* * xpram_windows.cpp - XPRAM handling, Windows specific stuff * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #define WIN32_LEAN_AND_MEAN #include #include using std::string; #include "xpram.h" // XPRAM file name and path #if POWERPC_ROM const char XPRAM_FILE_NAME[] = "SheepShaver_nvram.dat"; #else const char XPRAM_FILE_NAME[] = "BasiliskII_xpram.dat"; #endif static string xpram_path; /* * Construct XPRAM path */ static void build_xpram_path(void) { xpram_path.clear(); int pwd_len = GetCurrentDirectory(0, NULL); char *pwd = new char[pwd_len]; if (GetCurrentDirectory(pwd_len, pwd) == pwd_len - 1) xpram_path = string(pwd) + '\\'; delete[] pwd; xpram_path += XPRAM_FILE_NAME; } /* * Load XPRAM from settings file */ void LoadXPRAM(const char *vmdir) { // Construct XPRAM path build_xpram_path(); // Load XPRAM from settings file HANDLE fh = CreateFile(xpram_path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (fh != INVALID_HANDLE_VALUE) { DWORD bytesRead; ReadFile(fh, XPRAM, XPRAM_SIZE, &bytesRead, NULL); CloseHandle(fh); } } /* * Save XPRAM to settings file */ void SaveXPRAM(void) { HANDLE fh = CreateFile(xpram_path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (fh != INVALID_HANDLE_VALUE) { DWORD bytesWritten; WriteFile(fh, XPRAM, XPRAM_SIZE, &bytesWritten, NULL); CloseHandle(fh); } } /* * Delete PRAM file */ void ZapPRAM(void) { // Construct PRAM path build_xpram_path(); // Delete file DeleteFile(xpram_path.c_str()); } BasiliskII/src/Windows/cd_defs.h0000755000175000017500000001225510736405221016732 0ustar centriscentris/* * cd_defs.h * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #define MAXIMUM_NUMBER_TRACKS 100 #define MAXIMUM_CDROM_SIZE 804 typedef struct _TRACK_DATA { UCHAR Reserved; UCHAR Control : 4; UCHAR Adr : 4; UCHAR TrackNumber; UCHAR Reserved1; UCHAR Address[4]; } ATTRIBUTE_PACKED TRACK_DATA, *PTRACK_DATA; typedef struct _CDROM_TOC { UCHAR Length[2]; UCHAR FirstTrack; UCHAR LastTrack; TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; } ATTRIBUTE_PACKED CDROM_TOC, *PCDROM_TOC; // #include "ntddcdrm.h" #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM #define IOCTL_CDROM_UNLOAD_DRIVER CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) // // CDROM Audio Device Control Functions // #define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_PLAY_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_STOP_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_PAUSE_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_RESUME_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_GET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_SET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_GET_LAST_SESSION CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) #define IOCTL_CDROM_DISK_TYPE CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) typedef struct _VOLUME_CONTROL { UCHAR PortVolume[4]; } ATTRIBUTE_PACKED VOLUME_CONTROL, *PVOLUME_CONTROL; typedef struct _CDROM_PLAY_AUDIO_MSF { UCHAR StartingM; UCHAR StartingS; UCHAR StartingF; UCHAR EndingM; UCHAR EndingS; UCHAR EndingF; } ATTRIBUTE_PACKED CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; typedef struct _CDROM_SEEK_AUDIO_MSF { UCHAR M; UCHAR S; UCHAR F; } ATTRIBUTE_PACKED CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; // // CD ROM Sub-Q Channel Data Format // typedef struct _SUB_Q_HEADER { UCHAR Reserved; UCHAR AudioStatus; UCHAR DataLength[2]; } ATTRIBUTE_PACKED SUB_Q_HEADER, *PSUB_Q_HEADER; typedef struct _SUB_Q_CURRENT_POSITION { SUB_Q_HEADER Header; UCHAR FormatCode; UCHAR Control : 4; UCHAR ADR : 4; UCHAR TrackNumber; UCHAR IndexNumber; UCHAR AbsoluteAddress[4]; UCHAR TrackRelativeAddress[4]; } ATTRIBUTE_PACKED SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { SUB_Q_HEADER Header; UCHAR FormatCode; UCHAR Reserved[3]; UCHAR Reserved1 : 7; UCHAR Mcval : 1; UCHAR MediaCatalog[15]; } ATTRIBUTE_PACKED SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; typedef struct _SUB_Q_TRACK_ISRC { SUB_Q_HEADER Header; UCHAR FormatCode; UCHAR Reserved0; UCHAR Track; UCHAR Reserved1; UCHAR Reserved2 : 7; UCHAR Tcval : 1; UCHAR TrackIsrc[15]; } ATTRIBUTE_PACKED SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; typedef union _SUB_Q_CHANNEL_DATA { SUB_Q_CURRENT_POSITION CurrentPosition; SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; SUB_Q_TRACK_ISRC TrackIsrc; } SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; typedef enum _TRACK_MODE_TYPE { YellowMode2, XAForm2, CDDA } TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; typedef struct __RAW_READ_INFO { LARGE_INTEGER DiskOffset; ULONG SectorCount; TRACK_MODE_TYPE TrackMode; } ATTRIBUTE_PACKED RAW_READ_INFO, *PRAW_READ_INFO; typedef struct _CDROM_SUB_Q_DATA_FORMAT { UCHAR Format; UCHAR Track; } ATTRIBUTE_PACKED CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; #define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 #define IOCTL_CDROM_CURRENT_POSITION 0x01 #define IOCTL_CDROM_MEDIA_CATALOG 0x02 #define IOCTL_CDROM_TRACK_ISRC 0x03 #pragma pack() BasiliskII/src/Windows/BasiliskIIGUI.rc0000644000175000017500000000006010340133071020024 0ustar centriscentrisBasiliskIIGUI ICON PRELOAD "BasiliskIIGUI.ico" BasiliskII/src/Windows/Makefile.in0000755000175000017500000002047310424643264017245 0ustar centriscentris# Windows Makefile for Basilisk II ## System specific configuration SHELL = /bin/sh prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ datadir = @datadir@ mandir = @mandir@ man1dir = $(mandir)/man1 KEYCODES = ../SDL/keycodes DESTDIR = SDL_CFLAGS = @SDL_CFLAGS@ SDL_LIBS = @SDL_LIBS@ WANT_GTK = @WANT_GTK@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_LIBS = @GTK_LIBS@ SLIRP_CFLAGS = @SLIRP_CFLAGS@ SLIRP_SRCS = \ ../slirp/bootp.c ../slirp/ip_output.c ../slirp/tcp_input.c \ ../slirp/cksum.c ../slirp/mbuf.c ../slirp/tcp_output.c \ ../slirp/debug.c ../slirp/misc.c ../slirp/tcp_subr.c \ ../slirp/if.c ../slirp/sbuf.c ../slirp/tcp_timer.c \ ../slirp/ip_icmp.c ../slirp/slirp.c ../slirp/tftp.c \ ../slirp/ip_input.c ../slirp/socket.c ../slirp/udp.c SLIRP_OBJS = $(SLIRP_SRCS:../slirp/%.c=$(OBJ_DIR)/slirp-%.o) LN_S = @LN_S@ WINDRES = @WINDRES@ CC = @CC@ CXX = @CXX@ CFLAGS = @CFLAGS@ $(SDL_CFLAGS) CXXFLAGS = @CXXFLAGS@ $(SDL_CFLAGS) CPPFLAGS = @CPPFLAGS@ -I../include -I. @CPUINCLUDES@ -I../slirp DEFS = @DEFS@ @DEFINES@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -lwsock32 -liphlpapi CPUSRCS = @CPUSRCS@ HOST_CC = gcc HOST_CXX = g++ HOST_CFLAGS = -O2 HOST_CXXFLAGS = -O2 HOST_LDFLAGS = ## Files UNIXSRCS = vm_alloc.cpp vm_alloc.h sigsegv.cpp sigsegv.h video_vosf.h video_blit.cpp video_blit.h CDENABLESRCS = cdenable/cache.cpp cdenable/eject_nt.cpp cdenable/ntcd.cpp ROUTERSRCS = router/arp.cpp router/dump.cpp router/dynsockets.cpp router/ftp.cpp \ router/icmp.cpp router/mib/interfaces.cpp router/iphelp.cpp router/ipsocket.cpp \ router/mib/mibaccess.cpp router/router.cpp router/tcp.cpp router/udp.cpp b2ether/packet32.cpp SRCS = ../main.cpp main_windows.cpp ../prefs.cpp ../prefs_items.cpp prefs_windows.cpp \ sys_windows.cpp ../rom_patches.cpp ../slot_rom.cpp ../rsrc_patches.cpp \ ../emul_op.cpp ../macos_util.cpp ../xpram.cpp xpram_windows.cpp ../timer.cpp \ timer_windows.cpp ../adb.cpp ../serial.cpp serial_windows.cpp \ ../ether.cpp ether_windows.cpp ../sony.cpp ../disk.cpp ../cdrom.cpp \ ../scsi.cpp ../dummy/scsi_dummy.cpp ../video.cpp ../SDL/video_sdl.cpp \ video_blit.cpp ../audio.cpp ../SDL/audio_sdl.cpp clip_windows.cpp \ ../extfs.cpp extfs_windows.cpp ../user_strings.cpp user_strings_windows.cpp \ vm_alloc.cpp sigsegv.cpp posix_emu.cpp util_windows.cpp kernel_windows.cpp \ ../dummy/prefs_editor_dummy.cpp BasiliskII.rc \ $(CDENABLESRCS) $(ROUTERSRCS) $(CPUSRCS) $(SLIRP_OBJS) UI_SRCS = ../prefs.cpp prefs_windows.cpp prefs_editor_gtk.cpp xpram_windows.cpp \ ../prefs_items.cpp ../user_strings.cpp user_strings_windows.cpp util_windows.cpp \ b2ether/Packet32.cpp BasiliskIIGUI.rc UI_APP = BasiliskIIGUI.exe APP = BasiliskII.exe PROGS = $(APP) ifeq ($(WANT_GTK),yes) PROGS += $(UI_APP) endif ## Rules .PHONY: modules install installdirs uninstall mostlyclean clean distclean depend dep .SUFFIXES: .SUFFIXES: .c .cpp .s .o .h all: $(PROGS) $(UNIXSRCS): %: ../Unix/% $(LN_S) $< $@ OBJ_DIR = obj $(OBJ_DIR):: @[ -d $(OBJ_DIR) ] || mkdir $(OBJ_DIR) > /dev/null 2>&1 define SRCS_LIST_TO_OBJS $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(SRCS), \ $(basename $(notdir $(file)))))) endef OBJS = $(SRCS_LIST_TO_OBJS) define UI_SRCS_LIST_TO_OBJS $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(foreach file, $(UI_SRCS), \ $(basename $(notdir $(file)))))) endef UI_OBJS = $(UI_SRCS_LIST_TO_OBJS) SRC_PATHS += $(sort $(foreach file, $(SRCS), $(dir $(file)))) VPATH := VPATH += $(addprefix :, $(subst ,:, $(filter-out $($(subst, :, ,$(VPATH))), $(SRC_PATHS)))) $(APP): $(UNIXSRCS) $(OBJ_DIR) $(OBJS) $(CXX) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) $(SDL_LIBS) $(UI_APP): $(UNIXSRCS) $(OBJ_DIR) $(UI_OBJS) $(CXX) -o $@ $(LDFLAGS) $(UI_OBJS) $(LIBS) $(GTK_LIBS) -mwindows -mno-cygwin mostlyclean: rm -f $(APP) $(UI_APP) $(OBJ_DIR)/* core* *.core *~ *.bak clean: mostlyclean rm -f $(UNIXSRCS) rm -f cpuemu.cpp cpudefs.cpp cputmp*.s cpufast*.s cpustbl.cpp cputbl.h compemu.cpp compstbl.cpp comptbl.h distclean: clean rm -rf $(OBJ_DIR) rm -rf autom4te.cache rm -f Makefile rm -f config.cache config.log config.status config.h depend dep: makedepend $(CPPFLAGS) -Y. $(SRCS) 2>/dev/null $(OBJ_DIR)/%.ho : %.c $(HOST_CC) $(CPPFLAGS) $(DEFS) $(HOST_CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.ho : %.cpp $(HOST_CXX) $(CPPFLAGS) $(DEFS) $(HOST_CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/slirp-%.o : ../slirp/%.c $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) $(SLIRP_CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.c $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/%.o : %.s $(CC) $(CPPFLAGS) $(DEFS) $(CFLAGS) -c $< -o $@ $(OBJ_DIR)/prefs_editor_gtk.o: prefs_editor_gtk.cpp $(CXX) -O2 -mno-cygwin -mms-bitfields $(CPPFLAGS) $(DEFS) $(GTK_CFLAGS) -c $< -o $@ # Windows resources $(OBJ_DIR)/%.o: %.rc $(WINDRES) --include-dir ../Windows -i $< -o $@ $(OBJ_DIR)/build68k.exe: $(OBJ_DIR)/build68k.ho $(HOST_CC) $(HOST_LDFLAGS) -o $@ $< $(OBJ_DIR)/gencpu.exe: $(OBJ_DIR)/gencpu.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho $(HOST_CXX) $(HOST_LDFLAGS) -o $@ $(OBJ_DIR)/gencpu.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho $(OBJ_DIR)/gencomp.exe: $(OBJ_DIR)/gencomp.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho $(HOST_CXX) $(HOST_LDFLAGS) -o $@ $(OBJ_DIR)/gencomp.ho $(OBJ_DIR)/readcpu.ho $(OBJ_DIR)/cpudefs.ho cpudefs.cpp: $(OBJ_DIR)/build68k.exe ../uae_cpu/table68k $(OBJ_DIR)/build68k.exe ../uae_cpu/table68k >cpudefs.cpp cpustbl.cpp: cpuemu.cpp cpustbl_nf.cpp: cpustbl.cpp compstbl.cpp: compemu.cpp cputbl.h: cpuemu.cpp comptbl.h: compemu.cpp cpuemu.cpp: $(OBJ_DIR)/gencpu.exe $(OBJ_DIR)/gencpu.exe compemu.cpp: $(OBJ_DIR)/gencomp.exe $(OBJ_DIR)/gencomp.exe $(OBJ_DIR)/cpustbl_nf.o: cpustbl.cpp $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -DNOFLAGS -c $< -o $@ $(OBJ_DIR)/compemu_support.o: compemu_support.cpp comptbl.h $(CXX) $(CPPFLAGS) $(DEFS) $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu1.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu2.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu3.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu4.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu5.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu6.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu7.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu8.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu1_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu2_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu3_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu4_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu5_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu6_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu7_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/cpuemu8_nf.o: cpuemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 -DNOFLAGS $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu1.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_1 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu2.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_2 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu3.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_3 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu4.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_4 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu5.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_5 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu6.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_6 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu7.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_7 $(CXXFLAGS) -c $< -o $@ $(OBJ_DIR)/compemu8.o: compemu.cpp $(CXX) $(CPPFLAGS) $(DEFS) -DPART_8 $(CXXFLAGS) -c $< -o $@ #------------------------------------------------------------------------- # DO NOT DELETE THIS LINE -- make depend depends on it. BasiliskII/src/Windows/sys_windows.cpp0000755000175000017500000004730710736405222020275 0ustar centriscentris/* * sys_windows.cpp - System dependent routines, Windows implementation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #define WIN32_LEAN_AND_MEAN #include #include #include using std::string; #include using std::min; #include "main.h" #include "macos_util.h" #include "prefs.h" #include "user_strings.h" #include "sys.h" #include "cd_defs.h" #include "cdenable/ntcd.h" #include "cdenable/cache.h" #include "cdenable/eject_nt.h" #define DEBUG 0 #include "debug.h" // File handles are pointers to these structures struct file_handle { char *name; // Copy of device/file name HANDLE fh; bool is_file; // Flag: plain file or physical device? bool is_floppy; // Flag: floppy device bool is_cdrom; // Flag: CD-ROM device bool read_only; // Copy of Sys_open() flag loff_t start_byte; // Size of file header (if any) loff_t file_size; // Size of file data (only valid if is_file is true) cachetype cache; bool is_media_present; }; // Open file handles struct open_file_handle { file_handle *fh; open_file_handle *next; }; static open_file_handle *open_file_handles = NULL; // File handle of first floppy drive (for SysMountFirstFloppy()) static file_handle *first_floppy = NULL; // CD-ROM variables static const int CD_READ_AHEAD_SECTORS = 16; static char *sector_buffer = NULL; // Prototypes static bool is_cdrom_readable(file_handle *fh); /* * Initialization */ void SysInit(void) { // Initialize CD-ROM driver sector_buffer = (char *)VirtualAlloc(NULL, 8192, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); CdenableSysInstallStart(); } /* * Deinitialization */ void SysExit(void) { if (sector_buffer) { VirtualFree(sector_buffer, 0, MEM_RELEASE ); sector_buffer = NULL; } } /* * Manage open file handles */ static void sys_add_file_handle(file_handle *fh) { open_file_handle *p = new open_file_handle; p->fh = fh; p->next = open_file_handles; open_file_handles = p; } static void sys_remove_file_handle(file_handle *fh) { open_file_handle *p = open_file_handles; open_file_handle *q = NULL; while (p) { if (p->fh == fh) { if (q) q->next = p->next; else open_file_handles = p->next; delete p; break; } q = p; p = p->next; } } /* * Mount removable media now */ void mount_removable_media(int media) { for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) { file_handle * const fh = p->fh; if (fh->is_cdrom && (media & MEDIA_CD)) { cache_clear(&fh->cache); fh->start_byte = 0; if (fh->fh && fh->fh != INVALID_HANDLE_VALUE) CloseHandle(fh->fh); // Re-open device char device_name[MAX_PATH]; sprintf(device_name, "\\\\.\\%c:", fh->name[0]); fh->fh = CreateFile( device_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh->fh != INVALID_HANDLE_VALUE) { fh->is_media_present = is_cdrom_readable(fh); if (fh->is_media_present) MountVolume(fh); } else { fh->is_media_present = false; } } } } /* * Account for media that has just arrived */ void SysMediaArrived(void) { mount_removable_media(MEDIA_REMOVABLE); } /* * Account for media that has just been removed */ void SysMediaRemoved(void) { } /* * Mount first floppy disk */ void SysMountFirstFloppy(void) { if (first_floppy) MountVolume(first_floppy); } /* * This gets called when no "floppy" prefs items are found * It scans for available floppy drives and adds appropriate prefs items */ void SysAddFloppyPrefs(void) { } /* * This gets called when no "disk" prefs items are found * It scans for available HFS volumes and adds appropriate prefs items */ void SysAddDiskPrefs(void) { } /* * This gets called when no "cdrom" prefs items are found * It scans for available CD-ROM drives and adds appropriate prefs items */ void SysAddCDROMPrefs(void) { // Don't scan for drives if nocdrom option given if (PrefsFindBool("nocdrom")) return; for (char letter = 'C'; letter <= 'Z'; letter++) { int i = (int)(letter - 'A'); string rootdir = letter + ":\\"; if (GetDriveType(rootdir.c_str()) == DRIVE_CDROM) PrefsAddString("cdrom", rootdir.c_str()); } } /* * Add default serial prefs (must be added, even if no ports present) */ void SysAddSerialPrefs(void) { PrefsAddString("seriala", "COM1"); PrefsAddString("serialb", "COM2"); } /* * Read CD-ROM * Must give cd some time to settle * Can't give too much however, would be annoying, this is difficult.. */ static inline int cd_read_with_retry(file_handle *fh, ULONG LBA, int count, char *buf ) { if (!fh || !fh->fh) return 0; return CdenableSysReadCdBytes(fh->fh, LBA, count, buf); } static int cd_read(file_handle *fh, cachetype *cptr, ULONG LBA, int count, char *buf) { ULONG l1, l2, cc; int i, c_count, got_bytes = 0, nblocks, s_inx, ss, first_block; int ok_bytes = 0; char *ptr, *ttptr = 0, *tmpbuf; if (count <= 0) return 0; if (!fh || !fh->fh) return 0; ss = 2048; l1 = (LBA / ss) * ss; l2 = ((LBA + count - 1 + ss) / ss) * ss; cc = l2 - l1; nblocks = cc / ss; first_block = LBA / ss; ptr = buf; s_inx = LBA - l1; c_count = ss - s_inx; if (c_count > count) c_count = count; for (i = 0; i < nblocks; i++) { if (!cache_get(cptr, first_block + i, sector_buffer)) break; memcpy(ptr, sector_buffer + s_inx, c_count); ok_bytes += c_count; ptr += c_count; s_inx = 0; c_count = ss; if (c_count > count - ok_bytes) c_count = count - ok_bytes; } if (i != nblocks && count != ok_bytes) { int bytes_left = count - ok_bytes; int blocks_left = nblocks - i; int alignedleft; // NEW read ahead code: int ahead = CD_READ_AHEAD_SECTORS; if (blocks_left < ahead) { nblocks += (ahead - blocks_left); blocks_left = ahead; } alignedleft = blocks_left*ss; tmpbuf = (char *)VirtualAlloc( NULL, alignedleft, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (tmpbuf) { got_bytes = cd_read_with_retry(fh, (first_block + i) * ss, alignedleft, tmpbuf); if (got_bytes != alignedleft) { // should never happen // Yes it does ... if (got_bytes < 0) got_bytes = 0; if (c_count > got_bytes) c_count = got_bytes; if (c_count > 0) { ttptr = tmpbuf; memcpy(ptr, ttptr + s_inx, c_count); ok_bytes += c_count; } VirtualFree(tmpbuf, 0, MEM_RELEASE ); return ok_bytes; } ttptr = tmpbuf; for ( ; i < nblocks; i++) { if (c_count > 0) { memcpy(ptr, ttptr + s_inx, c_count); ok_bytes += c_count; ptr += c_count; } s_inx = 0; c_count = ss; if (c_count > count - ok_bytes) c_count = count - ok_bytes; cache_put(cptr, first_block + i, ttptr, ss); ttptr += ss; } VirtualFree(tmpbuf, 0, MEM_RELEASE ); } } return ok_bytes; } /* * Check if file handle FH represents a readable CD-ROM */ static bool is_cdrom_readable(file_handle *fh) { if (!fh || !fh->fh) return false; cache_clear(&fh->cache); DWORD dummy; bool result = (0 != DeviceIoControl( fh->fh, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &dummy, NULL)); if (!result) { const size_t n_bytes = 2048; char *buffer = (char *)VirtualAlloc(NULL, n_bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (buffer) { result = (cd_read_with_retry(fh, 0, n_bytes, buffer) == n_bytes); VirtualFree(buffer, 0, MEM_RELEASE); } } return result; } /* * Check if NAME represents a read-only file */ static bool is_read_only_path(const char *name) { DWORD attrib = GetFileAttributes((char *)name); return (attrib != INVALID_FILE_ATTRIBUTES && ((attrib & FILE_ATTRIBUTE_READONLY) != 0)); } /* * Open file/device, create new file handle (returns NULL on error) */ void *Sys_open(const char *path_name, bool read_only) { file_handle * fh = NULL; // Parse path name and options char name[MAX_PATH]; strcpy(name, path_name); // Normalize floppy / cd path int name_len = strlen(name); if (name_len == 1 && isalpha(name[0])) strcat(name, ":\\"); if (name_len > 0 && name[name_len - 1] == ':') strcat(name, "\\"); name_len = strlen(name); D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write")); if (name_len > 0 && name[name_len - 1] == '\\') { int type = GetDriveType(name); if (type == DRIVE_CDROM) { read_only = true; char device_name[MAX_PATH]; sprintf(device_name, "\\\\.\\%c:", name[0]); // Open device HANDLE h = CreateFile( device_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h != INVALID_HANDLE_VALUE) { fh = new file_handle; fh->name = strdup(name); fh->fh = h; fh->is_file = false; fh->read_only = read_only; fh->start_byte = 0; fh->is_floppy = false; fh->is_cdrom = true; memset(&fh->cache, 0, sizeof(cachetype)); cache_init(&fh->cache); cache_clear(&fh->cache); if (!PrefsFindBool("nocdrom")) fh->is_media_present = is_cdrom_readable(fh); } } } else { // Hard file // Check if write access is allowed, set read-only flag if not if (!read_only && is_read_only_path(name)) read_only = true; // Open file HANDLE h = CreateFile( name, read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE && !read_only) { // Read-write failed, try read-only read_only = true; h = CreateFile( name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } if (h != INVALID_HANDLE_VALUE) { fh = new file_handle; fh->name = strdup(name); fh->fh = h; fh->is_file = true; fh->read_only = read_only; fh->start_byte = 0; fh->is_floppy = false; fh->is_cdrom = false; // Detect disk image file layout loff_t size = GetFileSize(h, NULL); DWORD bytes_read; uint8 data[256]; ReadFile(h, data, sizeof(data), &bytes_read, NULL); FileDiskLayout(size, data, fh->start_byte, fh->file_size); } } if (fh->is_floppy && first_floppy == NULL) first_floppy = fh; if (fh) sys_add_file_handle(fh); return fh; } /* * Close file/device, delete file handle */ void Sys_close(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; sys_remove_file_handle(fh); if (fh->is_cdrom) { cache_final(&fh->cache); SysAllowRemoval((void *)fh); } if (fh->fh != NULL) { CloseHandle(fh->fh); fh->fh = NULL; } if (fh->name) free(fh->name); delete fh; } /* * Read "length" bytes from file/device, starting at "offset", to "buffer", * returns number of bytes read (or 0) */ size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length) { file_handle *fh = (file_handle *)arg; if (!fh) return 0; DWORD bytes_read = 0; if (fh->is_file) { // Seek to position LONG lo = (LONG)offset; LONG hi = (LONG)(offset >> 32); DWORD r = SetFilePointer(fh->fh, lo, &hi, FILE_BEGIN); if (r == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return 0; // Read data if (ReadFile(fh->fh, buffer, length, &bytes_read, NULL) == 0) bytes_read = 0; } else if (fh->is_cdrom) { int bytes_left, try_bytes, got_bytes; char *b = (char *)buffer; bytes_left = length; while (bytes_left) { try_bytes = min(bytes_left, 32768); if (fh->is_cdrom) { got_bytes = cd_read(fh, &fh->cache, (DWORD)offset, try_bytes, b); if (got_bytes != try_bytes && !PrefsFindBool("nocdrom")) fh->is_media_present = is_cdrom_readable(fh); } b += got_bytes; offset += got_bytes; bytes_read += got_bytes; bytes_left -= got_bytes; if (got_bytes != try_bytes) bytes_left = 0; } } // TODO: other media return bytes_read; } /* * Write "length" bytes from "buffer" to file/device, starting at "offset", * returns number of bytes written (or 0) */ size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length) { file_handle *fh = (file_handle *)arg; if (!fh) return 0; DWORD bytes_written = 0; if (fh->is_file) { // Seek to position LONG lo = (LONG)offset; LONG hi = (LONG)(offset >> 32); DWORD r = SetFilePointer(fh->fh, lo, &hi, FILE_BEGIN); if (r == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return 0; // Write data if (WriteFile(fh->fh, buffer, length, &bytes_written, NULL) == 0) bytes_written = 0; } // TODO: other media return bytes_written; } /* * Return size of file/device (minus header) */ loff_t SysGetFileSize(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; if (fh->is_file) return fh->file_size; else if (fh->is_cdrom) return 0x28A00000; // FIXME: get real CD-ROM size else { // TODO: other media return 0; } } /* * Eject volume (if applicable) */ void SysEject(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (fh->is_cdrom && fh->fh) { fh->is_media_present = false; // Commented out because there was some problems, but can't remember // exactly ... need to find out // EjectVolume(toupper(*fh->name),false); // Preventing is cumulative, try to make sure it's indeed released now for (int i = 0; i < 10; i++) PreventRemovalOfVolume(fh->fh, false); if (!PrefsFindBool("nocdrom")) { DWORD dummy; DeviceIoControl( fh->fh, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dummy, NULL ); } cache_clear(&fh->cache); fh->start_byte = 0; } // TODO: handle floppies } /* * Format volume (if applicable) */ bool SysFormat(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; //!! return true; } /* * Check if file/device is read-only (this includes the read-only flag on Sys_open()) */ bool SysIsReadOnly(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; return fh->read_only; } /* * Check if the given file handle refers to a fixed or a removable disk */ bool SysIsFixedDisk(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return true; if (fh->is_file) return true; else if (fh->is_floppy || fh->is_cdrom) return false; else return true; } /* * Check if a disk is inserted in the drive (always true for files) */ bool SysIsDiskInserted(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return false; if (fh->is_file) return true; else if (fh->is_cdrom && !PrefsFindBool("nocdrom")) { if (PrefsFindBool("pollmedia")) fh->is_media_present = is_cdrom_readable(fh); return fh->is_media_present; } else { // TODO: other media } return false; } /* * Prevent medium removal (if applicable) */ void SysPreventRemoval(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (fh->is_cdrom && fh->fh) PreventRemovalOfVolume(fh->fh, true); } /* * Allow medium removal (if applicable) */ void SysAllowRemoval(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh) return; if (fh->is_cdrom && fh->fh) PreventRemovalOfVolume(fh->fh, false); } /* * Read CD-ROM TOC (binary MSF format, 804 bytes max.) */ bool SysCDReadTOC(void *arg, uint8 *toc) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return false; DWORD dummy; return DeviceIoControl(fh->fh, IOCTL_CDROM_READ_TOC, NULL, 0, toc, min((int)sizeof(CDROM_TOC), 804), &dummy, NULL); } /* * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard) */ bool SysCDGetPosition(void *arg, uint8 *pos) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return false; SUB_Q_CHANNEL_DATA q_data; CDROM_SUB_Q_DATA_FORMAT q_format; q_format.Format = IOCTL_CDROM_CURRENT_POSITION; q_format.Track = 0; // used only by ISRC reads DWORD dwBytesReturned = 0; bool ok = DeviceIoControl(fh->fh, IOCTL_CDROM_READ_Q_CHANNEL, &q_format, sizeof(CDROM_SUB_Q_DATA_FORMAT), &q_data, sizeof(SUB_Q_CHANNEL_DATA), &dwBytesReturned, NULL); if (ok) memcpy(pos, &q_data.CurrentPosition, sizeof(SUB_Q_CURRENT_POSITION)); return ok; } /* * Play CD audio */ bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return false; CDROM_PLAY_AUDIO_MSF msf; msf.StartingM = start_m; msf.StartingS = start_s; msf.StartingF = start_f; msf.EndingM = end_m; msf.EndingS = end_s; msf.EndingF = end_f; DWORD dwBytesReturned = 0; return DeviceIoControl(fh->fh, IOCTL_CDROM_PLAY_AUDIO_MSF, &msf, sizeof(CDROM_PLAY_AUDIO_MSF), NULL, 0, &dwBytesReturned, NULL); } /* * Pause CD audio */ bool SysCDPause(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return false; DWORD dwBytesReturned = 0; return DeviceIoControl(fh->fh, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &dwBytesReturned, NULL); } /* * Resume paused CD audio */ bool SysCDResume(void *arg) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return false; DWORD dwBytesReturned = 0; return DeviceIoControl(fh->fh, IOCTL_CDROM_RESUME_AUDIO, NULL, 0, NULL, 0, &dwBytesReturned, NULL); } /* * Stop CD audio */ bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return false; DWORD dwBytesReturned = 0; return DeviceIoControl(fh->fh, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &dwBytesReturned, NULL); } /* * Perform CD audio fast-forward/fast-reverse operation starting from specified address */ bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return false; CDROM_SEEK_AUDIO_MSF msf; msf.M = start_m; msf.S = start_s; msf.F = start_f; DWORD dwBytesReturned = 0; return DeviceIoControl(fh->fh, IOCTL_CDROM_SEEK_AUDIO_MSF, &msf, sizeof(CDROM_SEEK_AUDIO_MSF), NULL, 0, &dwBytesReturned, NULL); } /* * Set CD audio volume (0..255 each channel) */ void SysCDSetVolume(void *arg, uint8 left, uint8 right) { file_handle *fh = (file_handle *)arg; if (!fh || !fh->fh || !fh->is_cdrom) return; VOLUME_CONTROL vc; vc.PortVolume[0] = left; vc.PortVolume[1] = right; vc.PortVolume[2] = left; vc.PortVolume[3] = right; DWORD dwBytesReturned = 0; DeviceIoControl(fh->fh, IOCTL_CDROM_SET_VOLUME, &vc, sizeof(VOLUME_CONTROL), NULL, 0, &dwBytesReturned, NULL); } /* * Get CD audio volume (0..255 each channel) */ void SysCDGetVolume(void *arg, uint8 &left, uint8 &right) { file_handle *fh = (file_handle *)arg; if (!fh) return; left = right = 0; if (!fh->fh || !fh->is_cdrom) return; VOLUME_CONTROL vc; memset(&vc, 0, sizeof(vc)); DWORD dwBytesReturned = 0; if (DeviceIoControl(fh->fh, IOCTL_CDROM_GET_VOLUME, NULL, 0, &vc, sizeof(VOLUME_CONTROL), &dwBytesReturned, NULL)) { left = vc.PortVolume[0]; right = vc.PortVolume[1]; } } BasiliskII/src/Windows/kernel_windows.h0000755000175000017500000000271310736405221020373 0ustar centriscentris/* * kernel_windows.h * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _KERNEL_WINDOWS_H_ #define _KERNEL_WINDOWS_H_ extern UINT (WINAPI *pfnGetWriteWatch) (DWORD,PVOID,SIZE_T,PVOID *,LPDWORD,LPDWORD); extern BOOL (WINAPI *pfnInitializeCriticalSectionAndSpinCount) (LPCRITICAL_SECTION,DWORD); extern BOOL (WINAPI *pfnCancelIo) (HANDLE); extern BOOL (WINAPI *pfnGETCDSECTORS) (BYTE,DWORD,WORD,LPBYTE); extern UINT (WINAPI *pfnSendInput) (UINT,LPVOID,int); extern BOOL (WINAPI *pfnGetDiskFreeSpaceEx) (LPCSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER); void KernelInit( void ); void KernelExit( void ); #endif // _KERNEL_WINDOWS_H_ BasiliskII/src/Windows/main_windows.cpp0000755000175000017500000003622011323745233020375 0ustar centriscentris/* * main_windows.cpp - Startup code for Windows * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include #include #include #include #include #include #include #include using std::string; #include "cpu_emulation.h" #include "sys.h" #include "rom_patches.h" #include "xpram.h" #include "timer.h" #include "video.h" #include "cdrom.h" #include "emul_op.h" #include "prefs.h" #include "prefs_editor.h" #include "macos_util.h" #include "user_strings.h" #include "version.h" #include "main.h" #include "vm_alloc.h" #include "sigsegv.h" #include "util_windows.h" #include "kernel_windows.h" #if USE_JIT extern void flush_icache_range(uint8 *start, uint32 size); // from compemu_support.cpp #endif #ifdef ENABLE_MON # include "mon.h" #endif #define DEBUG 0 #include "debug.h" // Constants const char ROM_FILE_NAME[] = "ROM"; const int SCRATCH_MEM_SIZE = 0x10000; // Size of scratch memory area // CPU and FPU type, addressing mode int CPUType; bool CPUIs68060; int FPUType; bool TwentyFourBitAddressing; // Global variables HANDLE emul_thread = NULL; // Handle of MacOS emulation thread (main thread) static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes static bool xpram_thread_active = false; // Flag: XPRAM watchdog installed static volatile bool xpram_thread_cancel = false; // Flag: Cancel XPRAM thread static SDL_Thread *xpram_thread = NULL; // XPRAM watchdog static bool tick_thread_active = false; // Flag: 60Hz thread installed static volatile bool tick_thread_cancel = false; // Flag: Cancel 60Hz thread static SDL_Thread *tick_thread; // 60Hz thread static SDL_mutex *intflag_lock = NULL; // Mutex to protect InterruptFlags #define LOCK_INTFLAGS SDL_LockMutex(intflag_lock) #define UNLOCK_INTFLAGS SDL_UnlockMutex(intflag_lock) DWORD win_os; // Windows OS id DWORD win_os_major; // Windows OS version major #if USE_SCRATCHMEM_SUBTERFUGE uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes #endif #if REAL_ADDRESSING static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped #endif // Prototypes static int xpram_func(void *arg); static int tick_func(void *arg); static void one_tick(...); /* * Ersatz functions */ extern "C" { #ifndef HAVE_STRDUP char *strdup(const char *s) { char *n = (char *)malloc(strlen(s) + 1); strcpy(n, s); return n; } #endif } /* * Map memory that can be accessed from the Mac side */ void *vm_acquire_mac(size_t size) { return vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT); } /* * SIGSEGV handler */ static sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip) { const uintptr fault_address = (uintptr)sigsegv_get_fault_address(sip); #if ENABLE_VOSF // Handle screen fault extern bool Screen_fault_handler(sigsegv_info_t *sip); if (Screen_fault_handler(sip)) return SIGSEGV_RETURN_SUCCESS; #endif #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION // Ignore writes to ROM if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // Ignore all other faults, if requested if (PrefsFindBool("ignoresegv")) return SIGSEGV_RETURN_SKIP_INSTRUCTION; #endif return SIGSEGV_RETURN_FAILURE; } /* * Dump state when everything went wrong after a SEGV */ static void sigsegv_dump_state(sigsegv_info_t *sip) { const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip); const sigsegv_address_t fault_instruction = sigsegv_get_fault_instruction_address(sip); fprintf(stderr, "Caught SIGSEGV at address %p", fault_address); if (fault_instruction != SIGSEGV_INVALID_ADDRESS) fprintf(stderr, " [IP=%p]", fault_instruction); fprintf(stderr, "\n"); uaecptr nextpc; extern void m68k_dumpstate(uaecptr *nextpc); m68k_dumpstate(&nextpc); #if USE_JIT && JIT_DEBUG extern void compiler_dumpstate(void); compiler_dumpstate(); #endif VideoQuitFullScreen(); #ifdef ENABLE_MON char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); QuitEmulator(); #endif } /* * Main program */ static void usage(const char *prg_name) { printf( "Usage: %s [OPTION...]\n" "\nUnix options:\n" " --config FILE\n read/write configuration from/to FILE\n" " --display STRING\n X display to use\n" " --break ADDRESS\n set ROM breakpoint\n" " --rominfo\n dump ROM information\n", prg_name ); LoadPrefs(NULL); // read the prefs file so PrefsPrintUsage() will print the correct default values PrefsPrintUsage(); exit(0); } int main(int argc, char **argv) { char str[256]; bool cd_boot = false; // Initialize variables RAMBaseHost = NULL; ROMBaseHost = NULL; srand(time(NULL)); tzset(); // Print some info printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR); printf(" %s\n", GetString(STR_ABOUT_TEXT2)); // Parse command line arguments for (int i=1; i i) { k -= i; for (int j=i+k; j= 4.0 OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx(&osvi)) { ErrorAlert("Could not determine OS type"); QuitEmulator(); } win_os = osvi.dwPlatformId; win_os_major = osvi.dwMajorVersion; if (win_os != VER_PLATFORM_WIN32_NT || win_os_major < 4) { ErrorAlert(STR_NO_WIN32_NT_4); QuitEmulator(); } // Check that drivers are installed if (!check_drivers()) QuitEmulator(); // Load win32 libraries KernelInit(); // FIXME: default to DIB driver if (getenv("SDL_VIDEODRIVER") == NULL) putenv("SDL_VIDEODRIVER=windib"); // Initialize SDL system int sdl_flags = 0; #ifdef USE_SDL_VIDEO sdl_flags |= SDL_INIT_VIDEO; #endif #ifdef USE_SDL_AUDIO sdl_flags |= SDL_INIT_AUDIO; #endif assert(sdl_flags != 0); if (SDL_Init(sdl_flags) == -1) { char str[256]; sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError()); ErrorAlert(str); QuitEmulator(); } atexit(SDL_Quit); // Init system routines SysInit(); // Show preferences editor if (!PrefsFindBool("nogui")) if (!PrefsEditor()) QuitEmulator(); // Install the handler for SIGSEGV if (!sigsegv_install_handler(sigsegv_handler)) { sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno)); ErrorAlert(str); QuitEmulator(); } // Register dump state function when we got mad after a segfault sigsegv_set_dump_state(sigsegv_dump_state); // Read RAM size RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary if (RAMSize < 1024*1024) { WarningAlert(GetString(STR_SMALL_RAM_WARN)); RAMSize = 1024*1024; } // Initialize VM system vm_init(); // Create areas for Mac RAM and ROM RAMBaseHost = (uint8 *)vm_acquire_mac(RAMSize); ROMBaseHost = (uint8 *)vm_acquire_mac(0x100000); if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } #if USE_SCRATCHMEM_SUBTERFUGE // Allocate scratch memory ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE); if (ScratchMem == VM_MAP_FAILED) { ErrorAlert(STR_NO_MEM_ERR); QuitEmulator(); } ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block #endif #if DIRECT_ADDRESSING // RAMBaseMac shall always be zero MEMBaseDiff = (uintptr)RAMBaseHost; RAMBaseMac = 0; ROMBaseMac = Host2MacAddr(ROMBaseHost); #endif D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac)); D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac)); // Get rom file path from preferences const char *rom_path = PrefsFindString("rom"); // Load Mac ROM HANDLE rom_fh = CreateFile(rom_path ? rom_path : ROM_FILE_NAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (rom_fh == INVALID_HANDLE_VALUE) { ErrorAlert(STR_NO_ROM_FILE_ERR); QuitEmulator(); } printf(GetString(STR_READING_ROM_FILE)); ROMSize = GetFileSize(rom_fh, NULL); if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) { ErrorAlert(STR_ROM_SIZE_ERR); CloseHandle(rom_fh); QuitEmulator(); } DWORD bytes_read; if (ReadFile(rom_fh, ROMBaseHost, ROMSize, &bytes_read, NULL) == 0 || bytes_read != ROMSize) { ErrorAlert(STR_ROM_FILE_READ_ERR); CloseHandle(rom_fh); QuitEmulator(); } // Initialize native timers timer_init(); // Initialize everything if (!InitAll(NULL)) QuitEmulator(); D(bug("Initialization complete\n")); // Get handle of main thread emul_thread = GetCurrentThread(); // SDL threads available, start 60Hz thread tick_thread_active = ((tick_thread = SDL_CreateThread(tick_func, NULL)) != NULL); if (!tick_thread_active) { sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno)); ErrorAlert(str); QuitEmulator(); } D(bug("60Hz thread started\n")); // Start XPRAM watchdog thread memcpy(last_xpram, XPRAM, XPRAM_SIZE); xpram_thread_active = ((xpram_thread = SDL_CreateThread(xpram_func, NULL)) != NULL); D(bug("XPRAM thread started\n")); // Start 68k and jump to ROM boot routine D(bug("Starting emulation...\n")); Start680x0(); QuitEmulator(); return 0; } /* * Quit emulator */ void QuitEmulator(void) { D(bug("QuitEmulator\n")); // Exit 680x0 emulation Exit680x0(); // Stop 60Hz thread if (tick_thread_active) { tick_thread_cancel = true; SDL_WaitThread(tick_thread, NULL); } // Stop XPRAM watchdog thread if (xpram_thread_active) { xpram_thread_cancel = true; SDL_WaitThread(xpram_thread, NULL); } // Deinitialize everything ExitAll(); // Free ROM/RAM areas if (RAMBaseHost != VM_MAP_FAILED) { vm_release(RAMBaseHost, RAMSize); RAMBaseHost = NULL; } if (ROMBaseHost != VM_MAP_FAILED) { vm_release(ROMBaseHost, 0x100000); ROMBaseHost = NULL; } #if USE_SCRATCHMEM_SUBTERFUGE // Delete scratch memory area if (ScratchMem != (uint8 *)VM_MAP_FAILED) { vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE); ScratchMem = NULL; } #endif // Exit VM wrappers vm_exit(); // Exit system routines SysExit(); // Exit preferences PrefsExit(); // Release win32 libraries KernelExit(); exit(0); } /* * Code was patched, flush caches if neccessary (i.e. when using a real 680x0 * or a dynamically recompiling emulator) */ void FlushCodeCache(void *start, uint32 size) { #if USE_JIT if (UseJIT) flush_icache_range((uint8 *)start, size); #endif } /* * Mutexes */ struct B2_mutex { B2_mutex() { m = SDL_CreateMutex(); } ~B2_mutex() { if (m) SDL_DestroyMutex(m); } SDL_mutex *m; }; B2_mutex *B2_create_mutex(void) { return new B2_mutex; } void B2_lock_mutex(B2_mutex *mutex) { if (mutex) SDL_LockMutex(mutex->m); } void B2_unlock_mutex(B2_mutex *mutex) { if (mutex) SDL_UnlockMutex(mutex->m); } void B2_delete_mutex(B2_mutex *mutex) { delete mutex; } /* * Interrupt flags (must be handled atomically!) */ uint32 InterruptFlags = 0; void SetInterruptFlag(uint32 flag) { LOCK_INTFLAGS; InterruptFlags |= flag; UNLOCK_INTFLAGS; } void ClearInterruptFlag(uint32 flag) { LOCK_INTFLAGS; InterruptFlags &= ~flag; UNLOCK_INTFLAGS; } /* * XPRAM watchdog thread (saves XPRAM every minute) */ static void xpram_watchdog(void) { if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) { memcpy(last_xpram, XPRAM, XPRAM_SIZE); SaveXPRAM(); } } static int xpram_func(void *arg) { while (!xpram_thread_cancel) { for (int i=0; i<60 && !xpram_thread_cancel; i++) Delay_usec(999999); // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true xpram_watchdog(); } return 0; } /* * 60Hz thread (really 60.15Hz) */ static void one_second(void) { // Pseudo Mac 1Hz interrupt, update local time WriteMacInt32(0x20c, TimerDateTime()); SetInterruptFlag(INTFLAG_1HZ); TriggerInterrupt(); } static void one_tick(...) { static int tick_counter = 0; if (++tick_counter > 60) { tick_counter = 0; one_second(); } // Trigger 60Hz interrupt if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) { SetInterruptFlag(INTFLAG_60HZ); TriggerInterrupt(); } } static int tick_func(void *arg) { uint64 start = GetTicks_usec(); int64 ticks = 0; uint64 next = GetTicks_usec(); while (!tick_thread_cancel) { one_tick(); next += 16625; int64 delay = next - GetTicks_usec(); if (delay > 0) Delay_usec(delay); else if (delay < -16625) next = GetTicks_usec(); ticks++; } uint64 end = GetTicks_usec(); D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start))); return 0; } /* * Get the main window handle */ #ifdef USE_SDL_VIDEO #include HWND GetMainWindowHandle(void) { SDL_SysWMinfo wmInfo; SDL_VERSION(&wmInfo.version); return SDL_GetWMInfo(&wmInfo) ? wmInfo.window : NULL; } #endif /* * Display alert */ static void display_alert(int title_id, const char *text, int flags) { HWND hMainWnd = GetMainWindowHandle(); MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags); } /* * Display error alert */ void ErrorAlert(const char *text) { if (PrefsFindBool("nogui")) return; VideoQuitFullScreen(); display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP); } /* * Display warning alert */ void WarningAlert(const char *text) { if (PrefsFindBool("nogui")) return; display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION); } /* * Display choice alert */ bool ChoiceAlert(const char *text, const char *pos, const char *neg) { printf(GetString(STR_SHELL_WARNING_PREFIX), text); return false; //!! } BasiliskII/src/Windows/BasiliskII.rc0000644000175000017500000000005210145767212017475 0ustar centriscentrisBasiliskII ICON PRELOAD "BasiliskII.ico" BasiliskII/src/Windows/router/0000755000175000017500000000000011735674761016523 5ustar centriscentrisBasiliskII/src/Windows/router/mib/0000755000175000017500000000000011735675027017266 5ustar centriscentrisBasiliskII/src/Windows/router/mib/mibaccess.cpp0000755000175000017500000002161010736405222021712 0ustar centriscentris/* * MibAccess.cpp * * The original code by Stas Khirman modified by Lauri Pesonen, December, 2000: * * SnmpUtilVarBindFree(), SnmpUtilOidNCmp() and SnmpUtilOidCpy() now loaded from * "snmpapi.dll" dynamically instead of linking statically. * * MibII ctor now takes a parameter whether to load Winsock or not. * WSAStartup maintains an internal reference counter so it would have been ok * to let it load always. * * Fixed a bug where the return value of LoadLibrary() was compared against * HINSTANCE_ERROR instead of NULL. * * Removed some type conversion warnings by casting. * * Added a check in MibExtLoad ctor that the function entry points were found. * * Added a check in GetIPMask() and GetIPAddress() that the library was loaded * before accessing the functions. * * Changed the return type of GetIPAddress() and GetIPMask() from BOOL to void * as they always returned TRUE. * */ /************************************************************************/ /* Copyright (C) Stas Khirman 1998. All rights reserved. */ /* Written by Stas Khirman (staskh@rocketmail.com). */ /* and */ /* Raz Galili (razgalili@hotmail.com) */ /* */ /* Free software: no warranty; use anywhere is ok; spread the */ /* sources; note any modifications; share variations and */ /* derivatives (including sending to staskh@rocketmail.com). */ /* */ /************************************************************************/ /* * MibAccess.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "mibaccess.h" #include "../dynsockets.h" #include "../dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" MibExtLoad::MibExtLoad( LPSTR MibDllName, LPSTR SnmpDllName ) { m_Init = NULL; m_InitEx = NULL; m_Query = NULL; m_Trap = NULL; m_hInst_snmputil = NULL; m_SnmpUtilVarBindFree = NULL; m_SnmpUtilOidNCmp = NULL; m_SnmpUtilOidCpy = NULL; m_hInst = LoadLibrary( MibDllName ); if(!m_hInst) { D(bug("MIB: library %s could not be loaded.\r\n", MibDllName)); return; } D(bug("MIB: library %s loaded ok.\r\n", MibDllName)); m_Init = (pSnmpExtensionInit)GetProcAddress(m_hInst ,"SnmpExtensionInit"); m_InitEx= (pSnmpExtensionInitEx)GetProcAddress(m_hInst ,"SnmpExtensionInitEx"); m_Query = (pSnmpExtensionQuery)GetProcAddress(m_hInst ,"SnmpExtensionQuery"); m_Trap = (pSnmpExtensionTrap)GetProcAddress(m_hInst ,"SnmpExtensionTrap"); if( !m_Init || !m_InitEx || !m_Query || !m_Trap ) { D(bug("MIB: required entry points not found in library %s.\r\n", MibDllName)); FreeLibrary( m_hInst ); m_hInst = NULL; } m_hInst_snmputil = LoadLibrary( SnmpDllName ); if(!m_hInst_snmputil){ D(bug("MIB: library %s could not be loaded.\r\n", SnmpDllName)); FreeLibrary( m_hInst ); m_hInst = NULL; return; } D(bug("MIB: library %s loaded ok.\r\n", SnmpDllName)); m_SnmpUtilVarBindFree = (VOID (SNMP_FUNC_TYPE *)(SnmpVarBind *))GetProcAddress( m_hInst_snmputil, "SnmpUtilVarBindFree" ); m_SnmpUtilOidNCmp = (SNMPAPI (SNMP_FUNC_TYPE *)(AsnObjectIdentifier *, AsnObjectIdentifier *, UINT))GetProcAddress( m_hInst_snmputil, "SnmpUtilOidNCmp" ); m_SnmpUtilOidCpy = (SNMPAPI (SNMP_FUNC_TYPE *)(AsnObjectIdentifier *, AsnObjectIdentifier *))GetProcAddress( m_hInst_snmputil, "SnmpUtilOidCpy" ); if( !m_SnmpUtilVarBindFree || !m_SnmpUtilOidNCmp || !m_SnmpUtilOidCpy ) { D(bug("MIB: required entry points not found in library %s.\r\n", SnmpDllName)); FreeLibrary( m_hInst ); FreeLibrary( m_hInst_snmputil ); m_hInst = NULL; m_hInst_snmputil = NULL; } #undef SNMP_FreeVarBind #undef SNMP_oidncmp #undef SNMP_oidcpy #define SNMP_FreeVarBind m_SnmpUtilVarBindFree #define SNMP_oidncmp m_SnmpUtilOidNCmp #define SNMP_oidcpy m_SnmpUtilOidCpy } MibExtLoad::~MibExtLoad() { if( m_hInst ) { FreeLibrary( m_hInst ); m_hInst = NULL; } if( m_hInst_snmputil ) { FreeLibrary( m_hInst_snmputil ); m_hInst_snmputil = NULL; } } BOOL MibExtLoad::Init(DWORD dwTimeZeroReference,HANDLE *hPollForTrapEvent,AsnObjectIdentifier *supportedView) { if(m_hInst && m_Init) return m_Init(dwTimeZeroReference,hPollForTrapEvent,supportedView); return FALSE; } BOOL MibExtLoad::InitEx(AsnObjectIdentifier *supportedView) { if(m_hInst && m_InitEx) return m_InitEx(supportedView); return FALSE; } BOOL MibExtLoad::Query(BYTE requestType,OUT RFC1157VarBindList *variableBindings, AsnInteger *errorStatus,AsnInteger *errorIndex) { if(m_hInst && m_Query) return m_Query(requestType,variableBindings,errorStatus,errorIndex); return FALSE; } BOOL MibExtLoad::Trap(AsnObjectIdentifier *enterprise, AsnInteger *genericTrap, AsnInteger *specificTrap, AsnTimeticks *timeStamp, RFC1157VarBindList *variableBindings) { if(m_hInst && m_Trap) return m_Trap(enterprise, genericTrap,specificTrap, timeStamp, variableBindings); return FALSE; } MibII::MibII( bool load_winsock ):MibExtLoad("inetmib1.dll","snmpapi.dll") { WSADATA wsa; m_load_winsock = load_winsock; if(load_winsock) { int err = _WSAStartup( 0x0101, &wsa ); } } MibII::~MibII() { if(m_load_winsock) _WSACleanup(); } BOOL MibII::Init() { HANDLE PollForTrapEvent; AsnObjectIdentifier SupportedView; return MibExtLoad::Init(GetTickCount(),&PollForTrapEvent,&SupportedView); } void MibII::GetIPAddress( UINT IpArray[], UINT &IpArraySize ) { if(!m_hInst) { IpArraySize = 0; return; } UINT OID_ipAdEntAddr[] = { 1, 3, 6, 1, 2, 1, 4 , 20, 1 ,1 }; AsnObjectIdentifier MIB_ipAdEntAddr = { sizeof(OID_ipAdEntAddr)/sizeof(UINT), OID_ipAdEntAddr }; RFC1157VarBindList varBindList; RFC1157VarBind varBind[1]; AsnInteger errorStatus; AsnInteger errorIndex; AsnObjectIdentifier MIB_NULL = {0,0}; BOOL Exit; int ret; int IpCount=0; DWORD dtmp; varBindList.list = varBind; varBindList.len = 1; varBind[0].name = MIB_NULL; SNMP_oidcpy(&varBind[0].name,&MIB_ipAdEntAddr); Exit = FALSE; IpCount=0; while(!Exit){ ret = Query(ASN_RFC1157_GETNEXTREQUEST,&varBindList,&errorStatus,&errorIndex); if(!ret) Exit=TRUE; else{ ret = SNMP_oidncmp(&varBind[0].name,&MIB_ipAdEntAddr,MIB_ipAdEntAddr.idLength); if(ret!=0){ Exit=TRUE; } else{ dtmp = *((DWORD *)varBind[0].value.asnValue.address.stream); IpArray[IpCount] = dtmp; IpCount++; if(IpCount>=(int)IpArraySize) Exit = TRUE; } } } IpArraySize = IpCount; SNMP_FreeVarBind(&varBind[0]); } void MibII::GetIPMask( UINT IpArray[], UINT &IpArraySize ) { if(!m_hInst) { IpArraySize = 0; return; } UINT OID_ipAdEntMask[] = { 1, 3, 6, 1, 2, 1, 4 , 20, 1 ,3 }; AsnObjectIdentifier MIB_ipAdEntMask = { sizeof(OID_ipAdEntMask)/sizeof(UINT), OID_ipAdEntMask }; RFC1157VarBindList varBindList; RFC1157VarBind varBind[1]; AsnInteger errorStatus; AsnInteger errorIndex; AsnObjectIdentifier MIB_NULL = {0,0}; BOOL Exit; int ret; int IpCount=0; DWORD dtmp; varBindList.list = varBind; varBindList.len = 1; varBind[0].name = MIB_NULL; SNMP_oidcpy(&varBind[0].name,&MIB_ipAdEntMask); Exit = FALSE; IpCount=0; while(!Exit){ ret = Query(ASN_RFC1157_GETNEXTREQUEST,&varBindList,&errorStatus,&errorIndex); if(!ret) Exit=TRUE; else{ ret = SNMP_oidncmp(&varBind[0].name,&MIB_ipAdEntMask,MIB_ipAdEntMask.idLength); if(ret!=0){ Exit=TRUE; } else{ dtmp = *((DWORD *)varBind[0].value.asnValue.address.stream); IpArray[IpCount] = dtmp; IpCount++; if(IpCount>=(int)IpArraySize) Exit = TRUE; } } } IpArraySize = IpCount; SNMP_FreeVarBind(&varBind[0]); } BasiliskII/src/Windows/router/mib/interfaces.cpp0000755000175000017500000000324010736405222022103 0ustar centriscentris/* * interfaces.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "interfaces.h" #include "../dump.h" #include "mibaccess.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" static UINT ip_array[100]; static UINT ip_array_sz = 0; void init_interfaces() { MibII _mibs(false); ip_array_sz = sizeof(ip_array) / sizeof(ip_array[0]); if(_mibs.Init()) { _mibs.GetIPAddress( ip_array, ip_array_sz ); } if(ip_array_sz == 0) { ip_array_sz = 1; ip_array[0] = 0; // localhost } D(bug("init_interfaces() found %d interfaces.\r\n", ip_array_sz)); } void final_interfaces() { // Currently nothing to do. } int get_ip_count() { return ip_array_sz; } uint32 get_ip_by_index( int index ) { return index >= 0 && index < (int)ip_array_sz ? ip_array[index] : 0; } BasiliskII/src/Windows/router/mib/interfaces.h0000755000175000017500000000230610736405222021552 0ustar centriscentris/* * intercafes.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _INTERFACES_H_ #define _INTERFACES_H_ // A wrapper to the MibII class. Enumerates all ip interfaces // currently in this computer. The interface list is not static. void init_interfaces(); void final_interfaces(); int get_ip_count(); uint32 get_ip_by_index( int index ); #endif // _INTERFACES_H_ BasiliskII/src/Windows/router/mib/mibaccess.h0000755000175000017500000000476610154635744021404 0ustar centriscentris////////////////////////////////////////////////////// // FILE : MibAccess.h // // #ifndef _SNMP_ACCESS_H_ #define _SNMP_ACCESS_H_ #include #ifndef SNMP_FUNC_TYPE #define SNMP_FUNC_TYPE WINAPI #endif ////////////////////////////////////////////////////////////// // Definition of pointers to the four functions in the Mib Dll // typedef BOOL (WINAPI *pSnmpExtensionInit)( IN DWORD dwTimeZeroReference, OUT HANDLE *hPollForTrapEvent, OUT AsnObjectIdentifier *supportedView); typedef BOOL (WINAPI *pSnmpExtensionTrap)( OUT AsnObjectIdentifier *enterprise, OUT AsnInteger *genericTrap, OUT AsnInteger *specificTrap, OUT AsnTimeticks *timeStamp, OUT RFC1157VarBindList *variableBindings); typedef BOOL (WINAPI *pSnmpExtensionQuery)( IN BYTE requestType, IN OUT RFC1157VarBindList *variableBindings, OUT AsnInteger *errorStatus, OUT AsnInteger *errorIndex); typedef BOOL (WINAPI *pSnmpExtensionInitEx)(OUT AsnObjectIdentifier *supportedView); class MibExtLoad { public: MibExtLoad( LPSTR MibDllName, LPSTR SnmpDllName ); ~MibExtLoad(); BOOL Init(DWORD dwTimeZeroReference,HANDLE *hPollForTrapEvent,AsnObjectIdentifier *supportedView); BOOL InitEx(AsnObjectIdentifier *supportedView); BOOL Query(BYTE requestType,OUT RFC1157VarBindList *variableBindings, AsnInteger *errorStatus,AsnInteger *errorIndex); BOOL Trap(AsnObjectIdentifier *enterprise, AsnInteger *genericTrap, AsnInteger *specificTrap, AsnTimeticks *timeStamp, RFC1157VarBindList *variableBindings); public: HINSTANCE m_hInst; HINSTANCE m_hInst_snmputil; private: pSnmpExtensionInit m_Init; pSnmpExtensionInitEx m_InitEx; pSnmpExtensionQuery m_Query; pSnmpExtensionTrap m_Trap; public: VOID (SNMP_FUNC_TYPE *m_SnmpUtilVarBindFree) (SnmpVarBind *); SNMPAPI (SNMP_FUNC_TYPE *m_SnmpUtilOidNCmp) (AsnObjectIdentifier *, AsnObjectIdentifier *, UINT); SNMPAPI (SNMP_FUNC_TYPE *m_SnmpUtilOidCpy) (AsnObjectIdentifier *, AsnObjectIdentifier *); }; class MibII: public MibExtLoad { public: MibII( bool load_winsock ); ~MibII(); BOOL Init(); void GetIPAddress(UINT IpArray[],UINT &IpArraySize); void GetIPMask(UINT IpArray[],UINT &IpArraySize); protected: bool m_load_winsock; }; #endif BasiliskII/src/Windows/router/dynsockets.h0000755000175000017500000000577210736405222021060 0ustar centriscentris/* * dynsockets.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _DYNSOCKETS_H_ #define _DYNSOCKETS_H_ bool dynsockets_init(void); void dynsockets_final(void); extern int (WSAAPI *_WSAStartup) (WORD, LPWSADATA); extern int (WSAAPI *_WSACleanup) (void); extern int (WSAAPI *_gethostname) (char *, int); extern char * (WSAAPI *_inet_ntoa) (struct in_addr); extern struct hostent * (WSAAPI *_gethostbyname) (const char *); extern int (WSAAPI *_send) (SOCKET, const char *, int, int); extern int (WSAAPI *_sendto) (SOCKET, const char *, int, int, const struct sockaddr *, int); extern int (WSAAPI *_recv) (SOCKET, char *, int, int); extern int (WSAAPI *_recvfrom) (SOCKET, char *, int, int, struct sockaddr *, int *); extern int (WSAAPI *_listen) (SOCKET, int); extern SOCKET (WSAAPI *_accept) (SOCKET, struct sockaddr *, int *); extern SOCKET (WSAAPI *_socket) (int, int, int); extern int (WSAAPI *_bind) (SOCKET, const struct sockaddr *, int); extern int (WSAAPI *_WSAAsyncSelect) (SOCKET, HWND, u_int, long); extern int (WSAAPI *_closesocket) (SOCKET); extern int (WSAAPI *_getsockname) (SOCKET, struct sockaddr *, int *); extern int (WSAAPI *_WSARecvFrom) (SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, struct sockaddr *, LPINT, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); extern int (WSAAPI *_WSAGetLastError) (void); extern int (WSAAPI *_WSAConnect) (SOCKET, const struct sockaddr *, int, LPWSABUF, LPWSABUF, LPQOS, LPQOS); extern int (WSAAPI *_setsockopt) (SOCKET, int, int, const char *, int); extern int (WSAAPI *_WSAEventSelect) (SOCKET, WSAEVENT, long); extern WSAEVENT (WSAAPI *_WSACreateEvent) (void); extern BOOL (WSAAPI *_WSACloseEvent) (WSAEVENT); extern BOOL (WSAAPI *_WSAResetEvent) (WSAEVENT); extern int (WSAAPI *_WSAEnumNetworkEvents) (SOCKET, WSAEVENT, LPWSANETWORKEVENTS); extern int (WSAAPI *_shutdown) (SOCKET, int); extern int (WSAAPI *_WSASend) (SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); extern int (WSAAPI *_WSARecv) (SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); extern unsigned long (WSAAPI *_inet_addr) (const char *); #endif // _DYNSOCKETS_H_ BasiliskII/src/Windows/router/router_types.h0000755000175000017500000001124110736405222021422 0ustar centriscentris/* * router_types.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _ROUTER_TYPES_H_ #define _ROUTER_TYPES_H_ #pragma pack(1) // --------------------------- MAC --------------------------- typedef struct { uint8 dest[6]; uint8 src[6]; uint16 type; } ATTRIBUTE_PACKED mac_t; enum { mac_type_llc_ipx_limit = 0x05DC, // <= mac_type_llc_ipx_limit -->> 802.3 MAC frame mac_type_ip4 = 0x0800, mac_type_arp = 0x0806, mac_type_rarp = 0x8035, mac_type_ip6 = 0x86DD, mac_type_loopback = 0x9000 }; // --------------------------- ARP --------------------------- typedef struct { mac_t mac; uint16 htype; uint16 ptype; uint8 halen; uint8 palen; uint16 opcode; uint8 srch[6]; // size for ethernet uint8 srcp[4]; // size for ip uint8 dsth[6]; // size for ethernet uint8 dstp[4]; // size for ip } ATTRIBUTE_PACKED arp_t; enum { arp_request = 1, arp_reply = 2 }; enum { arp_hwtype_enet = 1 }; // --------------------------- IP4 --------------------------- typedef struct { mac_t mac; uint8 header_len:4; uint8 version:4; uint8 tos; uint16 total_len; uint16 ident; uint16 flags_n_frag_offset; // foffset 0..11, flags 12..15 uint8 ttl; uint8 proto; uint16 checksum; uint32 src; uint32 dest; // ip options, size = 4 * header_len - 20 } ATTRIBUTE_PACKED ip_t; // Protocol STD numbers enum { ip_proto_icmp = IPPROTO_ICMP, ip_proto_tcp = IPPROTO_TCP, ip_proto_udp = IPPROTO_UDP }; // --------------------------- ICMP --------------------------- typedef struct { ip_t ip; uint8 type; uint8 code; uint16 checksum; // data } ATTRIBUTE_PACKED icmp_t; enum { icmp_Echo_reply = 0, icmp_Destination_unreachable = 3, icmp_Source_quench = 4, icmp_Redirect = 5, icmp_Echo = 8, icmp_Router_advertisement = 9, icmp_Router_solicitation = 10, icmp_Time_exceeded = 11, icmp_Parameter_problem = 12, icmp_Time_Stamp_request = 13, icmp_Time_Stamp_reply = 14, icmp_Information_request_obsolete = 15, icmp_Information_reply_obsolete = 16, icmp_Address_mask_request = 17, icmp_Address_mask_reply = 18, icmp_Traceroute = 30, icmp_Datagram_conversion_error = 31, icmp_Mobile_host_redirect = 32, icmp_IPv6_Where_Are_You = 33, icmp_IPv6_I_Am_Here = 34, icmp_Mobile_registration_request = 35, icmp_Mobile_registration_reply = 36, icmp_Domain_name_request = 37, icmp_Domain_name_reply = 38, icmp_SKIP = 39, icmp_Photuris = 40 }; // --------------------------- TCP --------------------------- typedef struct { ip_t ip; uint16 src_port; uint16 dest_port; uint32 seq; uint32 ack; uint8 header_len; // note: some reserved bits uint8 flags; // note: some reserved bits uint16 window; uint16 checksum; uint16 urgent_ptr; // options + padding: size = dataoffset*4-20 // data } ATTRIBUTE_PACKED tcp_t; enum { tcp_flags_URG = 0x20, // The urgent pointer field is significant in this segment. tcp_flags_ACK = 0x10, // The acknowledgment field is significant in this segment. tcp_flags_PSH = 0x08, // Push function. tcp_flags_RST = 0x04, // Resets the connection. tcp_flags_SYN = 0x02, // Synchronizes the sequence numbers. tcp_flags_FIN = 0x01 // No more data from sender. }; enum { tcp_state_closed, tcp_state_listen, tcp_state_syn_sent, tcp_state_syn_rcvd, tcp_state_established, tcp_state_close_wait, tcp_state_last_ack, tcp_state_finwait_1, tcp_state_finwait_2, tcp_state_closing, tcp_state_time_wait }; // --------------------------- UDP --------------------------- typedef struct { ip_t ip; uint16 src_port; uint16 dest_port; uint16 msg_len; uint16 checksum; // data } ATTRIBUTE_PACKED udp_t; typedef struct { uint16 src_lo, src_hi; uint16 dest_lo, dest_hi; uint16 proto; uint16 msg_len; } ATTRIBUTE_PACKED pseudo_ip_t; #pragma pack() #endif // _ROUTER_TYPES_H_ BasiliskII/src/Windows/router/arp.h0000755000175000017500000000173710736405222017451 0ustar centriscentris/* * arp.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _ARP_H_ #define _ARP_H_ bool write_arp( arp_t *req, int len ); #endif // _ARP_H_ BasiliskII/src/Windows/router/iphelp.h0000755000175000017500000000241010736405222020135 0ustar centriscentris/* * iphelp.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _IPHELP_H_ #define _IPHELP_H_ // Fake ttl exceeded code. #define WSAETTLEXCEEDED (WSABASEERR + 1999 + 17) void error_winsock_2_icmp( int err, ip_t *ip_err, int dlen_err ); void make_icmp_checksum( icmp_t *icmp, int len ); void make_ip4_checksum( ip_t *ip ); void make_udp_checksum( udp_t *udp ); void make_tcp_checksum( tcp_t *tcp, int len ); #endif // _IPHELP_H_ BasiliskII/src/Windows/router/ftp.h0000755000175000017500000000271010736405222017450 0ustar centriscentris/* * ftp.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _FTP_H_ #define _FTP_H_ // Read the preferences. void init_ftp(); // Compares against a list provided by the user. bool ftp_is_ftp_port( uint16 port ); // Determine whether this is a ftp client PORT command or ftp server entering to passive mode. void ftp_parse_port_command( char *buf, uint32 count, uint16 &ftp_data_port, bool is_pasv ); // Build a new command using ip and port. void ftp_modify_port_command( char *buf, int &count, const uint32 max_size, const uint32 ip, const uint16 port, const bool is_pasv ); #endif // _FTP_H_ BasiliskII/src/Windows/router/tcp.h0000755000175000017500000000200610736405222017443 0ustar centriscentris/* * tcp.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _TCP_H_ #define _TCP_H_ void write_tcp( tcp_t *tcp, int len ); void init_tcp(); void final_tcp(); #endif // _TCP_H_ BasiliskII/src/Windows/router/udp.h0000755000175000017500000000220110736405222017442 0ustar centriscentris/* * udp.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _UDP_H_ #define _UDP_H_ void write_udp( udp_t *udp, int len ); void CALLBACK udp_read_completion( DWORD error, DWORD bytes_read, LPWSAOVERLAPPED lpOverlapped, DWORD flags ); void init_udp(); void final_udp(); #endif // _UDP_H_ BasiliskII/src/Windows/router/dynsockets.cpp0000755000175000017500000002024410736405222021402 0ustar centriscentris/* * dynsockets.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "dynsockets.h" #include "dump.h" #include "main.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" /* Cannot link statically to winsock. We need ws2, but there are Win95 b2 users who can't (or won't) upgrade. */ static const char *wslib = "WS2_32.DLL"; static HMODULE hWinsock32 = 0; static WSADATA WSAData; int (WSAAPI *_WSAStartup) (WORD, LPWSADATA) = 0; int (WSAAPI *_WSACleanup) (void) = 0; int (WSAAPI *_gethostname) (char *, int) = 0; char * (WSAAPI *_inet_ntoa) (struct in_addr) = 0; struct hostent * (WSAAPI *_gethostbyname) (const char *) = 0; int (WSAAPI *_send) (SOCKET, const char *, int, int) = 0; int (WSAAPI *_sendto) (SOCKET, const char *, int, int, const struct sockaddr *, int) = 0; int (WSAAPI *_recv) (SOCKET, char *, int, int) = 0; int (WSAAPI *_recvfrom) (SOCKET, char *, int, int, struct sockaddr *, int *) = 0; int (WSAAPI *_listen) (SOCKET, int) = 0; SOCKET (WSAAPI *_accept) (SOCKET, struct sockaddr *, int *) = 0; SOCKET (WSAAPI *_socket) (int, int, int) = 0; int (WSAAPI *_bind) (SOCKET, const struct sockaddr *, int) = 0; int (WSAAPI *_WSAAsyncSelect) (SOCKET, HWND, u_int, long) = 0; int (WSAAPI *_closesocket) (SOCKET) = 0; int (WSAAPI *_getsockname) (SOCKET, struct sockaddr *, int *) = 0; int (WSAAPI *_WSARecvFrom) (SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, struct sockaddr *, LPINT, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE) = 0; int (WSAAPI *_WSAGetLastError) (void) = 0; int (WSAAPI *_WSAConnect) (SOCKET, const struct sockaddr *, int, LPWSABUF, LPWSABUF, LPQOS, LPQOS) = 0; int (WSAAPI *_setsockopt) (SOCKET, int, int, const char *, int) = 0; int (WSAAPI *_WSAEventSelect) (SOCKET, WSAEVENT, long) = 0; WSAEVENT (WSAAPI *_WSACreateEvent) (void) = 0; BOOL (WSAAPI *_WSACloseEvent) (WSAEVENT) = 0; BOOL (WSAAPI *_WSAResetEvent) (WSAEVENT) = 0; int (WSAAPI *_WSAEnumNetworkEvents) (SOCKET, WSAEVENT, LPWSANETWORKEVENTS) = 0; int (WSAAPI *_shutdown) (SOCKET, int) = 0; int (WSAAPI *_WSASend) (SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE) = 0; int (WSAAPI *_WSARecv) (SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE) = 0; unsigned long (WSAAPI *_inet_addr) (const char *) = 0; static bool load_sockets() { bool result = false; hWinsock32 = LoadLibrary( wslib ); if(!hWinsock32) { ErrorAlert("Could not load Winsock libraries; router module is not available. Please install Windows sockets 2."); } else { _WSAStartup = (int (WSAAPI *)(WORD, LPWSADATA))GetProcAddress( hWinsock32, "WSAStartup" ); _WSACleanup = (int (WSAAPI *)(void))GetProcAddress( hWinsock32, "WSACleanup" ); _gethostname = (int (WSAAPI *)(char *, int))GetProcAddress( hWinsock32, "gethostname" ); _inet_ntoa = (char * (WSAAPI *)(struct in_addr))GetProcAddress( hWinsock32, "inet_ntoa" ); _gethostbyname = (struct hostent * (WSAAPI *)(const char *))GetProcAddress( hWinsock32, "gethostbyname" ); _send = (int (WSAAPI *)(SOCKET, const char *, int, int))GetProcAddress( hWinsock32, "send" ); _sendto = (int (WSAAPI *)(SOCKET, const char *, int, int, const struct sockaddr *, int))GetProcAddress( hWinsock32, "sendto" ); _recv = (int (WSAAPI *)(SOCKET, char *, int, int))GetProcAddress( hWinsock32, "recv" ); _recvfrom = (int (WSAAPI *)(SOCKET, char *, int, int, struct sockaddr *, int *))GetProcAddress( hWinsock32, "recvfrom" ); _listen = (int (WSAAPI *)(SOCKET, int))GetProcAddress( hWinsock32, "listen" ); _accept = (SOCKET (WSAAPI *)(SOCKET, struct sockaddr *, int *))GetProcAddress( hWinsock32, "accept" ); _socket = (SOCKET (WSAAPI *)(int, int, int))GetProcAddress( hWinsock32, "socket" ); _bind = (int (WSAAPI *)(SOCKET, const struct sockaddr *, int))GetProcAddress( hWinsock32, "bind" ); _WSAAsyncSelect = (int (WSAAPI *)(SOCKET, HWND, u_int, long))GetProcAddress( hWinsock32, "WSAAsyncSelect" ); _closesocket = (int (WSAAPI *)(SOCKET))GetProcAddress( hWinsock32, "closesocket" ); _getsockname = (int (WSAAPI *)(SOCKET, struct sockaddr *, int *))GetProcAddress( hWinsock32, "getsockname" ); _WSARecvFrom = (int (WSAAPI *)(SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, struct sockaddr *, LPINT, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE))GetProcAddress( hWinsock32, "WSARecvFrom" ); _WSAGetLastError = (int (WSAAPI *)(void))GetProcAddress( hWinsock32, "WSAGetLastError" ); _WSAConnect = (int (WSAAPI *)(SOCKET, const struct sockaddr *, int, LPWSABUF, LPWSABUF, LPQOS, LPQOS))GetProcAddress( hWinsock32, "WSAConnect" ); _setsockopt = (int (WSAAPI *)(SOCKET, int, int, const char *, int))GetProcAddress( hWinsock32, "setsockopt" ); _WSAEventSelect = (int (WSAAPI *)(SOCKET, WSAEVENT, long))GetProcAddress( hWinsock32, "WSAEventSelect" ); _WSACreateEvent = (WSAEVENT (WSAAPI *)(void))GetProcAddress( hWinsock32, "WSACreateEvent" ); _WSACloseEvent = (BOOL (WSAAPI *)(WSAEVENT))GetProcAddress( hWinsock32, "WSACloseEvent" ); _WSAResetEvent = (BOOL (WSAAPI *)(WSAEVENT))GetProcAddress( hWinsock32, "WSAResetEvent" ); _WSAEnumNetworkEvents = (BOOL (WSAAPI *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS))GetProcAddress( hWinsock32, "WSAEnumNetworkEvents" ); _shutdown = (int (WSAAPI *)(SOCKET, int))GetProcAddress( hWinsock32, "shutdown" ); _WSASend = (int (WSAAPI *)(SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE))GetProcAddress( hWinsock32, "WSASend" ); _WSARecv = (int (WSAAPI *)(SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE))GetProcAddress( hWinsock32, "WSARecv" ); _inet_addr = (unsigned long (WSAAPI *)(const char *))GetProcAddress( hWinsock32, "inet_addr" ); if( _WSAStartup && _WSACleanup && _gethostname && _inet_ntoa && _gethostbyname && _send && _sendto && _recv && _recvfrom && _listen && _accept && _socket && _bind && _WSAAsyncSelect && _closesocket && _getsockname && _WSARecvFrom && _WSAGetLastError && _WSAConnect && _setsockopt && _WSAEventSelect && _WSACreateEvent && _WSACloseEvent && _WSAResetEvent && _WSAEnumNetworkEvents && _shutdown && _WSASend && _WSARecv && _inet_addr ) { result = true; } else { ErrorAlert("Could not find required entry points; router module is not available. Please install Windows sockets 2."); } } return result; } bool dynsockets_init(void) { bool result = false; if(load_sockets()) { if( (_WSAStartup(MAKEWORD(2,0), &WSAData)) != 0 || LOBYTE( WSAData.wVersion ) != 2 || HIBYTE( WSAData.wVersion ) != 0 ) { ErrorAlert("Could not start Windows sockets version 2."); } else { result = true; } } return result; } void dynsockets_final(void) { if(hWinsock32) { _WSACleanup(); FreeLibrary( hWinsock32 ); hWinsock32 = 0; } _WSAStartup = 0; _WSACleanup = 0; _gethostname = 0; _inet_ntoa = 0; _gethostbyname = 0; _send = 0; _sendto = 0; _recv = 0; _recvfrom = 0; _listen = 0; _accept = 0; _socket = 0; _bind = 0; _WSAAsyncSelect = 0; _closesocket = 0; _getsockname = 0; _WSARecvFrom = 0; _WSAGetLastError = 0; _WSAConnect = 0; _setsockopt = 0; _WSAEventSelect = 0; _WSACreateEvent = 0; _WSACloseEvent = 0; _WSAResetEvent = 0; _WSAEnumNetworkEvents = 0; _shutdown = 0; _WSASend = 0; _WSARecv = 0; _inet_addr = 0; } BasiliskII/src/Windows/router/icmp.cpp0000755000175000017500000001413710736405222020150 0ustar centriscentris/* * icmp.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "ws2tcpip.h" #include "prefs.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "dynsockets.h" #include "ipsocket.h" #include "iphelp.h" #include "icmp.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" // Saved for cleanup. static socket_t *icmp_incoming_s = 0; void stop_icmp_listen() { if(icmp_incoming_s) { delete icmp_incoming_s; icmp_incoming_s = 0; } } void start_icmp_listen() { if(!icmp_incoming_s) { icmp_incoming_s = new socket_t(IPPROTO_ICMP); icmp_incoming_s->permanent = TRUE; icmp_incoming_s->s = _socket( AF_INET, SOCK_RAW, IPPROTO_ICMP ); memset( &icmp_incoming_s->from, 0, icmp_incoming_s->from_len ); icmp_incoming_s->from.sin_family = AF_INET; if(icmp_incoming_s->s == INVALID_SOCKET) { D(bug("Failed to create icmp listening socket (NT/no admin?)\r\n" )); delete icmp_incoming_s; icmp_incoming_s = 0; } else { D(bug("icmp listening socket created\r\n" )); raw_sockets_available = true; struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; if( _bind ( icmp_incoming_s->s, (const struct sockaddr *)&to, sizeof(to) ) == SOCKET_ERROR ) { D(bug("Listening to inbound icmp failed, error code = %d\r\n", _WSAGetLastError() )); _closesocket( icmp_incoming_s->s ); delete icmp_incoming_s; icmp_incoming_s = 0; } else { D(bug("icmp listening socket bound\r\n" )); if(!icmp_incoming_s->b_recfrom()) { D(bug("b_recfrom() from inbound icmp failed, error code = %d\r\n", _WSAGetLastError() )); // _closesocket( icmp_incoming_s->s ); // delete icmp_incoming_s; // icmp_incoming_s = 0; } } } } } void CALLBACK icmp_read_completion( DWORD error, DWORD bytes_read, LPWSAOVERLAPPED lpOverlapped, DWORD flags ) { D(bug("icmp_read_completion(error=0x%x, bytes_read=%d, flags=0x%x)\r\n", error, bytes_read, flags)); socket_t *cmpl = (socket_t *)lpOverlapped->hEvent; if(error == 0 && macos_ip_address != 0) { if(bytes_read > 1460) { D(bug("discarding oversized icmp packet, size = \r\n", bytes_read)); } else { int icmp_size = sizeof(mac_t) + bytes_read; icmp_t *icmp = (icmp_t *)malloc( icmp_size ); if(icmp) { mac_t *mac = (mac_t *)icmp; ip_t *ip = (ip_t *)icmp; memcpy( mac->dest, ether_addr, 6 ); memcpy( mac->src, router_mac_addr, 6 ); mac->type = htons(mac_type_ip4); // Copy payload (used by ICMP checksum) memcpy( (char *)icmp + sizeof(mac_t), cmpl->buffers[0].buf, bytes_read ); switch( icmp->type ) { // May need to patch the returned ip header. case icmp_Destination_unreachable: case icmp_Source_quench: case icmp_Redirect: case icmp_Time_exceeded: case icmp_Parameter_problem: ip_t *ip_if = (ip_t *)( (char *)icmp + sizeof(icmp_t) + sizeof(uint32) - sizeof(mac_t) ); // This would be needed (traceroute) // ip_if->ident = ??; // Cannot fix some fields, this should be enough: ip_if->src = htonl(macos_ip_address); if(ip_if->proto == ip_proto_udp) { udp_t *udp_if = (udp_t *)ip_if; // udp_if->src_port = ... don't know!; } else if(ip_if->proto == ip_proto_tcp) { tcp_t *tcp_if = (tcp_t *)ip_if; // tcp_if->src_port = ... don't know!; } break; } make_icmp_checksum( icmp, icmp_size ); // Replace the target ip address ip->dest = htonl(macos_ip_address); ip->ttl--; make_ip4_checksum( ip ); dump_bytes( (uint8 *)icmp, icmp_size ); if( ip->ttl == 0 ) { D(bug("icmp packet ttl expired\r\n")); } else { enqueue_packet( (uint8 *)icmp, icmp_size ); } free(icmp); } } } memset( &cmpl->from, 0, cmpl->from_len ); if(is_router_shutting_down) { delete cmpl; } else if(cmpl->s == INVALID_SOCKET || !cmpl->b_recfrom()) { // delete cmpl; } } void write_icmp( icmp_t *icmp, int len ) { struct in_addr ia; ia.s_addr = icmp->ip.dest; D(bug("write_icmp(%s)\r\n", _inet_ntoa(ia) )); if(!raw_sockets_available) { D(bug("write_icmp() cannot proceed, raw sockets not available\r\n" )); return; } if(len < sizeof(icmp_t)) { D(bug("Too small icmp packet(%d), dropped\r\n", len)); return; } // must be updated, ttl changed make_icmp_checksum( icmp, len ); SOCKET s = _socket( AF_INET, SOCK_RAW, IPPROTO_ICMP ); if(s != INVALID_SOCKET) { struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; to.sin_addr.s_addr = icmp->ip.dest; char *data = (char *)icmp + sizeof(ip_t); int dlen = len - sizeof(ip_t); int ttl = icmp->ip.ttl; if(_setsockopt( s, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(int) ) == SOCKET_ERROR ) { D(bug("could not set ttl to %d.\r\n", ttl)); } else { D(bug("ttl set to %d.\r\n", ttl)); } if(SOCKET_ERROR == _sendto( s, data, dlen, 0, (struct sockaddr *)&to, sizeof(to) )) { D(bug("Failed to send icmp via raw socket\r\n" )); } _closesocket(s); } else { D(bug("Could not create raw socket for icmp\r\n" )); } } BasiliskII/src/Windows/router/tcp.cpp0000755000175000017500000013432710736405222020012 0ustar centriscentris/* * tcp.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ /* * Features implemented: * state machine, flow control, sequence numbers, RST/SYN/FIN/ACK/PSH * * Features not implemented: * oob data, urgent pointer, window sliding, some options * "Half-Nagle" implementation is a bit weird (mac-router interface; winsock has it on by default) * * * All possible tcp state machine transitions: * * CLOSED -> LISTEN passive open * CLOSED -> SYN_SENT active open SYN-> * * LISTEN -> SYN_SENT send data SYN-> * LISTEN -> SYN_RCVD ->SYN SYN+ACK-> * * SYN_SENT -> SYN_RCVD ->SYN SYN+ACK-> * SYN_SENT -> ESTABLISHED ->SYN+ACK ACK-> * SYN_SENT -> CLOSED close/timeout * * SYN_RCVD -> CLOSED timeout RST-> * SYN_RCVD -> LISTEN ->RST * SYN_RCVD -> ESTABLISHED ->ACK * SYN_RCVD -> FINWAIT_1 close FIN-> * * ESTABLISHED -> FINWAIT_1 close FIN-> * ESTABLISHED -> CLOSE_WAIT ->FIN ACK-> * * CLOSE_WAIT -> LAST_ACK close FIN-> * * LAST_ACK -> CLOSED ->ACK * * FINWAIT_1 -> CLOSING ->FIN ACK-> * FINWAIT_1 -> FINWAIT_2 ->ACK * FINWAIT_1 -> TIME_WAIT ->FIN+ACK ACK-> * * FINWAIT_2 -> TIME_WAIT ->FIN ACK-> * * CLOSING -> TIME_WAIT ->ACK * * TIME_WAIT -> CLOSED timeout (2*msl) * */ #include "sysdeps.h" #define WIN32_LEAN_AND_MEAN #include #include #include "cpu_emulation.h" #include "ws2tcpip.h" #include "ether_windows.h" #include "ether.h" #include "prefs.h" #include "router.h" #include "router_types.h" #include "dynsockets.h" #include "iphelp.h" #include "tcp.h" #include "dump.h" #include "mib/interfaces.h" #include "ftp.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" // If you need more, use multiple threads. #define MAX_SOCKETS MAXIMUM_WAIT_OBJECTS // If true, always sends the PSH tcp flag with data. // Otherwise only when a full buffer was received. #define PUSH_ALWAYS 0 // In milliseconds. A TCP implementation should implement // this dynamically, adapting the timeout value to match to the // averaged packet round-trip time. #define RESEND_TIMEOUT 750 // Just time out incoming connections after 5 secs if Mac has no time to reply // No backlogs. #define SYN_FLOOD_PROTECTION_TIMEOUT 5000 const int MAX_SEGMENT_SIZE = 1460; // Shorthands #define ISSET(f,x) ( ((f) & (x)) != 0 ) #define ISCLEAR(f,x) ( ((f) & (x)) == 0 ) // Local aliases #define URG tcp_flags_URG #define ACK tcp_flags_ACK #define PSH tcp_flags_PSH #define RST tcp_flags_RST #define SYN tcp_flags_SYN #define FIN tcp_flags_FIN // Local aliases #define CLOSED tcp_state_closed #define LISTEN tcp_state_listen #define SYN_SENT tcp_state_syn_sent #define SYN_RCVD tcp_state_syn_rcvd #define ESTABLISHED tcp_state_established #define CLOSE_WAIT tcp_state_close_wait #define LAST_ACK tcp_state_last_ack #define FINWAIT_1 tcp_state_finwait_1 #define FINWAIT_2 tcp_state_finwait_2 #define CLOSING tcp_state_closing #define TIME_WAIT tcp_state_time_wait // For debugging only static const char *_tcp_state_name[] = { "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "CLOSE_WAIT", "LAST_ACK", "FINWAIT_1", "FINWAIT_2", "CLOSING", "TIME_WAIT" }; #define STATENAME(i) _tcp_state_name[i] static CRITICAL_SECTION tcp_section; typedef struct { SOCKET s; int state; uint32 ip_src; // "source" is the mac, dest is the remote host, uint32 ip_dest; // no matter who opened the connection. uint16 src_port; // all in host byte order. uint16 dest_port; struct sockaddr_in from; // remote host address, network byte order. int from_len; // note: no true windows sliding, only one buffer. WSABUF buffers_read[1]; // data from remote host to Mac DWORD buffer_count_read; DWORD bytes_received; DWORD flags_read; WSAOVERLAPPED overlapped_read; WSABUF buffers_write[1]; // data from Mac to remote host DWORD buffer_count_write; DWORD bytes_written; DWORD flags_write; WSAOVERLAPPED overlapped_write; bool remote_closed; // remote will not send any more data bool accept_more_data_from_mac; // are we ready to accept more data from mac uint32 seq_in; // will ack this mac sequence number uint32 seq_out; // next sequence number to mac (unless a resend is needed) uint32 mac_ack; // mac has acked this byte count. can be used to determined when to send some more data uint32 bytes_to_send; // total send block size uint32 bytes_remaining_to_send; // unsent byte count uint16 mac_window; // mac tcp receive window, slides according to the window principle uint16 our_window; // not really used uint16 mac_mss; // maximum segment size that mac reported at SYN handshaking // resend info uint32 last_seq_out; // remember last packet seq number if a resend is needed uint32 resend_timeout; // currently set t0 0.75 secs but not updated uint32 stream_to_mac_stalled_until; // tick count indicating resend time DWORD time_wait; // do a graceful close after MSL*2 DWORD msl; int child; WSAEVENT ev; // used to signal remote-initiated close and host-initiated connect. bool in_use; } tcp_socket_t; static tcp_socket_t sockets[MAX_SOCKETS]; typedef struct { SOCKET s; uint16 port; uint32 ip; uint32 iface; bool once; int parent; WSAEVENT ev; } tcp_listening_socket_t; static tcp_listening_socket_t l_sockets[MAX_SOCKETS]; static void CALLBACK tcp_read_completion( DWORD error, DWORD bytes_read, LPWSAOVERLAPPED lpOverlapped, DWORD flags ); static void CALLBACK tcp_write_completion( DWORD error, DWORD bytes_read, LPWSAOVERLAPPED lpOverlapped, DWORD flags ); // socket utilities assume that the critical section has already been entered. static void free_socket( const int t ) { _WSAResetEvent( sockets[t].ev ); if(sockets[t].s != INVALID_SOCKET) { _closesocket( sockets[t].s ); sockets[t].s = INVALID_SOCKET; } sockets[t].state = CLOSED; sockets[t].stream_to_mac_stalled_until = 0; sockets[t].in_use = false; sockets[t].time_wait = 0; // if there was an attached listening socket (ftp), close it. int lst = sockets[t].child; if( lst >= 0 ) { if(l_sockets[lst].s != INVALID_SOCKET) { D(bug(" closing listening socket %d\r\n", lst)); _closesocket( l_sockets[lst].s ); l_sockets[lst].s = INVALID_SOCKET; } l_sockets[lst].port = 0; l_sockets[lst].parent = -1; } sockets[t].child = -1; } static int alloc_socket() { static int last_allocated_socket = -1; int i = last_allocated_socket; for( int j=0; j= MAX_SOCKETS ) i = 0; if( !sockets[i].in_use ) { D(bug("<%d> Socket allocated\r\n", i)); last_allocated_socket = i; sockets[i].in_use = true; sockets[i].s = INVALID_SOCKET; sockets[i].state = CLOSED; sockets[i].remote_closed = false; sockets[i].accept_more_data_from_mac = false; sockets[i].ip_src = sockets[i].ip_dest = 0; // sockets[i].src_port = sockets[i].dest_port = 0; memset( &sockets[i].overlapped_read, 0, sizeof(sockets[i].overlapped_read) ); sockets[i].overlapped_read.hEvent = (HANDLE)i; memset( &sockets[i].overlapped_write, 0, sizeof(sockets[i].overlapped_write) ); sockets[i].overlapped_write.hEvent = (HANDLE)i; sockets[i].bytes_received = 0; sockets[i].bytes_written = 0; sockets[i].flags_read = 0; sockets[i].flags_write = 0; // sockets[i].from_len = sizeof(struct sockaddr_in); // memset( &sockets[i].from, 0, sizeof(sockets[i].from) ); // sockets[i].from.sin_family = AF_INET; sockets[i].buffer_count_read = 1; sockets[i].buffers_read[0].len = MAX_SEGMENT_SIZE; if(!sockets[i].buffers_read[0].buf) { sockets[i].buffers_read[0].buf = new char [sockets[i].buffers_read[0].len]; } sockets[i].buffer_count_write = 1; sockets[i].buffers_write[0].len = MAX_SEGMENT_SIZE; if(!sockets[i].buffers_write[0].buf) { sockets[i].buffers_write[0].buf = new char [sockets[i].buffers_write[0].len]; } sockets[i].mac_window = MAX_SEGMENT_SIZE; // updated for all mac datagrams sockets[i].our_window = MAX_SEGMENT_SIZE; // should use about 8-16 kB, really sockets[i].mac_mss = 0; // not known yet sockets[i].time_wait = 0; sockets[i].msl = 5000L; // The round-trip time can be hard to estimate. sockets[i].seq_in = 0; sockets[i].seq_out = 0x00000001; sockets[i].mac_ack = 0; sockets[i].stream_to_mac_stalled_until = 0; sockets[i].resend_timeout = RESEND_TIMEOUT; sockets[i].child = -1; break; } } if(i == MAX_SOCKETS) { D(bug("Out of free sockets\r\n")); i = -1; } return i; } static int alloc_new_socket( const uint16 src_port, const uint16 dest_port, const uint32 ip_dest ) { int t = alloc_socket(); if(t >= 0) { sockets[t].s = _socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if(sockets[t].s == INVALID_SOCKET) { free_socket( t ); t = -1; } else { sockets[t].src_port = src_port; sockets[t].dest_port = dest_port; sockets[t].from_len = sizeof(sockets[t].from); memset( &sockets[t].from, 0, sockets[t].from_len ); sockets[t].from.sin_family = AF_INET; sockets[t].from.sin_port = htons(dest_port); sockets[t].from.sin_addr.s_addr = htonl(ip_dest); struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; if( _bind ( sockets[t].s, (const struct sockaddr *)&to, sizeof(to) ) == 0 ) { D(bug("<%d> socket bound\r\n", t)); } else { if( _WSAGetLastError() == WSAEINPROGRESS ) { D(bug("<%d> bind: a blocking call is in progress.\r\n", t)); } else { D(bug("<%d> bind failed with error code %d\r\n", t, _WSAGetLastError())); } free_socket( t ); t = -1; } } } return t; } static int get_socket_index( const uint16 src_port, const uint16 dest_port ) { for( int i=0; i= 0 ) { if( sockets[i].s == INVALID_SOCKET ) { D(bug("find_socket reusing slot %d...\r\n", i)); sockets[i].in_use = false; } else { D(bug("find_socket forcing close %d...\r\n", i)); free_socket( i ); } i = -1; } } D(bug("<%d> find_socket(%d,%d): %s\r\n", i, src_port, dest_port, i>=0 ? "found" : "not found")); return i; } static int alloc_listen_socket( const uint16 port, const uint32 ip, const uint32 iface, const bool once ) { static int last_allocated_socket = -1; int i = last_allocated_socket; for( int j=0; j= MAX_SOCKETS ) i = 0; if( l_sockets[i].port == 0 ) { D(bug("[%d] Slot allocated for listening port %d\r\n", i, port)); l_sockets[i].port = port; l_sockets[i].ip = ip; l_sockets[i].iface = iface; l_sockets[i].once = once; l_sockets[i].parent = -1; last_allocated_socket = i; _WSAResetEvent( l_sockets[i].ev ); return i; } } return -1; } static void tcp_start_listen( const int i ) { if( l_sockets[i].port ) { uint32 iface = l_sockets[i].iface; D(bug("[%d] binding to interface 0x%08X\r\n", i, iface)); l_sockets[i].s = _socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if(l_sockets[i].s != INVALID_SOCKET) { struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; to.sin_port = htons( l_sockets[i].port ); to.sin_addr.s_addr = htonl( iface ); if( _bind ( l_sockets[i].s, (const struct sockaddr *)&to, sizeof(to) ) == 0 ) { D(bug("[%d] socket bound to port %d on interface 0x%08X\r\n", i, l_sockets[i].port, iface)); if( _listen( l_sockets[i].s, SOMAXCONN ) == SOCKET_ERROR ) { D(bug("[%d] listen() failed with error code %d\r\n", i, _WSAGetLastError())); } else { D(bug("[%d] listening to port %d\r\n", i, l_sockets[i].port)); _WSAResetEvent( l_sockets[i].ev ); if( SOCKET_ERROR == _WSAEventSelect( l_sockets[i].s, l_sockets[i].ev, FD_ACCEPT ) ) { D(bug("[%d] WSAEventSelect() failed with error code %d\r\n", i, _WSAGetLastError())); } } } else { D(bug("[%d] bind to port %d failed with error code %d\r\n", i, l_sockets[i].port, _WSAGetLastError())); } } else { D(bug("[%d] could not create a socket for port %d, error = %d\r\n", i, l_sockets[i].port, _WSAGetLastError())); } } } static void set_ttl( const int t, const uint8 ttl ) { int _ttl = ttl; // defensive programming, I know VCx if(_setsockopt( sockets[t].s, IPPROTO_IP, IP_TTL, (const char *)&_ttl, sizeof(int) ) == SOCKET_ERROR ) { D(bug("<%d> could not set ttl to %d, error=%d\r\n", t, ttl, _WSAGetLastError())); } else { D(bug("<%d> ttl set to %d.\r\n", t, ttl)); } } static void tcp_reply( const int flags, const int t ) { int tcp_size = sizeof(tcp_t); tcp_t *tcp = (tcp_t *)malloc( tcp_size ); if(tcp) { memcpy( tcp->ip.mac.dest, ether_addr, 6 ); memcpy( tcp->ip.mac.src, router_mac_addr, 6 ); tcp->ip.mac.type = htons(mac_type_ip4); tcp->ip.version = 4; tcp->ip.header_len = 5; tcp->ip.tos = 0; tcp->ip.total_len = htons(tcp_size - sizeof(mac_t)); tcp->ip.ident = htons(next_ip_ident_number++); tcp->ip.flags_n_frag_offset = 0; tcp->ip.ttl = 128; tcp->ip.proto = ip_proto_tcp; tcp->ip.src = htonl(sockets[t].ip_dest); tcp->ip.dest = htonl(sockets[t].ip_src); make_ip4_checksum( (ip_t *)tcp ); D(bug("<%d> Reply: Seq=%d, Ack=%d\r\n", t, sockets[t].seq_out, sockets[t].seq_in)); tcp->src_port = htons(sockets[t].dest_port); tcp->dest_port = htons(sockets[t].src_port); tcp->seq = htonl(sockets[t].seq_out); tcp->ack = htonl(sockets[t].seq_in); tcp->header_len = (uint8)( 20 << 2 ); tcp->flags = flags; tcp->window = htons( sockets[t].our_window ); tcp->urgent_ptr = 0; make_tcp_checksum( tcp, tcp_size ); // dump_bytes( (uint8 *)tcp, tcp_size ); enqueue_packet( (uint8 *)tcp, tcp_size ); free(tcp); } } static bool has_mac_read_space( const int t ) { uint32 pending_bytes = sockets[t].seq_out - sockets[t].mac_ack; uint32 mac_can_accept_bytes = sockets[t].mac_window - pending_bytes; D(bug("<%d> mac_can_accept_bytes = %d\r\n", t, mac_can_accept_bytes)); // Modified Nagle, effectively disabling window sliding (which I don't support anyway): return pending_bytes == 0; // Use more of window bandwidth // Enabling this would require that the buffers seq numbers are stored somewhere // return mac_can_accept_bytes >= sockets[t].buffers_read[0].len; } static bool b_recfrom( const int t ) { bool result; if( !has_mac_read_space(t) ) { D(bug("<%d> read stalled, mac cannot accept any more data\r\n", t)); sockets[t].stream_to_mac_stalled_until = GetTickCount() + sockets[t].resend_timeout; return true; } int ret = _WSARecv( sockets[t].s, sockets[t].buffers_read, sockets[t].buffer_count_read, &sockets[t].bytes_received, &sockets[t].flags_read, &sockets[t].overlapped_read, tcp_read_completion ); if(ret == SOCKET_ERROR) { int socket_error = _WSAGetLastError(); if(socket_error == WSA_IO_PENDING) { D(bug("<%d> WSARecv() i/o pending\r\n", t)); result = true; } else { D(bug("<%d> WSARecv() returned error %d\r\n", t, socket_error)); result = false; } } else /*if(ret == 0) */ { D(bug("<%d> WSARecv() ok\r\n", t)); // Completion routine call is already scheduled. result = true; } return result; } static bool b_send( const int t ) { int ret = _WSASend( sockets[t].s, sockets[t].buffers_write, sockets[t].buffer_count_write, &sockets[t].bytes_written, sockets[t].flags_write, &sockets[t].overlapped_write, tcp_write_completion ); bool result; if(ret == SOCKET_ERROR) { int socket_error = _WSAGetLastError(); if(socket_error == WSA_IO_PENDING) { D(bug("<%d> WSASend() i/o pending\r\n", t)); result = true; } else { D(bug("<%d> WSASend() returned %d\r\n", t, socket_error)); result = false; } } else /*if(ret == 0) */ { D(bug("<%d> WSASend() ok\r\n", t)); // Completion routine call is already scheduled. result = true; } return result; } static void send_buffer( const int t, const bool resending ) { if(resending) { if(sockets[t].last_seq_out == 0) { D(bug("<%d> resend failure\r\n", t )); return; } sockets[t].seq_out = sockets[t].last_seq_out; } else { sockets[t].last_seq_out = sockets[t].seq_out; } D(bug("<%d> %s data to Mac: Seq=%d, Ack=%d\r\n", t, (resending ? "resending" : "sending"), sockets[t].seq_out, sockets[t].seq_in)); uint32 bytes_read = sockets[t].bytes_received; if( sockets[t].mac_mss && bytes_read > sockets[t].mac_mss ) { D(bug("<%d> impossible: %d bytes to send, Mac mss is only %d\r\n", t, sockets[t].mac_mss && bytes_read, sockets[t].mac_mss)); } int tcp_size = sizeof(tcp_t) + bytes_read; tcp_t *tcp = (tcp_t *)malloc( tcp_size ); if(tcp) { // Build MAC // memcpy( tcp->ip.mac.dest, sockets[t].mac_src, 6 ); memcpy( tcp->ip.mac.dest, ether_addr, 6 ); memcpy( tcp->ip.mac.src, router_mac_addr, 6 ); tcp->ip.mac.type = htons(mac_type_ip4); // Build IP tcp->ip.version = 4; tcp->ip.header_len = 5; tcp->ip.tos = 0; tcp->ip.total_len = htons(sizeof(tcp_t) - sizeof(mac_t) + bytes_read); // no options tcp->ip.ident = htons(next_ip_ident_number++); tcp->ip.flags_n_frag_offset = 0; tcp->ip.ttl = 128; // one hop actually! tcp->ip.proto = ip_proto_tcp; tcp->ip.src = htonl(sockets[t].ip_dest); tcp->ip.dest = htonl(sockets[t].ip_src); make_ip4_checksum( (ip_t *)tcp ); // Copy payload (used by tcp checksum) memcpy( (char *)tcp + sizeof(tcp_t), sockets[t].buffers_read[0].buf, bytes_read ); // Build tcp tcp->src_port = htons(sockets[t].dest_port); tcp->dest_port = htons(sockets[t].src_port); tcp->seq = htonl(sockets[t].seq_out); tcp->ack = htonl(sockets[t].seq_in); tcp->header_len = (uint8)( 20 << 2 ); #if PUSH_ALWAYS tcp->flags = ACK|PSH; #else tcp->flags = (bytes_read == MAX_SEGMENT_SIZE) ? ACK : (ACK|PSH); #endif tcp->window = htons( sockets[t].our_window ); tcp->urgent_ptr = 0; make_tcp_checksum( tcp, tcp_size ); sockets[t].seq_out += bytes_read; // dump_bytes( (uint8 *)tcp, tcp_size ); enqueue_packet( (uint8 *)tcp, tcp_size ); free(tcp); } } static void CALLBACK tcp_read_completion( DWORD error, DWORD bytes_read, LPWSAOVERLAPPED lpOverlapped, DWORD flags ) { EnterCriticalSection( &tcp_section ); const int t = (int)lpOverlapped->hEvent; sockets[t].bytes_received = bytes_read; D(bug("<%d> tcp_read_completion(error=%d, bytes_read=%d)\r\n", t, error, bytes_read)); D(bug("<%d> tcp_read_completion() start, old state = %s\r\n", t, STATENAME(sockets[t].state))); if(!sockets[t].in_use) { D(bug("<%d> ignoring canceled read\r\n", t)); } else { if( error != 0 ) { D(bug("<%d> resetting after read error\r\n", t)); tcp_reply( RST, t ); free_socket(t); } else { if(bytes_read == 0) { _closesocket( sockets[t].s ); sockets[t].s = INVALID_SOCKET; } else if( bytes_read > 0) { send_buffer( t, false ); } switch( sockets[t].state ) { case SYN_RCVD: if( bytes_read == 0 ) { D(bug("<%d> Closing: SYN_RCVD -> FINWAIT_1\r\n", t)); tcp_reply( ACK|FIN, t ); sockets[t].seq_out++; sockets[t].state = FINWAIT_1; } break; case ESTABLISHED: if( bytes_read == 0 ) { D(bug("<%d> Closing: ESTABLISHED -> FINWAIT_1\r\n", t)); tcp_reply( ACK|FIN, t ); sockets[t].seq_out++; sockets[t].state = FINWAIT_1; } break; case LISTEN: tcp_reply( SYN, t ); sockets[t].seq_out++; sockets[t].state = SYN_SENT; sockets[t].time_wait = GetTickCount() + SYN_FLOOD_PROTECTION_TIMEOUT; D(bug("<%d> LISTEN -> SYN_SENT\r\n", t)); break; case CLOSE_WAIT: if( bytes_read == 0) { tcp_reply( ACK|FIN, t ); sockets[t].seq_out++; sockets[t].state = LAST_ACK; D(bug("<%d> Closing: CLOSE_WAIT -> LAST_ACK\r\n", t)); if(sockets[t].remote_closed) { // Just in case that mac gets out of sync. _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } } break; default: break; } if(!is_router_shutting_down && sockets[t].s != INVALID_SOCKET) { if(sockets[t].state != LISTEN) { b_recfrom(t); } } } } LeaveCriticalSection( &tcp_section ); } static void CALLBACK tcp_write_completion( DWORD error, DWORD bytes_written, LPWSAOVERLAPPED lpOverlapped, DWORD flags ) { EnterCriticalSection( &tcp_section ); const int t = (int)lpOverlapped->hEvent; sockets[t].bytes_written = bytes_written; sockets[t].bytes_remaining_to_send -= bytes_written; D(bug("<%d> tcp_write_completion(error=%d, bytes_written=%d)\r\n", t, error, bytes_written)); if(!sockets[t].in_use) { D(bug("<%d> ignoring canceled write\r\n", t)); } else { if(is_router_shutting_down || sockets[t].s == INVALID_SOCKET) { D(bug("<%d> is not alive for sending.\r\n", t)); } else { if( sockets[t].bytes_remaining_to_send <= 0 ) { D(bug("<%d> all data sent, accepting some more.\r\n", t)); sockets[t].seq_in += sockets[t].bytes_to_send; sockets[t].bytes_to_send = sockets[t].bytes_remaining_to_send = 0; // superfluous tcp_reply( ACK, t ); sockets[t].accept_more_data_from_mac = true; } else { D(bug("<%d> %d bytes (of %d total) remaining, sending.\r\n", t, sockets[t].bytes_remaining_to_send, sockets[t].bytes_to_send)); sockets[t].buffers_write[0].len = sockets[t].bytes_remaining_to_send; char *p = sockets[t].buffers_write[0].buf; memmove( p, &p[bytes_written], sockets[t].bytes_remaining_to_send ); if(!b_send(t)) { } else { } } } } LeaveCriticalSection( &tcp_section ); } static void tcp_connect_callback( const int t ) { D(bug("<%d> tcp_connect_callback() start, old state = %s\r\n", t, STATENAME(sockets[t].state))); switch( sockets[t].state ) { case LISTEN: tcp_reply( SYN|ACK, t ); sockets[t].seq_out++; sockets[t].state = SYN_RCVD; D(bug("<%d> Connect: LISTEN -> SYN_RCVD\r\n", t)); break; default: break; } D(bug("<%d> tcp_connect_callback() end, new state = %s\r\n", t, STATENAME(sockets[t].state))); } static void tcp_accept_callback( const int lst ) { D(bug("[%d] tcp_accept_callback()\r\n", lst)); struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; int tolen = sizeof(to); SOCKET s = _accept( l_sockets[lst].s, (struct sockaddr *)&to, &tolen ); if( s == INVALID_SOCKET ) { D(bug("[%d] connection not accepted, error code %d\r\n", lst, _WSAGetLastError())); } else { _WSAEventSelect( s, 0, 0 ); uint16 src_port = l_sockets[lst].port; uint16 dest_port = ntohs(to.sin_port); uint32 ip_dest = ntohl(to.sin_addr.s_addr); D(bug("[%d] connection accepted, local port:%d, remote %s:%d\r\n", lst, src_port, _inet_ntoa(to.sin_addr), dest_port)); if( l_sockets[lst].ip != 0 && l_sockets[lst].ip != ip_dest ) { _closesocket( s ); D(bug("[%d] authorization failure. connection closed.\r\n", lst )); } else { int t = alloc_new_socket( src_port, dest_port, ip_dest ); if( t < 0 ) { D(bug("<%d> out of slot space, connection dropped\r\n", t )); free_socket(t); } else { sockets[t].s = s; sockets[t].state = LISTEN; sockets[t].src_port = src_port; sockets[t].dest_port = dest_port; sockets[t].ip_src = macos_ip_address; sockets[t].ip_dest = ip_dest; sockets[t].seq_out = 0x00000001; sockets[t].seq_in = 0; // not known yet sockets[t].mac_ack = sockets[t].seq_out; // zero out pending bytes tcp_reply( SYN, t ); sockets[t].seq_out++; sockets[t].state = SYN_SENT; sockets[t].time_wait = GetTickCount() + SYN_FLOOD_PROTECTION_TIMEOUT; D(bug("<%d> Connect: LISTEN -> SYN_SENT\r\n", t)); _WSAResetEvent( sockets[t].ev ); if( SOCKET_ERROR == _WSAEventSelect( sockets[t].s, sockets[t].ev, FD_CLOSE ) ) { D(bug("<%d> WSAEventSelect() failed with error code %d\r\n", t, _WSAGetLastError())); } // No data from the remote host is needed until the connection is established. // So don't initiate read yet. } } } } /* MSS is the only option I care about, and since I'm on ethernet I already pretty much know everything needed. AFAIK window scaling is not in effect unless both parties specify it, and I'm not doing it. */ static void process_options( const int t, const uint8 *opt, int len, uint32 &mss ) { mss = 0; while( len > 0 ) { switch( *opt ) { case 0: // End of Option List D(bug("<%d> End of Option List\r\n", t)); len = 0; break; case 1: // No-Operation D(bug("<%d> No-Operation\r\n", t)); len--; opt++; break; case 2: // Maximum Segment Size { mss = ntohs( *((uint16 *)&opt[2]) ); D(bug("<%d> Maximum Segment Size = %d\r\n", t, mss)); len -= 4; opt += 4; } break; case 3: // Window Scale { int wscale = opt[2]; D(bug("<%d> Window Scale = %d\r\n", t, (int)wscale)); len -= 3; opt += 3; } break; case 4: // Sack-Permitted D(bug("<%d> Sack-Permitted option is set\r\n", t)); len -= 2; opt += 2; break; case 5: // Sack { int sack_len = opt[1]; int hf = (sack_len-2) / 4; D(bug("<%d> Sack, %d half-blocks\r\n", t, hf)); len -= sack_len; opt += sack_len; } break; case 8: // Time Stamps { int valve = ntohl( *((uint32 *)&opt[2]) ); int ereply = ntohl( *((uint32 *)&opt[6]) ); D(bug("<%d> Time Stamps, TS valve = 0x%X, TS echo reply = 0x%X\r\n", t, valve, ereply)); len -= 10; opt += 10; } break; default: D(bug("<%d> Unknown tcp header option 0x%02x, breaking out\r\n", t, (int)*opt)); len = 0; break; } } } void write_tcp( tcp_t *tcp, int len ) { if(len < sizeof(tcp_t)) { D(bug("<%d> Too small tcp packet(%d) on unknown slot, dropped\r\n", -1, len)); return; } uint16 src_port = ntohs(tcp->src_port); uint16 dest_port = ntohs(tcp->dest_port); BOOL ok = true; BOOL handle_data = false; BOOL initiate_read = false; EnterCriticalSection( &tcp_section ); int t = find_socket( src_port, dest_port ); if(t < 0) { t = alloc_new_socket( src_port, dest_port, ntohl(tcp->ip.dest) ); ok = t >= 0; } if(ok) { D(bug("<%d> write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port)); } else { D(bug("<%d> FAILED write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port)); } if( ok && ISSET(tcp->flags,RST) ) { D(bug("<%d> RST set, resetting socket\r\n", t)); if( sockets[t].s != INVALID_SOCKET ) { D(bug("<%d> doing an extra shutdown (ie4)\r\n", t)); _shutdown( sockets[t].s, SD_BOTH ); } free_socket( t ); ok = false; } if(ok) { D(bug("<%d> State machine start = %s\r\n", t, STATENAME(sockets[t].state))); // always update receive window sockets[t].mac_window = ntohs(tcp->window); int header_len = tcp->header_len >> 2; int option_bytes = header_len - 20; char *data = (char *)tcp + sizeof(tcp_t) + option_bytes; int dlen = len - sizeof(tcp_t) - option_bytes; if( !ISSET(tcp->flags,ACK) ) { D(bug("<%d> ACK not set\r\n", t)); } if( ISSET(tcp->flags,SYN) ) { D(bug("<%d> SYN set\r\n", t)); // Note that some options are valid even if there is no SYN. // I don't care about those however. uint32 new_mss; process_options( t, (uint8 *)data - option_bytes, option_bytes, new_mss ); if(new_mss) { sockets[t].mac_mss = (int)new_mss; if( new_mss < sockets[t].buffers_read[0].len ) { sockets[t].buffers_read[0].len = new_mss; } D(bug("<%d> Max segment size set to %d\r\n", t, new_mss)); } } if( ISSET(tcp->flags,FIN) ) { D(bug("<%d> FIN set\r\n", t)); } // The sequence number Mac expects to see next time. sockets[t].mac_ack = ntohl(tcp->ack); D(bug("<%d> From Mac: Seq=%d, Ack=%d, window=%d, router Seq=%d\r\n", t, ntohl(tcp->seq), sockets[t].mac_ack, sockets[t].mac_window, sockets[t].seq_out)); if( sockets[t].stream_to_mac_stalled_until && sockets[t].mac_ack == sockets[t].seq_out && (sockets[t].state == ESTABLISHED || sockets[t].state == CLOSE_WAIT) ) { if( has_mac_read_space(t) ) { initiate_read = true; sockets[t].stream_to_mac_stalled_until = 0; D(bug("<%d> read resumed, mac can accept more data\r\n", t)); } } switch( sockets[t].state ) { case CLOSED: sockets[t].src_port = src_port; sockets[t].dest_port = dest_port; sockets[t].ip_src = ntohl(tcp->ip.src); sockets[t].ip_dest = ntohl(tcp->ip.dest); if( ISSET(tcp->flags,SYN) ) { sockets[t].seq_out = 0x00000001; sockets[t].seq_in = ntohl(tcp->seq) + 1; _WSAResetEvent( sockets[t].ev ); if( SOCKET_ERROR == _WSAEventSelect( sockets[t].s, sockets[t].ev, FD_CONNECT | FD_CLOSE ) ) { D(bug("<%d> WSAEventSelect() failed with error code %d\r\n", t, _WSAGetLastError())); } D(bug("<%d> connecting local port %d to remote %s:%d\r\n", t, src_port, _inet_ntoa(sockets[t].from.sin_addr), dest_port)); sockets[t].state = LISTEN; if( _WSAConnect( sockets[t].s, (const struct sockaddr *)&sockets[t].from, sockets[t].from_len, NULL, NULL, NULL, NULL ) == SOCKET_ERROR ) { int connect_error = _WSAGetLastError(); if( connect_error == WSAEWOULDBLOCK ) { D(bug("<%d> WSAConnect() i/o pending.\r\n", t)); } else { D(bug("<%d> WSAConnect() failed with error %d.\r\n", t, connect_error)); } } else { D(bug("<%d> WSAConnect() ok.\r\n", t)); } } else { if( ISSET(tcp->flags,FIN) ) { D(bug("<%d> No SYN but FIN on a closed socket.\r\n", t)); free_socket(t); } else { D(bug("<%d> No SYN on a closed socket. resetting.\r\n", t)); free_socket(t); } } break; case LISTEN: // handled in connect callback break; case SYN_SENT: if( ISSET(tcp->flags,SYN) && ISSET(tcp->flags,ACK) ) { sockets[t].seq_in = ntohl(tcp->seq) + 1; tcp_reply( ACK, t ); sockets[t].state = ESTABLISHED; initiate_read = true; sockets[t].accept_more_data_from_mac = true; sockets[t].time_wait = 0; } else if( ISSET(tcp->flags,SYN) ) { sockets[t].seq_in = ntohl(tcp->seq) + 1; tcp_reply( ACK|SYN, t ); sockets[t].seq_out++; sockets[t].state = SYN_RCVD; sockets[t].time_wait = 0; } else if( ISSET(tcp->flags,ACK) ) { // What was the bright idea here. D(bug("<%d> State is SYN_SENT, but got only ACK from Mac??\r\n", t)); sockets[t].state = FINWAIT_2; sockets[t].time_wait = 0; } break; case SYN_RCVD: if( ISSET(tcp->flags,ACK) ) { sockets[t].state = ESTABLISHED; handle_data = true; initiate_read = true; sockets[t].accept_more_data_from_mac = true; } break; case ESTABLISHED: if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); _shutdown( sockets[t].s, SD_SEND ); sockets[t].state = CLOSE_WAIT; } handle_data = true; break; case CLOSE_WAIT: // handled in tcp_read_completion break; case LAST_ACK: if( ISSET(tcp->flags,ACK) ) { D(bug("<%d> LAST_ACK received, socket closed\r\n", t)); free_socket( t ); } break; case FINWAIT_1: if( ISSET(tcp->flags,FIN) && ISSET(tcp->flags,ACK) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } else if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = CLOSING; } else if( ISSET(tcp->flags,ACK) ) { sockets[t].state = FINWAIT_2; } break; case FINWAIT_2: if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } break; case CLOSING: if( ISSET(tcp->flags,ACK) ) { sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } break; case TIME_WAIT: // Catching stray packets: wait MSL * 2 seconds, -> CLOSED // Timer already set since we might not get here at all. // I'm using exceptionally low MSL value (5 secs). D(bug("<%d> time wait, datagram discarded\r\n", t)); break; } // The "t" descriptor may already be freed. However, it's safe // to peek the state value inside the critical section. D(bug("<%d> State machine end = %s\r\n", t, STATENAME(sockets[t].state))); D(bug("<%d> handle_data=%d, initiate_read=%d\r\n", t, handle_data, initiate_read)); if( handle_data && dlen && sockets[t].accept_more_data_from_mac ) { if( sockets[t].seq_in != ntohl(tcp->seq) ) { D(bug("<%d> dropping duplicate datagram seq=%d, expected=%d\r\n", t, ntohl(tcp->seq), sockets[t].seq_in)); } else { set_ttl( t, tcp->ip.ttl ); struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; to.sin_port = tcp->dest_port; to.sin_addr.s_addr = tcp->ip.dest; D(bug("<%d> sending %d bytes to remote host\r\n", t, dlen)); sockets[t].accept_more_data_from_mac = false; if( dlen > MAX_SEGMENT_SIZE ) { D(bug("<%d> IMPOSSIBLE: b_send() dropped %d bytes! \r\n", t, dlen-MAX_SEGMENT_SIZE)); dlen = MAX_SEGMENT_SIZE; } memcpy( sockets[t].buffers_write[0].buf, data, dlen ); sockets[t].buffers_write[0].len = dlen; sockets[t].bytes_remaining_to_send = dlen; sockets[t].bytes_to_send = dlen; bool send_now = false; if( ISSET(tcp->flags,PSH) ) { send_now = true; } else { // todo -- delayed send send_now = true; } if(send_now) { // Patch ftp server or client address if needed. int lst = 1; bool is_pasv; uint16 ftp_data_port = 0; if(ftp_is_ftp_port(sockets[t].src_port)) { // Local ftp server may be entering to passive mode. is_pasv = true; ftp_parse_port_command( sockets[t].buffers_write[0].buf, dlen, ftp_data_port, is_pasv ); } else if(ftp_is_ftp_port(sockets[t].dest_port)) { // Local ftp client may be using port command. is_pasv = false; ftp_parse_port_command( sockets[t].buffers_write[0].buf, dlen, ftp_data_port, is_pasv ); } if(ftp_data_port) { D(bug("<%d> ftp %s command detected, port %d\r\n", t, (is_pasv ? "SERVER PASV REPLY" : "CLIENT PORT"), ftp_data_port )); // Note: for security reasons, only allow incoming connection from sockets[t].ip_dest lst = alloc_listen_socket( ftp_data_port, sockets[t].ip_dest, 0/*iface*/, true ); if(lst < 0) { D(bug("<%d> no more free slots\r\n", t)); } else { // First start listening (need to know the local name later) tcp_start_listen( lst ); // When t is closed, lst must be closed too. sockets[t].child = lst; l_sockets[lst].parent = t; // Find out the local name struct sockaddr_in name; int namelen = sizeof(name); memset( &name, 0, sizeof(name) ); if( _getsockname( sockets[t].s, (struct sockaddr *)&name, &namelen ) == SOCKET_ERROR ) { D(bug("_getsockname() failed, error=%d\r\n", _WSAGetLastError() )); } ftp_modify_port_command( sockets[t].buffers_write[0].buf, dlen, MAX_SEGMENT_SIZE, ntohl(name.sin_addr.s_addr), ftp_data_port, is_pasv ); sockets[t].buffers_write[0].len = dlen; sockets[t].bytes_remaining_to_send = dlen; // Do not change "bytes_to_send" field as it is used for ack calculation } } // end of ftp patch if(!b_send(t)) { // on error, close the ftp data listening socket if one was created if(lst >= 0) { D(bug("[%d] closing listening port %d after write error\r\n", t, l_sockets[lst].port)); _closesocket( l_sockets[lst].s ); l_sockets[lst].s = INVALID_SOCKET; l_sockets[lst].port = 0; l_sockets[lst].ip = 0; l_sockets[lst].parent = -1; sockets[t].child = -1; } } } } } if(initiate_read) { if(!b_recfrom(t)) { // post icmp error message } } } LeaveCriticalSection( &tcp_section ); } /* - Dispatch remote close and connect events. - Expire time-waits. - Handle resend timeouts. */ static WINAPI unsigned int tcp_connect_close_thread(void *arg) { WSAEVENT wait_handles[MAX_SOCKETS]; for( int i=0; i= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + MAX_SOCKETS ) { const int t = ret - WAIT_OBJECT_0; D(bug("<%d> Event %d\r\n", t, ret)); if(sockets[t].in_use) { WSANETWORKEVENTS what; if( _WSAEnumNetworkEvents( sockets[t].s, sockets[t].ev, &what ) != SOCKET_ERROR ) { if( what.lNetworkEvents & FD_CONNECT ) { if( what.iErrorCode[FD_CONNECT_BIT] == 0 ) { D(bug("<%d> Connect ok\r\n", t)); tcp_connect_callback(t); } else { D(bug("<%d> Connect error=%d\r\n", t, what.iErrorCode[FD_CONNECT_BIT])); // Post icmp error } } else if( what.lNetworkEvents & FD_CLOSE ) { if( what.iErrorCode[FD_CLOSE_BIT] == 0 ) { D(bug("<%d> graceful close, state = %s\r\n", t, STATENAME(sockets[t].state))); } else { D(bug("<%d> abortive close, state = %s, code=%d\r\n", t, STATENAME(sockets[t].state), what.iErrorCode[FD_CLOSE_BIT])); } sockets[t].remote_closed = true; } } else { int err = _WSAGetLastError(); if( err == WSAENOTSOCK ) { D(bug("<%d> WSAEnumNetworkEvents: socket is already closed\r\n", t)); } else { D(bug("<%d> WSAEnumNetworkEvents failed with error code %d, freeing slot\r\n", t, err)); free_socket( t ); } } } _WSAResetEvent( sockets[t].ev ); } else { static int interval = 5; if( !--interval ) { for( int i=0; i= tmw ) { if( sockets[i].state == SYN_SENT ) { /* A very basic SYN flood protection. Note that watching SYN_SENT instead of SYN_RCVD, because the state codes are from the point of view of the Mac-Router interface, not Router-Remote. */ D(bug("<%d> SYN_SENT time-out expired\r\n", i)); } else { D(bug("<%d> TIME_WAIT expired\r\n", i)); } free_socket( i ); } } else if( stl ) { if( sockets[i].state == ESTABLISHED ) { if( GetTickCount() >= stl ) { D(bug("<%d> RESEND timeout expired\r\n", i)); sockets[i].stream_to_mac_stalled_until = GetTickCount() + sockets[i].resend_timeout; send_buffer( i, true ); } } else { sockets[i].stream_to_mac_stalled_until = 0; } } } } interval = 5; } } LeaveCriticalSection( &tcp_section ); } return 0; } static WINAPI unsigned int tcp_listen_thread(void *arg) { WSAEVENT wait_handles[MAX_SOCKETS]; for( int i=0; i= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + MAX_SOCKETS ) { const int lst = ret - WAIT_OBJECT_0; D(bug("[%d] connection attempt to port %d\r\n", lst, l_sockets[lst].port)); WSANETWORKEVENTS what; if( _WSAEnumNetworkEvents( l_sockets[lst].s, l_sockets[lst].ev, &what ) != SOCKET_ERROR ) { if( what.lNetworkEvents & FD_ACCEPT ) { if( what.iErrorCode[FD_ACCEPT_BIT] == 0 ) { D(bug("[%d] Connect ok\r\n", lst)); tcp_accept_callback(lst); } else { D(bug("[%d] Connect error=%d\r\n", lst, what.iErrorCode[FD_ACCEPT_BIT])); // Post icmp error } } } // close on errors too if(l_sockets[lst].once) { D(bug("[%d] once mode: closing listening socket on port %d\r\n", lst, l_sockets[lst].port)); if( _closesocket( l_sockets[lst].s ) == SOCKET_ERROR ) { int err = _WSAGetLastError(); D(bug("[%d] close error %d\r\n", lst, err)); } l_sockets[lst].s = INVALID_SOCKET; l_sockets[lst].port = 0; l_sockets[lst].ip = 0; int t = l_sockets[lst].parent; if( t >= 0 ) { sockets[t].child = -1; } l_sockets[lst].parent = -1; } _WSAResetEvent( l_sockets[lst].ev ); } LeaveCriticalSection( &tcp_section ); } return 0; } /* tcp_port= [,] tcp_port=21,192.168.0.1 */ static void init_tcp_listen_ports() { int32 index = 0; const char *port_str; while ((port_str = PrefsFindString("tcp_port", index++)) != NULL) { uint32 iface = 0; char *if_str = strchr(port_str,','); if(if_str) { *if_str++ = 0; uint32 if_net = _inet_addr( if_str ); if(if_net == INADDR_NONE) if_net = INADDR_ANY; iface = ntohl( if_net ); } uint16 port = (uint16)strtoul( port_str, 0, 0 ); if( port ) { uint32 ip = 0; bool once = false; alloc_listen_socket( port, ip, iface, once ); } } } static HANDLE tcp_handle = 0; static HANDLE tcp_l_handle = 0; void init_tcp() { InitializeCriticalSection( &tcp_section ); for( int i=0; i #include #include "cpu_emulation.h" #include "prefs.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "dynsockets.h" #include "ipsocket.h" #include "iphelp.h" #include "arp.h" #include "icmp.h" #include "udp.h" #include "tcp.h" #include "ftp.h" #include "mib/interfaces.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" uint16 next_ip_ident_number = 1; uint32 macos_ip_address = 0; const uint8 router_mac_addr[6] = { '4', '2', '6', '7', '7', '9' }; uint32 router_ip_address = 0; bool raw_sockets_available = false; // Protected data. CRITICAL_SECTION router_section; bool is_router_shutting_down = false; static HANDLE r_handle = 0; static unsigned int rh_tid = 0; static void write_ip4( ip_t *ip, int len ) { if(len < sizeof(ip_t)) { D(bug("Too small ip packet(%d), dropped\r\n", len)); } else { uint8 proto = ip->proto; // This is a router, decrement the hop count if( --ip->ttl == 0 ) { // Most likely this is some Mac traceroute app D(bug("ip packet ttl expired, proto=%d.\r\n", proto)); error_winsock_2_icmp( WSAETTLEXCEEDED, ip, len ); } else { switch( proto ) { case ip_proto_icmp: write_icmp( (icmp_t *)ip, len ); break; case ip_proto_tcp: write_tcp( (tcp_t *)ip, len ); break; case ip_proto_udp: write_udp( (udp_t *)ip, len ); break; default: D(bug("write_ip4() len=%d, proto=%d\r\n", len, proto)); break; } } } } bool router_write_packet(uint8 *packet, int len) { bool result = false; if( len >= 14 ) { switch( ntohs( ((mac_t *)packet)->type ) ) { case mac_type_ip4: write_ip4( (ip_t *)packet, len ); result = true; break; case mac_type_ip6: D(bug("write_ip6() len=%d; unsupported.\r\n", len)); result = true; break; case mac_type_arp: result = write_arp( (arp_t *)packet, len ); break; } } return result; } bool router_read_packet(uint8 *packet, int len) { bool result = false; if( len >= 14 ) { switch( ntohs( ((mac_t *)packet)->type ) ) { case mac_type_ip4: case mac_type_ip6: case mac_type_arp: result = true; break; } } return result; } /* This has nothing to do with TCP TIME_WAITs or CLOSE_WAITs, the thread is needed to close down expired udp sockets. Arguably an ugly hack, but needed since there is no way to listen to all ports w/o writing another ndis filter driver */ static WINAPI unsigned int router_expire_thread(void *arg) { while(!is_router_shutting_down) { close_old_sockets(); Sleep(1000); } return 0; } bool router_init(void) { InitializeCriticalSection( &router_section ); if(dynsockets_init()) { char me[128]; if( _gethostname(me, sizeof(me)) == SOCKET_ERROR ) { D(bug("gethostname() failed, error = %d\r\n", _WSAGetLastError())); } else { struct hostent *hent = _gethostbyname(me); if( hent == NULL ) { D(bug("gethostbyname() failed, error = %d\r\n", _WSAGetLastError())); } else { struct in_addr *ina = (struct in_addr *) *hent->h_addr_list; router_ip_address = ntohl(ina->s_addr); D(bug("router protocol address seems to be %s (used only in icmp error messages)\r\n", _inet_ntoa(*ina))); } } is_router_shutting_down = false; r_handle = (HANDLE)_beginthreadex( 0, 0, router_expire_thread, 0, 0, &rh_tid ); init_interfaces(); init_tcp(); init_udp(); init_ftp(); return true; } return false; } void router_final(void) { final_interfaces(); stop_icmp_listen(); close_all_sockets(); if(r_handle) { is_router_shutting_down = true; WaitForSingleObject( r_handle, INFINITE ); final_tcp(); final_udp(); dynsockets_final(); } DeleteCriticalSection( &router_section ); } BasiliskII/src/Windows/router/udp.cpp0000755000175000017500000001312510736405222020004 0ustar centriscentris/* * udp.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "prefs.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "dynsockets.h" #include "ipsocket.h" #include "iphelp.h" #include "udp.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" void CALLBACK udp_read_completion( DWORD error, DWORD bytes_read, LPWSAOVERLAPPED lpOverlapped, DWORD flags ) { D(bug("udp_read_completion(error=0x%x, bytes_read=%d, flags=0x%x)\r\n", error, bytes_read, flags)); socket_t *cmpl = (socket_t *)lpOverlapped->hEvent; // It's not easy to know whether empty upd datagrams should be passed along. doh. if(error == 0 && bytes_read > 0) { if(bytes_read > 1460) { D(bug("discarding oversized udp packet, size = \r\n", bytes_read)); } else { struct sockaddr_in name; int namelen = sizeof(name); memset( &name, 0, sizeof(name) ); if( _getsockname( cmpl->s, (struct sockaddr *)&name, &namelen ) == SOCKET_ERROR ) { D(bug("_getsockname() failed, error=%d\r\n", _WSAGetLastError() )); } else { D(bug("_getsockname(): port=%d\r\n", ntohs(name.sin_port) )); } int udp_size = sizeof(udp_t) + bytes_read; udp_t *udp = (udp_t *)malloc( udp_size ); if(udp) { mac_t *mac = (mac_t *)udp; ip_t *ip = (ip_t *)udp; // Build MAC // memcpy( udp->ip.mac.dest, cmpl->mac_src, 6 ); memcpy( mac->dest, ether_addr, 6 ); memcpy( mac->src, router_mac_addr, 6 ); mac->type = htons(mac_type_ip4); // Build IP ip->version = 4; ip->header_len = 5; ip->tos = 0; ip->total_len = htons(sizeof(udp_t) - sizeof(mac_t) + bytes_read); // no options ip->ident = htons(next_ip_ident_number++); // htons() might be a macro... but does not really matter here. ip->flags_n_frag_offset = 0; ip->ttl = 128; // one hop actually! ip->proto = ip_proto_udp; ip->src = htonl(cmpl->ip_dest); ip->dest = htonl(cmpl->ip_src); make_ip4_checksum( (ip_t *)udp ); // Copy payload (used by UDP checksum) memcpy( (char *)udp + sizeof(udp_t), cmpl->buffers[0].buf, bytes_read ); // Build UDP udp->src_port = htons(cmpl->dest_port); udp->dest_port = htons(cmpl->src_port); udp->msg_len = htons(sizeof(udp_t) - sizeof(ip_t) + bytes_read); // no options make_udp_checksum( udp ); dump_bytes( (uint8 *)udp, udp_size ); enqueue_packet( (uint8 *)udp, udp_size ); free(udp); } } } if(!is_router_shutting_down && cmpl->s != INVALID_SOCKET && cmpl->b_recfrom()) { cmpl->socket_ttl = GetTickCount() + 60000L; } else { delete_socket( cmpl ); } } void write_udp( udp_t *udp, int len ) { if( len < sizeof(udp_t) ) { D(bug("Too small udp packet(%d), dropped\r\n", len)); return; } uint16 src_port = ntohs(udp->src_port); uint16 dest_port = ntohs(udp->dest_port); BOOL ok = true; socket_t *cmpl = find_socket( src_port, dest_port, IPPROTO_UDP ); BOOL old_socket_found = cmpl != 0; if(!cmpl) { cmpl = new socket_t(IPPROTO_UDP); if(cmpl) { cmpl->s = _socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if(cmpl->s == INVALID_SOCKET) { delete cmpl; cmpl = 0; ok = false; } else { cmpl->src_port = src_port; cmpl->dest_port = dest_port; add_socket( cmpl ); } } else { ok = false; } } if(ok) { cmpl->src_port = src_port; cmpl->dest_port = dest_port; cmpl->ip_src = ntohl(udp->ip.src); cmpl->ip_dest = ntohl(udp->ip.dest); struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; to.sin_port = udp->dest_port; to.sin_addr.s_addr = udp->ip.dest; char *data = (char *)udp + sizeof(udp_t); int dlen = len - sizeof(udp_t); // ttl changed, update checksum make_udp_checksum( udp ); cmpl->set_ttl( udp->ip.ttl ); bool please_close = true; /* Note that broadcast messages fill fail, no setsockopt(SO_BROADCAST). That's exactly what I want. */ if(SOCKET_ERROR != _sendto( cmpl->s, data, dlen, 0, (struct sockaddr *)&to, sizeof(to) )) { if(old_socket_found) { // This socket is not overlapped. please_close = false; } else { if(cmpl->b_recfrom()) please_close = false; } cmpl->socket_ttl = GetTickCount() + 60000L; } else { int socket_error = _WSAGetLastError(); D(bug("_sendto() completed with error %d\r\n", socket_error)); // TODO: check this out: error_winsock_2_icmp() uses router_ip_address // as source ip; but it's probably allright error_winsock_2_icmp( socket_error, (ip_t *)udp, len ); } if(please_close) { delete_socket(cmpl); } } } void init_udp() { } void final_udp() { } BasiliskII/src/Windows/router/icmp.h0000755000175000017500000000223110736405222017605 0ustar centriscentris/* * icmp.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _ICMP_H_ #define _ICMP_H_ void start_icmp_listen(); void stop_icmp_listen(); void write_icmp( icmp_t *icmp, int len ); void CALLBACK icmp_read_completion( DWORD error, DWORD bytes_read, LPWSAOVERLAPPED lpOverlapped, DWORD flags ); #endif // _ICMP_H_ BasiliskII/src/Windows/router/ftp.cpp0000755000175000017500000000775410736405222020020 0ustar centriscentris/* * ftp.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include #include "dump.h" #include "prefs.h" #include "ftp.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" static int m_ftp_port_count = 0; #define MAX_FTP_PORTS 100 static uint16 m_ftp_ports[MAX_FTP_PORTS]; bool ftp_is_ftp_port( uint16 port ) { for( int i=0; i> 24, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF, (port >> 8) & 0xFF, port & 0xFF, 0x0d, 0x0a ); count = strlen(buf); D(bug("ftp_modify_port_command: \"%s\"\r\n", buf )); } // this should be robust. rather skip it than do anything dangerous. void ftp_parse_port_command( char *buf, uint32 count, uint16 &ftp_data_port, bool is_pasv ) { ftp_data_port = 0; if( !count ) return; uint8 b[100]; uint32 ftp_ip = 0; // make it a c-string if( count >= sizeof(b) ) count = sizeof(b)-1; memcpy( b, buf, count ); b[ count ] = 0; for( uint32 i=0; i 'z' ) { b[i] = ' '; } else { b[i] = tolower(b[i]); } } // D(bug("FTP: \"%s\"\r\n", b )); char *s = (char *)b; while( *s == ' ' ) s++; if(is_pasv) { /* LOCAL SERVER: ..227 Entering Passive Mode (192,168,0,2,6,236). 0d 0a */ if( atoi(s) == 227 && strstr(s,"passive") ) { while( *s && *s != '(' ) s++; if( *s++ == 0 ) s = 0; } else { s = 0; } } else { /* LOCAL CLIENT: PORT 192,168,0,1,14,147 0d 0a */ if( strncmp(s,"port ",5) == 0 ) { s += 5; } else { s = 0; } } if(s && *s) { // get remote ip (used only for verification) for( uint32 i=0; i<4; i++ ) { while( *s == ' ' ) s++; if(!isdigit(*s)) { ftp_ip = 0; break; } ftp_ip = (ftp_ip << 8) + atoi(s); while( *s && *s != ',' ) s++; if(!*s) { ftp_ip = 0; break; } s++; } if(ftp_ip) { // get local port for( uint32 i=0; i<2; i++ ) { while( *s == ' ' ) s++; if(!isdigit(*s)) { ftp_data_port = 0; break; } ftp_data_port = (ftp_data_port << 8) + atoi(s); while( *s && *s != ',' && *s != ')' ) s++; if(!*s) break; else s++; } } } if(ftp_data_port) { D(bug("ftp_parse_port_command: \"%s\"; port is %d\r\n", b, ftp_data_port )); } } BasiliskII/src/Windows/router/router.h0000755000175000017500000000341510736405222020202 0ustar centriscentris/* * router.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _ROUTER_H_ #define _ROUTER_H_ extern bool is_router_shutting_down; extern CRITICAL_SECTION router_section; // Increased by one for each ip packet sent to the emulated enet interface. extern uint16 next_ip_ident_number; // Used by incoming icmp packets and internal icmp messages. Host byte order. extern uint32 macos_ip_address; // The magic constant extern const uint8 router_mac_addr[6]; // Used by internal icmp messages. Host byte order. extern uint32 router_ip_address; // False under NT/Win2k if the user has no admin rights extern bool raw_sockets_available; // Interface exposed to ether_windows module. bool router_init(void); void router_final(void); // Both of these return true if the ethernet module should drop the packet. bool router_write_packet(uint8 *packet, int len); bool router_read_packet(uint8 *packet, int len); #endif // _ROUTER_H_ BasiliskII/src/Windows/router/arp.cpp0000755000175000017500000000577710736405222020014 0ustar centriscentris/* * arp.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "prefs.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "iphelp.h" #include "arp.h" #include "icmp.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" // ARP queries can be replied immediately. bool write_arp( arp_t *req, int len ) { D(bug("write_arp() len=%d, htype=%d, ptype=%04x, opcode=%d, halen=%d, palen=%d\r\n",len, ntohs(req->htype), ntohs(req->ptype), ntohs(req->opcode), req->halen, req->palen)); start_icmp_listen(); bool result = false; if( len >= sizeof(arp_t) && req->htype == htons(arp_hwtype_enet) && req->ptype == htons(mac_type_ip4) && req->opcode == htons(arp_request) && req->halen == 6 && req->palen == 4 ) { if(memcmp( req->srcp, req->dstp, 4 ) == 0) { // No reply. MacOS is making sure that there are no duplicate ip addresses. // Update localhost (==Mac) ip address (needed by incoming icmp) macos_ip_address = ntohl( *((uint32 *)&req->srcp[0]) ); D(bug("Mac ip: %02x %02x %02x %02x\r\n", req->srcp[0], req->srcp[1], req->srcp[2], req->srcp[3])); } else { arp_t arp; D(bug("Source NIC: %02x %02x %02x %02x\r\n", req->srcp[0], req->srcp[1], req->srcp[2], req->srcp[3])); D(bug("Dest NIC: %02x %02x %02x %02x\r\n", req->dstp[0], req->dstp[1], req->dstp[2], req->dstp[3])); // memcpy( arp.mac.dest, req->mac.src, 6 ); memcpy( arp.mac.dest, ether_addr, 6 ); memcpy( arp.mac.src, router_mac_addr, 6 ); arp.mac.type = htons(mac_type_arp); arp.htype = htons(arp_hwtype_enet); arp.ptype = htons(mac_type_ip4); arp.halen = 6; arp.palen = 4; arp.opcode = htons(arp_reply); memcpy( arp.srch, router_mac_addr, 6 ); memcpy( arp.srcp, req->dstp, 4 ); // memcpy( arp.dsth, req->srch, 6 ); memcpy( arp.dsth, ether_addr, 6 ); memcpy( arp.dstp, req->srcp, 4 ); // Update here, too, just in case. macos_ip_address = ntohl( *((uint32 *)&req->srcp[0]) ); enqueue_packet( (uint8 *)&arp, sizeof(arp) ); } result = true; } return result; } BasiliskII/src/Windows/router/ipsocket.cpp0000755000175000017500000001464310736405222021043 0ustar centriscentris/* * ipsocket.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "ws2tcpip.h" #include "prefs.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "dynsockets.h" #include "ipsocket.h" #include "icmp.h" #include "tcp.h" #include "udp.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" socket_t::socket_t( int _proto ) { s = INVALID_SOCKET; proto = _proto; ip_src = ip_dest = 0; src_port = dest_port = 0; memset( &overlapped, 0, sizeof(overlapped) ); overlapped.hEvent = (HANDLE)this; bytes_received = 0; flags = 0; from_len = sizeof(struct sockaddr_in); memset( &from, 0, sizeof(from) ); from.sin_family = AF_INET; buffer_count = 1; buffers[0].len = 1460; buffers[0].buf = new char [buffers[0].len]; out_buffers[0].len = 1460; out_buffers[0].buf = new char [out_buffers[0].len]; socket_ttl = GetTickCount() + 60000L; permanent = false; } socket_t::~socket_t() { if(s != INVALID_SOCKET) { _closesocket( s ); // slam! s = INVALID_SOCKET; } delete [] out_buffers[0].buf; delete [] buffers[0].buf; } int socket_t::WSARecvFrom() { return _WSARecvFrom( s, buffers, buffer_count, &bytes_received, &flags, (struct sockaddr *)&from, &from_len, &overlapped, proto == IPPROTO_UDP ? udp_read_completion : icmp_read_completion ); } bool socket_t::b_recfrom() { bool result; int ret = WSARecvFrom(); if(ret == SOCKET_ERROR) { int socket_error = _WSAGetLastError(); if(socket_error == WSA_IO_PENDING) { D(bug("WSARecvFrom() i/o pending\r\n")); result = true; } else { D(bug("_WSAGetLastError() returned %d\r\n", socket_error)); result = false; } } else /*if(ret == 0) */ { D(bug("WSARecvFrom() ok\r\n")); // Completion routine call is already scheduled. result = true; } return result; } void socket_t::set_ttl( uint8 ttl ) { int _ttl = ttl; // defensive programming, I know VCx if(_setsockopt( s, IPPROTO_IP, IP_TTL, (const char *)&_ttl, sizeof(int) ) == SOCKET_ERROR ) { D(bug("could not set ttl to %d.\r\n", ttl)); } else { D(bug("ttl set to %d.\r\n", ttl)); } } #define MAX_OPEN_SOCKETS 1024 static socket_t *all_sockets[MAX_OPEN_SOCKETS]; static int open_sockets = 0; int get_socket_index( uint16 src_port, uint16 dest_port, int proto ) { int result = -1; for( int i=0; isrc_port == src_port && cmpl->dest_port == dest_port && cmpl->proto == proto ) { result = i; break; } } return result; } int get_socket_index( uint16 src_port, int proto ) { int result = -1; for( int i=0; isrc_port == src_port && cmpl->proto == proto ) { result = i; break; } } return result; } int get_socket_index( socket_t *cmpl ) { int result = -1; for( int i=0; isrc_port, cmpl->dest_port)); EnterCriticalSection( &router_section ); int i = get_socket_index( cmpl ); if( i >= 0 ) { delete all_sockets[i]; all_sockets[i] = all_sockets[--open_sockets]; } else { D(bug("Deleted socket not in table!\r\n")); // delete cmpl; } LeaveCriticalSection( &router_section ); } socket_t *find_socket( uint16 src_port, uint16 dest_port, int proto ) { socket_t *result = 0; EnterCriticalSection( &router_section ); int i = get_socket_index( src_port, dest_port, proto ); if( i >= 0 ) { result = all_sockets[i]; } else { i = get_socket_index( src_port, proto ); if( i >= 0 ) { delete_socket( all_sockets[i] ); } } LeaveCriticalSection( &router_section ); D(bug("find_socket(%d,%d): %s\r\n", src_port, dest_port, result ? "found" : "not found")); return result; } void add_socket( socket_t *cmpl ) { D(bug("adding socket(%d,%d)\r\n", cmpl->src_port, cmpl->dest_port)); EnterCriticalSection( &router_section ); if( open_sockets < MAX_OPEN_SOCKETS ) { all_sockets[open_sockets++] = cmpl; } else { // Urgchiyuppijee! (that's finnish language, meaning "do something about this") delete all_sockets[0]; all_sockets[0] = cmpl; } LeaveCriticalSection( &router_section ); } void close_old_sockets() { DWORD now = GetTickCount(); EnterCriticalSection( &router_section ); for( int i=open_sockets-1; i>=0; i-- ) { socket_t *cmpl = all_sockets[i]; if( !cmpl->permanent && now >= cmpl->socket_ttl ) { D(bug("expiring socket(%d,%d)\r\n", cmpl->src_port, cmpl->dest_port)); if(cmpl->s == INVALID_SOCKET) { delete all_sockets[i]; all_sockets[i] = all_sockets[--open_sockets]; } else { // read completion will deallocate _closesocket( cmpl->s ); } } } LeaveCriticalSection( &router_section ); } void close_all_sockets() { D(bug("closing all(%d) sockets\r\n", open_sockets)); EnterCriticalSection( &router_section ); for( int i=0; isrc_port, cmpl->dest_port)); if(cmpl->s == INVALID_SOCKET) { delete all_sockets[i]; all_sockets[i] = all_sockets[--open_sockets]; } else { // read completion will deallocate _closesocket( cmpl->s ); } } LeaveCriticalSection( &router_section ); } BasiliskII/src/Windows/router/iphelp.cpp0000755000175000017500000001331610736405222020477 0ustar centriscentris/* * iphelp.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "ether_windows.h" #include "ether.h" #include "router.h" #include "router_types.h" #include "tcp.h" #include "icmp.h" #include "udp.h" #include "iphelp.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" void make_icmp_checksum( icmp_t *icmp, int len ) { icmp->checksum = 0; uint16 sz = (len-sizeof(ip_t))/2; uint16 *p = (uint16 *)( (uint8 *)icmp + sizeof(ip_t) ); uint32 sum32 = 0; for( int i=0; ichecksum = htons((uint16)sum32); } void make_tcp_checksum( tcp_t *tcp, int len ) { tcp->checksum = 0; int tcp_len = len - sizeof(ip_t); uint16 sz = tcp_len/2; uint16 *p = (uint16 *)( (uint8 *)tcp + sizeof(ip_t) ); uint32 sum32 = 0; for( int i=0; iip.src)); pseudo.src_hi = HIWORD(ntohl(tcp->ip.src)); pseudo.dest_lo = LOWORD(ntohl(tcp->ip.dest)); pseudo.dest_hi = HIWORD(ntohl(tcp->ip.dest)); pseudo.proto = (uint16)tcp->ip.proto; pseudo.msg_len = tcp->header_len >> 2; int datalen = len - sizeof(tcp_t); pseudo.msg_len += datalen; p = (uint16 *)&pseudo; for( int i=0; ichecksum = htons((uint16)sum32); } void make_ip4_checksum( ip_t *ip ) { ip->checksum = 0; uint16 sz = ip->header_len * 2; uint16 *p = (uint16 *)( (uint8 *)ip + sizeof(mac_t) ); uint32 sum32 = 0; for( int i=0; ichecksum = htons((uint16)sum32); } void make_udp_checksum( udp_t *udp ) { udp->checksum = 0; return; // UDP checksums are optional. /* uint16 sz = ntohs(udp->msg_len) / 2; uint16 *p = (uint16 *)( (uint8 *)udp + sizeof(ip_t) ); uint32 sum32 = 0; for( int i=0; iip.src)); pseudo.src_hi = HIWORD(ntohl(udp->ip.src)); pseudo.dest_lo = LOWORD(ntohl(udp->ip.dest)); pseudo.dest_hi = HIWORD(ntohl(udp->ip.dest)); pseudo.proto = (uint16)udp->ip.proto; pseudo.msg_len = ntohs(udp->msg_len); // ??? p = (uint16 *)&pseudo; for( i=0; ichecksum = htons((uint16)sum32); */ } void error_winsock_2_icmp( int err, ip_t *ip_err, int dlen_err ) { int type = -1, code = -1, msg_size = 0; switch( err ) { case WSAEHOSTUNREACH: case WSAETIMEDOUT: type = icmp_Destination_unreachable; code = 1; // Host unreachable msg_size = (ip_err->header_len << 2) + 4 + 8; // ip header + unused + 64 msg bits break; case WSAENETDOWN: case WSAENETUNREACH: type = icmp_Destination_unreachable; code = 0; // Network unreachable msg_size = (ip_err->header_len << 2) + 4 + 8; // ip header + unused + 64 msg bits break; case WSAETTLEXCEEDED: type = icmp_Time_exceeded; code = 0; // Transit TTL exceeded msg_size = (ip_err->header_len << 2) + 4 + 8; // ip header + unused + 64 msg bits break; } if(type >= 0 && macos_ip_address != 0) { D(bug("sending icmp error reply. type=%d, code=%d, msg_size=%d\r\n", type, code, msg_size)); int icmp_size = sizeof(icmp_t) + msg_size; icmp_t *icmp = (icmp_t *)malloc( icmp_size ); if(icmp) { mac_t *mac = (mac_t *)icmp; ip_t *ip = (ip_t *)icmp; memcpy( mac->dest, ether_addr, 6 ); memcpy( mac->src, router_mac_addr, 6 ); mac->type = htons(mac_type_ip4); ip->version = 4; ip->header_len = 5; ip->tos = 0; ip->total_len = htons(sizeof(icmp_t) - sizeof(mac_t) + msg_size); ip->ident = htons(next_ip_ident_number++); ip->flags_n_frag_offset = 0; ip->ttl = 128; ip->proto = ip_proto_icmp; ip->src = htonl(router_ip_address); ip->dest = htonl(macos_ip_address); make_ip4_checksum( ip ); icmp->type = type; icmp->code = code; // zero out the unused field memset( (char *)icmp + sizeof(icmp_t), 0, sizeof(uint32) ); // copy 64 bits of original message memcpy( (char *)icmp + sizeof(icmp_t) + sizeof(uint32), (char *)ip_err + sizeof(mac_t), msg_size ); make_icmp_checksum( icmp, icmp_size ); dump_bytes( (uint8 *)icmp, icmp_size ); enqueue_packet( (uint8 *)icmp, icmp_size ); free(icmp); } } } BasiliskII/src/Windows/router/ipsocket.h0000755000175000017500000000356310736405222020507 0ustar centriscentris/* * ipsocket.h - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _IPSOCKET_H_ #define _IPSOCKET_H_ class socket_t { public: socket_t( int _proto ); ~socket_t(); bool b_recfrom(); void set_ttl( uint8 ttl ); protected: int WSARecvFrom(); public: SOCKET s; // Always a valid socket BOOL permanent; // T: a user-defined listening socket, int proto; // udp/icmp WSABUF buffers[1]; WSABUF out_buffers[1]; DWORD buffer_count; DWORD bytes_received; DWORD flags; struct sockaddr_in from; int from_len; WSAOVERLAPPED overlapped; uint32 ip_src; uint32 ip_dest; uint16 src_port; uint16 dest_port; DWORD socket_ttl; }; int get_socket_index( uint16 src_port, uint16 dest_port, int proto ); int get_socket_index( uint16 src_port, int proto ); int get_socket_index( socket_t *cmpl ); void delete_socket( socket_t *cmpl ); socket_t *find_socket( uint16 src_port, uint16 dest_port, int proto ); void add_socket( socket_t *cmpl ); void close_old_sockets(); void close_all_sockets(); #endif // _IPSOCKET_H_ BasiliskII/src/Windows/router/dump.cpp0000755000175000017500000000242310736405222020160 0ustar centriscentris/* * dump.cpp - ip router * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "dump.h" #if DEBUG #pragma optimize("",off) #endif #include "debug.h" void dump_bytes( uint8 *packet, int length ) { #if DEBUG char buf[1000], sm[10]; *buf = 0; if(length > 256) length = 256; for (int i=0; i #include #include #include using std::string; #include "prefs.h" // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {"keycodes", TYPE_BOOLEAN, false, "use keycodes rather than keysyms to decode keyboard"}, {"keycodefile", TYPE_STRING, false, "path of keycode translation file"}, {"mousewheelmode", TYPE_INT32, false, "mouse wheel support mode (0=page up/down, 1=cursor up/down)"}, {"mousewheellines", TYPE_INT32, false, "number of lines to scroll in mouse wheel mode 1"}, #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION {"ignoresegv", TYPE_BOOLEAN, false, "ignore illegal memory accesses"}, #endif {"idlewait", TYPE_BOOLEAN, false, "sleep when idle"}, {"enableextfs", TYPE_BOOLEAN, false, "enable extfs system"}, {"debugextfs", TYPE_BOOLEAN, false, "debug extfs system"}, {"extdrives", TYPE_STRING, false, "define allowed extfs drives"}, {"pollmedia", TYPE_BOOLEAN, false, "poll for new media (e.g. cd, floppy)"}, {"etherguid", TYPE_STRING, false, "GUID of the ethernet device to use"}, {"etherpermanentaddress", TYPE_BOOLEAN, false, "use permanent NIC address to identify itself"}, {"ethermulticastmode", TYPE_INT32, false, "how to multicast packets"}, {"etherfakeaddress", TYPE_STRING, false, "optional fake hardware address"}, {"routerenabled", TYPE_BOOLEAN, false, "enable NAT/Router module"}, {"ftp_port_list", TYPE_STRING, false, "FTP ports list"}, {"tcp_port", TYPE_STRING, false, "TCP ports list"}, {"portfile0", TYPE_STRING, false, "output file for serial port 0"}, {"portfile1", TYPE_STRING, false, "output file for serial port 1"}, {NULL, TYPE_END, false, NULL} // End of list }; // Prefs file name and path const char PREFS_FILE_NAME[] = "BasiliskII_prefs"; string UserPrefsPath; static string prefs_path; /* * Load preferences from settings file */ void LoadPrefs(const char *vmdir) { // Construct prefs path if (UserPrefsPath.empty()) { int pwd_len = GetCurrentDirectory(0, NULL); char *pwd = new char[pwd_len]; if (GetCurrentDirectory(pwd_len, pwd) == pwd_len - 1) prefs_path = string(pwd) + '\\'; delete[] pwd; prefs_path += PREFS_FILE_NAME; } else prefs_path = UserPrefsPath; // Read preferences from settings file FILE *f = fopen(prefs_path.c_str(), "r"); if (f != NULL) { // Prefs file found, load settings LoadPrefsFromStream(f); fclose(f); } else { // No prefs file, save defaults SavePrefs(); } } /* * Save preferences to settings file */ void SavePrefs(void) { FILE *f; if ((f = fopen(prefs_path.c_str(), "w")) != NULL) { SavePrefsToStream(f); fclose(f); } } /* * Add defaults of platform-specific prefs items * You may also override the defaults set in PrefsInit() */ void AddPlatformPrefsDefaults(void) { PrefsAddBool("keycodes", false); PrefsReplaceBool("pollmedia", true); PrefsReplaceBool("enableextfs", false); PrefsReplaceString("extfs", ""); PrefsReplaceString("extdrives", "CDEFGHIJKLMNOPQRSTUVWXYZ"); PrefsReplaceInt32("mousewheelmode", 1); PrefsReplaceInt32("mousewheellines", 3); #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION PrefsAddBool("ignoresegv", false); #endif PrefsAddBool("idlewait", true); PrefsReplaceBool("etherpermanentaddress", true); PrefsReplaceInt32("ethermulticastmode", 0); PrefsReplaceString("ftp_port_list", "21"); PrefsReplaceString("seriala", "COM1"); PrefsReplaceString("serialb", "COM2"); PrefsReplaceString("portfile0", "C:\\B2TEMP0.OUT"); PrefsReplaceString("portfile1", "C:\\B2TEMP1.OUT"); } BasiliskII/src/Windows/cdenable/0000755000175000017500000000000011735674761016740 5ustar centriscentrisBasiliskII/src/Windows/cdenable/cache.cpp0000755000175000017500000001004610736405222020473 0ustar centriscentris/* * cache.cpp - simple floppy/cd cache for Win32 * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ /* Note that this is particularly silly cache code and doesn't even use hash buckets. It is sufficient for floppies and maybe emulated cd's but that's it. */ #include "sysdeps.h" #include "windows.h" #include "cache.h" #ifdef __cplusplus extern "C" { #endif #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif void cache_clear( cachetype *cptr ) { if(cptr->inited) { cptr->res_count = 0; memset( cptr->LRU, 0, NBLOCKS * sizeof(int) ); } } static int init( cachetype *cptr, int sector_size ) { cache_clear( cptr ); cptr->sector_size = sector_size; cptr->blocks = (char *)VirtualAlloc( NULL, NBLOCKS*sector_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); cptr->block = (int *)VirtualAlloc( NULL, NBLOCKS*sizeof(int), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); cptr->LRU = (DWORD *)VirtualAlloc( NULL, NBLOCKS*sizeof(DWORD), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ); return(cptr->blocks != NULL); } static void final( cachetype *cptr ) { if(cptr->blocks) { VirtualFree( cptr->blocks, 0, MEM_RELEASE ); cptr->blocks = 0; } if(cptr->block) { VirtualFree( cptr->block, 0, MEM_RELEASE ); cptr->block = 0; } if(cptr->LRU) { VirtualFree( cptr->LRU, 0, MEM_RELEASE ); cptr->LRU = 0; } cptr->inited = 0; } void cache_init( cachetype *cptr ) { cptr->inited = 0; } void cache_final( cachetype *cptr ) { if(cptr->inited) { final( cptr ); cptr->inited = 0; } } static int in_cache( cachetype *cptr, int block ) { int i; for(i=cptr->res_count-1; i>=0; i--) { if(cptr->block[i] == block) return(i); } return(-1); } static int get_LRU( cachetype *cptr ) { int i, result = 0; DWORD mtime = cptr->LRU[0]; for(i=1; iLRU[i] < mtime) { mtime = cptr->LRU[i]; result = i; } } return(result); } void cache_put( cachetype *cptr, int block, char *buf, int ss ) { int inx; if(!cptr->inited) { if(!init(cptr,ss)) return; cptr->inited = 1; } inx = in_cache( cptr, block ); if(inx < 0) { if(cptr->res_count == NBLOCKS) { inx = get_LRU( cptr ); } else { inx = cptr->res_count++; } cptr->block[inx] = block; } cptr->LRU[inx] = GetTickCount(); memcpy( cptr->blocks + inx * ss, buf, ss ); } int cache_get( cachetype *cptr, int block, char *buf ) { int inx; if(!cptr->inited) return(0); inx = in_cache( cptr, block ); if(inx >= 0) { memcpy( buf, cptr->blocks + inx * cptr->sector_size, cptr->sector_size ); return(1); } else { return(0); } } void cache_remove( cachetype *cptr, int block, int ss ) { int inx, from; if(!cptr->inited) { if(!init(cptr,ss)) return; cptr->inited = 1; } inx = in_cache( cptr, block ); if(inx >= 0) { if(cptr->res_count > 1) { from = cptr->res_count-1; cptr->block[inx] = cptr->block[from]; cptr->LRU[inx] = cptr->LRU[from]; memcpy( cptr->blocks + inx * cptr->sector_size, cptr->blocks + from * cptr->sector_size, cptr->sector_size ); } cptr->res_count--; } } #ifdef __cplusplus } // extern "C" #endif BasiliskII/src/Windows/cdenable/eject_nt.cpp0000755000175000017500000001224110736405222021222 0ustar centriscentris/* * eject_nt.cpp - cd eject routines for WinNT (derived from MS samples) * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include "windows.h" #include // Prototypes extern "C" { #include "eject_nt.h" LPTSTR szVolumeFormat = TEXT("\\\\.\\%c:"); LPTSTR szRootFormat = TEXT("%c:\\"); LPTSTR szErrorFormat = TEXT("Error %d: %s\n"); void ReportError(LPTSTR szMsg) { // _tprintf(szErrorFormat, GetLastError(), szMsg); } HANDLE OpenVolume(TCHAR cDriveLetter) { HANDLE hVolume; UINT uDriveType; TCHAR szVolumeName[8]; TCHAR szRootName[5]; DWORD dwAccessFlags; wsprintf(szRootName, szRootFormat, cDriveLetter); uDriveType = GetDriveType(szRootName); switch(uDriveType) { case DRIVE_REMOVABLE: dwAccessFlags = GENERIC_READ | GENERIC_WRITE; break; case DRIVE_CDROM: dwAccessFlags = GENERIC_READ; break; default: // _tprintf(TEXT("Cannot eject. Drive type is incorrect.\n")); return INVALID_HANDLE_VALUE; } wsprintf(szVolumeName, szVolumeFormat, cDriveLetter); hVolume = CreateFile( szVolumeName, dwAccessFlags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if (hVolume == INVALID_HANDLE_VALUE) ReportError(TEXT("CreateFile")); return hVolume; } BOOL CloseVolume(HANDLE hVolume) { return CloseHandle(hVolume); } #define LOCK_TIMEOUT 1000 // 1 second #define LOCK_RETRIES 20 BOOL LockVolume(HANDLE hVolume) { DWORD dwBytesReturned; DWORD dwSleepAmount; int nTryCount; dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES; // Do this in a loop until a timeout period has expired for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) { if (DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) return TRUE; Sleep(dwSleepAmount); } return FALSE; } BOOL DismountVolume(HANDLE hVolume) { DWORD dwBytesReturned; return DeviceIoControl( hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL); } BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval) { DWORD dwBytesReturned; PREVENT_MEDIA_REMOVAL PMRBuffer; PMRBuffer.PreventMediaRemoval = fPreventRemoval; return DeviceIoControl( hVolume, IOCTL_STORAGE_MEDIA_REMOVAL, &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL), NULL, 0, &dwBytesReturned, NULL); } BOOL AutoEjectVolume( HANDLE hVolume, BOOL reload ) { DWORD dwBytesReturned; return DeviceIoControl( hVolume, reload ? IOCTL_STORAGE_LOAD_MEDIA : IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL); } BOOL EjectVolume( TCHAR cDriveLetter, BOOL reload ) { HANDLE hVolume; BOOL fRemoveSafely = FALSE; BOOL fAutoEject = FALSE; // Open the volume. hVolume = OpenVolume(cDriveLetter); if (hVolume == INVALID_HANDLE_VALUE) return FALSE; // Lock and dismount the volume. if (LockVolume(hVolume) && DismountVolume(hVolume)) { fRemoveSafely = TRUE; // Set prevent removal to false and eject the volume. if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume,reload)) fAutoEject = TRUE; } // Close the volume so other processes can use the drive. if (!CloseVolume(hVolume)) return FALSE; /* if (fAutoEject) printf("Media in Drive %c has been ejected safely.\n", cDriveLetter); else { if (fRemoveSafely) printf("Media in Drive %c can be safely removed.\n", cDriveLetter); } */ return TRUE; } } // extern "C" BasiliskII/src/Windows/cdenable/eject_nt.h0000755000175000017500000000261510736405222020673 0ustar centriscentris/* * eject_nt.cpp - cd eject routines for WinNT (derived from MS samples) * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifndef _EJECT_NT_H_ #define _EJECT_NT_H_ #ifdef __cplusplus extern "C" { #endif BOOL EjectVolume(TCHAR cDriveLetter,BOOL reload); HANDLE OpenVolume(TCHAR cDriveLetter); BOOL LockVolume(HANDLE hVolume); BOOL DismountVolume(HANDLE hVolume); BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPrevent); BOOL AutoEjectVolume(HANDLE hVolume,BOOL reload); BOOL CloseVolume(HANDLE hVolume); #ifdef __cplusplus } // extern "C" #endif #endif //_EJECT_NT_H_ BasiliskII/src/Windows/cdenable/ntcd.h0000755000175000017500000000570110736405222020027 0ustar centriscentris/* * ntcd.h - Interface to cdenable.sys driver * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ /* Installs the driver, if not already installed. Starts the driver, if not already running. You can either always call "CdenableSysInstallStart" when your program fires up and "CdenableSysStopRemove" when it terminates, or just let the installation program call "CdenableSysInstallStart" and leave it always be present. I recommend the latter option. Calling "CdenableSysInstallStart" always doesn't hurt anything, it will immediately return with success if the service is running. Returns non-zero if installation/startup was succesfull, zero if anything failed. Returns non-zero also if the driver was already running. The file "cdenable.sys" must already have been copied to the directory "System32\Drivers" */ #ifndef _NT_CD_H_ #define _NT_CD_H_ #ifdef __cplusplus extern "C" { #endif BOOL CdenableSysInstallStart(void); /* Stops and removes the driver. See above. This must be called when new version of the driver is updated. */ void CdenableSysStopRemove(void); /* HANDLE h: returned from CreateFile ( "\\\\.\\X:", GENERIC_READ, ... ); Returns the bytes actually read (==count), 0 on failure. NOTE: in my code, start and count are always aligned to sector boundaries (2048 bytes). I cannot guarantee that this works if they are not. Max read is 64 kb. Synchronous read, but quite fast. */ int CdenableSysReadCdBytes( HANDLE h, DWORD start, DWORD count, char *buf ); /* Same as SysReadCdBytes, but "start" and "count" are in 2048 byte sectors. */ int CdenableSysReadCdSectors( HANDLE h, DWORD start, DWORD count, char *buf ); /* Ditto for writing stuff. Not a cd of course but removable & hd media are supported now. */ int CdenableSysWriteCdBytes( HANDLE h, DWORD start, DWORD count, char *buf ); int CdenableSysWriteCdSectors( HANDLE h, DWORD start, DWORD count, char *buf ); /* Returns CDENABLE_CURRENT_VERSION (of the driver). */ DWORD CdenableSysGetVersion( void ); #ifdef __cplusplus } // extern "C" #endif #endif //_NT_CD_H_ BasiliskII/src/Windows/cdenable/ntcd.cpp0000755000175000017500000002104510736405222020361 0ustar centriscentris/* * ntcd.cpp - Interface to cdenable.sys driver * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include "sysdeps.h" #include extern "C" { #include #include #include "ntcd.h" #include "cdenable.h" static char *sDriverShort = "cdenable"; static char *sDriverLong = "System32\\Drivers\\cdenable.sys"; static char *sCompleteName = "\\\\.\\cdenable"; #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // Start type must be SERVICE_AUTO_START or lower, in order // it to start automatically and allow the mechanism work // for users with no admin rights. static BOOL InstallDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName, IN LPCTSTR ServiceExe ) { SC_HANDLE schService; DWORD err; schService = CreateService ( SchSCManager, // SCManager database DriverName, // name of service DriverName, // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_KERNEL_DRIVER, // service type SERVICE_AUTO_START, // SERVICE_DEMAND_START, // start type SERVICE_ERROR_NORMAL, // error control type ServiceExe, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL // no password ); if (schService == NULL) { err = GetLastError(); if (err == ERROR_SERVICE_EXISTS) { return TRUE; } else { return FALSE; } } CloseServiceHandle (schService); return TRUE; } static BOOL RemoveDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { SC_HANDLE schService; BOOL ret; schService = OpenService (SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) return FALSE; ret = DeleteService (schService); CloseServiceHandle (schService); return ret; } static BOOL StartDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { SC_HANDLE schService; BOOL ret; DWORD err; schService = OpenService (SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) return FALSE; ret = StartService (schService, // service identifier 0, // number of arguments NULL // pointer to arguments ); if(ret == 0) { err = GetLastError(); if (err == ERROR_SERVICE_ALREADY_RUNNING) { ret = TRUE; } else { ret = FALSE; } } CloseServiceHandle (schService); return ret; } static BOOL StopDriver( IN SC_HANDLE SchSCManager, IN LPCTSTR DriverName ) { SC_HANDLE schService; BOOL ret; SERVICE_STATUS serviceStatus; schService = OpenService (SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) return FALSE; ret = ControlService (schService, SERVICE_CONTROL_STOP, &serviceStatus ); CloseServiceHandle (schService); return ret; } static BOOL __cdecl start_driver( void ) { SC_HANDLE schSCManager; BOOL ret = FALSE; schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if(!schSCManager) return(FALSE); if(!InstallDriver( schSCManager, sDriverShort, sDriverLong )) { CloseServiceHandle( schSCManager ); return(FALSE); } ret = StartDriver( schSCManager, sDriverShort ); if(!ret) { (void)RemoveDriver( schSCManager, sDriverShort ); } CloseServiceHandle( schSCManager ); return( ret ); } static BOOL __cdecl stop_driver( void ) { SC_HANDLE schSCManager; BOOL ret = FALSE; schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if(!schSCManager) return(FALSE); if(StopDriver( schSCManager, sDriverShort )) ret = TRUE; CloseServiceHandle( schSCManager ); return( ret ); } static BOOL __cdecl remove_driver( void ) { SC_HANDLE schSCManager; BOOL ret = FALSE; schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if(!schSCManager) return(FALSE); if(RemoveDriver( schSCManager, sDriverShort )) ret = TRUE; CloseServiceHandle( schSCManager ); return( ret ); } // Exported stuff begins int CdenableSysReadCdBytes( HANDLE h, DWORD start, DWORD count, char *buf ) { HANDLE hDevice; int ret; DWORD nb; DWORD in_buffer[10]; DWORD out_buffer[10]; ret = 0; in_buffer[0] = (DWORD)h; in_buffer[1] = (DWORD)start; in_buffer[2] = (DWORD)count; in_buffer[3] = (DWORD)buf; out_buffer[0] = 0; hDevice = CreateFile (sCompleteName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hDevice == ((HANDLE)-1)) { ret = 0; } else { if ( DeviceIoControl( hDevice, IOCTL_CDENABLE_READ, (LPVOID)in_buffer, 16, (LPVOID)out_buffer, 4, &nb, NULL ) ) { if(out_buffer[0] != 0) ret = count; } CloseHandle (hDevice); } return ret; } int CdenableSysReadCdSectors( HANDLE h, DWORD start, DWORD count, char *buf ) { return( CdenableSysReadCdBytes( h, (start<<11), (count<<11), buf ) ); } int CdenableSysWriteCdBytes( HANDLE h, DWORD start, DWORD count, char *buf ) { return( 0 ); /* HANDLE hDevice; int ret; DWORD nb; DWORD in_buffer[10]; DWORD out_buffer[10]; ret = 0; in_buffer[0] = (DWORD)h; in_buffer[1] = (DWORD)start; in_buffer[2] = (DWORD)count; in_buffer[3] = (DWORD)buf; out_buffer[0] = 0; hDevice = CreateFile (sCompleteName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hDevice == ((HANDLE)-1)) { ret = 0; } else { if ( DeviceIoControl( hDevice, IOCTL_CDENABLE_WRITE, (LPVOID)in_buffer, 16, (LPVOID)out_buffer, 4, &nb, NULL ) ) { if(out_buffer[0] != 0) ret = count; } CloseHandle (hDevice); } return ret; */ } int CdenableSysWriteCdSectors( HANDLE h, DWORD start, DWORD count, char *buf ) { // return( CdenableSysWriteCdBytes( h, (start<<11), (count<<11), buf ) ); return( 0 ); } BOOL CdenableSysInstallStart(void) { return(start_driver()); } void CdenableSysStopRemove(void) { stop_driver(); remove_driver(); } DWORD CdenableSysGetVersion( void ) { HANDLE hDevice; DWORD ret; DWORD nb; DWORD out_buffer[10]; ret = 0; out_buffer[0] = 0; hDevice = CreateFile (sCompleteName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (hDevice == ((HANDLE)-1)) { ret = 0; } else { if ( DeviceIoControl( hDevice, IOCTL_CDENABLE_GET_VERSION, NULL, 0, (LPVOID)out_buffer, 4, &nb, NULL ) ) { ret = out_buffer[0]; } CloseHandle (hDevice); } return ret; } #ifdef __cplusplus } //extern "C" #endif BasiliskII/src/Windows/cdenable/cache.h0000755000175000017500000000274010736405222020142 0ustar centriscentris/* * cache.cpp - simple floppy/cd cache for Win32 * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #ifdef __cplusplus extern "C" { #endif #ifndef _CACHE_H_ #define _CACHE_H_ #define NBLOCKS 1000 typedef struct { int inited; int res_count; int sector_size; char *blocks; int *block; DWORD *LRU; } cachetype; void cache_init( cachetype *cptr ); void cache_clear( cachetype *cptr ); void cache_final( cachetype *cptr ); int cache_get( cachetype *cptr, int block, char *buf ); void cache_put( cachetype *cptr, int block, char *buf, int ss ); void cache_remove( cachetype *cptr, int block, int ss ); #endif #ifdef __cplusplus } // extern "C" #endif BasiliskII/src/Windows/cdenable/cdenable.h0000755000175000017500000000454410736405222020640 0ustar centriscentris/* * cdenable.h - cdenable.vxd definitions * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ // max read requests, if larger -> STATUS_INVALID_PARAMETER #define CDENABLE_MAX_TRANSFER_SIZE (0x10000) // A structure representing the instance information associated with // a particular device typedef struct _DEVICE_EXTENSION { // not needed. ULONG StateVariable; } DEVICE_EXTENSION, *PDEVICE_EXTENSION; // Define the various device type values. Note that values used by Microsoft // Corporation are in the range 0-32767, and 32768-65535 are reserved for use // by customers. #define FILE_DEVICE_CDENABLE 0x00008301 // Target NT version, internal version #define CDENABLE_CURRENT_VERSION 0x04000100 // Macro definition for defining IOCTL and FSCTL function control codes. Note // that function codes 0-2047 are reserved for Microsoft Corporation, and // 2048-4095 are reserved for customers. #define CDENABLE_IOCTL_READ 0x830 #define CDENABLE_IOCTL_GET_VERSION 0x831 #define IOCTL_CDENABLE_READ CTL_CODE(FILE_DEVICE_CDENABLE, \ CDENABLE_IOCTL_READ, \ METHOD_BUFFERED, \ FILE_ANY_ACCESS) #define IOCTL_CDENABLE_GET_VERSION CTL_CODE(FILE_DEVICE_CDENABLE, \ CDENABLE_IOCTL_GET_VERSION, \ METHOD_BUFFERED, \ FILE_ANY_ACCESS) BasiliskII/src/Windows/user_strings_windows.h0000755000175000017500000000340710736405222021644 0ustar centriscentris/* * user_strings_unix.h - Unix-specific localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef USER_STRINGS_UNIX_H #define USER_STRINGS_UNIX_H enum { STR_NO_XVISUAL_ERR = 10000, STR_VOSF_INIT_ERR, STR_SIG_INSTALL_ERR, STR_TICK_THREAD_ERR, STR_SLIRP_NO_DNS_FOUND_WARN, STR_NO_AUDIO_WARN, STR_KEYCODE_FILE_WARN, STR_KEYCODE_VENDOR_WARN, STR_WINDOW_TITLE_GRABBED, STR_NO_WIN32_NT_4, STR_PREFS_MENU_FILE_GTK, STR_PREFS_ITEM_START_GTK, STR_PREFS_ITEM_ZAP_PRAM_GTK, STR_PREFS_ITEM_SEPL_GTK, STR_PREFS_ITEM_QUIT_GTK, STR_HELP_MENU_GTK, STR_HELP_ITEM_ABOUT_GTK, STR_ABOUT_BUTTON, STR_FILE_CTRL, STR_BROWSE_CTRL, STR_BROWSE_TITLE, STR_SERIAL_PANE_TITLE, STR_NETWORK_PANE_TITLE, STR_INPUT_PANE_TITLE, STR_KEYCODES_CTRL, STR_KEYCODE_FILE_CTRL, STR_MOUSEWHEELMODE_CTRL, STR_MOUSEWHEELMODE_PAGE_LAB, STR_MOUSEWHEELMODE_CURSOR_LAB, STR_MOUSEWHEELLINES_CTRL, STR_POLLMEDIA_CTRL, STR_EXTFS_ENABLE_CTRL, STR_EXTFS_DRIVES_CTRL, STR_ETHER_FTP_PORT_LIST_CTRL, STR_ETHER_TCP_PORT_LIST_CTRL, STR_IGNORESEGV_CTRL, }; #endif BasiliskII/src/Windows/posix_emu.h0000755000175000017500000000642010736405221017350 0ustar centriscentris/* * posix_emu.h * * Basilisk II (C) 1997-2008 Christian Bauer * * Windows platform specific code copyright (C) Lauri Pesonen * * 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 */ #include #include #include #include #include #include "extfs.h" void init_posix_emu(void); void final_posix_emu(void); typedef struct dirent { char d_name[MAX_PATH_LENGTH]; } dirent; typedef struct DIR { HANDLE h; WIN32_FIND_DATA FindFileData; dirent de; char *vname_list; } DIR; // emulated DIR *opendir( const char *path ); void closedir( DIR *d ); struct dirent *readdir( DIR *d ); // access() mode: exists? #ifndef F_OK #define F_OK 0 #endif // access() mode: can do r/w? #ifndef W_OK #define W_OK 6 #endif // hook stat functions to create virtual desktop // because of errno all used funcs must be hooked. int my_stat( const char *, struct my_stat * ); int my_fstat( int, struct my_stat * ); int my_open( const char *, int, ... ); int my_rename( const char *, const char * ); int my_access( const char *, int ); int my_mkdir( const char *path, int mode ); int my_remove( const char * ); int my_creat( const char *path, int mode ); int my_creat( const char *path, int mode ); int my_close( int fd ); long my_lseek( int fd, long, int); int my_read( int fd, void *, unsigned int); int my_write( int fd, const void *, unsigned int); int my_chsize( int fd, unsigned int size ); int my_locking( int fd, int mode, long nbytes ); extern int my_errno; // must hook all other functions that manipulate file names #ifndef NO_POSIX_API_HOOK #define stat my_stat #define fstat my_fstat #define open my_open #define rename my_rename #define access my_access #define mkdir my_mkdir #define remove my_remove #define creat my_creat #define close my_close #define lseek my_lseek #define read my_read #define write my_write #define ftruncate my_chsize #define locking my_locking #undef errno #define errno my_errno #endif //!NO_POSIX_API_HOOK #ifndef S_ISDIR #define S_ISDIR(stat_mode) (((stat_mode) & _S_IFDIR) != 0) #endif // can't #define "stat" unless there's a replacement for "struct stat" struct my_stat { _dev_t st_dev; _ino_t st_ino; unsigned short st_mode; short st_nlink; short st_uid; short st_gid; _dev_t st_rdev; _off_t st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; }; // Your compiler may have different "struct stat" -> edit "struct my_stat" #define validate_stat_struct ( sizeof(struct my_stat) == sizeof(struct stat) ) #define st_crtime st_ctime BasiliskII/src/Windows/ether_windows.h0000755000175000017500000000027210424643264020225 0ustar centriscentris#ifndef _ETHER_WINDOWS_H_ #define _ETHER_WINDOWS_H_ void enqueue_packet( const uint8 *buf, int sz ); #ifdef SHEEPSHAVER extern uint8 ether_addr[6]; #endif #endif // _ETHER_WINDOWS_H_ BasiliskII/src/timer.cpp0000644000175000017500000001464110736405217015367 0ustar centriscentris/* * timer.cpp - Time Manager emulation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Processes, chapter 3 "Time Manager" * Technote 1063: "Inside Macintosh: Processes: Time Manager Addenda" */ #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "timer.h" #define DEBUG 0 #include "debug.h" // Set this to 1 to enable TMQueue management (doesn't work) #define TM_QUEUE 0 // Definitions for Time Manager enum { // TMTask struct tmAddr = 6, tmCount = 10, tmWakeUp = 14, tmReserved = 18 }; // Array of additional info for each installed TMTask struct TMDesc { uint32 task; // Mac address of associated TMTask tm_time_t wakeup; // Time this task is scheduled for execution bool in_use; // Flag: descriptor in use }; const int NUM_DESCS = 64; // Maximum number of descriptors static TMDesc desc[NUM_DESCS]; /* * Allocate descriptor for given TMTask in list */ static int alloc_desc(uint32 tm) { // Search for first free descriptor for (int i=0; i= 0) printf("WARNING: InsTime(): Task re-inserted\n"); else { int i = alloc_desc(tm); if (i < 0) printf("FATAL: InsTime(): No free Time Manager descriptor\n"); } return 0; } /* * Remove timer task */ int16 RmvTime(uint32 tm) { D(bug("RmvTime %08lx\n", tm)); // Find descriptor int i = find_desc(tm); if (i < 0) { printf("WARNING: RmvTime(%08x): Descriptor not found\n", tm); return 0; } // Task active? if (ReadMacInt16(tm + qType) & 0x8000) { // Yes, make task inactive and remove it from the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); dequeue_tm(tm); // Compute remaining time tm_time_t remaining, current; timer_current_time(current); timer_sub_time(remaining, desc[i].wakeup, current); WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining)); } else WriteMacInt32(tm + tmCount, 0); D(bug(" tmCount %d\n", ReadMacInt32(tm + tmCount))); // Free descriptor free_desc(i); return 0; } /* * Start timer task */ int16 PrimeTime(uint32 tm, int32 time) { D(bug("PrimeTime %08x, time %d\n", tm, time)); // Find descriptor int i = find_desc(tm); if (i < 0) { printf("FATAL: PrimeTime(): Descriptor not found\n"); return 0; } // Extended task? if (ReadMacInt16(tm + qType) & 0x4000) { // Convert delay time tm_time_t delay; timer_mac2host_time(delay, time); // Yes, tmWakeUp set? if (ReadMacInt32(tm + tmWakeUp)) { //!! PrimeTime(0) means continue previous delay // (save wakeup time in RmvTime?) if (time == 0) printf("WARNING: Unsupported PrimeTime(0)\n"); // Yes, calculate wakeup time relative to last scheduled time tm_time_t wakeup; timer_add_time(wakeup, desc[i].wakeup, delay); desc[i].wakeup = wakeup; } else { // No, calculate wakeup time relative to current time tm_time_t now; timer_current_time(now); timer_add_time(desc[i].wakeup, now, delay); } // Set tmWakeUp to indicate that task was scheduled WriteMacInt32(tm + tmWakeUp, 0x12345678); } else { // Not extended task, calculate wakeup time relative to current time tm_time_t delay; timer_mac2host_time(delay, time); timer_current_time(desc[i].wakeup); timer_add_time(desc[i].wakeup, desc[i].wakeup, delay); } // Make task active and enqueue it in the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000); enqueue_tm(tm); return 0; } /* * Timer interrupt function (executed as part of 60Hz interrupt) */ void TimerInterrupt(void) { // Look for active TMTasks that have expired tm_time_t now; timer_current_time(now); for (int i=0; i #include #ifndef NO_STD_NAMESPACE using std::vector; #endif #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "sys.h" #include "prefs.h" #include "disk.h" #define DEBUG 0 #include "debug.h" // .Disk Disk/drive icon const uint8 DiskIcon[258] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 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, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0 }; // Struct for each drive struct disk_drive_info { disk_drive_info() : num(0), fh(NULL), start_byte(0), read_only(false), status(0) {} disk_drive_info(void *fh_, bool ro) : num(0), fh(fh_), read_only(ro), status(0) {} void close_fh(void) { Sys_close(fh); } int num; // Drive number void *fh; // File handle loff_t start_byte; // Start of HFS partition on disk uint32 num_blocks; // Size in 512-byte blocks bool to_be_mounted; // Flag: drive must be mounted in accRun bool read_only; // Flag: force write protection uint32 status; // Mac address of drive status record }; // List of drives handled by this driver typedef vector drive_vec; static drive_vec drives; // Icon address (Mac address space, set by PatchROM()) uint32 DiskIconAddr; // Flag: Control(accRun) has been called, interrupt routine is now active static bool acc_run_called = false; /* * Get pointer to drive info or drives.end() if not found */ static drive_vec::iterator get_drive_info(int num) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { if (info->num == num) return info; } return info; } /* * Find HFS partition, set info->start_byte and info->num_blocks * (0 = no partition map or HFS partition found, assume flat disk image) */ static void find_hfs_partition(disk_drive_info &info) { info.start_byte = 0; info.num_blocks = 0; uint8 *map = new uint8[512]; // Search first 64 blocks for HFS partition for (int i=0; i<64; i++) { if (Sys_read(info.fh, map, i * 512, 512) != 512) break; // Not a partition map block? Then look at next block uint16 sig = (map[0] << 8) | map[1]; if (sig != 0x504d) continue; // Partition map block found, Apple HFS partition? if (strcmp((char *)(map + 48), "Apple_HFS") == 0) { info.start_byte = (loff_t)((map[8] << 24) | (map[9] << 16) | (map[10] << 8) | map[11]) << 9; info.num_blocks = (map[12] << 24) | (map[13] << 16) | (map[14] << 8) | map[15]; D(bug(" HFS partition found at %d, %d blocks\n", info.start_byte, info.num_blocks)); break; } } delete[] map; } /* * Initialization */ void DiskInit(void) { // No drives specified in prefs? Then add defaults if (PrefsFindString("disk", 0) == NULL) SysAddDiskPrefs(); // Add drives specified in preferences int index = 0; const char *str; while ((str = PrefsFindString("disk", index++)) != NULL) { bool read_only = false; if (str[0] == '*') { read_only = true; str++; } void *fh = Sys_open(str, read_only); if (fh) drives.push_back(disk_drive_info(fh, SysIsReadOnly(fh))); } } /* * Deinitialization */ void DiskExit(void) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) info->close_fh(); drives.clear(); } /* * Disk was inserted, flag for mounting */ bool DiskMountVolume(void *fh) { drive_vec::iterator info = drives.begin(), end = drives.end(); while (info != end && info->fh != fh) ++info; if (info != end) { if (SysIsDiskInserted(info->fh)) { info->read_only = SysIsReadOnly(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0); find_hfs_partition(*info); if (info->start_byte == 0) info->num_blocks = SysGetFileSize(info->fh) / 512; WriteMacInt16(info->status + dsDriveSize, info->num_blocks & 0xffff); WriteMacInt16(info->status + dsDriveS1, info->num_blocks >> 16); info->to_be_mounted = true; } return true; } else return false; } /* * Mount volumes for which the to_be_mounted flag is set * (called during interrupt time) */ static void mount_mountable_volumes(void) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { // Disk in drive? if (!ReadMacInt8(info->status + dsDiskInPlace)) { // No, check if disk was inserted if (SysIsDiskInserted(info->fh)) DiskMountVolume(info->fh); } // Mount disk if flagged if (info->to_be_mounted) { D(bug(" mounting drive %d\n", info->num)); M68kRegisters r; r.d[0] = info->num; r.a[0] = 7; // diskEvent Execute68kTrap(0xa02f, &r); // PostEvent() info->to_be_mounted = false; } } } /* * Driver Open() routine */ int16 DiskOpen(uint32 pb, uint32 dce) { D(bug("DiskOpen\n")); // Set up DCE WriteMacInt32(dce + dCtlPosition, 0); acc_run_called = false; // Install drives drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { info->num = FindFreeDriveNumber(1); info->to_be_mounted = false; if (info->fh) { // Allocate drive status record M68kRegisters r; r.d[0] = SIZEOF_DrvSts; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) continue; info->status = r.a[0]; D(bug(" DrvSts at %08lx\n", info->status)); // Set up drive status WriteMacInt16(info->status + dsQType, hard20); WriteMacInt8(info->status + dsInstalled, 1); bool disk_in_place = false; if (SysIsFixedDisk(info->fh)) { WriteMacInt8(info->status + dsDiskInPlace, 8); // Fixed disk disk_in_place = true; } else if (SysIsDiskInserted(info->fh)) { WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk disk_in_place = true; } if (disk_in_place) { D(bug(" disk inserted\n")); WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0x80 : 0); find_hfs_partition(*info); if (info->start_byte == 0) info->num_blocks = SysGetFileSize(info->fh) / 512; info->to_be_mounted = true; } D(bug(" %d blocks\n", info->num_blocks)); WriteMacInt16(info->status + dsDriveSize, info->num_blocks & 0xffff); WriteMacInt16(info->status + dsDriveS1, info->num_blocks >> 16); // Add drive to drive queue D(bug(" adding drive %d\n", info->num)); r.d[0] = (info->num << 16) | (DiskRefNum & 0xffff); r.a[0] = info->status + dsQLink; Execute68kTrap(0xa04e, &r); // AddDrive() } } return noErr; } /* * Driver Prime() routine */ int16 DiskPrime(uint32 pb, uint32 dce) { WriteMacInt32(pb + ioActCount, 0); // Drive valid and disk inserted? drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); if (info == drives.end()) return nsDrvErr; if (!ReadMacInt8(info->status + dsDiskInPlace)) return offLinErr; // Get parameters void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer)); size_t length = ReadMacInt32(pb + ioReqCount); loff_t position = ReadMacInt32(dce + dCtlPosition); if (ReadMacInt16(pb + ioPosMode) & 0x100) // 64 bit positioning position = ((loff_t)ReadMacInt32(pb + ioWPosOffset) << 32) | ReadMacInt32(pb + ioWPosOffset + 4); if ((length & 0x1ff) || (position & 0x1ff)) return paramErr; size_t actual = 0; if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) { // Read actual = Sys_read(info->fh, buffer, position + info->start_byte, length); if (actual != length) return readErr; } else { // Write if (info->read_only) return wPrErr; actual = Sys_write(info->fh, buffer, position + info->start_byte, length); if (actual != length) return writErr; } // Update ParamBlock and DCE WriteMacInt32(pb + ioActCount, actual); WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual); return noErr; } /* * Driver Control() routine */ int16 DiskControl(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("DiskControl %d\n", code)); // General codes switch (code) { case 1: // KillIO return noErr; case 65: { // Periodic action (accRun, "insert" disks on startup) mount_mountable_volumes(); WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000); // Disable periodic action acc_run_called = true; return noErr; } } // Drive valid? drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); if (info == drives.end()) return nsDrvErr; // Drive-specific codes switch (code) { case 5: // Verify disk if (ReadMacInt8(info->status + dsDiskInPlace) > 0) return noErr; else return offLinErr; case 6: // Format disk if (info->read_only) return wPrErr; else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) return noErr; else return offLinErr; case 7: // Eject disk if (ReadMacInt8(info->status + dsDiskInPlace) == 8) { // Fixed disk, re-insert M68kRegisters r; r.d[0] = info->num; r.a[0] = 7; // diskEvent Execute68kTrap(0xa02f, &r); // PostEvent() } else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { SysEject(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 0); } return noErr; case 21: // Get drive icon case 22: // Get disk icon WriteMacInt32(pb + csParam, DiskIconAddr); return noErr; case 23: // Get drive info if (ReadMacInt8(info->status + dsDiskInPlace) == 8) WriteMacInt32(pb + csParam, 0x0601); // Unspecified fixed SCSI disk else WriteMacInt32(pb + csParam, 0x0201); // Unspecified SCSI disk return noErr; case 24: // Get partition size if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { WriteMacInt32(pb + csParam, info->num_blocks); return noErr; } else return offLinErr; default: printf("WARNING: Unknown DiskControl(%d)\n", code); return controlErr; } } /* * Driver Status() routine */ int16 DiskStatus(uint32 pb, uint32 dce) { drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); uint16 code = ReadMacInt16(pb + csCode); D(bug("DiskStatus %d\n", code)); // General codes (we can get these even if the drive was invalid) switch (code) { case 43: { // Driver gestalt uint32 sel = ReadMacInt32(pb + csParam); D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel)); switch (sel) { case FOURCC('v','e','r','s'): // Version WriteMacInt32(pb + csParam + 4, 0x01008000); break; case FOURCC('d','e','v','t'): // Device type if (info != drives.end()) { if (ReadMacInt8(info->status + dsDiskInPlace) == 8) WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k')); else WriteMacInt32(pb + csParam + 4, FOURCC('r','d','s','k')); } else WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k')); break; case FOURCC('i','n','t','f'): // Interface type WriteMacInt32(pb + csParam + 4, EMULATOR_ID_4); break; case FOURCC('s','y','n','c'): // Only synchronous operation? WriteMacInt32(pb + csParam + 4, 0x01000000); break; case FOURCC('b','o','o','t'): // Boot ID if (info != drives.end()) WriteMacInt16(pb + csParam + 4, info->num); else WriteMacInt16(pb + csParam + 4, 0); WriteMacInt16(pb + csParam + 6, (uint16)DiskRefNum); break; case FOURCC('w','i','d','e'): // 64-bit access supported? WriteMacInt16(pb + csParam + 4, 0x0100); break; case FOURCC('p','u','r','g'): // Purge flags WriteMacInt32(pb + csParam + 4, 0); break; case FOURCC('e','j','e','c'): // Eject flags WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart break; case FOURCC('f','l','u','s'): // Flush flags WriteMacInt16(pb + csParam + 4, 0); break; case FOURCC('v','m','o','p'): // Virtual memory attributes WriteMacInt32(pb + csParam + 4, 0); // Drive not available for VM break; default: return statusErr; } return noErr; } } // Drive valid? if (info == drives.end()) return nsDrvErr; // Drive-specific codes switch (code) { case 8: // Get drive status Mac2Mac_memcpy(pb + csParam, info->status, 22); return noErr; case 44: // get startup partition status: http://developer.apple.com/documentation/Hardware/DeviceManagers/ata/ata_ref/ATA.21.html printf("WARNING: DiskStatus(44:'get startup partition status') Not Implemented\n"); return statusErr; case 45: // get partition write protect status: http://developer.apple.com/documentation/Hardware/DeviceManagers/ata/ata_ref/ATA.23.html printf("WARNING: DiskStatus(45:'get partition write protect status') Not Implemented\n"); return statusErr; case 46: // get partition mount status: http://developer.apple.com/documentation/Hardware/DeviceManagers/ata/ata_ref/ATA.22.html printf("WARNING: DiskStatus(46:'get partition mount status') Not Implemented\n"); return statusErr; case 70: // get power mode status: http://developer.apple.com/documentation/Hardware/DeviceManagers/ata/ata_ref/ATA.24.html printf("WARNING: DiskStatus(70:'get power mode status') Not Implemented\n"); return statusErr; default: printf("WARNING: Unknown DiskStatus(%d)\n", code); return statusErr; } } /* * Driver interrupt routine (1Hz) - check for volumes to be mounted */ void DiskInterrupt(void) { if (!acc_run_called) return; mount_mountable_volumes(); } BasiliskII/src/prefs.cpp0000644000175000017500000002241711232133662015360 0ustar centriscentris/* * prefs.cpp - Preferences handling * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include "sysdeps.h" #include "sys.h" #include "prefs.h" // Prefs items are stored in a linked list of these nodes struct prefs_node { prefs_node *next; const char *name; prefs_type type; void *data; }; // List of prefs nodes static prefs_node *the_prefs = NULL; // Prototypes static const prefs_desc *find_prefs_desc(const char *name); /* * Initialize preferences */ void PrefsInit(const char *vmdir, int &argc, char **&argv) { // Set defaults AddPrefsDefaults(); AddPlatformPrefsDefaults(); // Load preferences from settings file LoadPrefs(vmdir); // Override prefs with command line options for (int i=1; i= argc) { fprintf(stderr, "Option '%s' must be followed by a value\n", option); continue; } const char *value = argv[i]; argv[i] = NULL; // Add/replace prefs item switch (d->type) { case TYPE_STRING: if (d->multiple) PrefsAddString(keyword, value); else PrefsReplaceString(keyword, value); break; case TYPE_BOOLEAN: { if (!strcmp(value, "true") || !strcmp(value, "on") || !strcmp(value, "yes")) PrefsReplaceBool(keyword, true); else if (!strcmp(value, "false") || !strcmp(value, "off") || !strcmp(value, "no")) PrefsReplaceBool(keyword, false); else fprintf(stderr, "Value for option '%s' must be 'true' or 'false'\n", option); break; } case TYPE_INT32: PrefsReplaceInt32(keyword, atoi(value)); break; default: break; } } // Remove processed arguments for (int i=1; i i) { k -= i; for (int j=i+k; jnext; free((void *)p->name); free(p->data); delete p; p = next; } the_prefs = NULL; } /* * Print preferences options help */ static void print_options(const prefs_desc *list) { while (list->type != TYPE_END) { if (list->help) { const char *typestr, *defstr; char numstr[32]; switch (list->type) { case TYPE_STRING: typestr = "STRING"; defstr = PrefsFindString(list->name); if (defstr == NULL) defstr = "none"; break; case TYPE_BOOLEAN: typestr = "BOOL"; if (PrefsFindBool(list->name)) defstr = "true"; else defstr = "false"; break; case TYPE_INT32: typestr = "NUMBER"; sprintf(numstr, "%d", PrefsFindInt32(list->name)); defstr = numstr; break; default: typestr = ""; defstr = "none"; break; } printf(" --%s %s\n %s [default=%s]\n", list->name, typestr, list->help, defstr); } list++; } } void PrefsPrintUsage(void) { printf("\nGeneral options:\n"); print_options(common_prefs_items); printf("\nPlatform-specific options:\n"); print_options(platform_prefs_items); printf("\nBoolean options are specified as '--OPTION true|on|yes' or\n'--OPTION false|off|no'.\n"); } /* * Find preferences descriptor by keyword */ static const prefs_desc *find_prefs_desc(const char *name, const prefs_desc *list) { while (list->type != TYPE_ANY) { if (strcmp(list->name, name) == 0) return list; list++; } return NULL; } static const prefs_desc *find_prefs_desc(const char *name) { const prefs_desc *d = find_prefs_desc(name, common_prefs_items); if (d == NULL) d = find_prefs_desc(name, platform_prefs_items); return d; } /* * Set prefs items */ static void add_data(const char *name, prefs_type type, void *data, int size) { void *d = malloc(size); if (d == NULL) return; memcpy(d, data, size); prefs_node *p = new prefs_node; p->next = 0; p->name = strdup(name); p->type = type; p->data = d; if (the_prefs) { prefs_node *prev = the_prefs; while (prev->next) prev = prev->next; prev->next = p; } else the_prefs = p; } void PrefsAddString(const char *name, const char *s) { add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1); } void PrefsAddBool(const char *name, bool b) { add_data(name, TYPE_BOOLEAN, &b, sizeof(bool)); } void PrefsAddInt32(const char *name, int32 val) { add_data(name, TYPE_INT32, &val, sizeof(int32)); } /* * Replace prefs items */ static prefs_node *find_node(const char *name, prefs_type type, int index = 0) { prefs_node *p = the_prefs; int i = 0; while (p) { if ((type == TYPE_ANY || p->type == type) && !strcmp(p->name, name)) { if (i == index) return p; else i++; } p = p->next; } return NULL; } void PrefsReplaceString(const char *name, const char *s, int index) { prefs_node *p = find_node(name, TYPE_STRING, index); if (p) { free(p->data); p->data = strdup(s); } else add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1); } void PrefsReplaceBool(const char *name, bool b) { prefs_node *p = find_node(name, TYPE_BOOLEAN); if (p) *(bool *)(p->data) = b; else add_data(name, TYPE_BOOLEAN, &b, sizeof(bool)); } void PrefsReplaceInt32(const char *name, int32 val) { prefs_node *p = find_node(name, TYPE_INT32); if (p) *(int32 *)(p->data) = val; else add_data(name, TYPE_INT32, &val, sizeof(int32)); } /* * Get prefs items */ const char *PrefsFindString(const char *name, int index) { prefs_node *p = find_node(name, TYPE_STRING, index); if (p) return (char *)(p->data); else return NULL; } bool PrefsFindBool(const char *name) { prefs_node *p = find_node(name, TYPE_BOOLEAN, 0); if (p) return *(bool *)(p->data); else return false; } int32 PrefsFindInt32(const char *name) { prefs_node *p = find_node(name, TYPE_INT32, 0); if (p) return *(int32 *)(p->data); else return 0; } /* * Remove prefs items */ void PrefsRemoveItem(const char *name, int index) { prefs_node *p = find_node(name, TYPE_ANY, index); if (p) { free((void *)p->name); free(p->data); prefs_node *q = the_prefs; if (q == p) { the_prefs = NULL; delete p; return; } while (q) { if (q->next == p) { q->next = p->next; delete p; return; } q = q->next; } } } /* * Load prefs from stream (utility function for LoadPrefs() implementation) */ void LoadPrefsFromStream(FILE *f) { char line[256]; while(fgets(line, 255, f)) { // Read line int len = strlen(line); if (len == 0) continue; line[len-1] = 0; // Comments begin with "#" or ";" if (line[0] == '#' || line[0] == ';') continue; // Terminate string after keyword char *p = line; while (!isspace(*p)) p++; *p++ = 0; // Skip whitespace until value while (isspace(*p)) p++; char *keyword = line; char *value = p; int32 i = atol(value); // Look for keyword first in prefs item list const prefs_desc *desc = find_prefs_desc(keyword); if (desc == NULL) { printf("WARNING: Unknown preferences keyword '%s'\n", keyword); continue; } // Add item to prefs switch (desc->type) { case TYPE_STRING: if (desc->multiple) PrefsAddString(keyword, value); else PrefsReplaceString(keyword, value); break; case TYPE_BOOLEAN: PrefsReplaceBool(keyword, !strcmp(value, "true")); break; case TYPE_INT32: PrefsReplaceInt32(keyword, i); break; default: break; } } } /* * Save settings to stream (utility function for SavePrefs() implementation) */ static void write_prefs(FILE *f, const prefs_desc *list) { while (list->type != TYPE_ANY) { switch (list->type) { case TYPE_STRING: { int index = 0; const char *str; while ((str = PrefsFindString(list->name, index++)) != NULL) fprintf(f, "%s %s\n", list->name, str); break; } case TYPE_BOOLEAN: fprintf(f, "%s %s\n", list->name, PrefsFindBool(list->name) ? "true" : "false"); break; case TYPE_INT32: fprintf(f, "%s %d\n", list->name, PrefsFindInt32(list->name)); break; default: break; } list++; } } void SavePrefsToStream(FILE *f) { write_prefs(f, common_prefs_items); write_prefs(f, platform_prefs_items); } BasiliskII/src/rom_patches.cpp0000644000175000017500000015001211340220101016517 0ustar centriscentris/* * rom_patches.cpp - ROM patches * * Basilisk II (C) Christian Bauer * * 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 */ #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "emul_op.h" #include "macos_util.h" #include "slot_rom.h" #include "sony.h" #include "disk.h" #include "cdrom.h" #include "video.h" #include "extfs.h" #include "prefs.h" #include "rom_patches.h" #define DEBUG 0 #include "debug.h" // Global variables uint32 UniversalInfo; // ROM offset of UniversalInfo uint32 PutScrapPatch = 0; // Mac address of PutScrap() patch uint32 GetScrapPatch = 0; // Mac address of GetScrap() patch uint32 ROMBreakpoint = 0; // ROM offset of breakpoint (0 = disabled, 0x2310 = CritError) bool PrintROMInfo = false; // Flag: print ROM information in PatchROM() bool PatchHWBases = true; // Flag: patch hardware base addresses static uint32 sony_offset; // ROM offset of .Sony driver static uint32 serd_offset; // ROM offset of SERD resource (serial drivers) static uint32 microseconds_offset; // ROM offset of Microseconds() replacement routine static uint32 debugutil_offset; // ROM offset of DebugUtil() replacement routine // Prototypes uint16 ROMVersion; /* * Macros used to extract one of the 16-bit words from a 32-bit word value */ #define HiWord(X) (((X) >> 16) & 0xffff) #define LoWord(X) ((X) & 0xffff) /* * Search ROM for byte string, return ROM offset (or 0) */ static uint32 find_rom_data(uint32 start, uint32 end, const uint8 *data, uint32 data_len) { uint32 ofs = start; while (ofs < end) { if (!memcmp((void *)(ROMBaseHost + ofs), data, data_len)) return ofs; ofs++; } return 0; } /* * Search ROM resource by type/ID, return ROM offset of resource data */ static uint32 rsrc_ptr = 0; static uint32 find_rom_resource(uint32 s_type, int16 s_id, bool cont = false) { uint32 lp = ROMBaseMac + ReadMacInt32(ROMBaseMac + 0x1a); uint32 x = ReadMacInt32(lp); if (!cont) rsrc_ptr = x; else rsrc_ptr = ReadMacInt32(ROMBaseMac + rsrc_ptr + 8); for (;;) { lp = ROMBaseMac + rsrc_ptr; uint32 data = ReadMacInt32(lp + 12); uint32 type = ReadMacInt32(lp + 16); int16 id = ReadMacInt16(lp + 20); if (type == s_type && id == s_id) return data; rsrc_ptr = ReadMacInt32(lp + 8); if (!rsrc_ptr) break; } return 0; } /* * Search offset of A-Trap routine in ROM */ static uint32 find_rom_trap(uint16 trap) { uint8 *bp = (uint8 *)(ROMBaseHost + ReadMacInt32(ROMBaseMac + 0x22)); uint16 rom_trap = 0xa800; uint32 ofs = 0; again: for (int i=0; i<0x400; i++) { bool unimplemented = false; uint8 b = *bp++; if (b == 0x80) // Unimplemented trap unimplemented = true; else if (b == 0xff) { // Absolute address ofs = (bp[0] << 24) | (bp[1] << 16) | (bp[2] << 8) | bp[3]; bp += 4; } else if (b & 0x80) { // 1 byte offset int16 add = (b & 0x7f) << 1; if (!add) return 0; ofs += add; } else { // 2 byte offset int16 add = ((b << 8) | *bp++) << 1; if (!add) return 0; ofs += add; } if (rom_trap == trap) return unimplemented ? 0 : ofs; rom_trap++; } rom_trap = 0xa000; goto again; } /* * Print ROM information to stream, */ static void list_rom_resources(void) { printf("ROM Resources:\n"); printf("Offset\t Type\tID\tSize\tName\n"); printf("------------------------------------------------\n"); uint32 lp = ROMBaseMac + ReadMacInt32(ROMBaseMac + 0x1a); uint32 rsrc_ptr = ReadMacInt32(lp); for (;;) { lp = ROMBaseMac + rsrc_ptr; uint32 data = ReadMacInt32(lp + 12); char name[32]; int name_len = ReadMacInt8(lp + 23), i; for (i=0; i= 0; i++) if (MacDesc[i].id == id + 6) { name = MacDesc[i].name; break; } printf("%08x %02x\t%04x\t%04x\t%s\n", info - ROMBaseMac, id, hwcfg, rom85, name); } static void list_universal_infos(void) { uint32 ofs = 0x3000; for (int i=0; i<0x2000; i+=2, ofs+=2) if (ReadMacInt32(ROMBaseMac + ofs) == 0xdc000505) { ofs -= 16; uint32 q; for (q=ofs; q > 0 && ReadMacInt32(ROMBaseMac + q) != ofs - q; q-=4) ; if (q > 0) { printf("Universal Table at %08x:\n", q); printf("Offset\t ID\tHWCfg\tROM85\tModel\n"); printf("------------------------------------------------\n"); while ((ofs = ReadMacInt32(ROMBaseMac + q))) { print_universal_info(ROMBaseMac + ofs + q); q += 4; } } break; } printf("\n"); } static void print_rom_info(void) { printf("\nROM Info:\n"); printf("Checksum : %08x\n", ReadMacInt32(ROMBaseMac)); printf("Version : %04x\n", ROMVersion); printf("Sub Version : %04x\n", ReadMacInt16(ROMBaseMac + 18)); printf("Resource Map: %08x\n", ReadMacInt32(ROMBaseMac + 26)); printf("Trap Tables : %08x\n\n", ReadMacInt32(ROMBaseMac + 34)); if (ROMVersion == ROM_VERSION_32) { list_rom_resources(); list_universal_infos(); } } /* * Driver stubs */ static const uint8 sony_driver[] = { // Replacement for .Sony driver // Driver header SonyDriverFlags >> 8, SonyDriverFlags & 0xff, 0, 0, 0, 0, 0, 0, 0x00, 0x18, // Open() offset 0x00, 0x1c, // Prime() offset 0x00, 0x20, // Control() offset 0x00, 0x2c, // Status() offset 0x00, 0x52, // Close() offset 0x05, 0x2e, 0x53, 0x6f, 0x6e, 0x79, // ".Sony" // Open() M68K_EMUL_OP_SONY_OPEN >> 8, M68K_EMUL_OP_SONY_OPEN & 0xff, 0x4e, 0x75, // rts // Prime() M68K_EMUL_OP_SONY_PRIME >> 8, M68K_EMUL_OP_SONY_PRIME & 0xff, 0x60, 0x0e, // bra IOReturn // Control() M68K_EMUL_OP_SONY_CONTROL >> 8, M68K_EMUL_OP_SONY_CONTROL & 0xff, 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) 0x66, 0x04, // bne IOReturn 0x4e, 0x75, // rts // Status() M68K_EMUL_OP_SONY_STATUS >> 8, M68K_EMUL_OP_SONY_STATUS & 0xff, // IOReturn 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 0x08, 0x01, 0x00, 0x09, // btst #9,d1 0x67, 0x0c, // beq 1 0x4a, 0x40, // tst.w d0 0x6f, 0x02, // ble 2 0x42, 0x40, // clr.w d0 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) 0x4e, 0x75, // rts 0x4a, 0x40, //1 tst.w d0 0x6f, 0x04, // ble 3 0x42, 0x40, // clr.w d0 0x4e, 0x75, // rts 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(sp) 0x4e, 0x75, // rts // Close() 0x70, 0xe8, // moveq #-24,d0 0x4e, 0x75 // rts }; static const uint8 disk_driver[] = { // Generic disk driver // Driver header DiskDriverFlags >> 8, DiskDriverFlags & 0xff, 0, 0, 0, 0, 0, 0, 0x00, 0x18, // Open() offset 0x00, 0x1c, // Prime() offset 0x00, 0x20, // Control() offset 0x00, 0x2c, // Status() offset 0x00, 0x52, // Close() offset 0x05, 0x2e, 0x44, 0x69, 0x73, 0x6b, // ".Disk" // Open() M68K_EMUL_OP_DISK_OPEN >> 8, M68K_EMUL_OP_DISK_OPEN & 0xff, 0x4e, 0x75, // rts // Prime() M68K_EMUL_OP_DISK_PRIME >> 8, M68K_EMUL_OP_DISK_PRIME & 0xff, 0x60, 0x0e, // bra IOReturn // Control() M68K_EMUL_OP_DISK_CONTROL >> 8, M68K_EMUL_OP_DISK_CONTROL & 0xff, 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) 0x66, 0x04, // bne IOReturn 0x4e, 0x75, // rts // Status() M68K_EMUL_OP_DISK_STATUS >> 8, M68K_EMUL_OP_DISK_STATUS & 0xff, // IOReturn 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 0x08, 0x01, 0x00, 0x09, // btst #9,d1 0x67, 0x0c, // beq 1 0x4a, 0x40, // tst.w d0 0x6f, 0x02, // ble 2 0x42, 0x40, // clr.w d0 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) 0x4e, 0x75, // rts 0x4a, 0x40, //1 tst.w d0 0x6f, 0x04, // ble 3 0x42, 0x40, // clr.w d0 0x4e, 0x75, // rts 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(sp) 0x4e, 0x75, // rts // Close() 0x70, 0xe8, // moveq #-24,d0 0x4e, 0x75 // rts }; static const uint8 cdrom_driver[] = { // CD-ROM driver // Driver header CDROMDriverFlags >> 8, CDROMDriverFlags & 0xff, 0, 0, 0, 0, 0, 0, 0x00, 0x1c, // Open() offset 0x00, 0x20, // Prime() offset 0x00, 0x24, // Control() offset 0x00, 0x30, // Status() offset 0x00, 0x56, // Close() offset 0x08, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x43, 0x44, 0x00, // ".AppleCD" // Open() M68K_EMUL_OP_CDROM_OPEN >> 8, M68K_EMUL_OP_CDROM_OPEN & 0xff, 0x4e, 0x75, // rts // Prime() M68K_EMUL_OP_CDROM_PRIME >> 8, M68K_EMUL_OP_CDROM_PRIME & 0xff, 0x60, 0x0e, // bra IOReturn // Control() M68K_EMUL_OP_CDROM_CONTROL >> 8, M68K_EMUL_OP_CDROM_CONTROL & 0xff, 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) 0x66, 0x04, // bne IOReturn 0x4e, 0x75, // rts // Status() M68K_EMUL_OP_CDROM_STATUS >> 8, M68K_EMUL_OP_CDROM_STATUS & 0xff, // IOReturn 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 0x08, 0x01, 0x00, 0x09, // btst #9,d1 0x67, 0x0c, // beq 1 0x4a, 0x40, // tst.w d0 0x6f, 0x02, // ble 2 0x42, 0x40, // clr.w d0 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) 0x4e, 0x75, // rts 0x4a, 0x40, //1 tst.w d0 0x6f, 0x04, // ble 3 0x42, 0x40, // clr.w d0 0x4e, 0x75, // rts 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(sp) 0x4e, 0x75, // rts // Close() 0x70, 0xe8, // moveq #-24,d0 0x4e, 0x75 // rts }; static const uint8 ain_driver[] = { // .AIn driver header // Driver header 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, // Open() offset 0x00, 0x1e, // Prime() offset 0x00, 0x24, // Control() offset 0x00, 0x32, // Status() offset 0x00, 0x38, // Close() offset 0x04, 0x2e, 0x41, 0x49, 0x6e, 0x09, // ".AIn",9 // Open() 0x70, 0x00, // moveq #0,d0 M68K_EMUL_OP_SERIAL_OPEN >> 8, M68K_EMUL_OP_SERIAL_OPEN & 0xff, 0x4e, 0x75, // rts // Prime() 0x70, 0x00, // moveq #0,d0 M68K_EMUL_OP_SERIAL_PRIME >> 8, M68K_EMUL_OP_SERIAL_PRIME & 0xff, 0x60, 0x1a, // bra IOReturn // Control() 0x70, 0x00, // moveq #0,d0 M68K_EMUL_OP_SERIAL_CONTROL >> 8, M68K_EMUL_OP_SERIAL_CONTROL & 0xff, 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) 0x66, 0x0e, // bne IOReturn 0x4e, 0x75, // rts // Status() 0x70, 0x00, // moveq #0,d0 M68K_EMUL_OP_SERIAL_STATUS >> 8, M68K_EMUL_OP_SERIAL_STATUS & 0xff, 0x60, 0x06, // bra IOReturn // Close() 0x70, 0x00, // moveq #0,d0 M68K_EMUL_OP_SERIAL_CLOSE >> 8, M68K_EMUL_OP_SERIAL_CLOSE & 0xff, 0x4e, 0x75, // rts // IOReturn 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 0x08, 0x01, 0x00, 0x09, // btst #9,d1 0x67, 0x0c, // beq 1 0x4a, 0x40, // tst.w d0 0x6f, 0x02, // ble 2 0x42, 0x40, // clr.w d0 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) 0x4e, 0x75, // rts 0x4a, 0x40, //1 tst.w d0 0x6f, 0x04, // ble 3 0x42, 0x40, // clr.w d0 0x4e, 0x75, // rts 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(a7) 0x4e, 0x75, // rts }; static const uint8 aout_driver[] = { // .AOut driver header // Driver header 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, // Open() offset 0x00, 0x20, // Prime() offset 0x00, 0x26, // Control() offset 0x00, 0x34, // Status() offset 0x00, 0x3a, // Close() offset 0x05, 0x2e, 0x41, 0x4f, 0x75, 0x74, 0x09, 0x00, // ".AOut",9 // Open() 0x70, 0x01, // moveq #1,d0 M68K_EMUL_OP_SERIAL_OPEN >> 8, M68K_EMUL_OP_SERIAL_OPEN & 0xff, 0x4e, 0x75, // rts // Prime() 0x70, 0x01, // moveq #1,d0 M68K_EMUL_OP_SERIAL_PRIME >> 8, M68K_EMUL_OP_SERIAL_PRIME & 0xff, 0x60, 0x1a, // bra IOReturn // Control() 0x70, 0x01, // moveq #1,d0 M68K_EMUL_OP_SERIAL_CONTROL >> 8, M68K_EMUL_OP_SERIAL_CONTROL & 0xff, 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) 0x66, 0x0e, // bne IOReturn 0x4e, 0x75, // rts // Status() 0x70, 0x01, // moveq #1,d0 M68K_EMUL_OP_SERIAL_STATUS >> 8, M68K_EMUL_OP_SERIAL_STATUS & 0xff, 0x60, 0x06, // bra IOReturn // Close() 0x70, 0x01, // moveq #1,d0 M68K_EMUL_OP_SERIAL_CLOSE >> 8, M68K_EMUL_OP_SERIAL_CLOSE & 0xff, 0x4e, 0x75, // rts // IOReturn 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 0x08, 0x01, 0x00, 0x09, // btst #9,d1 0x67, 0x0c, // beq 1 0x4a, 0x40, // tst.w d0 0x6f, 0x02, // ble 2 0x42, 0x40, // clr.w d0 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) 0x4e, 0x75, // rts 0x4a, 0x40, //1 tst.w d0 0x6f, 0x04, // ble 3 0x42, 0x40, // clr.w d0 0x4e, 0x75, // rts 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(a7) 0x4e, 0x75, // rts }; static const uint8 bin_driver[] = { // .BIn driver header // Driver header 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, // Open() offset 0x00, 0x1e, // Prime() offset 0x00, 0x24, // Control() offset 0x00, 0x32, // Status() offset 0x00, 0x38, // Close() offset 0x04, 0x2e, 0x42, 0x49, 0x6e, 0x09, // ".BIn",9 // Open() 0x70, 0x02, // moveq #2,d0 M68K_EMUL_OP_SERIAL_OPEN >> 8, M68K_EMUL_OP_SERIAL_OPEN & 0xff, 0x4e, 0x75, // rts // Prime() 0x70, 0x02, // moveq #2,d0 M68K_EMUL_OP_SERIAL_PRIME >> 8, M68K_EMUL_OP_SERIAL_PRIME & 0xff, 0x60, 0x1a, // bra IOReturn // Control() 0x70, 0x02, // moveq #2,d0 M68K_EMUL_OP_SERIAL_CONTROL >> 8, M68K_EMUL_OP_SERIAL_CONTROL & 0xff, 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) 0x66, 0x0e, // bne IOReturn 0x4e, 0x75, // rts // Status() 0x70, 0x02, // moveq #2,d0 M68K_EMUL_OP_SERIAL_STATUS >> 8, M68K_EMUL_OP_SERIAL_STATUS & 0xff, 0x60, 0x06, // bra IOReturn // Close() 0x70, 0x02, // moveq #2,d0 M68K_EMUL_OP_SERIAL_CLOSE >> 8, M68K_EMUL_OP_SERIAL_CLOSE & 0xff, 0x4e, 0x75, // rts // IOReturn 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 0x08, 0x01, 0x00, 0x09, // btst #9,d1 0x67, 0x0c, // beq 1 0x4a, 0x40, // tst.w d0 0x6f, 0x02, // ble 2 0x42, 0x40, // clr.w d0 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) 0x4e, 0x75, // rts 0x4a, 0x40, //1 tst.w d0 0x6f, 0x04, // ble 3 0x42, 0x40, // clr.w d0 0x4e, 0x75, // rts 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(a7) 0x4e, 0x75, // rts }; static const uint8 bout_driver[] = { // .BOut driver header // Driver header 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, // Open() offset 0x00, 0x20, // Prime() offset 0x00, 0x26, // Control() offset 0x00, 0x34, // Status() offset 0x00, 0x3a, // Close() offset 0x05, 0x2e, 0x42, 0x4f, 0x75, 0x74, 0x09, 0x00, // ".BOut",9 // Open() 0x70, 0x03, // moveq #3,d0 M68K_EMUL_OP_SERIAL_OPEN >> 8, M68K_EMUL_OP_SERIAL_OPEN & 0xff, 0x4e, 0x75, // rts // Prime() 0x70, 0x03, // moveq #3,d0 M68K_EMUL_OP_SERIAL_PRIME >> 8, M68K_EMUL_OP_SERIAL_PRIME & 0xff, 0x60, 0x1a, // bra IOReturn // Control() 0x70, 0x03, // moveq #3,d0 M68K_EMUL_OP_SERIAL_CONTROL >> 8, M68K_EMUL_OP_SERIAL_CONTROL & 0xff, 0x0c, 0x68, 0x00, 0x01, 0x00, 0x1a, // cmp.w #1,$1a(a0) 0x66, 0x0e, // bne IOReturn 0x4e, 0x75, // rts // Status() 0x70, 0x03, // moveq #3,d0 M68K_EMUL_OP_SERIAL_STATUS >> 8, M68K_EMUL_OP_SERIAL_STATUS & 0xff, 0x60, 0x06, // bra IOReturn // Close() 0x70, 0x03, // moveq #3,d0 M68K_EMUL_OP_SERIAL_CLOSE >> 8, M68K_EMUL_OP_SERIAL_CLOSE & 0xff, 0x4e, 0x75, // rts // IOReturn 0x32, 0x28, 0x00, 0x06, // move.w 6(a0),d1 0x08, 0x01, 0x00, 0x09, // btst #9,d1 0x67, 0x0c, // beq 1 0x4a, 0x40, // tst.w d0 0x6f, 0x02, // ble 2 0x42, 0x40, // clr.w d0 0x31, 0x40, 0x00, 0x10, //2 move.w d0,$10(a0) 0x4e, 0x75, // rts 0x4a, 0x40, //1 tst.w d0 0x6f, 0x04, // ble 3 0x42, 0x40, // clr.w d0 0x4e, 0x75, // rts 0x2f, 0x38, 0x08, 0xfc, //3 move.l $8fc,-(a7) 0x4e, 0x75, // rts }; /* * ADBOp() patch */ static const uint8 adbop_patch[] = { // Call ADBOp() completion procedure // The completion procedure may call ADBOp() again! 0x40, 0xe7, // move sr,-(sp) 0x00, 0x7c, 0x07, 0x00, // ori #$0700,sr M68K_EMUL_OP_ADBOP >> 8, M68K_EMUL_OP_ADBOP & 0xff, 0x48, 0xe7, 0x70, 0xf0, // movem.l d1-d3/a0-a3,-(sp) 0x26, 0x48, // move.l a0,a3 0x4a, 0xab, 0x00, 0x04, // tst.l 4(a3) 0x67, 0x00, 0x00, 0x18, // beq 1 0x20, 0x53, // move.l (a3),a0 0x22, 0x6b, 0x00, 0x04, // move.l 4(a3),a1 0x24, 0x6b, 0x00, 0x08, // move.l 8(a3),a2 0x26, 0x78, 0x0c, 0xf8, // move.l $cf8,a3 0x4e, 0x91, // jsr (a1) 0x70, 0x00, // moveq #0,d0 0x60, 0x00, 0x00, 0x04, // bra 2 0x70, 0xff, //1 moveq #-1,d0 0x4c, 0xdf, 0x0f, 0x0e, //2 movem.l (sp)+,d1-d3/a0-a3 0x46, 0xdf, // move (sp)+,sr 0x4e, 0x75 // rts }; /* * Install .Sony, disk and CD-ROM drivers */ void InstallDrivers(uint32 pb) { D(bug("InstallDrivers, pb %08x\n", pb)); M68kRegisters r; // Install Microseconds() replacement routine r.a[0] = ROMBaseMac + microseconds_offset; r.d[0] = 0xa093; Execute68kTrap(0xa247, &r); // SetOSTrapAddress() // Install DebugUtil() replacement routine r.a[0] = ROMBaseMac + debugutil_offset; r.d[0] = 0xa08d; Execute68kTrap(0xa247, &r); // SetOSTrapAddress() // Install disk driver r.a[0] = ROMBaseMac + sony_offset + 0x100; r.d[0] = (uint32)DiskRefNum; Execute68kTrap(0xa43d, &r); // DrvrInstallRsrvMem() r.a[0] = ReadMacInt32(ReadMacInt32(0x11c) + ~DiskRefNum * 4); // Get driver handle from Unit Table Execute68kTrap(0xa029, &r); // HLock() uint32 dce = ReadMacInt32(r.a[0]); WriteMacInt32(dce + dCtlDriver, ROMBaseMac + sony_offset + 0x100); WriteMacInt16(dce + dCtlFlags, DiskDriverFlags); // Open disk driver WriteMacInt32(pb + ioNamePtr, ROMBaseMac + sony_offset + 0x112); r.a[0] = pb; Execute68kTrap(0xa000, &r); // Open() // Install CD-ROM driver unless nocdrom option given if (!PrefsFindBool("nocdrom")) { // Install CD-ROM driver r.a[0] = ROMBaseMac + sony_offset + 0x200; r.d[0] = (uint32)CDROMRefNum; Execute68kTrap(0xa43d, &r); // DrvrInstallRsrvMem() r.a[0] = ReadMacInt32(ReadMacInt32(0x11c) + ~CDROMRefNum * 4); // Get driver handle from Unit Table Execute68kTrap(0xa029, &r); // HLock() dce = ReadMacInt32(r.a[0]); WriteMacInt32(dce + dCtlDriver, ROMBaseMac + sony_offset + 0x200); WriteMacInt16(dce + dCtlFlags, CDROMDriverFlags); // Open CD-ROM driver WriteMacInt32(pb + ioNamePtr, ROMBaseMac + sony_offset + 0x212); r.a[0] = pb; Execute68kTrap(0xa000, &r); // Open() } } /* * Install serial drivers */ void InstallSERD(void) { D(bug("InstallSERD\n")); // All drivers are inside the SERD resource M68kRegisters r; // Install .AIn driver r.d[0] = (uint32)-6; r.a[0] = ROMBaseMac + serd_offset + 0x100; Execute68kTrap(0xa53d, &r); // DrvrInstallRsrvMem() Execute68kTrap(0xa029, &r); // HLock() uint32 drvr_ptr = ReadMacInt32(r.a[0]); WriteMacInt32(drvr_ptr + dCtlDriver, ROMBaseMac + serd_offset + 0x100); // Pointer to driver header WriteMacInt16(drvr_ptr + dCtlFlags, (ain_driver[0] << 8) + ain_driver[1]); // Driver flags WriteMacInt16(drvr_ptr + dCtlQHdr + qFlags, 9); // Version number // Install .AOut driver r.d[0] = (uint32)-7; r.a[0] = ROMBaseMac + serd_offset + 0x200; Execute68kTrap(0xa53d, &r); // DrvrInstallRsrvMem() Execute68kTrap(0xa029, &r); // HLock() drvr_ptr = ReadMacInt32(r.a[0]); WriteMacInt32(drvr_ptr + dCtlDriver, ROMBaseMac + serd_offset + 0x200); // Pointer to driver header WriteMacInt16(drvr_ptr + dCtlFlags, (aout_driver[0] << 8) + aout_driver[1]); // Driver flags WriteMacInt16(drvr_ptr + dCtlQHdr + qFlags, 9); // Version number // Install .BIn driver r.d[0] = (uint32)-8; r.a[0] = ROMBaseMac + serd_offset + 0x300; Execute68kTrap(0xa53d, &r); // DrvrInstallRsrvMem() Execute68kTrap(0xa029, &r); // HLock() drvr_ptr = ReadMacInt32(r.a[0]); WriteMacInt32(drvr_ptr + dCtlDriver, ROMBaseMac + serd_offset + 0x300); // Pointer to driver header WriteMacInt16(drvr_ptr + dCtlFlags, (bin_driver[0] << 8) + bin_driver[1]); // Driver flags WriteMacInt16(drvr_ptr + dCtlQHdr + qFlags, 9); // Version number // Install .BOut driver r.d[0] = (uint32)-9; r.a[0] = ROMBaseMac + serd_offset + 0x400; Execute68kTrap(0xa53d, &r); // DrvrInstallRsrvMem() Execute68kTrap(0xa029, &r); // HLock() drvr_ptr = ReadMacInt32(r.a[0]); WriteMacInt32(drvr_ptr + dCtlDriver, ROMBaseMac + serd_offset + 0x400); // Pointer to driver header WriteMacInt16(drvr_ptr + dCtlFlags, (bout_driver[0] << 8) + bout_driver[1]); // Driver flags WriteMacInt16(drvr_ptr + dCtlQHdr + qFlags, 9); // Version number } /* * Install patches after MacOS startup */ void PatchAfterStartup(void) { #if SUPPORTS_EXTFS // Install external file system InstallExtFS(); #endif } /* * Check ROM version, returns false if ROM version is not supported */ bool CheckROM(void) { // Read version ROMVersion = ntohs(*(uint16 *)(ROMBaseHost + 8)); #if REAL_ADDRESSING || DIRECT_ADDRESSING // Real and direct addressing modes require a 32-bit clean ROM return ROMVersion == ROM_VERSION_32; #else // Virtual addressing mode works with 32-bit clean Mac II ROMs and Classic ROMs return (ROMVersion == ROM_VERSION_CLASSIC) || (ROMVersion == ROM_VERSION_32); #endif } /* * Install ROM patches, returns false if ROM version is not supported */ // ROM patches for Mac Classic/SE ROMs (version $0276) static bool patch_rom_classic(void) { uint16 *wp; uint32 base; // Don't jump into debugger (VIA line) wp = (uint16 *)(ROMBaseHost + 0x1c40); *wp = htons(0x601e); // Don't complain about incorrect ROM checksum wp = (uint16 *)(ROMBaseHost + 0x1c6c); *wp = htons(0x7c00); // Don't initialize IWM wp = (uint16 *)(ROMBaseHost + 0x50); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Skip startup sound wp = (uint16 *)(ROMBaseHost + 0x6a); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Don't loop in ADB init wp = (uint16 *)(ROMBaseHost + 0x3364); *wp = htons(M68K_NOP); // Patch ClkNoMem wp = (uint16 *)(ROMBaseHost + 0xa2c0); *wp++ = htons(M68K_EMUL_OP_CLKNOMEM); *wp = htons(0x4ed5); // jmp (a5) // Skip main memory test (not that it wouldn't pass, but it's faster that way) wp = (uint16 *)(ROMBaseHost + 0x11e); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Install our own drivers wp = (uint16 *)(ROMBaseHost + 0x3f82a); *wp++ = htons(M68K_EMUL_OP_INSTALL_DRIVERS); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); #if 1 // Don't look for SCSI devices wp = (uint16 *)(ROMBaseHost + 0xd5a); *wp = htons(0x601e); #endif // Replace .Sony driver sony_offset = 0x34680; D(bug("sony %08lx\n", sony_offset)); memcpy(ROMBaseHost + sony_offset, sony_driver, sizeof(sony_driver)); // Install .Disk and .AppleCD drivers memcpy(ROMBaseHost + sony_offset + 0x100, disk_driver, sizeof(disk_driver)); memcpy(ROMBaseHost + sony_offset + 0x200, cdrom_driver, sizeof(cdrom_driver)); // Copy icons to ROM SonyDiskIconAddr = ROMBaseMac + sony_offset + 0x400; memcpy(ROMBaseHost + sony_offset + 0x400, SonyDiskIcon, sizeof(SonyDiskIcon)); SonyDriveIconAddr = ROMBaseMac + sony_offset + 0x600; memcpy(ROMBaseHost + sony_offset + 0x600, SonyDriveIcon, sizeof(SonyDriveIcon)); DiskIconAddr = ROMBaseMac + sony_offset + 0x800; memcpy(ROMBaseHost + sony_offset + 0x800, DiskIcon, sizeof(DiskIcon)); CDROMIconAddr = ROMBaseMac + sony_offset + 0xa00; memcpy(ROMBaseHost + sony_offset + 0xa00, CDROMIcon, sizeof(CDROMIcon)); // Install SERD patch and serial drivers serd_offset = 0x31bae; D(bug("serd %08lx\n", serd_offset)); wp = (uint16 *)(ROMBaseHost + serd_offset + 12); *wp++ = htons(M68K_EMUL_OP_SERD); *wp = htons(M68K_RTS); memcpy(ROMBaseHost + serd_offset + 0x100, ain_driver, sizeof(ain_driver)); memcpy(ROMBaseHost + serd_offset + 0x200, aout_driver, sizeof(aout_driver)); memcpy(ROMBaseHost + serd_offset + 0x300, bin_driver, sizeof(bin_driver)); memcpy(ROMBaseHost + serd_offset + 0x400, bout_driver, sizeof(bout_driver)); // Replace ADBOp() memcpy(ROMBaseHost + 0x3880, adbop_patch, sizeof(adbop_patch)); // Replace Time Manager wp = (uint16 *)(ROMBaseHost + 0x1a95c); *wp++ = htons(M68K_EMUL_OP_INSTIME); *wp = htons(M68K_RTS); wp = (uint16 *)(ROMBaseHost + 0x1a96a); *wp++ = htons(0x40e7); // move sr,-(sp) *wp++ = htons(0x007c); // ori #$0700,sr *wp++ = htons(0x0700); *wp++ = htons(M68K_EMUL_OP_RMVTIME); *wp++ = htons(0x46df); // move (sp)+,sr *wp = htons(M68K_RTS); wp = (uint16 *)(ROMBaseHost + 0x1a984); *wp++ = htons(0x40e7); // move sr,-(sp) *wp++ = htons(0x007c); // ori #$0700,sr *wp++ = htons(0x0700); *wp++ = htons(M68K_EMUL_OP_PRIMETIME); *wp++ = htons(0x46df); // move (sp)+,sr *wp++ = htons(M68K_RTS); microseconds_offset = (uint8 *)wp - ROMBaseHost; *wp++ = htons(M68K_EMUL_OP_MICROSECONDS); *wp++ = htons(M68K_RTS); // Replace DebugUtil debugutil_offset = (uint8 *)wp - ROMBaseHost; *wp++ = htons(M68K_EMUL_OP_DEBUGUTIL); *wp = htons(M68K_RTS); // Replace SCSIDispatch() wp = (uint16 *)(ROMBaseHost + 0x1a206); *wp++ = htons(M68K_EMUL_OP_SCSI_DISPATCH); *wp++ = htons(0x2e49); // move.l a1,a7 *wp = htons(M68K_JMP_A0); // Modify vCheckLoad() so we can patch resources wp = (uint16 *)(ROMBaseHost + 0xe740); *wp++ = htons(M68K_JMP); *wp++ = htons((ROMBaseMac + sony_offset + 0x300) >> 16); *wp = htons((ROMBaseMac + sony_offset + 0x300) & 0xffff); wp = (uint16 *)(ROMBaseHost + sony_offset + 0x300); *wp++ = htons(0x2f03); // move.l d3,-(sp) (save type) *wp++ = htons(0x2078); // move.l $07f0,a0 *wp++ = htons(0x07f0); *wp++ = htons(M68K_JSR_A0); *wp++ = htons(0x221f); // move.l (sp)+,d1 (restore type) *wp++ = htons(M68K_EMUL_OP_CHECKLOAD); *wp = htons(M68K_RTS); // Install PutScrap() patch for clipboard data exchange (the patch is activated by EMUL_OP_INSTALL_DRIVERS) PutScrapPatch = ROMBaseMac + sony_offset + 0xc00; base = ROMBaseMac + 0x12794; wp = (uint16 *)(ROMBaseHost + sony_offset + 0xc00); *wp++ = htons(M68K_EMUL_OP_PUT_SCRAP); *wp++ = htons(M68K_JMP); *wp++ = htons(base >> 16); *wp = htons(base & 0xffff); #if 0 // Boot from internal EDisk wp = (uint16 *)(ROMBaseHost + 0x3f83c); *wp = htons(M68K_NOP); #endif // Patch VIA interrupt handler wp = (uint16 *)(ROMBaseHost + 0x2b3a); // Level 1 handler *wp++ = htons(0x5888); // addq.l #4,a0 *wp++ = htons(0x5888); // addq.l #4,a0 *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); wp = (uint16 *)(ROMBaseHost + 0x2be4); // 60Hz handler (handles everything) *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_EMUL_OP_IRQ); *wp++ = htons(0x4a80); // tst.l d0 *wp = htons(0x67f4); // beq 0x402be2 return true; } // ROM patches for 32-bit clean Mac-II ROMs (version $067c) static bool patch_rom_32(void) { uint32 *lp; uint16 *wp; uint8 *bp; uint32 base; // Find UniversalInfo static const uint8 universal_dat[] = {0xdc, 0x00, 0x05, 0x05, 0x3f, 0xff, 0x01, 0x00}; if ((base = find_rom_data(0x3400, 0x3c00, universal_dat, sizeof(universal_dat))) == 0) return false; UniversalInfo = base - 0x10; D(bug("universal %08lx\n", UniversalInfo)); // Patch UniversalInfo (disable NuBus slots) bp = ROMBaseHost + UniversalInfo + ReadMacInt32(ROMBaseMac + UniversalInfo + 12); // nuBusInfoPtr bp[0] = 0x03; for (int i=1; i<16; i++) bp[i] = 0x08; // Set model ID from preferences bp = ROMBaseHost + UniversalInfo + 18; // productKind *bp = PrefsFindInt32("modelid"); #if !ROM_IS_WRITE_PROTECTED #if defined(USE_SCRATCHMEM_SUBTERFUGE) // Set hardware base addresses to scratch memory area if (PatchHWBases) { extern uint8 *ScratchMem; const uint32 ScratchMemBase = Host2MacAddr(ScratchMem); D(bug("LMGlob\tOfs/4\tBase\n")); base = ROMBaseMac + UniversalInfo + ReadMacInt32(ROMBaseMac + UniversalInfo); // decoderInfoPtr wp = (uint16 *)(ROMBaseHost + 0x94a); while (*wp != 0xffff) { int16 ofs = ntohs(*wp++); // offset in decoderInfo (/4) int16 lmg = ntohs(*wp++); // address of LowMem global D(bug("0x%04x\t%d\t0x%08x\n", lmg, ofs, ReadMacInt32(base + ofs*4))); // Fake address only if this is not the ASC base if (lmg != 0xcc0) WriteMacInt32(base + ofs*4, ScratchMemBase); } } #else #error System specific handling for writable ROM is required here #endif #endif // Make FPU optional if (FPUType == 0) { bp = ROMBaseHost + UniversalInfo + 22; // defaultRSRCs *bp = 4; // FPU optional } // Install special reset opcode and jump (skip hardware detection and tests) wp = (uint16 *)(ROMBaseHost + 0x8c); *wp++ = htons(M68K_EMUL_OP_RESET); *wp++ = htons(M68K_JMP); *wp++ = htons((ROMBaseMac + 0xba) >> 16); *wp = htons((ROMBaseMac + 0xba) & 0xffff); // Don't GetHardwareInfo wp = (uint16 *)(ROMBaseHost + 0xc2); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Don't init VIAs wp = (uint16 *)(ROMBaseHost + 0xc6); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Fake CPU type test wp = (uint16 *)(ROMBaseHost + 0x7c0); *wp++ = htons(0x7e00 + CPUType); *wp = htons(M68K_RTS); // Don't clear end of BootGlobs upto end of RAM (address xxxx0000) static const uint8 clear_globs_dat[] = {0x42, 0x9a, 0x36, 0x0a, 0x66, 0xfa}; base = find_rom_data(0xa00, 0xb00, clear_globs_dat, sizeof(clear_globs_dat)); D(bug("clear_globs %08lx\n", base)); if (base) { // ROM15/20/22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + base + 2); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); } // Patch InitMMU (no MMU present, don't choke on unknown CPU types) if (ROMSize <= 0x80000) { static const uint8 init_mmu_dat[] = {0x0c, 0x47, 0x00, 0x03, 0x62, 0x00, 0xfe}; if ((base = find_rom_data(0x4000, 0x50000, init_mmu_dat, sizeof(init_mmu_dat))) == 0) return false; } else { static const uint8 init_mmu_dat[] = {0x0c, 0x47, 0x00, 0x04, 0x62, 0x00, 0xfd}; if ((base = find_rom_data(0x80000, 0x90000, init_mmu_dat, sizeof(init_mmu_dat))) == 0) return false; } D(bug("init_mmu %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); wp++; *wp++ = htons(0x7000); // moveq #0,d0 *wp = htons(M68K_NOP); // Patch InitMMU (no RBV present) static const uint8 init_mmu2_dat[] = {0x08, 0x06, 0x00, 0x0d, 0x67}; if (ROMSize <= 0x80000) { base = find_rom_data(0x4000, 0x50000, init_mmu2_dat, sizeof(init_mmu2_dat)); } else { base = find_rom_data(0x80000, 0x90000, init_mmu2_dat, sizeof(init_mmu2_dat)); } D(bug("init_mmu2 %08lx\n", base)); if (base) { // ROM11/10/13/26 bp = (uint8 *)(ROMBaseHost + base + 4); *bp = 0x60; // bra } // Patch InitMMU (don't init MMU) static const uint8 init_mmu3_dat[] = {0x0c, 0x2e, 0x00, 0x01, 0xff, 0xe6, 0x66, 0x0c, 0x4c, 0xed, 0x03, 0x87, 0xff, 0xe8}; if (ROMSize <= 0x80000) { if ((base = find_rom_data(0x4000, 0x50000, init_mmu3_dat, sizeof(init_mmu3_dat))) == 0) return false; } else { if ((base = find_rom_data(0x80000, 0x90000, init_mmu3_dat, sizeof(init_mmu3_dat))) == 0) return false; } D(bug("init_mmu3 %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base + 6); *wp = htons(M68K_NOP); // Replace XPRAM routines static const uint8 read_xpram_dat[] = {0x26, 0x4e, 0x41, 0xf9, 0x50, 0xf0, 0x00, 0x00, 0x08, 0x90, 0x00, 0x02}; base = find_rom_data(0x40000, 0x50000, read_xpram_dat, sizeof(read_xpram_dat)); D(bug("read_xpram %08lx\n", base)); if (base) { // ROM10 wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_EMUL_OP_READ_XPRAM); *wp = htons(0x4ed6); // jmp (a6) } static const uint8 read_xpram2_dat[] = {0x26, 0x4e, 0x08, 0x92, 0x00, 0x02, 0xea, 0x59, 0x02, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0xb8}; base = find_rom_data(0x40000, 0x50000, read_xpram2_dat, sizeof(read_xpram2_dat)); D(bug("read_xpram2 %08lx\n", base)); if (base) { // ROM11 wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_EMUL_OP_READ_XPRAM); *wp = htons(0x4ed6); // jmp (a6) } if (ROMSize > 0x80000) { static const uint8 read_xpram3_dat[] = {0x48, 0xe7, 0xe0, 0x60, 0x02, 0x01, 0x00, 0x70, 0x0c, 0x01, 0x00, 0x20}; base = find_rom_data(0x80000, 0x90000, read_xpram3_dat, sizeof(read_xpram3_dat)); D(bug("read_xpram3 %08lx\n", base)); if (base) { // ROM15 wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_EMUL_OP_READ_XPRAM2); *wp = htons(M68K_RTS); } } // Patch ClkNoMem base = find_rom_trap(0xa053); wp = (uint16 *)(ROMBaseHost + base); if (ntohs(*wp) == 0x4ed5) { // ROM23/26/27/32 static const uint8 clk_no_mem_dat[] = {0x40, 0xc2, 0x00, 0x7c, 0x07, 0x00, 0x48, 0x42}; if ((base = find_rom_data(0xb0000, 0xb8000, clk_no_mem_dat, sizeof(clk_no_mem_dat))) == 0) return false; } D(bug("clk_no_mem %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_EMUL_OP_CLKNOMEM); *wp = htons(0x4ed5); // jmp (a5) // Patch BootGlobs wp = (uint16 *)(ROMBaseHost + 0x10e); *wp++ = htons(M68K_EMUL_OP_PATCH_BOOT_GLOBS); *wp = htons(M68K_NOP); // Don't init SCC static const uint8 init_scc_dat[] = {0x08, 0x38, 0x00, 0x01, 0x0d, 0xd1, 0x67, 0x04}; if ((base = find_rom_data(0xa00, 0xa80, init_scc_dat, sizeof(init_scc_dat))) == 0) return false; D(bug("init_scc %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base); *wp = htons(M68K_RTS); // Don't access 0x50f1a101 wp = (uint16 *)(ROMBaseHost + 0x4232); if (ntohs(wp[1]) == 0x50f1 && ntohs(wp[2]) == 0xa101) { // ROM32 *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); } // Don't init IWM wp = (uint16 *)(ROMBaseHost + 0x9c0); *wp = htons(M68K_RTS); // Don't init SCSI wp = (uint16 *)(ROMBaseHost + 0x9a0); *wp = htons(M68K_RTS); // Don't init ASC static const uint8 init_asc_dat[] = {0x26, 0x68, 0x00, 0x30, 0x12, 0x00, 0xeb, 0x01}; base = find_rom_data(0x4000, 0x5000, init_asc_dat, sizeof(init_asc_dat)); D(bug("init_asc %08lx\n", base)); if (base) { // ROM15/22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + base); *wp = htons(0x4ed6); // jmp (a6) } // Don't EnableExtCache wp = (uint16 *)(ROMBaseHost + 0x190); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Don't DisableIntSources wp = (uint16 *)(ROMBaseHost + 0x9f4c); *wp = htons(M68K_RTS); // Fake CPU speed test (SetupTimeK) // *** increased jl : MacsBug uses TimeDBRA for kbd repeat timing wp = (uint16 *)(ROMBaseHost + 0x800); *wp++ = htons(0x31fc); // move.w #xxx,TimeDBRA *wp++ = htons(10000); *wp++ = htons(0x0d00); *wp++ = htons(0x31fc); // move.w #xxx,TimeSCCDBRA *wp++ = htons(10000); *wp++ = htons(0x0d02); *wp++ = htons(0x31fc); // move.w #xxx,TimeSCSIDBRA *wp++ = htons(10000); *wp++ = htons(0x0b24); *wp++ = htons(0x31fc); // move.w #xxx,TimeRAMDBRA *wp++ = htons(10000); *wp++ = htons(0x0cea); *wp = htons(M68K_RTS); #if REAL_ADDRESSING // Move system zone to start of Mac RAM wp = (uint16 *)(ROMBaseHost + 0x50a); *wp++ = htons(HiWord(RAMBaseMac + 0x2000)); *wp++ = htons(LoWord(RAMBaseMac + 0x2000)); *wp++ = htons(HiWord(RAMBaseMac + 0x3800)); *wp = htons(LoWord(RAMBaseMac + 0x3800)); #endif #if !ROM_IS_WRITE_PROTECTED #if defined(USE_SCRATCHMEM_SUBTERFUGE) // Set fake handle at 0x0000 to scratch memory area (so broken Mac programs won't write into Mac ROM) extern uint8 *ScratchMem; const uint32 ScratchMemBase = Host2MacAddr(ScratchMem); wp = (uint16 *)(ROMBaseHost + 0xccaa); *wp++ = htons(0x203c); // move.l #ScratchMem,d0 *wp++ = htons(ScratchMemBase >> 16); *wp = htons(ScratchMemBase); #else #error System specific handling for writable ROM is required here #endif #endif #if REAL_ADDRESSING && defined(AMIGA) // Don't overwrite SysBase under AmigaOS wp = (uint16 *)(ROMBaseHost + 0xccb4); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); #endif #if REAL_ADDRESSING && !defined(AMIGA) // gb-- Temporary hack to get rid of crashes in Speedometer wp = (uint16 *)(ROMBaseHost + 0xdba2); if (ntohs(*wp) == 0x662c) // bne.b #$2c *wp = htons(0x602c); // bra.b #$2c #endif // Don't write to VIA in InitTimeMgr wp = (uint16 *)(ROMBaseHost + 0xb0e2); *wp++ = htons(0x4cdf); // movem.l (sp)+,d0-d5/a0-a4 *wp++ = htons(0x1f3f); *wp = htons(M68K_RTS); // Don't read ModelID from 0x5ffffffc static const uint8 model_id_dat[] = {0x20, 0x7c, 0x5f, 0xff, 0xff, 0xfc, 0x72, 0x07, 0xc2, 0x90}; base = find_rom_data(0x40000, 0x50000, model_id_dat, sizeof(model_id_dat)); D(bug("model_id %08lx\n", base)); if (base) { // ROM20 wp = (uint16 *)(ROMBaseHost + base + 8); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); } // Don't read ModelID from 0x5ffffffc static const uint8 model_id2_dat[] = {0x45, 0xf9, 0x5f, 0xff, 0xff, 0xfc, 0x20, 0x12}; base = find_rom_data(0x4000, 0x5000, model_id2_dat, sizeof(model_id2_dat)); D(bug("model_id2 %08lx\n", base)); if (base) { // ROM27/32 wp = (uint16 *)(ROMBaseHost + base + 6); *wp++ = htons(0x7000); // moveq #0,d0 *wp++ = htons(0xb040); // cmp.w d0,d0 *wp = htons(0x4ed6); // jmp (a6) } // Install slot ROM if (!InstallSlotROM()) return false; // Don't probe NuBus slots static const uint8 nubus_dat[] = {0x45, 0xfa, 0x00, 0x0a, 0x42, 0xa7, 0x10, 0x11}; base = find_rom_data(0x5000, 0x6000, nubus_dat, sizeof(nubus_dat)); D(bug("nubus %08lx\n", base)); if (base) { // ROM10/11 wp = (uint16 *)(ROMBaseHost + base + 6); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); } // Don't EnableOneSecInts static const uint8 lea_dat[] = {0x41, 0xf9}; if ((base = find_rom_data(0x226, 0x22a, lea_dat, sizeof(lea_dat))) == 0) return false; D(bug("enable_one_sec_ints %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Don't EnableParityPatch/Enable60HzInts if ((base = find_rom_data(0x230, 0x234, lea_dat, sizeof(lea_dat))) == 0) { wp = (uint16 *)(ROMBaseHost + 0x230); if (ntohs(*wp) == 0x6100) // ROM11 base = 0x230; else return false; } D(bug("enable_60hz_ints %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Compute boot stack pointer and fix logical/physical RAM size (CompBootStack) (must be done after InitMemMgr!) wp = (uint16 *)(ROMBaseHost + 0x490); *wp++ = htons(0x2038); // move.l $10c,d0 *wp++ = htons(0x010c); *wp++ = htons(0xd0b8); // add.l $2a6,d0 *wp++ = htons(0x02a6); *wp++ = htons(0xe288); // lsr.l #1,d0 *wp++ = htons(0x0880); // bclr #0,d0 *wp++ = htons(0x0000); *wp++ = htons(0x0440); // subi.w #$400,d0 *wp++ = htons(0x0400); *wp++ = htons(0x2040); // move.l d0,a0 *wp++ = htons(M68K_EMUL_OP_FIX_MEMSIZE); *wp++ = htons(M68K_RTS); static const uint8 fix_memsize2_dat[] = {0x22, 0x30, 0x81, 0xe2, 0x0d, 0xdc, 0xff, 0xba, 0xd2, 0xb0, 0x81, 0xe2, 0x0d, 0xdc, 0xff, 0xec, 0x21, 0xc1, 0x1e, 0xf8}; base = find_rom_data(0x4c000, 0x4c080, fix_memsize2_dat, sizeof(fix_memsize2_dat)); D(bug("fix_memsize2 %08lx\n", base)); if (base) { // ROM15/22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + base + 16); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); } // Don't open .Sound driver but install our own drivers wp = (uint16 *)(ROMBaseHost + 0x1142); *wp = htons(M68K_EMUL_OP_INSTALL_DRIVERS); // Don't access SonyVars wp = (uint16 *)(ROMBaseHost + 0x1144); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); wp += 2; *wp = htons(M68K_NOP); // Don't write to VIA in InitADB wp = (uint16 *)(ROMBaseHost + 0xa8a8); if (*wp == 0) { // ROM22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + 0xb2c6a); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); wp = (uint16 *)(ROMBaseHost + 0xb2d2e); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); wp += 2; *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); } else { *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); wp = (uint16 *)(ROMBaseHost + 0xa662); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); wp += 2; *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); } // Don't EnableSlotInts if ((base = find_rom_data(0x2ee, 0x2f2, lea_dat, sizeof(lea_dat))) == 0) return false; D(bug("enable_slot_ints %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); // Don't mangle frame buffer base (GetDevBase) wp = (uint16 *)(ROMBaseHost + 0x5b78); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(0x2401); // move.l d1,d2 *wp = htons(0x605e); // bra 0x40805bde // Really don't mangle frame buffer base if (ROMSize > 0x80000) { static const uint8 frame_base_dat[] = {0x22, 0x78, 0x0d, 0xd8, 0xd3, 0xe9, 0x00, 0x08}; base = find_rom_data(0x8c000, 0x8d000, frame_base_dat, sizeof(frame_base_dat)); D(bug("frame_base %08lx\n", base)); if (base) { // ROM22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + base); *wp++ = htons(0x2401); // move.l d1,d2 *wp = htons(M68K_RTS); } } // Don't write to VIA2 static const uint8 via2_dat[] = {0x20, 0x78, 0x0c, 0xec, 0x11, 0x7c, 0x00, 0x90}; if ((base = find_rom_data(0xa000, 0xa400, via2_dat, sizeof(via2_dat))) == 0) return false; D(bug("via2 %08lx\n", base)); wp = (uint16 *)(ROMBaseHost + base + 4); *wp = htons(M68K_RTS); // Don't write to VIA2, even on ROM20 static const uint8 via2b_dat[] = {0x20, 0x78, 0x0c, 0xec, 0x11, 0x7c, 0x00, 0x90, 0x00, 0x13, 0x4e, 0x75}; base = find_rom_data(0x40000, 0x44000, via2b_dat, sizeof(via2b_dat)); D(bug("via2b %08lx\n", base)); if (base) { // ROM19/20 wp = (uint16 *)(ROMBaseHost + base + 4); *wp = htons(M68K_RTS); } // Don't use PTEST instruction on 68040/060 if (ROMSize > 0x80000) { // BlockMove() static const uint8 bmove_dat[] = {0x20, 0x5f, 0x22, 0x5f, 0x0c, 0x38, 0x00, 0x04, 0x01, 0x2f}; base = find_rom_data(0x87000, 0x87800, bmove_dat, sizeof(bmove_dat)); D(bug("block_move %08lx\n", base)); if (base) { // ROM15/22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + base + 4); *wp++ = htons(M68K_EMUL_OP_BLOCK_MOVE); *wp++ = htons(0x7000); *wp = htons(M68K_RTS); } // SANE static const uint8 ptest2_dat[] = {0x0c, 0x38, 0x00, 0x04, 0x01, 0x2f, 0x6d, 0x54, 0x48, 0xe7, 0xf8, 0x60}; base = find_rom_data(0, ROMSize, ptest2_dat, sizeof(ptest2_dat)); D(bug("ptest2 %08lx\n", base)); if (base) { // ROM15/20/22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + base + 8); *wp++ = htons(M68K_NOP); *wp++ = htons(0xf4f8); // cpusha dc/ic *wp++ = htons(M68K_NOP); *wp++ = htons(0x7000); // moveq #0,d0 *wp = htons(M68K_RTS); } } // Don't set MemoryDispatch() to unimplemented trap static const uint8 memdisp_dat[] = {0x30, 0x3c, 0xa8, 0x9f, 0xa7, 0x46, 0x30, 0x3c, 0xa0, 0x5c, 0xa2, 0x47}; base = find_rom_data(0x4f100, 0x4f180, memdisp_dat, sizeof(memdisp_dat)); D(bug("memdisp %08lx\n", base)); if (base) { // ROM15/22/23/26/27/32 wp = (uint16 *)(ROMBaseHost + base + 10); *wp = htons(M68K_NOP); } // Patch .EDisk driver (don't scan for EDisks in the area ROMBase..0xe00000) uint32 edisk_offset = find_rom_resource(FOURCC('D','R','V','R'), 51); if (edisk_offset) { static const uint8 edisk_dat[] = {0xd5, 0xfc, 0x00, 0x01, 0x00, 0x00, 0xb5, 0xfc, 0x00, 0xe0, 0x00, 0x00}; base = find_rom_data(edisk_offset, edisk_offset + 0x10000, edisk_dat, sizeof(edisk_dat)); D(bug("edisk %08lx\n", base)); if (base) { wp = (uint16 *)(ROMBaseHost + base + 8); *wp++ = 0; *wp = 0; } } // Replace .Sony driver sony_offset = find_rom_resource(FOURCC('D','R','V','R'), 4); D(bug("sony %08lx\n", sony_offset)); memcpy(ROMBaseHost + sony_offset, sony_driver, sizeof(sony_driver)); // Install .Disk and .AppleCD drivers memcpy(ROMBaseHost + sony_offset + 0x100, disk_driver, sizeof(disk_driver)); memcpy(ROMBaseHost + sony_offset + 0x200, cdrom_driver, sizeof(cdrom_driver)); // Copy icons to ROM SonyDiskIconAddr = ROMBaseMac + sony_offset + 0x400; memcpy(ROMBaseHost + sony_offset + 0x400, SonyDiskIcon, sizeof(SonyDiskIcon)); SonyDriveIconAddr = ROMBaseMac + sony_offset + 0x600; memcpy(ROMBaseHost + sony_offset + 0x600, SonyDriveIcon, sizeof(SonyDriveIcon)); DiskIconAddr = ROMBaseMac + sony_offset + 0x800; memcpy(ROMBaseHost + sony_offset + 0x800, DiskIcon, sizeof(DiskIcon)); CDROMIconAddr = ROMBaseMac + sony_offset + 0xa00; memcpy(ROMBaseHost + sony_offset + 0xa00, CDROMIcon, sizeof(CDROMIcon)); // Install SERD patch and serial drivers serd_offset = find_rom_resource(FOURCC('S','E','R','D'), 0); D(bug("serd %08lx\n", serd_offset)); wp = (uint16 *)(ROMBaseHost + serd_offset + 12); *wp++ = htons(M68K_EMUL_OP_SERD); *wp = htons(M68K_RTS); memcpy(ROMBaseHost + serd_offset + 0x100, ain_driver, sizeof(ain_driver)); memcpy(ROMBaseHost + serd_offset + 0x200, aout_driver, sizeof(aout_driver)); memcpy(ROMBaseHost + serd_offset + 0x300, bin_driver, sizeof(bin_driver)); memcpy(ROMBaseHost + serd_offset + 0x400, bout_driver, sizeof(bout_driver)); // Replace ADBOp() memcpy(ROMBaseHost + find_rom_trap(0xa07c), adbop_patch, sizeof(adbop_patch)); // Replace Time Manager (the Microseconds patch is activated in InstallDrivers()) wp = (uint16 *)(ROMBaseHost + find_rom_trap(0xa058)); *wp++ = htons(M68K_EMUL_OP_INSTIME); *wp = htons(M68K_RTS); wp = (uint16 *)(ROMBaseHost + find_rom_trap(0xa059)); *wp++ = htons(0x40e7); // move sr,-(sp) *wp++ = htons(0x007c); // ori #$0700,sr *wp++ = htons(0x0700); *wp++ = htons(M68K_EMUL_OP_RMVTIME); *wp++ = htons(0x46df); // move (sp)+,sr *wp = htons(M68K_RTS); wp = (uint16 *)(ROMBaseHost + find_rom_trap(0xa05a)); *wp++ = htons(0x40e7); // move sr,-(sp) *wp++ = htons(0x007c); // ori #$0700,sr *wp++ = htons(0x0700); *wp++ = htons(M68K_EMUL_OP_PRIMETIME); *wp++ = htons(0x46df); // move (sp)+,sr *wp++ = htons(M68K_RTS); microseconds_offset = (uint8 *)wp - ROMBaseHost; *wp++ = htons(M68K_EMUL_OP_MICROSECONDS); *wp++ = htons(M68K_RTS); // Replace DebugUtil debugutil_offset = (uint8 *)wp - ROMBaseHost; *wp++ = htons(M68K_EMUL_OP_DEBUGUTIL); *wp = htons(M68K_RTS); // Replace SCSIDispatch() wp = (uint16 *)(ROMBaseHost + find_rom_trap(0xa815)); *wp++ = htons(M68K_EMUL_OP_SCSI_DISPATCH); *wp++ = htons(0x2e49); // move.l a1,a7 *wp = htons(M68K_JMP_A0); // Modify vCheckLoad() so we can patch resources wp = (uint16 *)(ROMBaseHost + 0x1b8f4); *wp++ = htons(M68K_JMP); *wp++ = htons((ROMBaseMac + sony_offset + 0x300) >> 16); *wp = htons((ROMBaseMac + sony_offset + 0x300) & 0xffff); wp = (uint16 *)(ROMBaseHost + sony_offset + 0x300); *wp++ = htons(0x2f03); // move.l d3,-(sp) (save type) *wp++ = htons(0x2078); // move.l $07f0,a0 *wp++ = htons(0x07f0); *wp++ = htons(M68K_JSR_A0); *wp++ = htons(0x221f); // move.l (sp)+,d1 (restore type) *wp++ = htons(M68K_EMUL_OP_CHECKLOAD); *wp = htons(M68K_RTS); // Patch PowerOff() wp = (uint16 *)(ROMBaseHost + find_rom_trap(0xa05b)); // PowerOff() *wp = htons(M68K_EMUL_OP_SHUTDOWN); // Install PutScrap() patch for clipboard data exchange (the patch is activated by EMUL_OP_INSTALL_DRIVERS) PutScrapPatch = ROMBaseMac + sony_offset + 0xc00; base = ROMBaseMac + find_rom_trap(0xa9fe); wp = (uint16 *)(ROMBaseHost + sony_offset + 0xc00); *wp++ = htons(M68K_EMUL_OP_PUT_SCRAP); *wp++ = htons(M68K_JMP); *wp++ = htons(base >> 16); *wp = htons(base & 0xffff); // Install GetScrap() patch for clipboard data exchange (the patch is activated by EMUL_OP_INSTALL_DRIVERS) GetScrapPatch = ROMBaseMac + sony_offset + 0xd00; base = ROMBaseMac + find_rom_trap(0xa9fd); wp = (uint16 *)(ROMBaseHost + sony_offset + 0xd00); *wp++ = htons(M68K_EMUL_OP_GET_SCRAP); *wp++ = htons(M68K_JMP); *wp++ = htons(base >> 16); *wp = htons(base & 0xffff); // Look for double PACK 4 resources if ((base = find_rom_resource(FOURCC('P','A','C','K'), 4)) == 0) return false; if ((base = find_rom_resource(FOURCC('P','A','C','K'), 4, true)) == 0 && FPUType == 0) printf("WARNING: This ROM seems to require an FPU\n"); // Patch VIA interrupt handler wp = (uint16 *)(ROMBaseHost + 0x9bc4); // Level 1 handler *wp++ = htons(0x7002); // moveq #2,d0 (always 60Hz interrupt) *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp = htons(M68K_NOP); wp = (uint16 *)(ROMBaseHost + 0xa296); // 60Hz handler (handles everything) *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_NOP); *wp++ = htons(M68K_EMUL_OP_IRQ); *wp++ = htons(0x4a80); // tst.l d0 *wp = htons(0x67f4); // beq 0x4080a294 return true; } bool PatchROM(void) { // Print some information about the ROM if (PrintROMInfo) print_rom_info(); // Patch ROM depending on version switch (ROMVersion) { case ROM_VERSION_CLASSIC: if (!patch_rom_classic()) return false; break; case ROM_VERSION_32: if (!patch_rom_32()) return false; break; default: return false; } // Install breakpoint if (ROMBreakpoint) { uint16 *wp = (uint16 *)(ROMBaseHost + ROMBreakpoint); *wp = htons(M68K_EMUL_BREAK); } // Clear caches as we loaded and patched code FlushCodeCache(ROMBaseHost, ROMSize); return true; } BasiliskII/src/main.cpp0000644000175000017500000001247211232133662015165 0ustar centriscentris/* * main.cpp - Startup/shutdown code * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "xpram.h" #include "timer.h" #include "sony.h" #include "disk.h" #include "cdrom.h" #include "scsi.h" #include "extfs.h" #include "audio.h" #include "video.h" #include "serial.h" #include "ether.h" #include "clip.h" #include "adb.h" #include "rom_patches.h" #include "user_strings.h" #include "prefs.h" #include "main.h" #define DEBUG 0 #include "debug.h" #if ENABLE_MON #include "mon.h" static uint32 mon_read_byte_b2(uintptr adr) { return ReadMacInt8(adr); } static void mon_write_byte_b2(uintptr adr, uint32 b) { WriteMacInt8(adr, b); } #endif /* * Initialize everything, returns false on error */ bool InitAll(const char *vmdir) { // Check ROM version if (!CheckROM()) { ErrorAlert(STR_UNSUPPORTED_ROM_TYPE_ERR); return false; } #if EMULATED_68K // Set CPU and FPU type (UAE emulation) switch (ROMVersion) { case ROM_VERSION_64K: case ROM_VERSION_PLUS: case ROM_VERSION_CLASSIC: CPUType = 0; FPUType = 0; TwentyFourBitAddressing = true; break; case ROM_VERSION_II: CPUType = PrefsFindInt32("cpu"); if (CPUType < 2) CPUType = 2; if (CPUType > 4) CPUType = 4; FPUType = PrefsFindBool("fpu") ? 1 : 0; if (CPUType == 4) FPUType = 1; // 68040 always with FPU TwentyFourBitAddressing = true; break; case ROM_VERSION_32: CPUType = PrefsFindInt32("cpu"); if (CPUType < 2) CPUType = 2; if (CPUType > 4) CPUType = 4; FPUType = PrefsFindBool("fpu") ? 1 : 0; if (CPUType == 4) FPUType = 1; // 68040 always with FPU TwentyFourBitAddressing = false; break; } CPUIs68060 = false; #endif // Load XPRAM XPRAMInit(vmdir); // Load XPRAM default values if signature not found if (XPRAM[0x0c] != 0x4e || XPRAM[0x0d] != 0x75 || XPRAM[0x0e] != 0x4d || XPRAM[0x0f] != 0x63) { D(bug("Loading XPRAM default values\n")); memset(XPRAM, 0, 0x100); XPRAM[0x0c] = 0x4e; // "NuMc" signature XPRAM[0x0d] = 0x75; XPRAM[0x0e] = 0x4d; XPRAM[0x0f] = 0x63; XPRAM[0x01] = 0x80; // InternalWaitFlags = DynWait (don't wait for SCSI devices upon bootup) XPRAM[0x10] = 0xa8; // Standard PRAM values XPRAM[0x11] = 0x00; XPRAM[0x12] = 0x00; XPRAM[0x13] = 0x22; XPRAM[0x14] = 0xcc; XPRAM[0x15] = 0x0a; XPRAM[0x16] = 0xcc; XPRAM[0x17] = 0x0a; XPRAM[0x1c] = 0x00; XPRAM[0x1d] = 0x02; XPRAM[0x1e] = 0x63; XPRAM[0x1f] = 0x00; XPRAM[0x08] = 0x13; XPRAM[0x09] = 0x88; XPRAM[0x0a] = 0x00; XPRAM[0x0b] = 0xcc; XPRAM[0x76] = 0x00; // OSDefault = MacOS XPRAM[0x77] = 0x01; } // Set boot volume int16 i16 = PrefsFindInt32("bootdrive"); XPRAM[0x78] = i16 >> 8; XPRAM[0x79] = i16 & 0xff; i16 = PrefsFindInt32("bootdriver"); XPRAM[0x7a] = i16 >> 8; XPRAM[0x7b] = i16 & 0xff; // Init drivers SonyInit(); DiskInit(); CDROMInit(); SCSIInit(); #if SUPPORTS_EXTFS // Init external file system ExtFSInit(); #endif // Init serial ports SerialInit(); // Init network EtherInit(); // Init Time Manager TimerInit(); // Init clipboard ClipInit(); // Init ADB ADBInit(); // Init audio AudioInit(); // Init video if (!VideoInit(ROMVersion == ROM_VERSION_64K || ROMVersion == ROM_VERSION_PLUS || ROMVersion == ROM_VERSION_CLASSIC)) return false; // Set default video mode in XPRAM XPRAM[0x56] = 0x42; // 'B' XPRAM[0x57] = 0x32; // '2' const monitor_desc &main_monitor = *VideoMonitors[0]; XPRAM[0x58] = main_monitor.depth_to_apple_mode(main_monitor.get_current_mode().depth); XPRAM[0x59] = 0; #if EMULATED_68K // Init 680x0 emulation (this also activates the memory system which is needed for PatchROM()) if (!Init680x0()) return false; #endif // Install ROM patches if (!PatchROM()) { ErrorAlert(STR_UNSUPPORTED_ROM_TYPE_ERR); return false; } #if ENABLE_MON // Initialize mon mon_init(); mon_read_byte = mon_read_byte_b2; mon_write_byte = mon_write_byte_b2; #endif return true; } /* * Deinitialize everything */ void ExitAll(void) { #if ENABLE_MON // Deinitialize mon mon_exit(); #endif // Save XPRAM XPRAMExit(); // Exit video VideoExit(); // Exit audio AudioExit(); // Exit ADB ADBExit(); // Exit clipboard ClipExit(); // Exit Time Manager TimerExit(); // Exit serial ports SerialExit(); // Exit network EtherExit(); #if SUPPORTS_EXTFS // Exit external file system ExtFSExit(); #endif // Exit drivers SCSIExit(); CDROMExit(); DiskExit(); SonyExit(); } /* * Display error/warning alert given the message string ID */ void ErrorAlert(int string_id) { ErrorAlert(GetString(string_id)); } void WarningAlert(int string_id) { WarningAlert(GetString(string_id)); } BasiliskII/src/audio.cpp0000644000175000017500000004746110736405217015356 0ustar centriscentris/* * audio.cpp - Audio support * * Basilisk II (C) 1997-2008 Christian Bauer * Portions written by Marc Hellwig * * 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 */ /* * SEE ALSO * Inside Macintosh: Sound, chapter 5 "Sound Components" */ #include "sysdeps.h" #include "cpu_emulation.h" #include "macos_util.h" #include "emul_op.h" #include "main.h" #include "audio.h" #include "audio_defs.h" #define DEBUG 0 #include "debug.h" // Supported sample rates, sizes and channels vector audio_sample_rates; vector audio_sample_sizes; vector audio_channel_counts; // Global variables struct audio_status AudioStatus; // Current audio status (sample rate etc.) bool audio_open = false; // Flag: audio is initialized and ready int audio_frames_per_block; // Number of audio frames per block uint32 audio_component_flags; // Component feature flags uint32 audio_data = 0; // Mac address of global data area static int open_count = 0; // Open/close nesting count bool AudioAvailable = false; // Flag: audio output available (from the software point of view) /* * Reset audio emulation */ void AudioReset(void) { audio_data = 0; } /* * Get audio info */ static int32 AudioGetInfo(uint32 infoPtr, uint32 selector, uint32 sourceID) { D(bug(" AudioGetInfo %c%c%c%c, infoPtr %08lx, source ID %08lx\n", selector >> 24, (selector >> 16) & 0xff, (selector >> 8) & 0xff, selector & 0xff, infoPtr, sourceID)); M68kRegisters r; switch (selector) { case siSampleSize: WriteMacInt16(infoPtr, AudioStatus.sample_size); break; case siSampleSizeAvailable: { r.d[0] = audio_sample_sizes.size() * 2; Execute68kTrap(0xa122, &r); // NewHandle() uint32 h = r.a[0]; if (h == 0) return memFullErr; WriteMacInt16(infoPtr + sil_count, audio_sample_sizes.size()); WriteMacInt32(infoPtr + sil_infoHandle, h); uint32 sp = ReadMacInt32(h); for (unsigned i=0; i> 24, (selector >> 16) & 0xff, (selector >> 8) & 0xff, selector & 0xff, infoPtr, sourceID)); M68kRegisters r; switch (selector) { case siSampleSize: D(bug(" set sample size %08lx\n", infoPtr)); if (AudioStatus.num_sources) return siDeviceBusyErr; if (infoPtr == AudioStatus.sample_size) return noErr; for (unsigned i=0; i= 0x100) goto delegate; else return badComponentSelector; } } /* * Sound input driver Open() routine */ int16 SoundInOpen(uint32 pb, uint32 dce) { D(bug("SoundInOpen\n")); return noErr; } /* * Sound input driver Prime() routine */ int16 SoundInPrime(uint32 pb, uint32 dce) { D(bug("SoundInPrime\n")); //!! return paramErr; } /* * Sound input driver Control() routine */ int16 SoundInControl(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("SoundInControl %d\n", code)); if (code == 1) { D(bug(" SoundInKillIO\n")); //!! return noErr; } if (code != 2) return -231; // siUnknownInfoType uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam); uint32 selector = param[0]; D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector)); switch (selector) { default: return -231; // siUnknownInfoType } } /* * Sound input driver Status() routine */ int16 SoundInStatus(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("SoundInStatus %d\n", code)); if (code != 2) return -231; // siUnknownInfoType uint32 *param = (uint32 *)Mac2HostAddr(pb + csParam); uint32 selector = param[0]; D(bug(" selector %c%c%c%c\n", selector >> 24, selector >> 16, selector >> 8, selector)); switch (selector) { #if 0 case siDeviceName: { const char *str = GetString(STR_SOUND_IN_NAME); param[0] = 0; memcpy((void *)param[1], str, strlen(str)); return noErr; } case siDeviceIcon: { M68kRegisters r; static const uint8 proc[] = { 0x55, 0x8f, // subq.l #2,sp 0xa9, 0x94, // CurResFile 0x42, 0x67, // clr.w -(sp) 0xa9, 0x98, // UseResFile 0x59, 0x8f, // subq.l #4,sp 0x48, 0x79, 0x49, 0x43, 0x4e, 0x23, // move.l #'ICN#',-(sp) 0x3f, 0x3c, 0xbf, 0x76, // move.w #-16522,-(sp) 0xa9, 0xa0, // GetResource 0x24, 0x5f, // move.l (sp)+,a2 0xa9, 0x98, // UseResFile 0x20, 0x0a, // move.l a2,d0 0x66, 0x04, // bne 1 0x70, 0x00, // moveq #0,d0 M68K_RTS >> 8, M68K_RTS & 0xff, 0x2f, 0x0a, //1 move.l a2,-(sp) 0xa9, 0x92, // DetachResource 0x20, 0x4a, // move.l a2,a0 0xa0, 0x4a, // HNoPurge 0x70, 0x01, // moveq #1,d0 M68K_RTS >> 8, M68K_RTS & 0xff }; Execute68k(Host2MacAddr((uint8 *)proc), &r); if (r.d[0]) { param[0] = 4; // Length of returned data param[1] = r.a[2]; // Handle to icon suite return noErr; } else return -192; // resNotFound } #endif default: return -231; // siUnknownInfoType } } /* * Sound input driver Close() routine */ int16 SoundInClose(uint32 pb, uint32 dce) { D(bug("SoundInClose\n")); return noErr; } BasiliskII/src/cdrom.cpp0000644000175000017500000007307611031502242015343 0ustar centriscentris/* * cdrom.cpp - CD-ROM driver * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 1 "Device Manager" * Technote DV 05: "Drive Queue Elements" * Technote DV 22: "CD-ROM Driver Calls" * Technote DV 23: "Driver Education" * Technote FL 24: "Don't Look at ioPosOffset for Devices" * Technote FL 36: "Apple Extensions to ISO 9660" */ #include "sysdeps.h" #include #include #ifndef NO_STD_NAMESPACE using std::vector; #endif #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "sys.h" #include "prefs.h" #include "cdrom.h" #define DEBUG 0 #include "debug.h" // CDROM disk/drive icon const uint8 CDROMIcon[258] = { 0x3f, 0xff, 0xff, 0xf0, 0x40, 0x00, 0x00, 0x08, 0x80, 0x1f, 0xc0, 0x04, 0x80, 0x75, 0x70, 0x04, 0x81, 0xaa, 0xac, 0x04, 0x83, 0x55, 0x56, 0x04, 0x86, 0xaa, 0xab, 0x04, 0x8d, 0x55, 0x55, 0x84, 0x8a, 0xaa, 0xaa, 0xc4, 0x95, 0x5f, 0xd5, 0x44, 0x9a, 0xb0, 0x6a, 0xe4, 0xb5, 0x67, 0x35, 0x64, 0xaa, 0xcf, 0x9a, 0xb4, 0xb5, 0x5c, 0x55, 0x74, 0xaa, 0xd8, 0x5a, 0xb4, 0xb5, 0x58, 0x55, 0x74, 0xaa, 0xc8, 0x9a, 0xb4, 0xb5, 0x67, 0x35, 0x74, 0x9a, 0xb0, 0x6a, 0xf4, 0x95, 0x5f, 0xd5, 0x64, 0x8a, 0xaa, 0xaa, 0xe4, 0x8d, 0x55, 0x55, 0xc4, 0x86, 0xaa, 0xab, 0xc4, 0x83, 0x55, 0x57, 0x84, 0x81, 0xaa, 0xaf, 0x04, 0x80, 0xf5, 0x7e, 0x04, 0x80, 0x3f, 0xf8, 0x04, 0x80, 0x0f, 0xe0, 0x04, 0xff, 0xff, 0xff, 0xfc, 0x80, 0x00, 0x00, 0x04, 0x80, 0x1f, 0xf0, 0x04, 0x7f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, 0, 0 }; // Tables for converting bin<->BCD static const uint8 bin2bcd[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 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, 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 }; static const uint8 bcd2bin[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 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 }; // Struct for each drive struct cdrom_drive_info { cdrom_drive_info() : num(0), fh(NULL), start_byte(0), status(0) {} cdrom_drive_info(void *fh_) : num(0), fh(fh_), start_byte(0), status(0) {} void close_fh(void) { SysAllowRemoval(fh); Sys_close(fh); } int num; // Drive number void *fh; // File handle int block_size; // CD-ROM block size int twok_offset; // Offset of beginning of 2K block to last Prime position loff_t start_byte; // Start of HFS partition on disk bool to_be_mounted; // Flag: drive must be mounted in accRun bool mount_non_hfs; // Flag: Issue disk-inserted events for non-HFS disks uint8 toc[804]; // TOC of currently inserted disk uint8 lead_out[3]; // MSF address of lead-out track uint8 stop_at[3]; // MSF address of audio play stopping point uint8 play_mode; // Audio play mode uint8 power_mode; // Power mode uint32 status; // Mac address of drive status record }; // List of drives handled by this driver typedef vector drive_vec; static drive_vec drives; // Icon address (Mac address space, set by PatchROM()) uint32 CDROMIconAddr; // Flag: Control(accRun) has been called, interrupt routine is now active static bool acc_run_called = false; /* * Get pointer to drive info or drives.end() if not found */ static drive_vec::iterator get_drive_info(int num) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { if (info->num == num) return info; } return info; } /* * Find HFS partition, set info->start_byte (0 = no HFS partition) */ static void find_hfs_partition(cdrom_drive_info &info) { info.start_byte = 0; uint8 *map = new uint8[512]; D(bug("Looking for HFS partitions on CD-ROM...\n")); // Search first 64 blocks for HFS partition for (int i=0; i<64; i++) { if (Sys_read(info.fh, map, i * 512, 512) != 512) break; D(bug(" block %d, signature '%c%c' (%02x%02x)\n", i, map[0], map[1], map[0], map[1])); // Not a partition map block? Then look at next block uint16 sig = (map[0] << 8) | map[1]; if (sig != 0x504d) continue; // Partition map block found, Apple HFS partition? if (strcmp((char *)(map + 48), "Apple_HFS") == 0) { info.start_byte = (loff_t)((map[8] << 24) | (map[9] << 16) | (map[10] << 8) | map[11]) << 9; uint32 num_blocks = (map[12] << 24) | (map[13] << 16) | (map[14] << 8) | map[15]; D(bug(" HFS partition found at %d, %d blocks\n", info.start_byte, num_blocks)); break; } } delete[] map; } /* * Read TOC of disk and set lead_out */ static void read_toc(cdrom_drive_info &info) { // Read TOC memset(info.toc, 0, sizeof(info.toc)); SysCDReadTOC(info.fh, info.toc); #if DEBUG // Dump TOC for debugging D(bug(" TOC:\n %02x%02x%02x%02x : %d bytes, first track = %d, last track = %d\n", info.toc[0], info.toc[1], info.toc[2], info.toc[3], (info.toc[0] << 8) | info.toc[1], info.toc[2], info.toc[3])); for (int i=4; i<804; i+=8) { D(bug(" %02x%02x%02x%02x%02x%02x%02x%02x: ", info.toc[i+0], info.toc[i+1], info.toc[i+2], info.toc[i+3], info.toc[i+4], info.toc[i+5], info.toc[i+6], info.toc[i+7])); const char *type = (info.toc[i+2] == 0xaa ? "lead-out" : (info.toc[i+1] & 0x04 ? "data" : "audio")); D(bug("track %d (%s), addr/ctrl 0x%02x, M %d S %d F %d\n", info.toc[i+2], type, info.toc[i+1], info.toc[i+5], info.toc[i+6], info.toc[i+7])); if (info.toc[i+2] == 0xaa) break; } #endif // Find lead-out track info.lead_out[0] = 0; info.lead_out[1] = 0; info.lead_out[2] = 0; for (int i=4; i<804; i+=8) { if (info.toc[i+2] == 0xaa) { info.stop_at[0] = info.lead_out[0] = info.toc[i+5]; info.stop_at[1] = info.lead_out[1] = info.toc[i+6]; info.stop_at[2] = info.lead_out[2] = info.toc[i+7]; break; } } D(bug(" Lead-Out M %d S %d F %d\n", info.lead_out[0], info.lead_out[1], info.lead_out[2])); } /* * Convert audio positioning type/position to MSF address * Return: false = error */ static bool position2msf(const cdrom_drive_info &info, uint16 postype, uint32 pos, bool stopping, uint8 &m, uint8 &s, uint8 &f) { switch (postype) { case 0: m = pos / (60 * 75); s = (pos / 75) % 60; f = pos % 75; return true; case 1: m = bcd2bin[(pos >> 16) & 0xff]; s = bcd2bin[(pos >> 8) & 0xff]; f = bcd2bin[pos & 0xff]; return true; case 2: { uint8 track = bcd2bin[pos & 0xff]; if (stopping) track++; for (int i=4; i<804; i+=8) { if (info.toc[i+2] == track || info.toc[i+2] == 0xaa) { m = info.toc[i+5]; s = info.toc[i+6]; f = info.toc[i+7]; return true; } } return false; } default: return false; } } /* * Initialization */ void CDROMInit(void) { // No drives specified in prefs? Then add defaults if (PrefsFindString("cdrom", 0) == NULL) SysAddCDROMPrefs(); // Add drives specified in preferences int index = 0; const char *str; while ((str = PrefsFindString("cdrom", index++)) != NULL) { void *fh = Sys_open(str, true); if (fh) drives.push_back(cdrom_drive_info(fh)); } } /* * Deinitialization */ void CDROMExit(void) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) info->close_fh(); drives.clear(); } /* * Disk was inserted, flag for mounting */ bool CDROMMountVolume(void *fh) { drive_vec::iterator info = drives.begin(), end = drives.end(); while (info != end && info->fh != fh) ++info; if (info != end) { if (SysIsDiskInserted(info->fh)) { SysPreventRemoval(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 1); read_toc(*info); find_hfs_partition(*info); if (info->start_byte != 0 || info->mount_non_hfs) info->to_be_mounted = true; } return true; } else return false; } /* * Mount volumes for which the to_be_mounted flag is set * (called during interrupt time) */ static void mount_mountable_volumes(void) { drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { // Disk in drive? if (ReadMacInt8(info->status + dsDiskInPlace) == 0) { // No, check if disk was inserted if (SysIsDiskInserted(info->fh)) CDROMMountVolume(info->fh); } // Mount disk if flagged if (info->to_be_mounted) { D(bug(" mounting drive %d\n", info->num)); M68kRegisters r; r.d[0] = info->num; r.a[0] = 7; // diskEvent Execute68kTrap(0xa02f, &r); // PostEvent() info->to_be_mounted = false; } } } /* * Driver Open() routine */ int16 CDROMOpen(uint32 pb, uint32 dce) { D(bug("CDROMOpen\n")); // Set up DCE WriteMacInt32(dce + dCtlPosition, 0); acc_run_called = false; // Install drives drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { info->num = FindFreeDriveNumber(1); info->to_be_mounted = false; if (info->fh) { info->mount_non_hfs = true; info->block_size = 512; info->twok_offset = -1; info->play_mode = 0x09; info->power_mode = 0; // Allocate drive status record M68kRegisters r; r.d[0] = SIZEOF_DrvSts; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) continue; info->status = r.a[0]; D(bug(" DrvSts at %08lx\n", info->status)); // Set up drive status WriteMacInt8(info->status + dsWriteProt, 0x80); WriteMacInt8(info->status + dsInstalled, 1); WriteMacInt8(info->status + dsSides, 1); // Disk in drive? if (SysIsDiskInserted(info->fh)) { SysPreventRemoval(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 1); read_toc(*info); find_hfs_partition(*info); info->to_be_mounted = true; } // Add drive to drive queue D(bug(" adding drive %d\n", info->num)); r.d[0] = (info->num << 16) | (CDROMRefNum & 0xffff); r.a[0] = info->status + dsQLink; Execute68kTrap(0xa04e, &r); // AddDrive() } } return noErr; } /* * Driver Prime() routine */ int16 CDROMPrime(uint32 pb, uint32 dce) { WriteMacInt32(pb + ioActCount, 0); // Drive valid and disk inserted? drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); if (info == drives.end()) return nsDrvErr; if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; // Get parameters void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer)); size_t length = ReadMacInt32(pb + ioReqCount); loff_t position = ReadMacInt32(dce + dCtlPosition); if ((length & (info->block_size - 1)) || (position & (info->block_size - 1))) return paramErr; info->twok_offset = (position + info->start_byte) & 0x7ff; size_t actual = 0; if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) { // Read actual = Sys_read(info->fh, buffer, position + info->start_byte, length); if (actual != length) { // Read error, tried to read HFS root block? if (length == 0x200 && position == 0x400) { // Yes, fake (otherwise audio CDs won't get mounted) memset(buffer, 0, 0x200); actual = 0x200; } else return readErr; } } else return wPrErr; // Update ParamBlock and DCE WriteMacInt32(pb + ioActCount, actual); WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual); return noErr; } /* * Driver Control() routine */ int16 CDROMControl(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("CDROMControl %d\n", code)); // General codes switch (code) { case 1: // KillIO return noErr; case 65: { // Periodic action (accRun, "insert" disks on startup) mount_mountable_volumes(); WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000); // Disable periodic action acc_run_called = true; return noErr; } case 81: // Set poll freq WriteMacInt16(dce + dCtlDelay, ReadMacInt16(pb + csParam)); return noErr; } // Drive valid? drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); if (info == drives.end()) { if (drives.empty()) return nsDrvErr; else info = drives.begin(); // This is needed for Apple's Audio CD program } // Drive-specific codes switch (code) { case 5: // VerifyTheDisc if (ReadMacInt8(info->status + dsDiskInPlace) > 0) return noErr; else return offLinErr; case 6: // FormatTheDisc return writErr; case 7: // EjectTheDisc if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { SysAllowRemoval(info->fh); SysEject(info->fh); WriteMacInt8(info->status + dsDiskInPlace, 0); info->twok_offset = -1; } return noErr; case 21: // GetDriveIcon case 22: // GetMediaIcon WriteMacInt32(pb + csParam, CDROMIconAddr); return noErr; case 23: // drive_info WriteMacInt32(pb + csParam, 0x00000b01); // Unspecified external removable SCSI disk return noErr; case 70: { // SetPowerMode uint8 mode = ReadMacInt8(pb + csParam); if (mode > 3) return paramErr; else { info->power_mode = mode; return noErr; } } case 76: // ModifyPostEvent info->mount_non_hfs = ReadMacInt16(pb + csParam); return noErr; case 79: { // Change block size uint16 size = ReadMacInt16(pb + csParam); D(bug(" change block size to %d bytes\n", size)); if (size != 512 && size != 2048) return paramErr; else { info->block_size = size; return noErr; } } case 80: // SetUserEject if (ReadMacInt8(info->status + dsDiskInPlace) > 0) { if (ReadMacInt16(pb + csParam) == 1) SysAllowRemoval(info->fh); else SysPreventRemoval(info->fh); return noErr; } else return offLinErr; case 100: { // ReadTOC if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; int action = ReadMacInt16(pb + csParam); D(bug(" read TOC %d\n", action)); switch (action) { case 1: // Get first/last track number WriteMacInt8(pb + csParam, bin2bcd[info->toc[2]]); WriteMacInt8(pb + csParam + 1, bin2bcd[info->toc[3]]); WriteMacInt16(pb + csParam + 2, 0); break; case 2: // Get lead out MSF starting address WriteMacInt8(pb + csParam, bin2bcd[info->lead_out[0]]); WriteMacInt8(pb + csParam + 1, bin2bcd[info->lead_out[1]]); WriteMacInt8(pb + csParam + 2, bin2bcd[info->lead_out[2]]); WriteMacInt8(pb + csParam + 3, 0); break; case 3: { // Get track starting address uint32 buf = ReadMacInt32(pb + csParam + 2); uint16 buf_size = ReadMacInt16(pb + csParam + 6); int track = bcd2bin[ReadMacInt8(pb + csParam + 8)]; // Search start track in TOC int i; for (i=4; i<804; i+=8) { if (info->toc[i+2] == track) break; } // Fill buffer if (i != 804) while (buf_size > 0) { WriteMacInt8(buf, info->toc[i+1] & 0x0f); buf++; // Control WriteMacInt8(buf, bin2bcd[info->toc[i+5]]); buf++; // M WriteMacInt8(buf, bin2bcd[info->toc[i+6]]); buf++; // S WriteMacInt8(buf, bin2bcd[info->toc[i+7]]); buf++; // F // Lead-Out? Then stop if (info->toc[i+2] == 0xaa) break; buf_size -= 4; i += 8; } break; } case 5: // Get session information WriteMacInt16(pb + csParam, 1); // First session number WriteMacInt16(pb + csParam + 2, 1); // Last session number WriteMacInt16(pb + csParam + 4, bin2bcd[info->toc[2]]); // First track number of last session WriteMacInt8(pb + csParam + 6, info->toc[5] & 0x0f); // Control WriteMacInt8(pb + csParam + 7, bin2bcd[info->toc[9]]); // M WriteMacInt8(pb + csParam + 8, bin2bcd[info->toc[10]]); // S WriteMacInt8(pb + csParam + 9, bin2bcd[info->toc[11]]); // F break; default: printf("FATAL: .AppleCD/Control(100): unimplemented TOC type\n"); return paramErr; } return noErr; } case 101: { // ReadTheQSubcode if (ReadMacInt8(info->status + dsDiskInPlace) == 0) { Mac_memset(pb + csParam, 0, 10); return offLinErr; } uint8 pos[16]; if (SysCDGetPosition(info->fh, pos)) { uint32 p = pb + csParam; WriteMacInt8(p, pos[5] & 0x0f); p++; // Control WriteMacInt8(p, bin2bcd[pos[6]]); p++; // Track number WriteMacInt8(p, bin2bcd[pos[7]]); p++; // Index number WriteMacInt8(p, bin2bcd[pos[13]]); p++; // M (rel) WriteMacInt8(p, bin2bcd[pos[14]]); p++; // S (rel) WriteMacInt8(p, bin2bcd[pos[15]]); p++; // F (rel) WriteMacInt8(p, bin2bcd[pos[9]]); p++; // M (abs) WriteMacInt8(p, bin2bcd[pos[10]]); p++; // S (abs) WriteMacInt8(p, bin2bcd[pos[11]]); p++; // F (abs) WriteMacInt8(p, 0); return noErr; } else return ioErr; } case 102: // ReadHeader printf("FATAL: .AppleCD/Control(102): unimplemented call\n"); return controlErr; case 103: { // AudioTrackSearch D(bug(" AudioTrackSearch postype %d, pos %08x, hold %d\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), ReadMacInt16(pb + csParam + 6))); if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; uint8 start_m, start_s, start_f; if (!position2msf(*info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f)) return paramErr; info->play_mode = ReadMacInt8(pb + csParam + 9) & 0x0f; if (!SysCDPlay(info->fh, start_m, start_s, start_f, info->stop_at[0], info->stop_at[1], info->stop_at[2])) return paramErr; if (ReadMacInt16(pb + csParam + 6) == 0) // Hold SysCDPause(info->fh); return noErr; } case 104: // AudioPlay D(bug(" AudioPlay postype %d, pos %08lx, hold %d\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), ReadMacInt16(pb + csParam + 6))); if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; if (ReadMacInt16(pb + csParam + 6)) { // Given stopping address if (!position2msf(*info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), true, info->stop_at[0], info->stop_at[1], info->stop_at[2])) return paramErr; } else { // Given starting address uint8 start_m, start_s, start_f; if (!position2msf(*info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f)) return paramErr; info->play_mode = ReadMacInt8(pb + csParam + 9) & 0x0f; if (!SysCDPlay(info->fh, start_m, start_s, start_f, info->stop_at[0], info->stop_at[1], info->stop_at[2])) return paramErr; } return noErr; case 105: // AudioPause if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; switch (ReadMacInt32(pb + csParam)) { case 0: if (!SysCDResume(info->fh)) return paramErr; break; case 1: if (!SysCDPause(info->fh)) return paramErr; break; default: return paramErr; } return noErr; case 106: // AudioStop D(bug(" AudioStop postype %d, pos %08lx\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2))); if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; if (ReadMacInt16(pb + csParam) == 0 && ReadMacInt32(pb + csParam + 2) == 0) { // Stop immediately if (!SysCDStop(info->fh, info->lead_out[0], info->lead_out[1], info->lead_out[2])) return paramErr; } else { // Given stopping address if (!position2msf(*info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), true, info->stop_at[0], info->stop_at[1], info->stop_at[2])) return paramErr; } return noErr; case 107: { // AudioStatus if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; uint8 pos[16]; if (!SysCDGetPosition(info->fh, pos)) return paramErr; uint32 p = pb + csParam; switch (pos[1]) { case 0x11: WriteMacInt8(p, 0); // Audio play in progress break; case 0x12: WriteMacInt8(p, 1); // Audio play paused break; case 0x13: WriteMacInt8(p, 3); // Audio play completed break; case 0x14: WriteMacInt8(p, 4); // Error occurred break; default: WriteMacInt8(p, 5); // No audio play operation requested break; } p++; WriteMacInt8(p, info->play_mode); p++; WriteMacInt8(p, pos[5] & 0x0f); p++; // Control WriteMacInt8(p, bin2bcd[pos[9]]); p++; // M (abs) WriteMacInt8(p, bin2bcd[pos[10]]); p++; // S (abs) WriteMacInt8(p, bin2bcd[pos[11]]); p++; // F (abs) return noErr; } case 108: { // AudioScan if (ReadMacInt8(info->status + dsDiskInPlace) == 0) return offLinErr; uint8 start_m, start_s, start_f; if (!position2msf(*info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f)) return paramErr; if (!SysCDScan(info->fh, start_m, start_s, start_f, ReadMacInt16(pb + csParam + 6))) return paramErr; else return noErr; } case 109: // AudioControl SysCDSetVolume(info->fh, ReadMacInt8(pb + csParam), ReadMacInt8(pb + csParam + 1)); return noErr; case 110: // ReadMCN printf("FATAL: .AppleCD/Control(110): unimplemented call\n"); return controlErr; case 111: // ReadISRC printf("FATAL: .AppleCD/Control(111): unimplemented call\n"); return controlErr; case 112: { // ReadAudioVolume uint8 left, right; SysCDGetVolume(info->fh, left, right); WriteMacInt8(pb + csParam, left); WriteMacInt8(pb + csParam + 1, right); return noErr; } case 113: // GetSpindleSpeed WriteMacInt16(pb + csParam, 0xff); return noErr; case 114: // SetSpindleSpeed return noErr; case 115: // ReadAudio printf("FATAL: .AppleCD/Control(115): unimplemented call\n"); return controlErr; case 116: // ReadAllSubcodes printf("FATAL: .AppleCD/Control(116): unimplemented call\n"); return controlErr; case 122: // SetTrackList printf("FATAL: .AppleCD/Control(122): unimplemented call\n"); return controlErr; case 123: // GetTrackList printf("FATAL: .AppleCD/Control(123): unimplemented call\n"); return controlErr; case 124: // GetTrackIndex printf("FATAL: .AppleCD/Control(124): unimplemented call\n"); return controlErr; case 125: // SetPlayMode D(bug(" SetPlayMode %04x\n", ReadMacInt16(pb + csParam))); printf("FATAL: .AppleCD/Control(125): unimplemented call\n"); return controlErr; case 126: // GetPlayMode (Apple's Audio CD program needs this) WriteMacInt16(pb + csParam, 0); return noErr; default: printf("WARNING: Unknown CDROMControl(%d)\n", code); return controlErr; } } /* * Driver Status() routine */ int16 CDROMStatus(uint32 pb, uint32 dce) { drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum)); uint16 code = ReadMacInt16(pb + csCode); D(bug("CDROMStatus %d\n", code)); // General codes (we can get these even if the drive was invalid) switch (code) { case 43: { // DriverGestalt uint32 sel = ReadMacInt32(pb + csParam); D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel)); switch (sel) { case FOURCC('v','e','r','s'): // Version WriteMacInt32(pb + csParam + 4, 0x05208000); break; case FOURCC('d','e','v','t'): // Device type WriteMacInt32(pb + csParam + 4, FOURCC('c','d','r','m')); break; case FOURCC('i','n','t','f'): // Interface type WriteMacInt32(pb + csParam + 4, EMULATOR_ID_4); break; case FOURCC('s','y','n','c'): // Only synchronous operation? WriteMacInt32(pb + csParam + 4, 0x01000000); break; case FOURCC('b','o','o','t'): // Boot ID if (info != drives.end()) WriteMacInt16(pb + csParam + 4, info->num); else WriteMacInt16(pb + csParam + 4, 0); WriteMacInt16(pb + csParam + 6, (uint16)CDROMRefNum); break; case FOURCC('w','i','d','e'): // 64-bit access supported? WriteMacInt16(pb + csParam + 4, 0); break; case FOURCC('p','u','r','g'): // Purge flags WriteMacInt32(pb + csParam + 4, 0); break; case FOURCC('e','j','e','c'): // Eject flags WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart break; case FOURCC('f','l','u','s'): // Flush flags WriteMacInt16(pb + csParam + 4, 0); break; case FOURCC('v','m','o','p'): // Virtual memory attributes WriteMacInt32(pb + csParam + 4, 0); // Drive not available for VM break; default: return statusErr; } return noErr; } case 97: { // WhoIsThere uint8 drives_present = 0; drive_vec::iterator info, end = drives.end(); for (info = drives.begin(); info != end; ++info) { if (info->num <= 6) drives_present |= (1 << info->num); } WriteMacInt8(pb + csParam + 1, drives_present); return noErr; } } // Drive valid? if (info == drives.end()) { if (drives.empty()) return nsDrvErr; else info = drives.begin(); // This is needed for Apple's Audio CD program } // Drive-specific codes switch (code) { case 6: // Return format list if (ReadMacInt16(pb + csParam) > 0) { uint32 adr = ReadMacInt32(pb + csParam + 2); WriteMacInt16(pb + csParam, 1); // 1 format WriteMacInt32(adr, SysGetFileSize(info->fh) / 512); // Number of blocks WriteMacInt32(adr + 4, 0); // heads/track/sectors return noErr; } else return paramErr; case 8: // DriveStatus Mac2Mac_memcpy(pb + csParam, info->status, 22); return noErr; case 70: // GetPowerMode WriteMacInt16(pb + csParam, info->power_mode << 8); return noErr; case 95: // Get2KOffset if (info->twok_offset > 0) { WriteMacInt16(pb + csParam, info->twok_offset); return noErr; } else return statusErr; case 96: // Get drive type WriteMacInt16(pb + csParam, 3); // Apple CD 300 or newer return noErr; case 98: // Get block size WriteMacInt16(pb + csParam, info->block_size); return noErr; case 120: // Return device ident WriteMacInt32(pb + csParam, 0); return noErr; case 121: // Get CD features WriteMacInt16(pb + csParam, 0x0200); // 300 KB/s WriteMacInt16(pb + csParam + 2, 0x0c00); // SCSI-2, stereo return noErr; default: printf("WARNING: Unknown CDROMStatus(%d)\n", code); return statusErr; } } /* * Driver interrupt routine (1Hz) - check for volumes to be mounted */ void CDROMInterrupt(void) { if (!acc_run_called) return; mount_mountable_volumes(); } BasiliskII/src/scsi.cpp0000644000175000017500000001623510736405217015211 0ustar centriscentris/* * scsi.cpp - SCSI Manager * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 3 "SCSI Manager" * Technote DV 24: "Fear No SCSI" */ #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "user_strings.h" #include "scsi.h" #define DEBUG 0 #include "debug.h" // Error codes enum { scCommErr = 2, scArbNBErr, scBadParmsErr, scPhaseErr, scCompareErr, scMgrBusyErr, scSequenceErr, scBusTOErr, scComplPhaseErr }; // TIB opcodes enum { scInc = 1, scNoInc, scAdd, scMove, scLoop, scNop, scStop, scComp }; // Logical SCSI phases enum { PH_FREE, // Bus free PH_ARBITRATED, // Bus arbitrated (after SCSIGet()) PH_SELECTED, // Target selected (after SCSISelect()) PH_TRANSFER // Command sent (after SCSICmd()) }; // Global variables static int target_id; // ID of active target static int phase; // Logical SCSI phase static uint16 fake_status; // Faked 5830 status word static bool reading; // Flag: reading from device const int SG_TABLE_SIZE = 1024; static int sg_index; // Index of first unused entry in S/G table static uint8 *sg_ptr[SG_TABLE_SIZE]; // Scatter/gather table data pointer (host address space) static uint32 sg_len[SG_TABLE_SIZE]; // Scatter/gather table data length static uint32 sg_total_length; // Total data length /* * Execute TIB, constructing S/G table */ static int16 exec_tib(uint32 tib) { for (;;) { // Read next opcode and parameters uint16 cmd = ReadMacInt16(tib); tib += 2; uint32 ptr = ReadMacInt32(tib); tib += 4; uint32 len = ReadMacInt32(tib); tib += 4; #if DEBUG const char *cmd_str; switch (cmd) { case scInc: cmd_str = "INC "; break; case scNoInc: cmd_str = "NOINC"; break; case scAdd: cmd_str = "ADD "; break; case scMove: cmd_str = "MOVE "; break; case scLoop: cmd_str = "LOOP "; break; case scNop: cmd_str = "NOP "; break; case scStop: cmd_str = "STOP "; break; case scComp: cmd_str = "COMP "; break; default: cmd_str = "??? "; break; } D(bug(" %s(%d) %08x %d\n", cmd_str, cmd, ptr, len)); #endif switch (cmd) { case scInc: WriteMacInt32(tib - 8, ptr + len); case scNoInc: if ((sg_index > 0) && (Mac2HostAddr(ptr) == sg_ptr[sg_index-1] + sg_len[sg_index-1])) sg_len[sg_index-1] += len; // Merge to previous entry else { if (sg_index == SG_TABLE_SIZE) { ErrorAlert(GetString(STR_SCSI_SG_FULL_ERR)); return -108; } sg_ptr[sg_index] = Mac2HostAddr(ptr); // Create new entry sg_len[sg_index] = len; sg_index++; } sg_total_length += len; break; case scAdd: WriteMacInt32(ptr, ReadMacInt32(ptr) + len); break; case scMove: WriteMacInt32(len, ReadMacInt32(ptr)); break; case scLoop: WriteMacInt32(tib - 4, len - 1); if (len - 1 > 0) tib += (int32)ptr - 10; break; case scNop: break; case scStop: return 0; case scComp: printf("WARNING: Unimplemented scComp opcode\n"); return scCompareErr; default: printf("FATAL: Unrecognized TIB opcode %d\n", cmd); return scBadParmsErr; } } } /* * Reset SCSI bus */ int16 SCSIReset(void) { D(bug("SCSIReset\n")); phase = PH_FREE; fake_status = 0x0000; // Bus free sg_index = 0; target_id = 8; return 0; } /* * Arbitrate bus */ int16 SCSIGet(void) { D(bug("SCSIGet\n")); if (phase != PH_FREE) return scMgrBusyErr; phase = PH_ARBITRATED; fake_status = 0x0040; // Bus busy reading = false; sg_index = 0; // Flush S/G table sg_total_length = 0; return 0; } /* * Select SCSI device */ int16 SCSISelect(int id) { D(bug("SCSISelect %d\n", id)); if (phase != PH_ARBITRATED) return scSequenceErr; // ID valid? if (id >= 0 && id <= 7) { target_id = id; // Target present? if (scsi_is_target_present(target_id)) { phase = PH_SELECTED; fake_status = 0x006a; // Target selected, command phase return 0; } } // Error phase = PH_FREE; fake_status = 0x0000; // Bus free return scCommErr; } /* * Send SCSI command */ int16 SCSICmd(int cmd_length, uint8 *cmd) { #if DEBUG switch (cmd_length) { case 6: D(bug("SCSICmd len 6, cmd %02x %02x %02x %02x %02x %02x\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5])); break; case 10: D(bug("SCSICmd len 10, cmd %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9])); break; case 12: D(bug("SCSICmd len 12, cmd %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], cmd[9], cmd[10], cmd[11])); break; default: D(bug("SCSICmd bogus length %d\n", cmd_length)); break; } #endif if (phase != PH_SELECTED) return scPhaseErr; // Commdn length valid? if (cmd_length != 6 && cmd_length != 10 && cmd_length != 12) return scBadParmsErr; // Set command, extract LUN scsi_set_cmd(cmd_length, cmd); // Extract LUN, set target if (!scsi_set_target(target_id, (cmd[1] >> 5) & 7)) { phase = PH_FREE; fake_status = 0x0000; // Bus free return scCommErr; } phase = PH_TRANSFER; fake_status = 0x006e; // Target selected, data phase return 0; } /* * Read data */ int16 SCSIRead(uint32 tib) { D(bug("SCSIRead TIB %08lx\n", tib)); if (phase != PH_TRANSFER) return scPhaseErr; // Execute TIB, fill S/G table reading = true; return exec_tib(tib); } /* * Write data */ int16 SCSIWrite(uint32 tib) { D(bug("SCSIWrite TIB %08lx\n", tib)); if (phase != PH_TRANSFER) return scPhaseErr; // Execute TIB, fill S/G table return exec_tib(tib); } /* * Wait for command completion (we're actually doing everything in here...) */ int16 SCSIComplete(uint32 timeout, uint32 message, uint32 stat) { D(bug("SCSIComplete wait %d, msg %08lx, stat %08lx\n", timeout, message, stat)); WriteMacInt16(message, 0); if (phase != PH_TRANSFER) return scPhaseErr; // Send command, process S/G table uint16 scsi_stat = 0; bool success = scsi_send_cmd(sg_total_length, reading, sg_index, sg_ptr, sg_len, &scsi_stat, timeout); WriteMacInt16(stat, scsi_stat); // Complete command phase = PH_FREE; fake_status = 0x0000; // Bus free return success ? 0 : scCommErr; } /* * Get bus status */ uint16 SCSIStat(void) { D(bug("SCSIStat returns %04x\n", fake_status)); return fake_status; } /* * SCSI Manager busy? */ int16 SCSIMgrBusy(void) { // D(bug("SCSIMgrBusy\n")); return phase != PH_FREE; } BasiliskII/src/user_strings.cpp0000644000175000017500000002155010736405217016773 0ustar centriscentris/* * user_strings.cpp - Common localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * NOTES: * * This should only be used for user-interface related messages that must be * translated or transcibed for localized versions of Basilisk. * It should NOT be used for: * - file names * - names of threads, areas, ports, semaphores, drivers, views and other "invisible" names * - debugging messages * - error messages that only go to the shell ("FATAL"/"WARNING", those are really debugging messages) */ #include "sysdeps.h" #include "user_strings.h" #ifdef __BEOS__ #define ELLIPSIS "\xE2\x80\xA6" #else #define ELLIPSIS "..." #endif // Common string definitions user_string_def common_strings[] = { {STR_ABOUT_TEXT1, "Basilisk II V%d.%d"}, {STR_ABOUT_TEXT2, "by Christian Bauer et al."}, {STR_READING_ROM_FILE, "Reading ROM file...\n"}, {STR_SHELL_ERROR_PREFIX, "ERROR: %s\n"}, {STR_GUI_ERROR_PREFIX, "Basilisk II error:\n%s"}, {STR_ERROR_ALERT_TITLE, "Basilisk II Error"}, {STR_SHELL_WARNING_PREFIX, "WARNING: %s\n"}, {STR_GUI_WARNING_PREFIX, "Basilisk II warning:\n%s"}, {STR_WARNING_ALERT_TITLE, "Basilisk II Warning"}, {STR_NOTICE_ALERT_TITLE, "Basilisk II Notice"}, {STR_ABOUT_TITLE, "About Basilisk II"}, {STR_OK_BUTTON, "OK"}, {STR_START_BUTTON, "Start"}, {STR_QUIT_BUTTON, "Quit"}, {STR_CANCEL_BUTTON, "Cancel"}, {STR_NO_MEM_ERR, "Not enough free memory."}, {STR_NOT_ENOUGH_MEMORY_ERR, "Your computer does not have enough memory to run Basilisk II."}, {STR_NO_RAM_AREA_ERR, "Not enough memory to create RAM area."}, {STR_NO_ROM_AREA_ERR, "Not enough memory to create ROM area."}, {STR_NO_ROM_FILE_ERR, "Cannot open ROM file."}, {STR_ROM_FILE_READ_ERR, "Cannot read ROM file."}, {STR_ROM_SIZE_ERR, "Invalid ROM file size. Basilisk II requires a 512K or 1MB MacII ROM."}, {STR_UNSUPPORTED_ROM_TYPE_ERR, "Unsupported ROM type."}, {STR_OPEN_WINDOW_ERR, "Cannot open Mac window."}, {STR_OPEN_SCREEN_ERR, "Cannot open Mac screen."}, {STR_SCSI_BUFFER_ERR, "Cannot allocate SCSI buffer (requested %d bytes). Giving up."}, {STR_SCSI_SG_FULL_ERR, "SCSI scatter/gather table full. Giving up."}, {STR_SMALL_RAM_WARN, "Selected less than 1MB Mac RAM, using 1MB."}, {STR_CREATE_VOLUME_WARN, "Cannot create hardfile (%s)."}, {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted. Basilisk II will try to unmount it."}, {STR_CANNOT_UNMOUNT_WARN, "The volume '%s' could not be unmounted. Basilisk II will not use it."}, {STR_PREFS_TITLE, "Basilisk II Settings"}, {STR_PREFS_MENU, "Settings"}, {STR_PREFS_ITEM_ABOUT, "About Basilisk II" ELLIPSIS}, {STR_PREFS_ITEM_START, "Start Basilisk II"}, {STR_PREFS_ITEM_ZAP_PRAM, "Zap PRAM File"}, {STR_PREFS_ITEM_QUIT, "Quit Basilisk II"}, {STR_NONE_LAB, ""}, {STR_VOLUMES_PANE_TITLE, "Volumes"}, {STR_VOLUMES_CTRL, "Mac Volumes"}, {STR_ADD_VOLUME_BUTTON, "Add" ELLIPSIS}, {STR_CREATE_VOLUME_BUTTON, "Create" ELLIPSIS}, {STR_EDIT_VOLUME_BUTTON, "Edit" ELLIPSIS}, {STR_REMOVE_VOLUME_BUTTON, "Remove"}, {STR_ADD_VOLUME_PANEL_BUTTON, "Add"}, {STR_CREATE_VOLUME_PANEL_BUTTON, "Create"}, {STR_CDROM_DRIVE_CTRL, "CD-ROM Drive"}, {STR_BOOTDRIVER_CTRL, "Boot From"}, {STR_BOOT_ANY_LAB, "Any"}, {STR_BOOT_CDROM_LAB, "CD-ROM"}, {STR_NOCDROM_CTRL, "Disable CD-ROM Driver"}, {STR_EXTFS_CTRL, "Host Root"}, {STR_DEVICE_CTRL, "Device"}, {STR_UNIT_CTRL, "Unit"}, {STR_ADD_VOLUME_TITLE, "Add Volume"}, {STR_CREATE_VOLUME_TITLE, "Create Hardfile"}, {STR_EDIT_VOLUME_TITLE, "Edit Volume"}, {STR_HARDFILE_SIZE_CTRL, "Size (MB)"}, {STR_VOL_READONLY_CTRL, "Read-Only"}, {STR_VOL_TYPE_CTRL, "Type"}, {STR_VOL_FILE_LAB, "File"}, {STR_VOL_DEVICE_LAB, "Device"}, {STR_VOL_OPENFLAGS_CTRL, "Open Flags"}, {STR_VOL_STARTBLOCK_CTRL, "Start Block"}, {STR_VOL_SIZE_CTRL, "Size (Blocks)"}, {STR_VOL_BLOCKSIZE_CTRL, "Block Size"}, {STR_VOL_FILE_CTRL, "File"}, {STR_SCSI_PANE_TITLE, "SCSI"}, {STR_SCSI_ID_0, "ID 0"}, {STR_SCSI_ID_1, "ID 1"}, {STR_SCSI_ID_2, "ID 2"}, {STR_SCSI_ID_3, "ID 3"}, {STR_SCSI_ID_4, "ID 4"}, {STR_SCSI_ID_5, "ID 5"}, {STR_SCSI_ID_6, "ID 6"}, {STR_GRAPHICS_SOUND_PANE_TITLE, "Graphics/Sound"}, {STR_GRAPHICS_CTRL, "Graphics"}, {STR_VIDEO_TYPE_CTRL, "Video Type"}, {STR_WINDOW_LAB, "Window"}, {STR_FULLSCREEN_LAB, "Fullscreen"}, {STR_PIP_LAB, "PIP"}, {STR_FRAMESKIP_CTRL, "Window Refresh Rate"}, {STR_REF_5HZ_LAB, "5 Hz"}, {STR_REF_7_5HZ_LAB, "7.5 Hz"}, {STR_REF_10HZ_LAB, "10 Hz"}, {STR_REF_15HZ_LAB, "15 Hz"}, {STR_REF_30HZ_LAB, "30 Hz"}, {STR_REF_60HZ_LAB, "60 Hz"}, {STR_REF_DYNAMIC_LAB, "Dynamic"}, {STR_DISPLAY_X_CTRL, "Width"}, {STR_DISPLAY_Y_CTRL, "Height"}, {STR_SIZE_384_LAB, "384"}, {STR_SIZE_480_LAB, "480"}, {STR_SIZE_512_LAB, "512"}, {STR_SIZE_600_LAB, "600"}, {STR_SIZE_640_LAB, "640"}, {STR_SIZE_768_LAB, "768"}, {STR_SIZE_800_LAB, "800"}, {STR_SIZE_1024_LAB, "1024"}, {STR_SIZE_MAX_LAB, "Maximum"}, {STR_COLOR_DEPTH_CTRL, "Color Depth"}, {STR_1_BIT_LAB, "B/W (1 Bit)"}, {STR_2_BIT_LAB, "4 (2 Bit)"}, {STR_4_BIT_LAB, "16 (4 Bit)"}, {STR_8_BIT_LAB, "256 (8 Bit)"}, {STR_15_BIT_LAB, "Thousands (15 Bit)"}, {STR_24_BIT_LAB, "Millions (24 Bit)"}, {STR_SCREEN_MODE_CTRL, "Screen Mode"}, {STR_8_BIT_640x480_LAB, "640x480, 8 Bit"}, {STR_8_BIT_800x600_LAB, "800x600, 8 Bit"}, {STR_8_BIT_1024x768_LAB, "1024x768, 8 Bit"}, {STR_8_BIT_1152x900_LAB, "1152x900, 8 Bit"}, {STR_8_BIT_1280x1024_LAB, "1280x1024, 8 Bit"}, {STR_8_BIT_1600x1200_LAB, "1600x1200, 8 Bit"}, {STR_15_BIT_640x480_LAB, "640x480, 15 Bit"}, {STR_15_BIT_800x600_LAB, "800x600, 15 Bit"}, {STR_15_BIT_1024x768_LAB, "1024x768, 15 Bit"}, {STR_15_BIT_1152x900_LAB, "1152x900, 15 Bit"}, {STR_15_BIT_1280x1024_LAB, "1280x1024, 15 Bit"}, {STR_15_BIT_1600x1200_LAB, "1600x1200, 15 Bit"}, {STR_24_BIT_640x480_LAB, "640x480, 24 Bit"}, {STR_24_BIT_800x600_LAB, "800x600, 24 Bit"}, {STR_24_BIT_1024x768_LAB, "1024x768, 24 Bit"}, {STR_24_BIT_1152x900_LAB, "1152x900, 24 Bit"}, {STR_24_BIT_1280x1024_LAB, "1280x1024, 24 Bit"}, {STR_24_BIT_1600x1200_LAB, "1600x1200, 24 Bit"}, {STR_SOUND_CTRL, "Sound"}, {STR_NOSOUND_CTRL, "Disable Sound Output"}, {STR_SERIAL_NETWORK_PANE_TITLE, "Serial/Network"}, {STR_SERIALA_CTRL, "Modem Port"}, {STR_SERIALB_CTRL, "Printer Port"}, {STR_ISPAR_CTRL, "Parallel Device"}, {STR_ETHER_ENABLE_CTRL, "Enable Ethernet"}, {STR_ETHERNET_IF_CTRL, "Ethernet Interface"}, {STR_UDPTUNNEL_CTRL, "Tunnel MacOS Networking over UDP"}, {STR_UDPPORT_CTRL, "UDP Port Number"}, {STR_MEMORY_MISC_PANE_TITLE, "Memory/Misc"}, {STR_RAMSIZE_CTRL, "MacOS RAM Size (MB)"}, {STR_RAMSIZE_2MB_LAB, "2"}, {STR_RAMSIZE_4MB_LAB, "4"}, {STR_RAMSIZE_8MB_LAB, "8"}, {STR_RAMSIZE_16MB_LAB, "16"}, {STR_RAMSIZE_32MB_LAB, "32"}, {STR_RAMSIZE_64MB_LAB, "64"}, {STR_RAMSIZE_128MB_LAB, "128"}, {STR_RAMSIZE_256MB_LAB, "256"}, {STR_RAMSIZE_512MB_LAB, "512"}, {STR_RAMSIZE_1024MB_LAB, "1024"}, {STR_RAMSIZE_SLIDER, "MacOS RAM Size:"}, {STR_RAMSIZE_FMT, "%ld MB"}, {STR_MODELID_CTRL, "Mac Model ID"}, {STR_MODELID_5_LAB, "Mac IIci (MacOS 7.x)"}, {STR_MODELID_14_LAB, "Quadra 900 (MacOS 8.x)"}, {STR_CPU_CTRL, "CPU Type"}, {STR_CPU_68020_LAB, "68020"}, {STR_CPU_68020_FPU_LAB, "68020 with FPU"}, {STR_CPU_68030_LAB, "68030"}, {STR_CPU_68030_FPU_LAB, "68030 with FPU"}, {STR_CPU_68040_LAB, "68040"}, {STR_ROM_FILE_CTRL, "ROM File"}, {STR_IDLEWAIT_CTRL, "Don't Use CPU When Idle"}, {STR_JIT_PANE_TITLE, "JIT Compiler"}, {STR_JIT_CTRL, "Enable JIT Compiler"}, {STR_JIT_FPU_CTRL, "Compile FPU Instructions"}, {STR_JIT_CACHE_SIZE_CTRL, "Translation Cache Size (KB)"}, {STR_JIT_CACHE_SIZE_2MB_LAB, "2048"}, {STR_JIT_CACHE_SIZE_4MB_LAB, "4096"}, {STR_JIT_CACHE_SIZE_8MB_LAB, "8192"}, {STR_JIT_CACHE_SIZE_16MB_LAB, "16384"}, {STR_JIT_LAZY_CINV_CTRL, "Enable lazy invalidation of translation cache"}, {STR_JIT_FOLLOW_CONST_JUMPS, "Translate through constant jumps (inline blocks)"}, {STR_WINDOW_TITLE, "Basilisk II"}, {STR_WINDOW_TITLE_FROZEN, "Basilisk II *** FROZEN ***"}, {STR_WINDOW_MENU, "Basilisk II"}, {STR_WINDOW_ITEM_ABOUT, "About Basilisk II" ELLIPSIS}, {STR_WINDOW_ITEM_REFRESH, "Refresh Rate"}, {STR_WINDOW_ITEM_MOUNT, "Mount"}, {STR_SUSPEND_WINDOW_TITLE, "Basilisk II suspended. Press space to reactivate."}, {STR_EXTFS_NAME, "Host Directory Tree"}, {STR_EXTFS_VOLUME_NAME, "Host"}, {-1, NULL} // End marker }; BasiliskII/src/xpram.cpp0000644000175000017500000000244011232133662015362 0ustar centriscentris/* * xpram.cpp - XPRAM handling * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Operating System Utilities, chapter 7 "Parameter RAM Utilities" */ #include #include "sysdeps.h" #include "xpram.h" // Extended parameter RAM uint8 XPRAM[XPRAM_SIZE]; /* * Initialize XPRAM */ void XPRAMInit(const char *vmdir) { // Clear XPRAM memset(XPRAM, 0, XPRAM_SIZE); // Load XPRAM from settings file LoadXPRAM(vmdir); } /* * Deinitialize XPRAM */ void XPRAMExit(void) { // Save XPRAM to settings file SaveXPRAM(); } BasiliskII/src/uae_cpu/0000755000175000017500000000000011735674751015171 5ustar centriscentrisBasiliskII/src/uae_cpu/fpu/0000755000175000017500000000000011735674761015764 5ustar centriscentrisBasiliskII/src/uae_cpu/fpu/rounding.cpp0000644000175000017500000000400010736405224020271 0ustar centriscentris/* * fpu/rounding.cpp - system-dependant FPU rounding mode and precision * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #undef PRIVATE #define PRIVATE /**/ #undef PUBLIC #define PUBLIC /**/ #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* -------------------------------------------------------------------------- */ /* --- Native X86 Rounding Mode --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_X86_ROUNDING_MODE const uae_u32 FFPU x86_control_word_rm_mac2host[] = { CW_RC_NEAR, CW_RC_ZERO, CW_RC_DOWN, CW_RC_UP }; #endif /* -------------------------------------------------------------------------- */ /* --- Native X86 Rounding Precision --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_X86_ROUNDING_PRECISION const uae_u32 FFPU x86_control_word_rp_mac2host[] = { CW_PC_EXTENDED, CW_PC_SINGLE, CW_PC_DOUBLE, CW_PC_RESERVED }; #endif BasiliskII/src/uae_cpu/fpu/fpu_ieee.h0000644000175000017500000001011310736405224017674 0ustar centriscentris/* * fpu/fpu_uae.h - Extra Definitions for the old UAE FPU core * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_IEEE_H #define FPU_IEEE_H /* NOTE: this file shall be included from fpu/fpu_uae.cpp */ #undef PUBLIC #define PUBLIC extern #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. // Lauri-- full words to avoid partial register stalls. struct double_flags { uae_u32 in_range; uae_u32 zero; uae_u32 infinity; uae_u32 nan; uae_u32 negative; }; PRIVATE double_flags fl_source; PRIVATE double_flags fl_dest; PRIVATE inline void FFPU get_dest_flags(fpu_register const & r); PRIVATE inline void FFPU get_source_flags(fpu_register const & r); PRIVATE inline void FFPU make_nan(fpu_register & r); PRIVATE inline void FFPU make_zero_positive(fpu_register & r); PRIVATE inline void FFPU make_zero_negative(fpu_register & r); PRIVATE inline void FFPU make_inf_positive(fpu_register & r); PRIVATE inline void FFPU make_inf_negative(fpu_register & r); PRIVATE inline void FFPU fast_scale(fpu_register & r, int add); PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r); // May be optimized for particular processors #ifndef FPU_USE_NATIVE_FLAGS PRIVATE inline void FFPU make_fpsr(fpu_register const & r); #endif // Normalize to range 1..2 PRIVATE inline void FFPU fast_remove_exponent(fpu_register & r); // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. PRIVATE inline uae_u32 FFPU get_quotient_sign( fpu_register const & ra, fpu_register const & rb ); // Quotient Byte is loaded with the sign and least significant // seven bits of the quotient. PRIVATE inline void FFPU make_quotient( fpu_register const & quotient, uae_u32 sign ); // to_single PRIVATE inline fpu_register FFPU make_single( uae_u32 value ); // from_single PRIVATE inline uae_u32 FFPU extract_single( fpu_register const & src ); // to_exten PRIVATE inline fpu_register FFPU make_extended( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3 ); /* Would be so much easier with full size floats :( ... this is so vague. */ // to_exten_no_normalize PRIVATE inline void FFPU make_extended_no_normalize( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & result ); // from_exten PRIVATE inline void FFPU extract_extended(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 ); // to_double PRIVATE inline fpu_register FFPU make_double( uae_u32 wrd1, uae_u32 wrd2 ); // from_double PRIVATE inline void FFPU extract_double(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2 ); PRIVATE inline fpu_register FFPU make_packed( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3 ); PRIVATE inline void FFPU extract_packed( fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 ); PRIVATE inline int FFPU get_fp_value( uae_u32 opcode, uae_u16 extra, fpu_register & src ); PRIVATE inline int FFPU put_fp_value( uae_u32 opcode, uae_u16 extra, fpu_register const & value ); PRIVATE inline int FFPU get_fp_ad( uae_u32 opcode, uae_u32 * ad ); PRIVATE inline int FFPU fpp_cond( int condition ); #endif /* FPU_IEEE_H */ BasiliskII/src/uae_cpu/fpu/fpu.h0000644000175000017500000000271410736405224016715 0ustar centriscentris/* * fpu/fpu.h - public header * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_PUBLIC_HEADER_H #define FPU_PUBLIC_HEADER_H #ifndef FPU_DEBUG #define FPU_DEBUG 0 #endif #if FPU_DEBUG #define fpu_debug(args) printf args; #define FPU_DUMP_REGISTERS 0 #define FPU_DUMP_FIRST_BYTES 0 #else #define fpu_debug(args) ; #undef FPU_DUMP_REGISTERS #undef FPU_DUMP_FIRST_BYTES #endif #include "sysdeps.h" #include "fpu/types.h" #include "fpu/core.h" #endif /* FPU_PUBLIC_HEADER_H */ BasiliskII/src/uae_cpu/fpu/flags.cpp0000644000175000017500000001416110736405224017551 0ustar centriscentris/* * fpu/flags.cpp - Floating-point flags * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ /* NOTE: this file shall be included only from fpu/fpu_*.cpp */ #undef PRIVATE #define PRIVATE /**/ #undef PUBLIC #define PUBLIC /**/ #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* -------------------------------------------------------------------------- */ /* --- Native X86 floating-point flags --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_X86_FLAGS /* Initialization */ void FFPU fpu_init_native_fflags(void) { // Adapted from fpu_x86.cpp #define SW_Z_I_NAN_MASK (SW_C0|SW_C2|SW_C3) #define SW_Z (SW_C3) #define SW_I (SW_C0|SW_C2) #define SW_NAN (SW_C0) #define SW_FINITE (SW_C2) #define SW_EMPTY_REGISTER (SW_C0|SW_C3) #define SW_DENORMAL (SW_C2|SW_C3) #define SW_UNSUPPORTED (0) #define SW_N (SW_C1) // Sanity checks #if (SW_Z != NATIVE_FFLAG_ZERO) #error "Incorrect X86 Z fflag" #endif #if (SW_I != NATIVE_FFLAG_INFINITY) #error "Incorrect X86 I fflag" #endif #if (SW_N != NATIVE_FFLAG_NEGATIVE) #error "Incorrect X86 N fflag" #endif #if (SW_NAN != NATIVE_FFLAG_NAN) #error "Incorrect X86 NAN fflag" #endif // Native status word to m68k mappings for (uae_u32 i = 0; i < 0x48; i++) { to_m68k_fpcond[i] = 0; const uae_u32 native_fpcond = i << 8; switch (native_fpcond & SW_Z_I_NAN_MASK) { #ifndef FPU_UAE // gb-- enabling it would lead to incorrect drawing of digits // in Speedometer Performance Test case SW_UNSUPPORTED: #endif case SW_NAN: case SW_EMPTY_REGISTER: to_m68k_fpcond[i] |= FPSR_CCB_NAN; break; case SW_FINITE: case SW_DENORMAL: break; case SW_I: to_m68k_fpcond[i] |= FPSR_CCB_INFINITY; break; case SW_Z: to_m68k_fpcond[i] |= FPSR_CCB_ZERO; break; } if (native_fpcond & SW_N) to_m68k_fpcond[i] |= FPSR_CCB_NEGATIVE; } // m68k to native status word mappings for (uae_u32 i = 0; i < 0x10; i++) { const uae_u32 m68k_fpcond = i << 24; if (m68k_fpcond & FPSR_CCB_NAN) to_host_fpcond[i] = SW_NAN; else if (m68k_fpcond & FPSR_CCB_ZERO) to_host_fpcond[i] = SW_Z; else if (m68k_fpcond & FPSR_CCB_INFINITY) to_host_fpcond[i] = SW_I; else to_host_fpcond[i] = SW_FINITE; if (m68k_fpcond & FPSR_CCB_NEGATIVE) to_host_fpcond[i] |= SW_N; } // truth-table for FPU conditions for (uae_u32 host_fpcond = 0; host_fpcond < 0x08; host_fpcond++) { // host_fpcond: C3 on bit 2, C1 and C0 are respectively on bits 1 and 0 const uae_u32 real_host_fpcond = ((host_fpcond & 4) << 12) | ((host_fpcond & 3) << 8); const bool N = ((real_host_fpcond & NATIVE_FFLAG_NEGATIVE) == NATIVE_FFLAG_NEGATIVE); const bool Z = ((real_host_fpcond & NATIVE_FFLAG_ZERO) == NATIVE_FFLAG_ZERO); const bool NaN = ((real_host_fpcond & NATIVE_FFLAG_NAN) == NATIVE_FFLAG_NAN); int value; for (uae_u32 m68k_fpcond = 0; m68k_fpcond < 0x20; m68k_fpcond++) { switch (m68k_fpcond) { case 0x00: value = 0; break; // False case 0x01: value = Z; break; // Equal case 0x02: value = !(NaN || Z || N); break; // Ordered Greater Than case 0x03: value = Z || !(NaN || N); break; // Ordered Greater Than or Equal case 0x04: value = N && !(NaN || Z); break; // Ordered Less Than case 0x05: value = Z || (N && !NaN); break; // Ordered Less Than or Equal case 0x06: value = !(NaN || Z); break; // Ordered Greater or Less Than case 0x07: value = !NaN; break; // Ordered case 0x08: value = NaN; break; // Unordered case 0x09: value = NaN || Z; break; // Unordered or Equal case 0x0a: value = NaN || !(N || Z); break; // Unordered or Greater Than case 0x0b: value = NaN || Z || !N; break; // Unordered or Greater or Equal case 0x0c: value = NaN || (N && !Z); break; // Unordered or Less Than case 0x0d: value = NaN || Z || N; break; // Unordered or Less or Equal case 0x0e: value = !Z; break; // Not Equal case 0x0f: value = 1; break; // True case 0x10: value = 0; break; // Signaling False case 0x11: value = Z; break; // Signaling Equal case 0x12: value = !(NaN || Z || N); break; // Greater Than case 0x13: value = Z || !(NaN || N); break; // Greater Than or Equal case 0x14: value = N && !(NaN || Z); break; // Less Than case 0x15: value = Z || (N && !NaN); break; // Less Than or Equal case 0x16: value = !(NaN || Z); break; // Greater or Less Than case 0x17: value = !NaN; break; // Greater, Less or Equal case 0x18: value = NaN; break; // Not Greater, Less or Equal case 0x19: value = NaN || Z; break; // Not Greater or Less Than case 0x1a: value = NaN || !(N || Z); break; // Not Less Than or Equal case 0x1b: value = NaN || Z || !N; break; // Not Less Than case 0x1c: value = NaN || (N && !Z); break; // Not Greater Than or Equal // case 0x1c: value = !Z && (NaN || N); break; // Not Greater Than or Equal case 0x1d: value = NaN || Z || N; break; // Not Greater Than case 0x1e: value = !Z; break; // Signaling Not Equal case 0x1f: value = 1; break; // Signaling True default: value = -1; } fpcond_truth_table[m68k_fpcond][host_fpcond] = value; } } } #endif BasiliskII/src/uae_cpu/fpu/flags.h0000644000175000017500000001627010736405224017221 0ustar centriscentris/* * fpu/flags.h - Floating-point flags * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_FLAGS_H #define FPU_FLAGS_H /* NOTE: this file shall be included only from fpu/fpu_*.cpp */ #undef PUBLIC #define PUBLIC extern #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* Defaults to generic flags */ #define FPU_USE_GENERIC_FLAGS /* -------------------------------------------------------------------------- */ /* --- Selection of floating-point flags handling mode --- */ /* -------------------------------------------------------------------------- */ /* Optimized i386 fpu core must use native flags */ #if defined(FPU_X86) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_FLAGS # define FPU_USE_X86_FLAGS #endif /* Old UAE FPU core can use native flags */ #if defined(FPU_UAE) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_FLAGS # define FPU_USE_X86_FLAGS #endif /* IEEE-based implementation must use lazy flag evaluation */ #if defined(FPU_IEEE) # undef FPU_USE_GENERIC_FLAGS # define FPU_USE_LAZY_FLAGS #endif /* JIT Compilation for FPU only works with lazy evaluation of FPU flags */ #if defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) && defined(USE_JIT_FPU) # undef FPU_USE_GENERIC_FLAGS # define FPU_USE_LAZY_FLAGS #endif #ifdef FPU_IMPLEMENTATION /* -------------------------------------------------------------------------- */ /* --- Native X86 Floating-Point Flags --- */ /* -------------------------------------------------------------------------- */ /* FPU_X86 has its own set of lookup functions */ #ifdef FPU_USE_X86_FLAGS #define FPU_USE_NATIVE_FLAGS #define NATIVE_FFLAG_NEGATIVE 0x0200 #define NATIVE_FFLAG_ZERO 0x4000 #define NATIVE_FFLAG_INFINITY 0x0500 #define NATIVE_FFLAG_NAN 0x0100 /* Translation tables between native and m68k floating-point flags */ PRIVATE uae_u32 to_m68k_fpcond[0x48]; PRIVATE uae_u32 to_host_fpcond[0x10]; /* Truth table for floating-point condition codes */ PRIVATE uae_u32 fpcond_truth_table[32][8]; // 32 m68k conditions x 8 host condition codes /* Initialization */ PUBLIC void FFPU fpu_init_native_fflags(void); #ifdef FPU_UAE /* Native to m68k floating-point condition codes */ PRIVATE inline uae_u32 FFPU get_fpccr(void) { return to_m68k_fpcond[(FPU fpsr.condition_codes >> 8) & 0x47]; } /* M68k to native floating-point condition codes */ PRIVATE inline void FFPU set_fpccr(uae_u32 new_fpcond) /* Precondition: new_fpcond is only valid for floating-point condition codes */ { FPU fpsr.condition_codes = to_host_fpcond[new_fpcond >> 24]; } /* Make FPSR according to the value passed in argument */ PRIVATE inline void FFPU make_fpsr(fpu_register const & r) { uae_u16 sw; __asm__ __volatile__ ("fxam\n\tfnstsw %0" : "=r" (sw) : "f" (r)); FPU fpsr.condition_codes = sw; } /* Return the corresponding ID of the current floating-point condition codes */ /* NOTE: only valid for evaluation of a condition */ PRIVATE inline int FFPU host_fpcond_id(void) { return ((FPU fpsr.condition_codes >> 12) & 4) | ((FPU fpsr.condition_codes >> 8) & 3); } /* Return true if the floating-point condition is satisfied */ PRIVATE inline bool FFPU fpcctrue(int condition) { return fpcond_truth_table[condition][host_fpcond_id()]; } #endif /* FPU_UAE */ /* Return the address of the floating-point condition codes truth table */ static inline uae_u8 * const FFPU address_of_fpcond_truth_table(void) { return ((uae_u8*)&fpcond_truth_table[0][0]); } #endif /* FPU_X86_USE_NATIVE_FLAGS */ /* -------------------------------------------------------------------------- */ /* --- Use Original M68K FPU Mappings --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_GENERIC_FLAGS #undef FPU_USE_NATIVE_FLAGS #define NATIVE_FFLAG_NEGATIVE 0x08000000 #define NATIVE_FFLAG_ZERO 0x04000000 #define NATIVE_FFLAG_INFINITY 0x02000000 #define NATIVE_FFLAG_NAN 0x01000000 /* Initialization - NONE */ PRIVATE inline void FFPU fpu_init_native_fflags(void) { } /* Native to m68k floating-point condition codes - SELF */ PRIVATE inline uae_u32 FFPU get_fpccr(void) { return FPU fpsr.condition_codes; } /* M68k to native floating-point condition codes - SELF */ PRIVATE inline void FFPU set_fpccr(uae_u32 new_fpcond) { FPU fpsr.condition_codes = new_fpcond; } #endif /* FPU_USE_GENERIC_FLAGS */ /* -------------------------------------------------------------------------- */ /* --- Use Lazy Flags Evaluation --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_LAZY_FLAGS #undef FPU_USE_NATIVE_FLAGS #define NATIVE_FFLAG_NEGATIVE 0x08000000 #define NATIVE_FFLAG_ZERO 0x04000000 #define NATIVE_FFLAG_INFINITY 0x02000000 #define NATIVE_FFLAG_NAN 0x01000000 /* Initialization - NONE */ PRIVATE inline void FFPU fpu_init_native_fflags(void) { } /* Native to m68k floating-point condition codes - SELF */ PRIVATE inline uae_u32 FFPU get_fpccr(void) { uae_u32 fpccr = 0; if (isnan(FPU result)) fpccr |= FPSR_CCB_NAN; else if (FPU result == 0.0) fpccr |= FPSR_CCB_ZERO; else if (FPU result < 0.0) fpccr |= FPSR_CCB_NEGATIVE; if (isinf(FPU result)) fpccr |= FPSR_CCB_INFINITY; return fpccr; } /* M68k to native floating-point condition codes - SELF */ PRIVATE inline void FFPU set_fpccr(uae_u32 new_fpcond) { if (new_fpcond & FPSR_CCB_NAN) make_nan(FPU result); else if (new_fpcond & FPSR_CCB_ZERO) FPU result = 0.0; else if (new_fpcond & FPSR_CCB_NEGATIVE) FPU result = -1.0; else FPU result = +1.0; /* gb-- where is Infinity ? */ } /* Make FPSR according to the value passed in argument */ PRIVATE inline void FFPU make_fpsr(fpu_register const & r) { FPU result = r; } #endif /* FPU_USE_LAZY_FLAGS */ #endif /* -------------------------------------------------------------------------- */ /* --- Common methods --- */ /* -------------------------------------------------------------------------- */ /* Return the address of the floating-point condition codes register */ static inline uae_u32 * const FFPU address_of_fpccr(void) { return ((uae_u32 *)& FPU fpsr.condition_codes); } #endif /* FPU_FLAGS_H */ BasiliskII/src/uae_cpu/fpu/mathlib.h0000644000175000017500000006634610736405224017556 0ustar centriscentris/* * fpu/mathlib.h - Floating-point math support library * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2001 Lauri Pesonen * New framework, copyright 2000-2001 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 * * 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 */ #ifndef FPU_MATHLIB_H #define FPU_MATHLIB_H /* NOTE: this file shall be included only from fpu/fpu_*.cpp */ #undef PUBLIC #define PUBLIC extern #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. // Define the following macro if branches are expensive. If so, // integer-based isnan() and isinf() functions are implemented. // TODO: move to Makefile.in #define BRANCHES_ARE_EXPENSIVE 1 // Use ISO C99 extended-precision math functions (glibc 2.1+) #define FPU_USE_ISO_C99 1 // NOTE: this is irrelevant on Win32 platforms since the MS libraries // don't support extended-precision floating-point computations #ifdef WIN32 #undef FPU_USE_ISO_C99 #endif // Use faster implementation of math functions, but this could cause // some incorrect results (?) // TODO: actually implement the slower but safer versions #define FPU_FAST_MATH 1 #if FPU_USE_ISO_C99 // NOTE: no prior shall be included at this point #define __USE_ISOC99 1 // for glibc 2.2.X and newer #define __USE_ISOC9X 1 // for glibc 2.1.X #include #else #include using namespace std; #endif /* -------------------------------------------------------------------------- */ /* --- Floating-point register types --- */ /* -------------------------------------------------------------------------- */ // Single : S 8*E 23*F #define FP_SINGLE_EXP_MAX 0xff #define FP_SINGLE_EXP_BIAS 0x7f // Double : S 11*E 52*F #define FP_DOUBLE_EXP_MAX 0x7ff #define FP_DOUBLE_EXP_BIAS 0x3ff // Extended : S 15*E 64*F #define FP_EXTENDED_EXP_MAX 0x7fff #define FP_EXTENDED_EXP_BIAS 0x3fff // Zeroes : E = 0 & F = 0 // Infinities : E = MAX & F = 0 // Not-A-Number : E = MAX & F # 0 /* -------------------------------------------------------------------------- */ /* --- Floating-point type shapes (IEEE-compliant) --- */ /* -------------------------------------------------------------------------- */ // Taken from glibc 2.2.x: ieee754.h // IEEE-754 float format union fpu_single_shape { fpu_single value; /* This is the IEEE 754 single-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:8; unsigned int mantissa:23; #else unsigned int mantissa:23; unsigned int exponent:8; unsigned int negative:1; #endif } ieee; /* This format makes it easier to see if a NaN is a signalling NaN. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:8; unsigned int quiet_nan:1; unsigned int mantissa:22; #else unsigned int mantissa:22; unsigned int quiet_nan:1; unsigned int exponent:8; unsigned int negative:1; #endif } ieee_nan; }; // IEEE-754 double format union fpu_double_shape { fpu_double value; /* This is the IEEE 754 double-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:11; /* Together these comprise the mantissa. */ unsigned int mantissa0:20; unsigned int mantissa1:32; #else # if HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int mantissa0:20; unsigned int exponent:11; unsigned int negative:1; unsigned int mantissa1:32; # else /* Together these comprise the mantissa. */ unsigned int mantissa1:32; unsigned int mantissa0:20; unsigned int exponent:11; unsigned int negative:1; # endif #endif } ieee; /* This format makes it easier to see if a NaN is a signalling NaN. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:11; unsigned int quiet_nan:1; /* Together these comprise the mantissa. */ unsigned int mantissa0:19; unsigned int mantissa1:32; #else # if HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int mantissa0:19; unsigned int quiet_nan:1; unsigned int exponent:11; unsigned int negative:1; unsigned int mantissa1:32; # else /* Together these comprise the mantissa. */ unsigned int mantissa1:32; unsigned int mantissa0:19; unsigned int quiet_nan:1; unsigned int exponent:11; unsigned int negative:1; # endif #endif } ieee_nan; /* This format is used to extract the sign_exponent and mantissa parts only */ struct { #if HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int msw:32; unsigned int lsw:32; #else unsigned int lsw:32; unsigned int msw:32; #endif } parts; }; #ifdef USE_LONG_DOUBLE // IEEE-854 long double format union fpu_extended_shape { fpu_extended value; /* This is the IEEE 854 double-extended-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:15; unsigned int empty:16; unsigned int mantissa0:32; unsigned int mantissa1:32; #else # if HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int exponent:15; unsigned int negative:1; unsigned int empty:16; unsigned int mantissa0:32; unsigned int mantissa1:32; # else unsigned int mantissa1:32; unsigned int mantissa0:32; unsigned int exponent:15; unsigned int negative:1; unsigned int empty:16; # endif #endif } ieee; /* This is for NaNs in the IEEE 854 double-extended-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:15; unsigned int empty:16; unsigned int one:1; unsigned int quiet_nan:1; unsigned int mantissa0:30; unsigned int mantissa1:32; #else # if HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int exponent:15; unsigned int negative:1; unsigned int empty:16; unsigned int mantissa0:30; unsigned int quiet_nan:1; unsigned int one:1; unsigned int mantissa1:32; # else unsigned int mantissa1:32; unsigned int mantissa0:30; unsigned int quiet_nan:1; unsigned int one:1; unsigned int exponent:15; unsigned int negative:1; unsigned int empty:16; # endif #endif } ieee_nan; /* This format is used to extract the sign_exponent and mantissa parts only */ struct { #if HOST_FLOAT_WORDS_BIG_ENDIAN unsigned int sign_exponent:16; unsigned int empty:16; unsigned int msw:32; unsigned int lsw:32; #else unsigned int lsw:32; unsigned int msw:32; unsigned int sign_exponent:16; unsigned int empty:16; #endif } parts; }; #endif #ifdef USE_QUAD_DOUBLE // IEEE-854 quad double format union fpu_extended_shape { fpu_extended value; /* This is the IEEE 854 quad-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:15; unsigned int mantissa0:16; unsigned int mantissa1:32; unsigned int mantissa2:32; unsigned int mantissa3:32; #else unsigned int mantissa3:32; unsigned int mantissa2:32; unsigned int mantissa1:32; unsigned int mantissa0:16; unsigned int exponent:15; unsigned int negative:1; #endif } ieee; /* This is for NaNs in the IEEE 854 quad-precision format. */ struct { #ifdef WORDS_BIGENDIAN unsigned int negative:1; unsigned int exponent:15; unsigned int quiet_nan:1; unsigned int mantissa0:15; unsigned int mantissa1:30; unsigned int mantissa2:32; unsigned int mantissa3:32; #else unsigned int mantissa3:32; unsigned int mantissa2:32; unsigned int mantissa1:32; unsigned int mantissa0:15; unsigned int quiet_nan:1; unsigned int exponent:15; unsigned int negative:1; #endif } ieee_nan; /* This format is used to extract the sign_exponent and mantissa parts only */ #if HOST_FLOAT_WORDS_BIG_ENDIAN struct { uae_u64 msw; uae_u64 lsw; } parts64; struct { uae_u32 w0; uae_u32 w1; uae_u32 w2; uae_u32 w3; } parts32; #else struct { uae_u64 lsw; uae_u64 msw; } parts64; struct { uae_u32 w3; uae_u32 w2; uae_u32 w1; uae_u32 w0; } parts32; #endif }; #endif // Declare and initialize a pointer to a shape of the requested FP type #define fp_declare_init_shape(psvar, rfvar, ftype) \ fpu_ ## ftype ## _shape * psvar = (fpu_ ## ftype ## _shape *)( &rfvar ) /* -------------------------------------------------------------------------- */ /* --- Extra Math Functions --- */ /* --- (most of them had to be defined before including ) --- */ /* -------------------------------------------------------------------------- */ #undef isnan #if 0 && defined(HAVE_ISNANL) # define isnan(x) isnanl((x)) #else # define isnan(x) fp_do_isnan((x)) #endif PRIVATE inline bool FFPU fp_do_isnan(fpu_register const & r) { #ifdef BRANCHES_ARE_EXPENSIVE #ifndef USE_LONG_DOUBLE fp_declare_init_shape(sxp, r, double); uae_s32 hx = sxp->parts.msw; uae_s32 lx = sxp->parts.lsw; hx &= 0x7fffffff; hx |= (uae_u32)(lx | (-lx)) >> 31; hx = 0x7ff00000 - hx; return (int)(((uae_u32)hx) >> 31); #elif USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); uae_s64 hx = sxp->parts64.msw; uae_s64 lx = sxp->parts64.lsw; hx &= 0x7fffffffffffffffLL; hx |= (uae_u64)(lx | (-lx)) >> 63; hx = 0x7fff000000000000LL - hx; return (int)((uae_u64)hx >> 63); #else fp_declare_init_shape(sxp, r, extended); uae_s32 se = sxp->parts.sign_exponent; uae_s32 hx = sxp->parts.msw; uae_s32 lx = sxp->parts.lsw; se = (se & 0x7fff) << 1; lx |= hx & 0x7fffffff; se |= (uae_u32)(lx | (-lx)) >> 31; se = 0xfffe - se; // TODO: check whether rshift count is 16 or 31 return (int)(((uae_u32)(se)) >> 16); #endif #else #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); return (sxp->ieee_nan.exponent == FP_EXTENDED_EXP_MAX) #else fp_declare_init_shape(sxp, r, double); return (sxp->ieee_nan.exponent == FP_DOUBLE_EXP_MAX) #endif && (sxp->ieee_nan.mantissa0 != 0) && (sxp->ieee_nan.mantissa1 != 0) #ifdef USE_QUAD_DOUBLE && (sxp->ieee_nan.mantissa2 != 0) && (sxp->ieee_nan.mantissa3 != 0) #endif ; #endif } #undef isinf #if 0 && defined(HAVE_ISINFL) # define isinf(x) isinfl((x)) #else # define isinf(x) fp_do_isinf((x)) #endif PRIVATE inline bool FFPU fp_do_isinf(fpu_register const & r) { #ifdef BRANCHES_ARE_EXPENSIVE #ifndef USE_LONG_DOUBLE fp_declare_init_shape(sxp, r, double); uae_s32 hx = sxp->parts.msw; uae_s32 lx = sxp->parts.lsw; lx |= (hx & 0x7fffffff) ^ 0x7ff00000; lx |= -lx; return ~(lx >> 31) & (hx >> 30); #elif USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); uae_s64 hx = sxp->parts64.msw; uae_s64 lx = sxp->parts64.lsw; lx |= (hx & 0x7fffffffffffffffLL) ^ 0x7fff000000000000LL; lx |= -lx; return ~(lx >> 63) & (hx >> 62); #else fp_declare_init_shape(sxp, r, extended); uae_s32 se = sxp->parts.sign_exponent; uae_s32 hx = sxp->parts.msw; uae_s32 lx = sxp->parts.lsw; /* This additional ^ 0x80000000 is necessary because in Intel's internal representation of the implicit one is explicit. NOTE: anyway, this is equivalent to & 0x7fffffff in that case. */ #ifdef __i386__ lx |= (hx ^ 0x80000000) | ((se & 0x7fff) ^ 0x7fff); #else lx |= (hx & 0x7fffffff) | ((se & 0x7fff) ^ 0x7fff); #endif lx |= -lx; se &= 0x8000; return ~(lx >> 31) & (1 - (se >> 14)); #endif #else #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); return (sxp->ieee_nan.exponent == FP_EXTENDED_EXP_MAX) #else fp_declare_init_shape(sxp, r, double); return (sxp->ieee_nan.exponent == FP_DOUBLE_EXP_MAX) #endif && (sxp->ieee_nan.mantissa0 == 0) && (sxp->ieee_nan.mantissa1 == 0) #ifdef USE_QUAD_DOUBLE && (sxp->ieee_nan.mantissa2 == 0) && (sxp->ieee_nan.mantissa3 == 0) #endif ; #endif } #undef isneg #define isneg(x) fp_do_isneg((x)) PRIVATE inline bool FFPU fp_do_isneg(fpu_register const & r) { #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); #else fp_declare_init_shape(sxp, r, double); #endif return sxp->ieee.negative; } #undef iszero #define iszero(x) fp_do_iszero((x)) PRIVATE inline bool FFPU fp_do_iszero(fpu_register const & r) { // TODO: BRANCHES_ARE_EXPENSIVE #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); #else fp_declare_init_shape(sxp, r, double); #endif return (sxp->ieee.exponent == 0) && (sxp->ieee.mantissa0 == 0) && (sxp->ieee.mantissa1 == 0) #ifdef USE_QUAD_DOUBLE && (sxp->ieee.mantissa2 == 0) && (sxp->ieee.mantissa3 == 0) #endif ; } PRIVATE inline void FFPU get_dest_flags(fpu_register const & r) { fl_dest.negative = isneg(r); fl_dest.zero = iszero(r); fl_dest.infinity = isinf(r); fl_dest.nan = isnan(r); fl_dest.in_range = !fl_dest.zero && !fl_dest.infinity && !fl_dest.nan; } PRIVATE inline void FFPU get_source_flags(fpu_register const & r) { fl_source.negative = isneg(r); fl_source.zero = iszero(r); fl_source.infinity = isinf(r); fl_source.nan = isnan(r); fl_source.in_range = !fl_source.zero && !fl_source.infinity && !fl_source.nan; } PRIVATE inline void FFPU make_nan(fpu_register & r) { // FIXME: is that correct ? #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); sxp->ieee.exponent = FP_EXTENDED_EXP_MAX; sxp->ieee.mantissa0 = 0xffffffff; #else fp_declare_init_shape(sxp, r, double); sxp->ieee.exponent = FP_DOUBLE_EXP_MAX; sxp->ieee.mantissa0 = 0xfffff; #endif sxp->ieee.mantissa1 = 0xffffffff; #ifdef USE_QUAD_DOUBLE sxp->ieee.mantissa2 = 0xffffffff; sxp->ieee.mantissa3 = 0xffffffff; #endif } PRIVATE inline void FFPU make_zero_positive(fpu_register & r) { #if 1 r = +0.0; #else #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); #else fp_declare_init_shape(sxp, r, double); #endif sxp->ieee.negative = 0; sxp->ieee.exponent = 0; sxp->ieee.mantissa0 = 0; sxp->ieee.mantissa1 = 0; #ifdef USE_QUAD_DOUBLE sxp->ieee.mantissa2 = 0; sxp->ieee.mantissa3 = 0; #endif #endif } PRIVATE inline void FFPU make_zero_negative(fpu_register & r) { #if 1 r = -0.0; #else #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); #else fp_declare_init_shape(sxp, r, double); #endif sxp->ieee.negative = 1; sxp->ieee.exponent = 0; sxp->ieee.mantissa0 = 0; sxp->ieee.mantissa1 = 0; #ifdef USE_QUAD_DOUBLE sxp->ieee.mantissa2 = 0; sxp->ieee.mantissa3 = 0; #endif #endif } PRIVATE inline void FFPU make_inf_positive(fpu_register & r) { #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); sxp->ieee_nan.exponent = FP_EXTENDED_EXP_MAX; #else fp_declare_init_shape(sxp, r, double); sxp->ieee_nan.exponent = FP_DOUBLE_EXP_MAX; #endif sxp->ieee_nan.negative = 0; sxp->ieee_nan.mantissa0 = 0; sxp->ieee_nan.mantissa1 = 0; #ifdef USE_QUAD_DOUBLE sxp->ieee_nan.mantissa2 = 0; sxp->ieee_nan.mantissa3 = 0; #endif } PRIVATE inline void FFPU make_inf_negative(fpu_register & r) { #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); sxp->ieee_nan.exponent = FP_EXTENDED_EXP_MAX; #else fp_declare_init_shape(sxp, r, double); sxp->ieee_nan.exponent = FP_DOUBLE_EXP_MAX; #endif sxp->ieee_nan.negative = 1; sxp->ieee_nan.mantissa0 = 0; sxp->ieee_nan.mantissa1 = 0; #ifdef USE_QUAD_DOUBLE sxp->ieee_nan.mantissa2 = 0; sxp->ieee_nan.mantissa3 = 0; #endif } PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r) { #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); return (sxp->ieee.exponent - FP_EXTENDED_EXP_BIAS); #else fp_declare_init_shape(sxp, r, double); return (sxp->ieee.exponent - FP_DOUBLE_EXP_BIAS); #endif } // Normalize to range 1..2 PRIVATE inline void FFPU fast_remove_exponent(fpu_register & r) { #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, r, extended); sxp->ieee.exponent = FP_EXTENDED_EXP_BIAS; #else fp_declare_init_shape(sxp, r, double); sxp->ieee.exponent = FP_DOUBLE_EXP_BIAS; #endif } // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. PRIVATE inline uae_u32 FFPU get_quotient_sign(fpu_register const & ra, fpu_register const & rb) { #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sap, ra, extended); fp_declare_init_shape(sbp, rb, extended); #else fp_declare_init_shape(sap, ra, double); fp_declare_init_shape(sbp, rb, double); #endif return ((sap->ieee.negative ^ sbp->ieee.negative) ? FPSR_QUOTIENT_SIGN : 0); } /* -------------------------------------------------------------------------- */ /* --- Math functions --- */ /* -------------------------------------------------------------------------- */ #if FPU_USE_ISO_C99 && (USE_LONG_DOUBLE || USE_QUAD_DOUBLE) # ifdef HAVE_LOGL # define fp_log logl # endif # ifdef HAVE_LOG10L # define fp_log10 log10l # endif # ifdef HAVE_EXPL # define fp_exp expl # endif # ifdef HAVE_POWL # define fp_pow powl # endif # ifdef HAVE_FABSL # define fp_fabs fabsl # endif # ifdef HAVE_SQRTL # define fp_sqrt sqrtl # endif # ifdef HAVE_SINL # define fp_sin sinl # endif # ifdef HAVE_COSL # define fp_cos cosl # endif # ifdef HAVE_TANL # define fp_tan tanl # endif # ifdef HAVE_SINHL # define fp_sinh sinhl # endif # ifdef HAVE_COSHL # define fp_cosh coshl # endif # ifdef HAVE_TANHL # define fp_tanh tanhl # endif # ifdef HAVE_ASINL # define fp_asin asinl # endif # ifdef HAVE_ACOSL # define fp_acos acosl # endif # ifdef HAVE_ATANL # define fp_atan atanl # endif # ifdef HAVE_ASINHL # define fp_asinh asinhl # endif # ifdef HAVE_ACOSHL # define fp_acosh acoshl # endif # ifdef HAVE_ATANHL # define fp_atanh atanhl # endif # ifdef HAVE_FLOORL # define fp_floor floorl # endif # ifdef HAVE_CEILL # define fp_ceil ceill # endif #endif #ifndef fp_log # define fp_log log #endif #ifndef fp_log10 # define fp_log10 log10 #endif #ifndef fp_exp # define fp_exp exp #endif #ifndef fp_pow # define fp_pow pow #endif #ifndef fp_fabs # define fp_fabs fabs #endif #ifndef fp_sqrt # define fp_sqrt sqrt #endif #ifndef fp_sin # define fp_sin sin #endif #ifndef fp_cos # define fp_cos cos #endif #ifndef fp_tan # define fp_tan tan #endif #ifndef fp_sinh # define fp_sinh sinh #endif #ifndef fp_cosh # define fp_cosh cosh #endif #ifndef fp_tanh # define fp_tanh tanh #endif #ifndef fp_asin # define fp_asin asin #endif #ifndef fp_acos # define fp_acos acos #endif #ifndef fp_atan # define fp_atan atan #endif #ifndef fp_asinh # define fp_asinh asinh #endif #ifndef fp_acosh # define fp_acosh acosh #endif #ifndef fp_atanh # define fp_atanh atanh #endif #ifndef fp_floor # define fp_floor floor #endif #ifndef fp_ceil # define fp_ceil ceil #endif #if defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) // Assembly optimized support functions. Taken from glibc 2.2.2 #undef fp_log #define fp_log fp_do_log #ifndef FPU_FAST_MATH // FIXME: unimplemented PRIVATE fpu_extended fp_do_log(fpu_extended x); #else PRIVATE inline fpu_extended fp_do_log(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fldln2; fxch; fyl2x" : "=t" (value) : "0" (x) : "st(1)"); return value; } #endif #undef fp_log10 #define fp_log10 fp_do_log10 #ifndef FPU_FAST_MATH // FIXME: unimplemented PRIVATE fpu_extended fp_do_log10(fpu_extended x); #else PRIVATE inline fpu_extended fp_do_log10(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fldlg2; fxch; fyl2x" : "=t" (value) : "0" (x) : "st(1)"); return value; } #endif #undef fp_exp #define fp_exp fp_do_exp #ifndef FPU_FAST_MATH // FIXME: unimplemented PRIVATE fpu_extended fp_do_exp(fpu_extended x); #else PRIVATE inline fpu_extended fp_do_exp(fpu_extended x) { fpu_extended value, exponent; __asm__ __volatile__("fldl2e # e^x = 2^(x * log2(e))\n\t" "fmul %%st(1) # x * log2(e)\n\t" "fst %%st(1)\n\t" "frndint # int(x * log2(e))\n\t" "fxch\n\t" "fsub %%st(1) # fract(x * log2(e))\n\t" "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" : "=t" (value), "=u" (exponent) : "0" (x)); value += 1.0; __asm__ __volatile__("fscale" : "=t" (value) : "0" (value), "u" (exponent)); return value; } #endif #undef fp_pow #define fp_pow fp_do_pow PRIVATE fpu_extended fp_do_pow(fpu_extended x, fpu_extended y); #undef fp_fabs #define fp_fabs fp_do_fabs PRIVATE inline fpu_extended fp_do_fabs(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fabs" : "=t" (value) : "0" (x)); return value; } #undef fp_sqrt #define fp_sqrt fp_do_sqrt PRIVATE inline fpu_extended fp_do_sqrt(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fsqrt" : "=t" (value) : "0" (x)); return value; } #undef fp_sin #define fp_sin fp_do_sin PRIVATE inline fpu_extended fp_do_sin(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fsin" : "=t" (value) : "0" (x)); return value; } #undef fp_cos #define fp_cos fp_do_cos PRIVATE inline fpu_extended fp_do_cos(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fcos" : "=t" (value) : "0" (x)); return value; } #undef fp_tan #define fp_tan fp_do_tan PRIVATE inline fpu_extended fp_do_tan(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fptan" : "=t" (value) : "0" (x)); return value; } #undef fp_expm1 #define fp_expm1 fp_do_expm1 // Returns: exp(X) - 1.0 PRIVATE inline fpu_extended fp_do_expm1(fpu_extended x) { fpu_extended value, exponent, temp; __asm__ __volatile__("fldl2e # e^x - 1 = 2^(x * log2(e)) - 1\n\t" "fmul %%st(1) # x * log2(e)\n\t" "fst %%st(1)\n\t" "frndint # int(x * log2(e))\n\t" "fxch\n\t" "fsub %%st(1) # fract(x * log2(e))\n\t" "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t" "fscale # 2^(x * log2(e)) - 2^(int(x * log2(e)))\n\t" : "=t" (value), "=u" (exponent) : "0" (x)); __asm__ __volatile__("fscale" : "=t" (temp) : "0" (1.0), "u" (exponent)); temp -= 1.0; return temp + value ? temp + value : x; } #undef fp_sgn1 #define fp_sgn1 fp_do_sgn1 PRIVATE inline fpu_extended fp_do_sgn1(fpu_extended x) { #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, x, extended); sxp->ieee_nan.exponent = FP_EXTENDED_EXP_MAX; sxp->ieee_nan.one = 1; #else fp_declare_init_shape(sxp, x, double); sxp->ieee_nan.exponent = FP_DOUBLE_EXP_MAX; #endif sxp->ieee_nan.quiet_nan = 0; sxp->ieee_nan.mantissa0 = 0; sxp->ieee_nan.mantissa1 = 0; return x; } #undef fp_sinh #define fp_sinh fp_do_sinh #ifndef FPU_FAST_MATH // FIXME: unimplemented PRIVATE fpu_extended fp_do_sinh(fpu_extended x); #else PRIVATE inline fpu_extended fp_do_sinh(fpu_extended x) { fpu_extended exm1 = fp_expm1(fp_fabs(x)); return 0.5 * (exm1 / (exm1 + 1.0) + exm1) * fp_sgn1(x); } #endif #undef fp_cosh #define fp_cosh fp_do_cosh #ifndef FPU_FAST_MATH // FIXME: unimplemented PRIVATE fpu_extended fp_do_cosh(fpu_extended x); #else PRIVATE inline fpu_extended fp_do_cosh(fpu_extended x) { fpu_extended ex = fp_exp(x); return 0.5 * (ex + 1.0 / ex); } #endif #undef fp_tanh #define fp_tanh fp_do_tanh #ifndef FPU_FAST_MATH // FIXME: unimplemented PRIVATE fpu_extended fp_do_tanh(fpu_extended x); #else PRIVATE inline fpu_extended fp_do_tanh(fpu_extended x) { fpu_extended exm1 = fp_expm1(-fp_fabs(x + x)); return exm1 / (exm1 + 2.0) * fp_sgn1(-x); } #endif #undef fp_atan2 #define fp_atan2 fp_do_atan2 PRIVATE inline fpu_extended fp_do_atan2(fpu_extended y, fpu_extended x) { fpu_extended value; __asm__ __volatile__("fpatan" : "=t" (value) : "0" (x), "u" (y) : "st(1)"); return value; } #undef fp_asin #define fp_asin fp_do_asin PRIVATE inline fpu_extended fp_do_asin(fpu_extended x) { return fp_atan2(x, fp_sqrt(1.0 - x * x)); } #undef fp_acos #define fp_acos fp_do_acos PRIVATE inline fpu_extended fp_do_acos(fpu_extended x) { return fp_atan2(fp_sqrt(1.0 - x * x), x); } #undef fp_atan #define fp_atan fp_do_atan PRIVATE inline fpu_extended fp_do_atan(fpu_extended x) { fpu_extended value; __asm__ __volatile__("fld1; fpatan" : "=t" (value) : "0" (x) : "st(1)"); return value; } #undef fp_log1p #define fp_log1p fp_do_log1p // Returns: ln(1.0 + X) PRIVATE fpu_extended fp_do_log1p(fpu_extended x); #undef fp_asinh #define fp_asinh fp_do_asinh PRIVATE inline fpu_extended fp_do_asinh(fpu_extended x) { fpu_extended y = fp_fabs(x); return (fp_log1p(y * y / (fp_sqrt(y * y + 1.0) + 1.0) + y) * fp_sgn1(x)); } #undef fp_acosh #define fp_acosh fp_do_acosh PRIVATE inline fpu_extended fp_do_acosh(fpu_extended x) { return fp_log(x + fp_sqrt(x - 1.0) * fp_sqrt(x + 1.0)); } #undef fp_atanh #define fp_atanh fp_do_atanh PRIVATE inline fpu_extended fp_do_atanh(fpu_extended x) { fpu_extended y = fp_fabs(x); return -0.5 * fp_log1p(-(y + y) / (1.0 + y)) * fp_sgn1(x); } #undef fp_floor #define fp_floor fp_do_floor PRIVATE inline fpu_extended fp_do_floor(fpu_extended x) { volatile unsigned int cw; __asm__ __volatile__("fnstcw %0" : "=m" (cw)); volatile unsigned int cw_temp = (cw & 0xf3ff) | 0x0400; // rounding down __asm__ __volatile__("fldcw %0" : : "m" (cw_temp)); fpu_extended value; __asm__ __volatile__("frndint" : "=t" (value) : "0" (x)); __asm__ __volatile__("fldcw %0" : : "m" (cw)); return value; } #undef fp_ceil #define fp_ceil fp_do_ceil PRIVATE inline fpu_extended fp_do_ceil(fpu_extended x) { volatile unsigned int cw; __asm__ __volatile__("fnstcw %0" : "=m" (cw)); volatile unsigned int cw_temp = (cw & 0xf3ff) | 0x0800; // rounding up __asm__ __volatile__("fldcw %0" : : "m" (cw_temp)); fpu_extended value; __asm__ __volatile__("frndint" : "=t" (value) : "0" (x)); __asm__ __volatile__("fldcw %0" : : "m" (cw)); return value; } #define DEFINE_ROUND_FUNC(rounding_mode_str, rounding_mode) \ PRIVATE inline fpu_extended fp_do_round_to_ ## rounding_mode_str(fpu_extended x) \ { \ volatile unsigned int cw; \ __asm__ __volatile__("fnstcw %0" : "=m" (cw)); \ volatile unsigned int cw_temp = (cw & 0xf3ff) | (rounding_mode); \ __asm__ __volatile__("fldcw %0" : : "m" (cw_temp)); \ fpu_extended value; \ __asm__ __volatile__("frndint" : "=t" (value) : "0" (x)); \ __asm__ __volatile__("fldcw %0" : : "m" (cw)); \ return value; \ } #undef fp_round_to_minus_infinity #define fp_round_to_minus_infinity fp_do_round_to_minus_infinity DEFINE_ROUND_FUNC(minus_infinity, 0x400) #undef fp_round_to_plus_infinity #define fp_round_to_plus_infinity fp_do_round_to_plus_infinity DEFINE_ROUND_FUNC(plus_infinity, 0x800) #undef fp_round_to_zero #define fp_round_to_zero fp_do_round_to_zero DEFINE_ROUND_FUNC(zero, 0xc00) #undef fp_round_to_nearest #define fp_round_to_nearest fp_do_round_to_nearest DEFINE_ROUND_FUNC(nearest, 0x000) #endif /* USE_X87_ASSEMBLY */ #ifndef fp_round_to_minus_infinity #define fp_round_to_minus_infinity(x) fp_floor(x) #endif #ifndef fp_round_to_plus_infinity #define fp_round_to_plus_infinity(x) fp_ceil(x) #endif #ifndef fp_round_to_zero #define fp_round_to_zero(x) ((int)(x)) #endif #ifndef fp_round_to_nearest #define fp_round_to_nearest(x) ((int)((x) + 0.5)) #endif #endif /* FPU_MATHLIB_H */ BasiliskII/src/uae_cpu/fpu/core.h0000644000175000017500000002302710736405224017053 0ustar centriscentris/* * fpu/core.h - base fpu context definition * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_CORE_H #define FPU_CORE_H #include "sysdeps.h" #include "fpu/types.h" /* Always use x87 FPU stack on IA-32. */ #if defined(X86_ASSEMBLY) #define USE_X87_ASSEMBLY 1 #endif /* Only use x87 FPU on x86-64 if long double precision is requested. */ #if defined(X86_64_ASSEMBLY) && USE_LONG_DOUBLE #define USE_X87_ASSEMBLY 1 #endif /* ========================================================================== */ /* ========================= FPU CONTEXT DEFINITION ========================= */ /* ========================================================================== */ /* We don't use all features of the C++ language so that we may still * easily backport that code to C. */ struct fpu_t { /* ---------------------------------------------------------------------- */ /* --- Floating-Point Data Registers --- */ /* ---------------------------------------------------------------------- */ /* The eight %fp0 .. %fp7 registers */ fpu_register registers[8]; /* Used for lazy evalualation of FPU flags */ fpu_register result; /* ---------------------------------------------------------------------- */ /* --- Floating-Point Control Register --- */ /* ---------------------------------------------------------------------- */ struct { /* Exception Enable Byte */ uae_u32 exception_enable; #define FPCR_EXCEPTION_ENABLE 0x0000ff00 #define FPCR_EXCEPTION_BSUN 0x00008000 #define FPCR_EXCEPTION_SNAN 0x00004000 #define FPCR_EXCEPTION_OPERR 0x00002000 #define FPCR_EXCEPTION_OVFL 0x00001000 #define FPCR_EXCEPTION_UNFL 0x00000800 #define FPCR_EXCEPTION_DZ 0x00000400 #define FPCR_EXCEPTION_INEX2 0x00000200 #define FPCR_EXCEPTION_INEX1 0x00000100 /* Mode Control Byte Mask */ #define FPCR_MODE_CONTROL 0x000000ff /* Rounding precision */ uae_u32 rounding_precision; #define FPCR_ROUNDING_PRECISION 0x000000c0 #define FPCR_PRECISION_SINGLE 0x00000040 #define FPCR_PRECISION_DOUBLE 0x00000080 #define FPCR_PRECISION_EXTENDED 0x00000000 /* Rounding mode */ uae_u32 rounding_mode; #define FPCR_ROUNDING_MODE 0x00000030 #define FPCR_ROUND_NEAR 0x00000000 #define FPCR_ROUND_ZERO 0x00000010 #define FPCR_ROUND_MINF 0x00000020 #define FPCR_ROUND_PINF 0x00000030 } fpcr; /* ---------------------------------------------------------------------- */ /* --- Floating-Point Status Register --- */ /* ---------------------------------------------------------------------- */ struct { /* Floating-Point Condition Code Byte */ uae_u32 condition_codes; #define FPSR_CCB 0xff000000 #define FPSR_CCB_NEGATIVE 0x08000000 #define FPSR_CCB_ZERO 0x04000000 #define FPSR_CCB_INFINITY 0x02000000 #define FPSR_CCB_NAN 0x01000000 /* Quotient Byte */ uae_u32 quotient; #define FPSR_QUOTIENT 0x00ff0000 #define FPSR_QUOTIENT_SIGN 0x00800000 #define FPSR_QUOTIENT_VALUE 0x007f0000 /* Exception Status Byte */ uae_u32 exception_status; #define FPSR_EXCEPTION_STATUS FPCR_EXCEPTION_ENABLE #define FPSR_EXCEPTION_BSUN FPCR_EXCEPTION_BSUN #define FPSR_EXCEPTION_SNAN FPCR_EXCEPTION_SNAN #define FPSR_EXCEPTION_OPERR FPCR_EXCEPTION_OPERR #define FPSR_EXCEPTION_OVFL FPCR_EXCEPTION_OVFL #define FPSR_EXCEPTION_UNFL FPCR_EXCEPTION_UNFL #define FPSR_EXCEPTION_DZ FPCR_EXCEPTION_DZ #define FPSR_EXCEPTION_INEX2 FPCR_EXCEPTION_INEX2 #define FPSR_EXCEPTION_INEX1 FPCR_EXCEPTION_INEX1 /* Accrued Exception Byte */ uae_u32 accrued_exception; #define FPSR_ACCRUED_EXCEPTION 0x000000ff #define FPSR_ACCR_IOP 0x00000080 #define FPSR_ACCR_OVFL 0x00000040 #define FPSR_ACCR_UNFL 0x00000020 #define FPSR_ACCR_DZ 0x00000010 #define FPSR_ACCR_INEX 0x00000008 } fpsr; /* ---------------------------------------------------------------------- */ /* --- Floating-Point Instruction Address Register --- */ /* ---------------------------------------------------------------------- */ uae_u32 instruction_address; /* ---------------------------------------------------------------------- */ /* --- Initialization / Finalization --- */ /* ---------------------------------------------------------------------- */ /* Flag set if we emulate an integral 68040 FPU */ bool is_integral; /* ---------------------------------------------------------------------- */ /* --- Extra FPE-dependant defines --- */ /* ---------------------------------------------------------------------- */ #if defined(FPU_X86) \ || (defined(FPU_UAE) && defined(USE_X87_ASSEMBLY)) \ || (defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY)) #define CW_RESET 0x0040 // initial CW value after RESET #define CW_FINIT 0x037F // initial CW value after FINIT #define SW_RESET 0x0000 // initial SW value after RESET #define SW_FINIT 0x0000 // initial SW value after FINIT #define TW_RESET 0x5555 // initial TW value after RESET #define TW_FINIT 0x0FFF // initial TW value after FINIT #define CW_X 0x1000 // infinity control #define CW_RC_ZERO 0x0C00 // rounding control toward zero #define CW_RC_UP 0x0800 // rounding control toward + #define CW_RC_DOWN 0x0400 // rounding control toward - #define CW_RC_NEAR 0x0000 // rounding control toward even #define CW_PC_EXTENDED 0x0300 // precision control 64bit #define CW_PC_DOUBLE 0x0200 // precision control 53bit #define CW_PC_RESERVED 0x0100 // precision control reserved #define CW_PC_SINGLE 0x0000 // precision control 24bit #define CW_PM 0x0020 // precision exception mask #define CW_UM 0x0010 // underflow exception mask #define CW_OM 0x0008 // overflow exception mask #define CW_ZM 0x0004 // zero divide exception mask #define CW_DM 0x0002 // denormalized operand exception mask #define CW_IM 0x0001 // invalid operation exception mask #define SW_B 0x8000 // busy flag #define SW_C3 0x4000 // condition code flag 3 #define SW_TOP_7 0x3800 // top of stack = ST(7) #define SW_TOP_6 0x3000 // top of stack = ST(6) #define SW_TOP_5 0x2800 // top of stack = ST(5) #define SW_TOP_4 0x2000 // top of stack = ST(4) #define SW_TOP_3 0x1800 // top of stack = ST(3) #define SW_TOP_2 0x1000 // top of stack = ST(2) #define SW_TOP_1 0x0800 // top of stack = ST(1) #define SW_TOP_0 0x0000 // top of stack = ST(0) #define SW_C2 0x0400 // condition code flag 2 #define SW_C1 0x0200 // condition code flag 1 #define SW_C0 0x0100 // condition code flag 0 #define SW_ES 0x0080 // error summary status flag #define SW_SF 0x0040 // stack fault flag #define SW_PE 0x0020 // precision exception flag #define SW_UE 0x0010 // underflow exception flag #define SW_OE 0x0008 // overflow exception flag #define SW_ZE 0x0004 // zero divide exception flag #define SW_DE 0x0002 // denormalized operand exception flag #define SW_IE 0x0001 // invalid operation exception flag #define X86_ROUNDING_MODE 0x0C00 #define X86_ROUNDING_PRECISION 0x0300 #endif /* FPU_X86 */ }; /* We handle only one global fpu */ extern fpu_t fpu; /* Return the address of a particular register */ inline fpu_register * const fpu_register_address(int i) { return &fpu.registers[i]; } /* Dump functions for m68k_dumpstate */ extern void fpu_dump_registers(void); extern void fpu_dump_flags(void); /* Accessors to FPU Control Register */ static inline uae_u32 get_fpcr(void); static inline void set_fpcr(uae_u32 new_fpcr); /* Accessors to FPU Status Register */ static inline uae_u32 get_fpsr(void); static inline void set_fpsr(uae_u32 new_fpsr); /* Accessors to FPU Instruction Address Register */ static inline uae_u32 get_fpiar(); static inline void set_fpiar(uae_u32 new_fpiar); /* Initialization / Finalization */ extern void fpu_init(bool integral_68040); extern void fpu_exit(void); extern void fpu_reset(void); /* Floating-point arithmetic instructions */ void fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) REGPARAM; /* Floating-point program control operations */ void fpuop_bcc(uae_u32 opcode, uaecptr pc, uae_u32 extra) REGPARAM; void fpuop_dbcc(uae_u32 opcode, uae_u32 extra) REGPARAM; void fpuop_scc(uae_u32 opcode, uae_u32 extra) REGPARAM; /* Floating-point system control operations */ void fpuop_save(uae_u32 opcode) REGPARAM; void fpuop_restore(uae_u32 opcode) REGPARAM; void fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) REGPARAM; #endif /* FPU_CORE_H */ BasiliskII/src/uae_cpu/fpu/exceptions.cpp0000644000175000017500000001221210736405224020631 0ustar centriscentris/* * fpu/exceptions.cpp - system-dependant FPU exceptions management * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #undef PRIVATE #define PRIVATE /**/ #undef PUBLIC #define PUBLIC /**/ #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* -------------------------------------------------------------------------- */ /* --- Native X86 exceptions --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_X86_EXCEPTIONS void FFPU fpu_init_native_exceptions(void) { // Mapping for "sw" -> fpsr exception byte for (uae_u32 i = 0; i < 0x80; i++) { exception_host2mac[i] = 0; if(i & SW_FAKE_BSUN) { exception_host2mac[i] |= FPSR_EXCEPTION_BSUN; } // precision exception if(i & SW_PE) { exception_host2mac[i] |= FPSR_EXCEPTION_INEX2; } // underflow exception if(i & SW_UE) { exception_host2mac[i] |= FPSR_EXCEPTION_UNFL; } // overflow exception if(i & SW_OE) { exception_host2mac[i] |= FPSR_EXCEPTION_OVFL; } // zero divide exception if(i & SW_ZE) { exception_host2mac[i] |= FPSR_EXCEPTION_DZ; } // denormalized operand exception. // wrong, but should not get here, normalization is done in elsewhere if(i & SW_DE) { exception_host2mac[i] |= FPSR_EXCEPTION_SNAN; } // invalid operation exception if(i & SW_IE) { exception_host2mac[i] |= FPSR_EXCEPTION_OPERR; } } // Mapping for fpsr exception byte -> "sw" for (uae_u32 i = 0; i < 0x100; i++) { uae_u32 fpsr = (i << 8); exception_mac2host[i] = 0; // BSUN; make sure that you don't generate FPU stack faults. if(fpsr & FPSR_EXCEPTION_BSUN) { exception_mac2host[i] |= SW_FAKE_BSUN; } // precision exception if(fpsr & FPSR_EXCEPTION_INEX2) { exception_mac2host[i] |= SW_PE; } // underflow exception if(fpsr & FPSR_EXCEPTION_UNFL) { exception_mac2host[i] |= SW_UE; } // overflow exception if(fpsr & FPSR_EXCEPTION_OVFL) { exception_mac2host[i] |= SW_OE; } // zero divide exception if(fpsr & FPSR_EXCEPTION_DZ) { exception_mac2host[i] |= SW_ZE; } // denormalized operand exception if(fpsr & FPSR_EXCEPTION_SNAN) { exception_mac2host[i] |= SW_DE; //Wrong } // invalid operation exception if(fpsr & FPSR_EXCEPTION_OPERR) { exception_mac2host[i] |= SW_IE; } } } #endif #ifdef FPU_USE_X86_ACCRUED_EXCEPTIONS void FFPU fpu_init_native_accrued_exceptions(void) { /* 68881/68040 accrued exceptions accumulate as follows: Accrued.IOP |= (Exception.SNAN | Exception.OPERR) Accrued.OVFL |= (Exception.OVFL) Accrued.UNFL |= (Exception.UNFL | Exception.INEX2) Accrued.DZ |= (Exception.DZ) Accrued.INEX |= (Exception.INEX1 | Exception.INEX2 | Exception.OVFL) */ // Mapping for "fpsr.accrued_exception" -> fpsr accrued exception byte for (uae_u32 i = 0; i < 0x40; i++ ) { accrued_exception_host2mac[i] = 0; // precision exception if(i & SW_PE) { accrued_exception_host2mac[i] |= FPSR_ACCR_INEX; } // underflow exception if(i & SW_UE) { accrued_exception_host2mac[i] |= FPSR_ACCR_UNFL; } // overflow exception if(i & SW_OE) { accrued_exception_host2mac[i] |= FPSR_ACCR_OVFL; } // zero divide exception if(i & SW_ZE) { accrued_exception_host2mac[i] |= FPSR_ACCR_DZ; } // denormalized operand exception if(i & SW_DE) { accrued_exception_host2mac[i] |= FPSR_ACCR_IOP; //?????? } // invalid operation exception if(i & SW_IE) { accrued_exception_host2mac[i] |= FPSR_ACCR_IOP; } } // Mapping for fpsr accrued exception byte -> "fpsr.accrued_exception" for (uae_u32 i = 0; i < 0x20; i++) { int fpsr = (i << 3); accrued_exception_mac2host[i] = 0; // precision exception if(fpsr & FPSR_ACCR_INEX) { accrued_exception_mac2host[i] |= SW_PE; } // underflow exception if(fpsr & FPSR_ACCR_UNFL) { accrued_exception_mac2host[i] |= SW_UE; } // overflow exception if(fpsr & FPSR_ACCR_OVFL) { accrued_exception_mac2host[i] |= SW_OE; } // zero divide exception if(fpsr & FPSR_ACCR_DZ) { accrued_exception_mac2host[i] |= SW_ZE; } // What about SW_DE; //?????? // invalid operation exception if(fpsr & FPSR_ACCR_IOP) { accrued_exception_mac2host[i] |= SW_IE; } } } #endif BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp0000644000175000017500000016317211735673707020262 0ustar centriscentris/* * fpu/fpu_ieee.cpp * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ /* * Following fixes by Lauri Pesonen, July 1999: * * FMOVEM list handling: * The lookup tables did not work correctly, rewritten. * FINT: * (int) cast does not work, fixed. * Further, now honors the FPU fpcr rounding modes. * FINTRZ: * (int) cast cannot be used, fixed. * FGETEXP: * Input argument value 0 returned erroneous value. * FMOD: * (int) cast cannot be used. Replaced by proper rounding. * Quotient byte handling was missing. * FREM: * (int) cast cannot be used. Replaced by proper rounding. * Quotient byte handling was missing. * FSCALE: * Input argument value 0 was not handled correctly. * FMOVEM Control Registers to/from address FPU registers An: * A bug caused the code never been called. * FMOVEM Control Registers pre-decrement: * Moving of control regs from memory to FPP was not handled properly, * if not all of the three FPU registers were moved. * Condition code "Not Greater Than or Equal": * Returned erroneous value. * FSINCOS: * Cosine must be loaded first if same register. * FMOVECR: * Status register was not updated (yes, this affects it). * FMOVE -> reg: * Status register was not updated (yes, this affects it). * FMOVE reg -> reg: * Status register was not updated. * FDBcc: * The loop termination condition was wrong. * Possible leak from int16 to int32 fixed. * get_fp_value: * Immediate addressing mode && Operation Length == Byte -> * Use the low-order byte of the extension word. * Now FPU fpcr high 16 bits are always read as zeroes, no matter what was * written to them. * * Other: * - Optimized single/double/extended to/from conversion functions. * Huge speed boost, but not (necessarily) portable to other systems. * Enabled/disabled by #define FPU_HAVE_IEEE_DOUBLE 1 * - Optimized versions of FSCALE, FGETEXP, FGETMAN * - Conversion routines now handle NaN and infinity better. * - Some constants precalculated. Not all compilers can optimize the * expressions previously used. * * TODO: * - Floating point exceptions. * - More Infinity/NaN/overflow/underflow checking. * - FPU instruction_address (only needed when exceptions are implemented) * - Should be written in assembly to support long doubles. * - Precision rounding single/double */ #include "sysdeps.h" #include #include "memory.h" #include "readcpu.h" #include "newcpu.h" #include "main.h" #define FPU_IMPLEMENTATION #include "fpu/fpu.h" #include "fpu/fpu_ieee.h" /* Global FPU context */ fpu_t fpu; /* -------------------------------------------------------------------------- */ /* --- Scopes Definition --- */ /* -------------------------------------------------------------------------- */ #undef PUBLIC #define PUBLIC /**/ #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* -------------------------------------------------------------------------- */ /* --- Native Support --- */ /* -------------------------------------------------------------------------- */ #include "fpu/mathlib.h" #include "fpu/flags.h" #include "fpu/exceptions.h" #include "fpu/rounding.h" #include "fpu/impl.h" #include "fpu/mathlib.cpp" #include "fpu/flags.cpp" #include "fpu/exceptions.cpp" #include "fpu/rounding.cpp" /* -------------------------------------------------------------------------- */ /* --- Debugging --- */ /* -------------------------------------------------------------------------- */ PUBLIC void FFPU fpu_dump_registers(void) { for (int i = 0; i < 8; i++){ printf ("FP%d: %g ", i, fpu_get_register(i)); if ((i & 3) == 3) printf ("\n"); } } PUBLIC void FFPU fpu_dump_flags(void) { printf ("N=%d Z=%d I=%d NAN=%d\n", (get_fpsr() & FPSR_CCB_NEGATIVE) != 0, (get_fpsr() & FPSR_CCB_ZERO)!= 0, (get_fpsr() & FPSR_CCB_INFINITY) != 0, (get_fpsr() & FPSR_CCB_NAN) != 0); } PRIVATE void FFPU dump_registers(const char * str) { #if FPU_DEBUG && FPU_DUMP_REGISTERS char temp_str[512]; sprintf(temp_str, "%s: %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f\n", str, fpu_get_register(0), fpu_get_register(1), fpu_get_register(2), fpu_get_register(3), fpu_get_register(4), fpu_get_register(5), fpu_get_register(6), fpu_get_register(7) ); fpu_debug((temp_str)); #endif } PRIVATE void FFPU dump_first_bytes(uae_u8 * buffer, uae_s32 actual) { #if FPU_DEBUG && FPU_DUMP_FIRST_BYTES char temp_buf1[256], temp_buf2[10]; int bytes = sizeof(temp_buf1)/3-1-3; if (actual < bytes) bytes = actual; temp_buf1[0] = 0; for (int i = 0; i < bytes; i++) { sprintf(temp_buf2, "%02x ", (uae_u32)buffer[i]); strcat(temp_buf1, temp_buf2); } strcat(temp_buf1, "\n"); fpu_debug((temp_buf1)); #endif } // Quotient Byte is loaded with the sign and least significant // seven bits of the quotient. PRIVATE inline void FFPU make_quotient(fpu_register const & quotient, uae_u32 sign) { uae_u32 lsb = (uae_u32)fp_fabs(quotient) & 0x7f; FPU fpsr.quotient = sign | (lsb << 16); } // to_single PRIVATE inline fpu_register FFPU make_single(uae_u32 value) { #if 1 // Use a single, otherwise some checks for NaN, Inf, Zero would have to // be performed fpu_single result = 0; // = 0 to workaround a compiler bug on SPARC fp_declare_init_shape(srp, result, single); srp->ieee.negative = (value >> 31) & 1; srp->ieee.exponent = (value >> 23) & FP_SINGLE_EXP_MAX; srp->ieee.mantissa = value & 0x007fffff; fpu_debug(("make_single (%X) = %.04f\n",value,(double)result)); return result; #elif 0 /* Original code */ if ((value & 0x7fffffff) == 0) return (0.0); fpu_register result; uae_u32 * p = (uae_u32 *)&result; uae_u32 sign = (value & 0x80000000); uae_u32 exp = ((value & 0x7F800000) >> 23) + 1023 - 127; p[FLO] = value << 29; p[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3); fpu_debug(("make_single (%X) = %.04f\n",value,(double)result)); return(result); #endif } // from_single PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) { #if 1 fpu_single input = (fpu_single) src; fp_declare_init_shape(sip, input, single); uae_u32 result = (sip->ieee.negative << 31) | (sip->ieee.exponent << 23) | sip->ieee.mantissa; fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result)); return result; #elif 0 /* Original code */ if (src == 0.0) return 0; uae_u32 result; uae_u32 *p = (uae_u32 *)&src; uae_u32 sign = (p[FHI] & 0x80000000); uae_u32 exp = (p[FHI] & 0x7FF00000) >> 20; if(exp + 127 < 1023) { exp = 0; } else if(exp > 1023 + 127) { exp = 255; } else { exp = exp + 127 - 1023; } result = sign | (exp << 23) | ((p[FHI] & 0x000FFFFF) << 3) | (p[FLO] >> 29); fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result)); return (result); #endif } // to_exten PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { // is it zero? if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) return 0.0; fpu_register result; #if USE_QUAD_DOUBLE // is it NaN? if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) { make_nan(result); return result; } // is it inf? if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { if ((wrd1 & 0x80000000) == 0) make_inf_positive(result); else make_inf_negative(result); return result; } fp_declare_init_shape(srp, result, extended); srp->ieee.negative = (wrd1 >> 31) & 1; srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; srp->ieee.mantissa3 = 0; #elif USE_LONG_DOUBLE fp_declare_init_shape(srp, result, extended); srp->ieee.negative = (wrd1 >> 31) & 1; srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; srp->ieee.mantissa0 = wrd2; srp->ieee.mantissa1 = wrd3; #else uae_u32 sgn = (wrd1 >> 31) & 1; uae_u32 exp = (wrd1 >> 16) & 0x7fff; // the explicit integer bit is not set, must normalize if ((wrd2 & 0x80000000) == 0) { fpu_debug(("make_extended denormalized mantissa (%X,%X,%X)\n",wrd1,wrd2,wrd3)); if (wrd2 | wrd3) { // mantissa, not fraction. uae_u64 man = ((uae_u64)wrd2 << 32) | wrd3; while (exp > 0 && (man & UVAL64(0x8000000000000000)) == 0) { man <<= 1; exp--; } wrd2 = (uae_u32)(man >> 32); wrd3 = (uae_u32)(man & 0xFFFFFFFF); } else if (exp != 0x7fff) // zero exp = FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS; } if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) exp = 0; else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS) exp = FP_DOUBLE_EXP_MAX; else exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; fp_declare_init_shape(srp, result, double); srp->ieee.negative = sgn; srp->ieee.exponent = exp; // drop the explicit integer bit srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); #endif fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); return result; } /* Would be so much easier with full size floats :( ... this is so vague. */ // make_extended_no_normalize PRIVATE inline void FFPU make_extended_no_normalize( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & result ) { // is it zero? if ((wrd1 && 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { make_zero_positive(result); return; } // is it NaN? if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) { make_nan(result); return; } #if USE_QUAD_DOUBLE // is it inf? if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) { if ((wrd1 & 0x80000000) == 0) make_inf_positive(result); else make_inf_negative(result); return; } fp_declare_init_shape(srp, result, extended); srp->ieee.negative = (wrd1 >> 31) & 1; srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff; srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff); srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16; srp->ieee.mantissa3 = 0; #elif USE_LONG_DOUBLE fp_declare_init_shape(srp, result, extended); srp->ieee.negative = (wrd1 >> 31) & 1; srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX; srp->ieee.mantissa0 = wrd2; srp->ieee.mantissa1 = wrd3; #else uae_u32 exp = (wrd1 >> 16) & 0x7fff; if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) exp = 0; else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS) exp = FP_DOUBLE_EXP_MAX; else exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; fp_declare_init_shape(srp, result, double); srp->ieee.negative = (wrd1 >> 31) & 1; srp->ieee.exponent = exp; // drop the explicit integer bit srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11; srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11); #endif fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); } // from_exten PRIVATE inline void FFPU extract_extended(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 ) { if (src == 0.0) { *wrd1 = *wrd2 = *wrd3 = 0; return; } #if USE_QUAD_DOUBLE // FIXME: deal with denormals? fp_declare_init_shape(srp, src, extended); *wrd1 = (srp->ieee.negative << 31) | (srp->ieee.exponent << 16); // always set the explicit integer bit. *wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 15) | ((srp->ieee.mantissa1 & 0xfffe0000) >> 17); *wrd3 = (srp->ieee.mantissa1 << 15) | ((srp->ieee.mantissa2 & 0xfffe0000) >> 17); #elif USE_LONG_DOUBLE uae_u32 *p = (uae_u32 *)&src; #ifdef WORDS_BIGENDIAN *wrd1 = p[0]; *wrd2 = p[1]; *wrd3 = p[2]; #else *wrd3 = p[0]; *wrd2 = p[1]; *wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; #endif #else fp_declare_init_shape(srp, src, double); fpu_debug(("extract_extended (%d,%d,%X,%X)\n", srp->ieee.negative , srp->ieee.exponent, srp->ieee.mantissa0, srp->ieee.mantissa1)); uae_u32 exp = srp->ieee.exponent; if (exp == FP_DOUBLE_EXP_MAX) exp = FP_EXTENDED_EXP_MAX; else exp += FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS; *wrd1 = (srp->ieee.negative << 31) | (exp << 16); // always set the explicit integer bit. *wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 11) | ((srp->ieee.mantissa1 & 0xffe00000) >> 21); *wrd3 = srp->ieee.mantissa1 << 11; #endif fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); } // to_double PRIVATE inline fpu_register FFPU make_double(uae_u32 wrd1, uae_u32 wrd2) { union { fpu_double value; uae_u32 parts[2]; } dest; #ifdef WORDS_BIGENDIAN dest.parts[0] = wrd1; dest.parts[1] = wrd2; #else dest.parts[0] = wrd2; dest.parts[1] = wrd1; #endif fpu_debug(("make_double (%X,%X) = %.04f\n",wrd1,wrd2,dest.value)); return (fpu_register)(dest.value); } // from_double PRIVATE inline void FFPU extract_double(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2 ) { union { fpu_double value; uae_u32 parts[2]; } dest; dest.value = (fpu_double)src; #ifdef WORDS_BIGENDIAN *wrd1 = dest.parts[0]; *wrd2 = dest.parts[1]; #else *wrd2 = dest.parts[0]; *wrd1 = dest.parts[1]; #endif fpu_debug(("extract_double (%.04f) = %X,%X\n",(double)src,*wrd1,*wrd2)); } // to_pack PRIVATE inline fpu_register FFPU make_packed(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { fpu_double d; char *cp; char str[100]; cp = str; if (wrd1 & 0x80000000) *cp++ = '-'; *cp++ = (char)((wrd1 & 0xf) + '0'); *cp++ = '.'; *cp++ = (char)(((wrd2 >> 28) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 16) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 12) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 8) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 4) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 0) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 28) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 16) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 12) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 8) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 4) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 0) & 0xf) + '0'); *cp++ = 'E'; if (wrd1 & 0x40000000) *cp++ = '-'; *cp++ = (char)(((wrd1 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd1 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd1 >> 16) & 0xf) + '0'); *cp = 0; sscanf(str, "%le", &d); fpu_debug(("make_packed str = %s\n",str)); fpu_debug(("make_packed(%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)d)); return d; } // from_pack PRIVATE inline void FFPU extract_packed(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { int i; int t; char *cp; char str[100]; sprintf(str, "%.16e", src); fpu_debug(("extract_packed(%.04f,%s)\n",(double)src,str)); cp = str; *wrd1 = *wrd2 = *wrd3 = 0; if (*cp == '-') { cp++; *wrd1 = 0x80000000; } if (*cp == '+') cp++; *wrd1 |= (*cp++ - '0'); if (*cp == '.') cp++; for (i = 0; i < 8; i++) { *wrd2 <<= 4; if (*cp >= '0' && *cp <= '9') *wrd2 |= *cp++ - '0'; } for (i = 0; i < 8; i++) { *wrd3 <<= 4; if (*cp >= '0' && *cp <= '9') *wrd3 |= *cp++ - '0'; } if (*cp == 'e' || *cp == 'E') { cp++; if (*cp == '-') { cp++; *wrd1 |= 0x40000000; } if (*cp == '+') cp++; t = 0; for (i = 0; i < 3; i++) { if (*cp >= '0' && *cp <= '9') t = (t << 4) | (*cp++ - '0'); } *wrd1 |= t << 16; } fpu_debug(("extract_packed(%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); } PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_register & src) { uaecptr tmppc; uae_u16 tmp; int size; int mode; int reg; uae_u32 ad = 0; static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // fpu_debug(("get_fp_value(%X,%X)\n",(int)opcode,(int)extra)); // dump_first_bytes( regs.pc_p-4, 16 ); if ((extra & 0x4000) == 0) { src = FPU registers[(extra >> 10) & 7]; return 1; } mode = (opcode >> 3) & 7; reg = opcode & 7; size = (extra >> 10) & 7; fpu_debug(("get_fp_value mode=%d, reg=%d, size=%d\n",(int)mode,(int)reg,(int)size)); switch (mode) { case 0: switch (size) { case 6: src = (fpu_register) (uae_s8) m68k_dreg (regs, reg); break; case 4: src = (fpu_register) (uae_s16) m68k_dreg (regs, reg); break; case 0: src = (fpu_register) (uae_s32) m68k_dreg (regs, reg); break; case 1: src = make_single(m68k_dreg (regs, reg)); break; default: return 0; } return 1; case 1: return 0; case 2: ad = m68k_areg (regs, reg); break; case 3: ad = m68k_areg (regs, reg); m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ad = m68k_areg (regs, reg); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch (reg) { case 0: ad = (uae_s32) (uae_s16) next_iword(); break; case 1: ad = next_ilong(); break; case 2: ad = m68k_getpc (); ad += (uae_s32) (uae_s16) next_iword(); fpu_debug(("get_fp_value next_iword()=%X\n",ad-m68k_getpc()-2)); break; case 3: tmppc = m68k_getpc (); tmp = (uae_u16)next_iword(); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: ad = m68k_getpc (); m68k_setpc (ad + sz2[size]); // Immediate addressing mode && Operation Length == Byte -> // Use the low-order byte of the extension word. if(size == 6) ad++; break; default: return 0; } } fpu_debug(("get_fp_value m68k_getpc()=%X\n",m68k_getpc())); fpu_debug(("get_fp_value ad=%X\n",ad)); fpu_debug(("get_fp_value get_long (ad)=%X\n",get_long (ad))); dump_first_bytes( get_real_address(ad)-64, 64 ); dump_first_bytes( get_real_address(ad), 64 ); switch (size) { case 0: src = (fpu_register) (uae_s32) get_long (ad); break; case 1: src = make_single(get_long (ad)); break; case 2: { uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); src = make_extended(wrd1, wrd2, wrd3); break; } case 3: { uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); src = make_packed(wrd1, wrd2, wrd3); break; } case 4: src = (fpu_register) (uae_s16) get_word(ad); break; case 5: { uae_u32 wrd1, wrd2; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); src = make_double(wrd1, wrd2); break; } case 6: src = (fpu_register) (uae_s8) get_byte(ad); break; default: return 0; } // fpu_debug(("get_fp_value result = %.04f\n",(float)src)); return 1; } /* Convert the FP value to integer according to the current m68k rounding mode */ PRIVATE inline uae_s32 FFPU toint(fpu_register const & src) { fpu_register result; switch (get_fpcr() & 0x30) { case FPCR_ROUND_ZERO: result = fp_round_to_zero(src); break; case FPCR_ROUND_MINF: result = fp_round_to_minus_infinity(src); break; case FPCR_ROUND_NEAR: result = fp_round_to_nearest(src); break; case FPCR_ROUND_PINF: result = fp_round_to_plus_infinity(src); break; default: result = src; /* should never be reached */ break; } return (uae_s32)result; } PRIVATE inline int FFPU put_fp_value (uae_u32 opcode, uae_u16 extra, fpu_register const & value) { uae_u16 tmp; uaecptr tmppc; int size; int mode; int reg; uae_u32 ad; static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // fpu_debug(("put_fp_value(%.04f,%X,%X)\n",(float)value,(int)opcode,(int)extra)); if ((extra & 0x4000) == 0) { int dest_reg = (extra >> 10) & 7; FPU registers[dest_reg] = value; make_fpsr(FPU registers[dest_reg]); return 1; } mode = (opcode >> 3) & 7; reg = opcode & 7; size = (extra >> 10) & 7; ad = 0xffffffff; switch (mode) { case 0: switch (size) { case 6: m68k_dreg (regs, reg) = ((toint(value) & 0xff) | (m68k_dreg (regs, reg) & ~0xff)); break; case 4: m68k_dreg (regs, reg) = ((toint(value) & 0xffff) | (m68k_dreg (regs, reg) & ~0xffff)); break; case 0: m68k_dreg (regs, reg) = toint(value); break; case 1: m68k_dreg (regs, reg) = extract_single(value); break; default: return 0; } return 1; case 1: return 0; case 2: ad = m68k_areg (regs, reg); break; case 3: ad = m68k_areg (regs, reg); m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ad = m68k_areg (regs, reg); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch (reg) { case 0: ad = (uae_s32) (uae_s16) next_iword(); break; case 1: ad = next_ilong(); break; case 2: ad = m68k_getpc (); ad += (uae_s32) (uae_s16) next_iword(); break; case 3: tmppc = m68k_getpc (); tmp = (uae_u16)next_iword(); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: ad = m68k_getpc (); m68k_setpc (ad + sz2[size]); break; default: return 0; } } switch (size) { case 0: put_long (ad, toint(value)); break; case 1: put_long (ad, extract_single(value)); break; case 2: { uae_u32 wrd1, wrd2, wrd3; extract_extended(value, &wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); break; } case 3: { uae_u32 wrd1, wrd2, wrd3; extract_packed(value, &wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); break; } case 4: put_word(ad, (uae_s16) toint(value)); break; case 5: { uae_u32 wrd1, wrd2; extract_double(value, &wrd1, &wrd2); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); break; } case 6: put_byte(ad, (uae_s8) toint(value)); break; default: return 0; } return 1; } PRIVATE inline int FFPU get_fp_ad(uae_u32 opcode, uae_u32 * ad) { uae_u16 tmp; uaecptr tmppc; int mode; int reg; mode = (opcode >> 3) & 7; reg = opcode & 7; switch (mode) { case 0: case 1: return 0; case 2: *ad = m68k_areg (regs, reg); break; case 3: *ad = m68k_areg (regs, reg); break; case 4: *ad = m68k_areg (regs, reg); break; case 5: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch (reg) { case 0: *ad = (uae_s32) (uae_s16) next_iword(); break; case 1: *ad = next_ilong(); break; case 2: *ad = m68k_getpc (); *ad += (uae_s32) (uae_s16) next_iword(); break; case 3: tmppc = m68k_getpc (); tmp = (uae_u16)next_iword(); *ad = get_disp_ea_020 (tmppc, tmp); break; default: return 0; } } return 1; } #if FPU_DEBUG # define CONDRET(s,x) fpu_debug(("fpp_cond %s = %d\n",s,(uint32)(x))); return (x) #else # define CONDRET(s,x) return (x) #endif PRIVATE inline int FFPU fpp_cond(int condition) { int N = (FPU result < 0.0); int Z = (FPU result == 0.0); int NaN = isnan(FPU result); if (NaN) N = Z = 0; switch (condition) { case 0x00: CONDRET("False",0); case 0x01: CONDRET("Equal",Z); case 0x02: CONDRET("Ordered Greater Than",!(NaN || Z || N)); case 0x03: CONDRET("Ordered Greater Than or Equal",Z || !(NaN || N)); case 0x04: CONDRET("Ordered Less Than",N && !(NaN || Z)); case 0x05: CONDRET("Ordered Less Than or Equal",Z || (N && !NaN)); case 0x06: CONDRET("Ordered Greater or Less Than",!(NaN || Z)); case 0x07: CONDRET("Ordered",!NaN); case 0x08: CONDRET("Unordered",NaN); case 0x09: CONDRET("Unordered or Equal",NaN || Z); case 0x0a: CONDRET("Unordered or Greater Than",NaN || !(N || Z)); case 0x0b: CONDRET("Unordered or Greater or Equal",NaN || Z || !N); case 0x0c: CONDRET("Unordered or Less Than",NaN || (N && !Z)); case 0x0d: CONDRET("Unordered or Less or Equal",NaN || Z || N); case 0x0e: CONDRET("Not Equal",!Z); case 0x0f: CONDRET("True",1); case 0x10: CONDRET("Signaling False",0); case 0x11: CONDRET("Signaling Equal",Z); case 0x12: CONDRET("Greater Than",!(NaN || Z || N)); case 0x13: CONDRET("Greater Than or Equal",Z || !(NaN || N)); case 0x14: CONDRET("Less Than",N && !(NaN || Z)); case 0x15: CONDRET("Less Than or Equal",Z || (N && !NaN)); case 0x16: CONDRET("Greater or Less Than",!(NaN || Z)); case 0x17: CONDRET("Greater, Less or Equal",!NaN); case 0x18: CONDRET("Not Greater, Less or Equal",NaN); case 0x19: CONDRET("Not Greater or Less Than",NaN || Z); case 0x1a: CONDRET("Not Less Than or Equal",NaN || !(N || Z)); case 0x1b: CONDRET("Not Less Than",NaN || Z || !N); case 0x1c: CONDRET("Not Greater Than or Equal", NaN || (N && !Z)); case 0x1d: CONDRET("Not Greater Than",NaN || Z || N); case 0x1e: CONDRET("Signaling Not Equal",!Z); case 0x1f: CONDRET("Signaling True",1); default: CONDRET("",-1); } } void FFPU fpuop_dbcc(uae_u32 opcode, uae_u32 extra) { fpu_debug(("fdbcc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); uaecptr pc = (uae_u32) m68k_getpc (); uae_s32 disp = (uae_s32) (uae_s16) next_iword(); int cc = fpp_cond(extra & 0x3f); if (cc == -1) { m68k_setpc (pc - 4); op_illg (opcode); } else if (!cc) { int reg = opcode & 0x7; // this may have leaked. /* m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff) | ((m68k_dreg (regs, reg) - 1) & 0xffff)); */ m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000) | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff)); // condition reversed. // if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff) if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) m68k_setpc (pc + disp); } } void FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra) { fpu_debug(("fscc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); uae_u32 ad; int cc = fpp_cond(extra & 0x3f); if (cc == -1) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } else if ((opcode & 0x38) == 0) { m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00); } else if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } else put_byte(ad, cc ? 0xff : 0x00); } void FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) { fpu_debug(("ftrapcc_opp %X at %08lx\n", (uae_u32)opcode, m68k_getpc ())); int cc = fpp_cond(opcode & 0x3f); if (cc == -1) { m68k_setpc (oldpc); op_illg (opcode); } if (cc) Exception(7, oldpc - 2); } // NOTE that we get here also when there is a FNOP (nontrapping false, displ 0) void FFPU fpuop_bcc(uae_u32 opcode, uaecptr pc, uae_u32 extra) { fpu_debug(("fbcc_opp %X, %X at %08lx, jumpto=%X\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc (), extra )); int cc = fpp_cond(opcode & 0x3f); if (cc == -1) { m68k_setpc (pc); op_illg (opcode); } else if (cc) { if ((opcode & 0x40) == 0) extra = (uae_s32) (uae_s16) extra; m68k_setpc (pc + extra); } } // FSAVE has no post-increment // 0x1f180000 == IDLE state frame, coprocessor version number 1F void FFPU fpuop_save(uae_u32 opcode) { fpu_debug(("fsave_opp at %08lx\n", m68k_getpc ())); uae_u32 ad; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; int i; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 2); op_illg (opcode); return; } if (CPUType == 4) { // Put 4 byte 68040 IDLE frame. if (incr < 0) { ad -= 4; put_long (ad, 0x41000000); } else { put_long (ad, 0x41000000); ad += 4; } } else { // Put 28 byte 68881 IDLE frame. if (incr < 0) { fpu_debug(("fsave_opp pre-decrement\n")); ad -= 4; // What's this? Some BIU flags, or (incorrectly placed) command/condition? put_long (ad, 0x70000000); for (i = 0; i < 5; i++) { ad -= 4; put_long (ad, 0x00000000); } ad -= 4; put_long (ad, 0x1f180000); // IDLE, vers 1f } else { put_long (ad, 0x1f180000); // IDLE, vers 1f ad += 4; for (i = 0; i < 5; i++) { put_long (ad, 0x00000000); ad += 4; } // What's this? Some BIU flags, or (incorrectly placed) command/condition? put_long (ad, 0x70000000); ad += 4; } } if ((opcode & 0x38) == 0x18) { m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 fpu_debug(("PROBLEM: fsave_opp post-increment\n")); } if ((opcode & 0x38) == 0x20) { m68k_areg (regs, opcode & 7) = ad; fpu_debug(("fsave_opp pre-decrement %X -> A%d\n",ad,opcode & 7)); } } // FRESTORE has no pre-decrement void FFPU fpuop_restore(uae_u32 opcode) { fpu_debug(("frestore_opp at %08lx\n", m68k_getpc ())); uae_u32 ad; uae_u32 d; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 2); op_illg (opcode); return; } if (CPUType == 4) { // 68040 if (incr < 0) { fpu_debug(("PROBLEM: frestore_opp incr < 0\n")); // this may be wrong, but it's never called. ad -= 4; d = get_long (ad); if ((d & 0xff000000) != 0) { // Not a NULL frame? if ((d & 0x00ff0000) == 0) { // IDLE fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP fpu_debug(("PROBLEM: frestore_opp found UNIMP frame at %X\n",ad-4)); ad -= 44; } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4)); ad -= 92; } } } else { d = get_long (ad); fpu_debug(("frestore_opp frame at %X = %X\n",ad,d)); ad += 4; if ((d & 0xff000000) != 0) { // Not a NULL frame? if ((d & 0x00ff0000) == 0) { // IDLE fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP fpu_debug(("PROBLEM: frestore_opp found UNIMP frame at %X\n",ad-4)); ad += 44; } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4)); ad += 92; } } } } else { // 68881 if (incr < 0) { fpu_debug(("PROBLEM: frestore_opp incr < 0\n")); // this may be wrong, but it's never called. ad -= 4; d = get_long (ad); if ((d & 0xff000000) != 0) { if ((d & 0x00ff0000) == 0x00180000) ad -= 6 * 4; else if ((d & 0x00ff0000) == 0x00380000) ad -= 14 * 4; else if ((d & 0x00ff0000) == 0x00b40000) ad -= 45 * 4; } } else { d = get_long (ad); fpu_debug(("frestore_opp frame at %X = %X\n",ad,d)); ad += 4; if ((d & 0xff000000) != 0) { // Not a NULL frame? if ((d & 0x00ff0000) == 0x00180000) { // IDLE fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4)); ad += 6 * 4; } else if ((d & 0x00ff0000) == 0x00380000) {// UNIMP? shouldn't it be 3C? ad += 14 * 4; fpu_debug(("PROBLEM: frestore_opp found UNIMP? frame at %X\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00b40000) {// BUSY fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4)); ad += 45 * 4; } } } } if ((opcode & 0x38) == 0x18) { m68k_areg (regs, opcode & 7) = ad; fpu_debug(("frestore_opp post-increment %X -> A%d\n",ad,opcode & 7)); } if ((opcode & 0x38) == 0x20) { m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 fpu_debug(("PROBLEM: frestore_opp pre-decrement\n")); } } void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) { int reg; fpu_register src; fpu_debug(("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff, m68k_getpc () - 4)); dump_registers( "START"); switch ((extra >> 13) & 0x7) { case 3: fpu_debug(("FMOVE -> \n")); if (put_fp_value (opcode, extra, FPU registers[(extra >> 7) & 7]) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } dump_registers( "END "); return; case 4: case 5: if ((opcode & 0x38) == 0) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { // according to the manual, the msb bits are always zero. m68k_dreg (regs, opcode & 7) = get_fpcr() & 0xFFFF; fpu_debug(("FMOVEM FPU fpcr (%X) -> D%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { m68k_dreg (regs, opcode & 7) = get_fpsr(); fpu_debug(("FMOVEM FPU fpsr (%X) -> D%d\n", get_fpsr(), opcode & 7)); } if (extra & 0x0400) { m68k_dreg (regs, opcode & 7) = FPU instruction_address; fpu_debug(("FMOVEM FPU instruction_address (%X) -> D%d\n", FPU instruction_address, opcode & 7)); } } else { if (extra & 0x1000) { set_fpcr( m68k_dreg (regs, opcode & 7) ); fpu_debug(("FMOVEM D%d (%X) -> FPU fpcr\n", opcode & 7, get_fpcr())); } if (extra & 0x0800) { set_fpsr( m68k_dreg (regs, opcode & 7) ); fpu_debug(("FMOVEM D%d (%X) -> FPU fpsr\n", opcode & 7, get_fpsr())); } if (extra & 0x0400) { FPU instruction_address = m68k_dreg (regs, opcode & 7); fpu_debug(("FMOVEM D%d (%X) -> FPU instruction_address\n", opcode & 7, FPU instruction_address)); } } // } else if ((opcode & 0x38) == 1) { } else if ((opcode & 0x38) == 8) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { // according to the manual, the msb bits are always zero. m68k_areg (regs, opcode & 7) = get_fpcr() & 0xFFFF; fpu_debug(("FMOVEM FPU fpcr (%X) -> A%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { m68k_areg (regs, opcode & 7) = get_fpsr(); fpu_debug(("FMOVEM FPU fpsr (%X) -> A%d\n", get_fpsr(), opcode & 7)); } if (extra & 0x0400) { m68k_areg (regs, opcode & 7) = FPU instruction_address; fpu_debug(("FMOVEM FPU instruction_address (%X) -> A%d\n", FPU instruction_address, opcode & 7)); } } else { if (extra & 0x1000) { set_fpcr( m68k_areg (regs, opcode & 7) ); fpu_debug(("FMOVEM A%d (%X) -> FPU fpcr\n", opcode & 7, get_fpcr())); } if (extra & 0x0800) { set_fpsr( m68k_areg (regs, opcode & 7) ); fpu_debug(("FMOVEM A%d (%X) -> FPU fpsr\n", opcode & 7, get_fpsr())); } if (extra & 0x0400) { FPU instruction_address = m68k_areg (regs, opcode & 7); fpu_debug(("FMOVEM A%d (%X) -> FPU instruction_address\n", opcode & 7, FPU instruction_address)); } } } else if ((opcode & 0x3f) == 0x3c) { if ((extra & 0x2000) == 0) { if (extra & 0x1000) { set_fpcr( next_ilong() ); fpu_debug(("FMOVEM #<%X> -> FPU fpcr\n", get_fpcr())); } if (extra & 0x0800) { set_fpsr( next_ilong() ); fpu_debug(("FMOVEM #<%X> -> FPU fpsr\n", get_fpsr())); } if (extra & 0x0400) { FPU instruction_address = next_ilong(); fpu_debug(("FMOVEM #<%X> -> FPU instruction_address\n", FPU instruction_address)); } } } else if (extra & 0x2000) { /* FMOVEM FPP->memory */ uae_u32 ad; int incr = 0; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } if ((opcode & 0x38) == 0x20) { if (extra & 0x1000) incr += 4; if (extra & 0x0800) incr += 4; if (extra & 0x0400) incr += 4; } ad -= incr; if (extra & 0x1000) { // according to the manual, the msb bits are always zero. put_long (ad, get_fpcr() & 0xFFFF); fpu_debug(("FMOVEM FPU fpcr (%X) -> mem %X\n", get_fpcr(), ad )); ad += 4; } if (extra & 0x0800) { put_long (ad, get_fpsr()); fpu_debug(("FMOVEM FPU fpsr (%X) -> mem %X\n", get_fpsr(), ad )); ad += 4; } if (extra & 0x0400) { put_long (ad, FPU instruction_address); fpu_debug(("FMOVEM FPU instruction_address (%X) -> mem %X\n", FPU instruction_address, ad )); ad += 4; } ad -= incr; if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? m68k_areg (regs, opcode & 7) = ad; } else { /* FMOVEM memory->FPP */ uae_u32 ad; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } // ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad; int incr = 0; if((opcode & 0x38) == 0x20) { if (extra & 0x1000) incr += 4; if (extra & 0x0800) incr += 4; if (extra & 0x0400) incr += 4; ad = ad - incr; } if (extra & 0x1000) { set_fpcr( get_long (ad) ); fpu_debug(("FMOVEM mem %X (%X) -> FPU fpcr\n", ad, get_fpcr() )); ad += 4; } if (extra & 0x0800) { set_fpsr( get_long (ad) ); fpu_debug(("FMOVEM mem %X (%X) -> FPU fpsr\n", ad, get_fpsr() )); ad += 4; } if (extra & 0x0400) { FPU instruction_address = get_long (ad); fpu_debug(("FMOVEM mem %X (%X) -> FPU instruction_address\n", ad, FPU instruction_address )); ad += 4; } if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? // m68k_areg (regs, opcode & 7) = ad - 12; m68k_areg (regs, opcode & 7) = ad - incr; } dump_registers( "END "); return; case 6: case 7: { uae_u32 ad, list = 0; int incr = 0; if (extra & 0x2000) { /* FMOVEM FPP->memory */ fpu_debug(("FMOVEM FPP->memory\n")); if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } switch ((extra >> 11) & 3) { case 0: /* static pred */ list = extra & 0xff; incr = -1; break; case 1: /* dynamic pred */ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = -1; break; case 2: /* static postinc */ list = extra & 0xff; incr = 1; break; case 3: /* dynamic postinc */ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = 1; break; } if (incr < 0) { for(reg=7; reg>=0; reg--) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { extract_extended(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } } else { for(reg=0; reg<8; reg++) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { extract_extended(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } } if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? m68k_areg (regs, opcode & 7) = ad; } else { /* FMOVEM memory->FPP */ fpu_debug(("FMOVEM memory->FPP\n")); if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } switch ((extra >> 11) & 3) { case 0: /* static pred */ fpu_debug(("memory->FMOVEM FPP not legal mode.\n")); list = extra & 0xff; incr = -1; break; case 1: /* dynamic pred */ fpu_debug(("memory->FMOVEM FPP not legal mode.\n")); list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = -1; break; case 2: /* static postinc */ list = extra & 0xff; incr = 1; break; case 3: /* dynamic postinc */ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = 1; break; } /**/ if (incr < 0) { // not reached for(reg=7; reg>=0; reg--) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); // FPU registers[reg] = make_extended(wrd1, wrd2, wrd3); make_extended_no_normalize (wrd1, wrd2, wrd3, FPU registers[reg]); } list <<= 1; } } else { for(reg=0; reg<8; reg++) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; // FPU registers[reg] = make_extended(wrd1, wrd2, wrd3); make_extended_no_normalize (wrd1, wrd2, wrd3, FPU registers[reg]); } list <<= 1; } } if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? m68k_areg (regs, opcode & 7) = ad; } dump_registers( "END "); return; } case 0: case 2: reg = (extra >> 7) & 7; if ((extra & 0xfc00) == 0x5c00) { fpu_debug(("FMOVECR memory->FPP\n")); switch (extra & 0x7f) { case 0x00: // FPU registers[reg] = 4.0 * atan(1.0); FPU registers[reg] = 3.1415926535897932384626433832795; fpu_debug(("FP const: Pi\n")); break; case 0x0b: // FPU registers[reg] = log10 (2.0); FPU registers[reg] = 0.30102999566398119521373889472449; fpu_debug(("FP const: Log 10 (2)\n")); break; case 0x0c: // FPU registers[reg] = exp (1.0); FPU registers[reg] = 2.7182818284590452353602874713527; fpu_debug(("FP const: e\n")); break; case 0x0d: // FPU registers[reg] = log (exp (1.0)) / log (2.0); FPU registers[reg] = 1.4426950408889634073599246810019; fpu_debug(("FP const: Log 2 (e)\n")); break; case 0x0e: // FPU registers[reg] = log (exp (1.0)) / log (10.0); FPU registers[reg] = 0.43429448190325182765112891891661; fpu_debug(("FP const: Log 10 (e)\n")); break; case 0x0f: FPU registers[reg] = 0.0; fpu_debug(("FP const: zero\n")); break; case 0x30: // FPU registers[reg] = log (2.0); FPU registers[reg] = 0.69314718055994530941723212145818; fpu_debug(("FP const: ln(2)\n")); break; case 0x31: // FPU registers[reg] = log (10.0); FPU registers[reg] = 2.3025850929940456840179914546844; fpu_debug(("FP const: ln(10)\n")); break; case 0x32: // ?? FPU registers[reg] = 1.0e0; fpu_debug(("FP const: 1.0e0\n")); break; case 0x33: FPU registers[reg] = 1.0e1; fpu_debug(("FP const: 1.0e1\n")); break; case 0x34: FPU registers[reg] = 1.0e2; fpu_debug(("FP const: 1.0e2\n")); break; case 0x35: FPU registers[reg] = 1.0e4; fpu_debug(("FP const: 1.0e4\n")); break; case 0x36: FPU registers[reg] = 1.0e8; fpu_debug(("FP const: 1.0e8\n")); break; case 0x37: FPU registers[reg] = 1.0e16; fpu_debug(("FP const: 1.0e16\n")); break; case 0x38: FPU registers[reg] = 1.0e32; fpu_debug(("FP const: 1.0e32\n")); break; case 0x39: FPU registers[reg] = 1.0e64; fpu_debug(("FP const: 1.0e64\n")); break; case 0x3a: FPU registers[reg] = 1.0e128; fpu_debug(("FP const: 1.0e128\n")); break; case 0x3b: FPU registers[reg] = 1.0e256; fpu_debug(("FP const: 1.0e256\n")); break; #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE case 0x3c: FPU registers[reg] = 1.0e512L; fpu_debug(("FP const: 1.0e512\n")); break; case 0x3d: FPU registers[reg] = 1.0e1024L; fpu_debug(("FP const: 1.0e1024\n")); break; case 0x3e: FPU registers[reg] = 1.0e2048L; fpu_debug(("FP const: 1.0e2048\n")); break; case 0x3f: FPU registers[reg] = 1.0e4096L; fpu_debug(("FP const: 1.0e4096\n")); #endif break; default: m68k_setpc (m68k_getpc () - 4); op_illg (opcode); break; } // these *do* affect the status reg make_fpsr(FPU registers[reg]); dump_registers( "END "); return; } if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } fpu_debug(("returned from get_fp_value m68k_getpc()=%X\n",m68k_getpc())); if (FPU is_integral) { // 68040-specific operations switch (extra & 0x7f) { case 0x40: /* FSMOVE */ fpu_debug(("FSMOVE %.04f\n",(double)src)); FPU registers[reg] = (float)src; make_fpsr(FPU registers[reg]); break; case 0x44: /* FDMOVE */ fpu_debug(("FDMOVE %.04f\n",(double)src)); FPU registers[reg] = (double)src; make_fpsr(FPU registers[reg]); break; case 0x41: /* FSSQRT */ fpu_debug(("FSQRT %.04f\n",(double)src)); FPU registers[reg] = (float)fp_sqrt (src); make_fpsr(FPU registers[reg]); break; case 0x45: /* FDSQRT */ fpu_debug(("FSQRT %.04f\n",(double)src)); FPU registers[reg] = (double)fp_sqrt (src); make_fpsr(FPU registers[reg]); break; case 0x58: /* FSABS */ fpu_debug(("FSABS %.04f\n",(double)src)); FPU registers[reg] = (float)fp_fabs(src); make_fpsr(FPU registers[reg]); break; case 0x5c: /* FDABS */ fpu_debug(("FDABS %.04f\n",(double)src)); FPU registers[reg] = (double)fp_fabs(src); make_fpsr(FPU registers[reg]); break; case 0x5a: /* FSNEG */ fpu_debug(("FSNEG %.04f\n",(double)src)); FPU registers[reg] = (float)-src; make_fpsr(FPU registers[reg]); break; case 0x5e: /* FDNEG */ fpu_debug(("FDNEG %.04f\n",(double)src)); FPU registers[reg] = (double)-src; make_fpsr(FPU registers[reg]); break; case 0x60: /* FSDIV */ fpu_debug(("FSDIV %.04f\n",(double)src)); FPU registers[reg] = (float)(FPU registers[reg] / src); make_fpsr(FPU registers[reg]); break; case 0x64: /* FDDIV */ fpu_debug(("FDDIV %.04f\n",(double)src)); FPU registers[reg] = (double)(FPU registers[reg] / src); make_fpsr(FPU registers[reg]); break; case 0x62: /* FSADD */ fpu_debug(("FSADD %.04f\n",(double)src)); FPU registers[reg] = (float)(FPU registers[reg] + src); make_fpsr(FPU registers[reg]); break; case 0x66: /* FDADD */ fpu_debug(("FDADD %.04f\n",(double)src)); FPU registers[reg] = (double)(FPU registers[reg] + src); make_fpsr(FPU registers[reg]); break; case 0x68: /* FSSUB */ fpu_debug(("FSSUB %.04f\n",(double)src)); FPU registers[reg] = (float)(FPU registers[reg] - src); make_fpsr(FPU registers[reg]); break; case 0x6c: /* FDSUB */ fpu_debug(("FDSUB %.04f\n",(double)src)); FPU registers[reg] = (double)(FPU registers[reg] - src); make_fpsr(FPU registers[reg]); break; case 0x63: /* FSMUL */ case 0x67: /* FDMUL */ fpu_debug(("FMUL %.04f\n",(double)src)); get_dest_flags(FPU registers[reg]); get_source_flags(src); if(fl_dest.in_range && fl_source.in_range) { if ((extra & 0x7f) == 0x63) FPU registers[reg] = (float)(FPU registers[reg] * src); else FPU registers[reg] = (double)(FPU registers[reg] * src); } else if (fl_dest.nan || fl_source.nan || fl_dest.zero && fl_source.infinity || fl_dest.infinity && fl_source.zero ) { make_nan( FPU registers[reg] ); } else if (fl_dest.zero || fl_source.zero ) { if (fl_dest.negative && !fl_source.negative || !fl_dest.negative && fl_source.negative) { make_zero_negative(FPU registers[reg]); } else { make_zero_positive(FPU registers[reg]); } } else { if( fl_dest.negative && !fl_source.negative || !fl_dest.negative && fl_source.negative) { make_inf_negative(FPU registers[reg]); } else { make_inf_positive(FPU registers[reg]); } } make_fpsr(FPU registers[reg]); break; default: // Continue decode-execute 6888x instructions below goto process_6888x_instructions; } fpu_debug(("END m68k_getpc()=%X\n",m68k_getpc())); dump_registers( "END "); return; } process_6888x_instructions: switch (extra & 0x7f) { case 0x00: /* FMOVE */ fpu_debug(("FMOVE %.04f\n",(double)src)); FPU registers[reg] = src; make_fpsr(FPU registers[reg]); break; case 0x01: /* FINT */ fpu_debug(("FINT %.04f\n",(double)src)); FPU registers[reg] = toint(src); make_fpsr(FPU registers[reg]); break; case 0x02: /* FSINH */ fpu_debug(("FSINH %.04f\n",(double)src)); FPU registers[reg] = fp_sinh (src); make_fpsr(FPU registers[reg]); break; case 0x03: /* FINTRZ */ fpu_debug(("FINTRZ %.04f\n",(double)src)); FPU registers[reg] = fp_round_to_zero(src); make_fpsr(FPU registers[reg]); break; case 0x04: /* FSQRT */ fpu_debug(("FSQRT %.04f\n",(double)src)); FPU registers[reg] = fp_sqrt (src); make_fpsr(FPU registers[reg]); break; case 0x06: /* FLOGNP1 */ fpu_debug(("FLOGNP1 %.04f\n",(double)src)); FPU registers[reg] = fp_log (src + 1.0); make_fpsr(FPU registers[reg]); break; case 0x08: /* FETOXM1 */ fpu_debug(("FETOXM1 %.04f\n",(double)src)); FPU registers[reg] = fp_exp (src) - 1.0; make_fpsr(FPU registers[reg]); break; case 0x09: /* FTANH */ fpu_debug(("FTANH %.04f\n",(double)src)); FPU registers[reg] = fp_tanh (src); make_fpsr(FPU registers[reg]); break; case 0x0a: /* FATAN */ fpu_debug(("FATAN %.04f\n",(double)src)); FPU registers[reg] = fp_atan (src); make_fpsr(FPU registers[reg]); break; case 0x0c: /* FASIN */ fpu_debug(("FASIN %.04f\n",(double)src)); FPU registers[reg] = fp_asin (src); make_fpsr(FPU registers[reg]); break; case 0x0d: /* FATANH */ fpu_debug(("FATANH %.04f\n",(double)src)); FPU registers[reg] = fp_atanh (src); make_fpsr(FPU registers[reg]); break; case 0x0e: /* FSIN */ fpu_debug(("FSIN %.04f\n",(double)src)); FPU registers[reg] = fp_sin (src); make_fpsr(FPU registers[reg]); break; case 0x0f: /* FTAN */ fpu_debug(("FTAN %.04f\n",(double)src)); FPU registers[reg] = fp_tan (src); make_fpsr(FPU registers[reg]); break; case 0x10: /* FETOX */ fpu_debug(("FETOX %.04f\n",(double)src)); FPU registers[reg] = fp_exp (src); make_fpsr(FPU registers[reg]); break; case 0x11: /* FTWOTOX */ fpu_debug(("FTWOTOX %.04f\n",(double)src)); FPU registers[reg] = fp_pow(2.0, src); make_fpsr(FPU registers[reg]); break; case 0x12: /* FTENTOX */ fpu_debug(("FTENTOX %.04f\n",(double)src)); FPU registers[reg] = fp_pow(10.0, src); make_fpsr(FPU registers[reg]); break; case 0x14: /* FLOGN */ fpu_debug(("FLOGN %.04f\n",(double)src)); FPU registers[reg] = fp_log (src); make_fpsr(FPU registers[reg]); break; case 0x15: /* FLOG10 */ fpu_debug(("FLOG10 %.04f\n",(double)src)); FPU registers[reg] = fp_log10 (src); make_fpsr(FPU registers[reg]); break; case 0x16: /* FLOG2 */ fpu_debug(("FLOG2 %.04f\n",(double)src)); FPU registers[reg] = fp_log (src) / fp_log (2.0); make_fpsr(FPU registers[reg]); break; case 0x18: /* FABS */ fpu_debug(("FABS %.04f\n",(double)src)); FPU registers[reg] = fp_fabs(src); make_fpsr(FPU registers[reg]); break; case 0x19: /* FCOSH */ fpu_debug(("FCOSH %.04f\n",(double)src)); FPU registers[reg] = fp_cosh(src); make_fpsr(FPU registers[reg]); break; case 0x1a: /* FNEG */ fpu_debug(("FNEG %.04f\n",(double)src)); FPU registers[reg] = -src; make_fpsr(FPU registers[reg]); break; case 0x1c: /* FACOS */ fpu_debug(("FACOS %.04f\n",(double)src)); FPU registers[reg] = fp_acos(src); make_fpsr(FPU registers[reg]); break; case 0x1d: /* FCOS */ fpu_debug(("FCOS %.04f\n",(double)src)); FPU registers[reg] = fp_cos(src); make_fpsr(FPU registers[reg]); break; case 0x1e: /* FGETEXP */ fpu_debug(("FGETEXP %.04f\n",(double)src)); if( isinf(src) ) { make_nan( FPU registers[reg] ); } else { FPU registers[reg] = fast_fgetexp( src ); } make_fpsr(FPU registers[reg]); break; case 0x1f: /* FGETMAN */ fpu_debug(("FGETMAN %.04f\n",(double)src)); if( src == 0 ) { FPU registers[reg] = 0; } else if( isinf(src) ) { make_nan( FPU registers[reg] ); } else { FPU registers[reg] = src; fast_remove_exponent( FPU registers[reg] ); } make_fpsr(FPU registers[reg]); break; case 0x20: /* FDIV */ fpu_debug(("FDIV %.04f\n",(double)src)); FPU registers[reg] /= src; make_fpsr(FPU registers[reg]); break; case 0x21: /* FMOD */ fpu_debug(("FMOD %.04f\n",(double)src)); // FPU registers[reg] = FPU registers[reg] - (fpu_register) ((int) (FPU registers[reg] / src)) * src; { fpu_register quot = fp_round_to_zero(FPU registers[reg] / src); uae_u32 sign = get_quotient_sign(FPU registers[reg],src); FPU registers[reg] = FPU registers[reg] - quot * src; make_fpsr(FPU registers[reg]); make_quotient(quot, sign); } break; case 0x23: /* FMUL */ fpu_debug(("FMUL %.04f\n",(double)src)); get_dest_flags(FPU registers[reg]); get_source_flags(src); if(fl_dest.in_range && fl_source.in_range) { FPU registers[reg] *= src; } else if (fl_dest.nan || fl_source.nan || fl_dest.zero && fl_source.infinity || fl_dest.infinity && fl_source.zero ) { make_nan( FPU registers[reg] ); } else if (fl_dest.zero || fl_source.zero ) { if (fl_dest.negative && !fl_source.negative || !fl_dest.negative && fl_source.negative) { make_zero_negative(FPU registers[reg]); } else { make_zero_positive(FPU registers[reg]); } } else { if( fl_dest.negative && !fl_source.negative || !fl_dest.negative && fl_source.negative) { make_inf_negative(FPU registers[reg]); } else { make_inf_positive(FPU registers[reg]); } } make_fpsr(FPU registers[reg]); break; case 0x24: /* FSGLDIV */ fpu_debug(("FSGLDIV %.04f\n",(double)src)); FPU registers[reg] = (float)(FPU registers[reg] / src); make_fpsr(FPU registers[reg]); break; case 0x25: /* FREM */ fpu_debug(("FREM %.04f\n",(double)src)); // FPU registers[reg] = FPU registers[reg] - (double) ((int) (FPU registers[reg] / src + 0.5)) * src; { fpu_register quot = fp_round_to_nearest(FPU registers[reg] / src); uae_u32 sign = get_quotient_sign(FPU registers[reg],src); FPU registers[reg] = FPU registers[reg] - quot * src; make_fpsr(FPU registers[reg]); make_quotient(quot,sign); } break; case 0x26: /* FSCALE */ fpu_debug(("FSCALE %.04f\n",(double)src)); // TODO: overflow flags get_dest_flags(FPU registers[reg]); get_source_flags(src); if (fl_source.in_range && fl_dest.in_range) { // When the absolute value of the source operand is >= 2^14, // an overflow or underflow always results. // Here (int) cast is okay. int scale_factor = (int)fp_round_to_zero(src); #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE fp_declare_init_shape(sxp, FPU registers[reg], extended); sxp->ieee.exponent += scale_factor; #else fp_declare_init_shape(sxp, FPU registers[reg], double); uae_u32 exp = sxp->ieee.exponent + scale_factor; if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS) exp = 0; else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS) exp = FP_DOUBLE_EXP_MAX; else exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS; sxp->ieee.exponent = exp; #endif } else if (fl_source.infinity) { // Returns NaN for any Infinity source make_nan( FPU registers[reg] ); } make_fpsr(FPU registers[reg]); break; case 0x27: /* FSGLMUL */ fpu_debug(("FSGLMUL %.04f\n",(double)src)); FPU registers[reg] = (float)(FPU registers[reg] * src); make_fpsr(FPU registers[reg]); break; case 0x28: /* FSUB */ fpu_debug(("FSUB %.04f\n",(double)src)); FPU registers[reg] -= src; make_fpsr(FPU registers[reg]); break; case 0x22: /* FADD */ fpu_debug(("FADD %.04f\n",(double)src)); FPU registers[reg] += src; make_fpsr(FPU registers[reg]); break; case 0x30: /* FSINCOS */ case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: fpu_debug(("FSINCOS %.04f\n",(double)src)); // Cosine must be calculated first if same register FPU registers[extra & 7] = fp_cos(src); FPU registers[reg] = fp_sin (src); // Set FPU fpsr according to the sine result make_fpsr(FPU registers[reg]); break; case 0x38: /* FCMP */ fpu_debug(("FCMP %.04f\n",(double)src)); set_fpsr(0); make_fpsr(FPU registers[reg] - src); break; case 0x3a: /* FTST */ fpu_debug(("FTST %.04f\n",(double)src)); set_fpsr(0); make_fpsr(src); break; default: fpu_debug(("ILLEGAL F OP %X\n",opcode)); m68k_setpc (m68k_getpc () - 4); op_illg (opcode); break; } fpu_debug(("END m68k_getpc()=%X\n",m68k_getpc())); dump_registers( "END "); return; } fpu_debug(("ILLEGAL F OP 2 %X\n",opcode)); m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); } /* -------------------------- Initialization -------------------------- */ PRIVATE uae_u8 m_fpu_state_original[108]; // 90/94/108 PUBLIC void FFPU fpu_init (bool integral_68040) { fpu_debug(("fpu_init\n")); static bool initialized_lookup_tables = false; if (!initialized_lookup_tables) { fpu_init_native_fflags(); fpu_init_native_exceptions(); fpu_init_native_accrued_exceptions(); initialized_lookup_tables = true; } FPU is_integral = integral_68040; FPU instruction_address = 0; FPU fpsr.quotient = 0; set_fpcr(0); set_fpsr(0); #if defined(FPU_USE_X86_ROUNDING) // Initial state after boot, reset and frestore(null frame) x86_control_word = CW_INITIAL; #elif defined(USE_X87_ASSEMBLY) volatile unsigned short int cw; __asm__ __volatile__("fnstcw %0" : "=m" (cw)); cw &= ~0x0300; cw |= 0x0300; // CW_PC_EXTENDED cw &= ~0x0C00; cw |= 0x0000; // CW_RC_NEAR __asm__ __volatile__("fldcw %0" : : "m" (cw)); #endif FPU result = 1; for (int i = 0; i < 8; i++) make_nan(FPU registers[i]); } PUBLIC void FFPU fpu_exit (void) { fpu_debug(("fpu_exit\n")); } PUBLIC void FFPU fpu_reset (void) { fpu_debug(("fpu_reset\n")); fpu_exit(); fpu_init(FPU is_integral); } BasiliskII/src/uae_cpu/fpu/fpu_x86.cpp0000644000175000017500000050441510736405224017762 0ustar centriscentris/* * fpu_x86.cpp - 68881/68040 fpu code for x86/Windows an Linux/x86. * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Based on UAE FPU, original copyright 1996 Herman ten Brugge, * rewritten for x86 by Lauri Pesonen 1999-2000, * accomodated to GCC's Extended Asm syntax by Gwenole Beauchesne 2000. * * 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 * * * Interface * Almost the same as original. Please see the comments in "fpu.h". * * * Why assembly? * The reason is not really speed, but to get infinities, * NANs and flags finally working. * * * How to maintain Mac and x86 FPU flags -- plan B * * regs.piar is not updated. * * regs.FPU fpcr always contains the real 68881/68040 control word. * * regs.FPU fpsr is not kept up-to-date, for efficiency reasons. * Most of the FPU commands update this in a way or another, but it is not * read nearly that often. Therefore, three host-specific words hold the * status byte and exception byte ("x86_status_word"), accrued exception * byte ("x86_status_word_accrued") and the quotient byte ("FPU fpsr.quotient"), * as explained below. * * CONDITION CODE - QUOTIENT - EXCEPTION STATUS - ACCRUED EXCEPTION * CONDITION CODE (N,Z,I,NAN) * - updated after each opcode, if needed. * - x86 assembly opcodes call FXAM and store the status word to * "x86_status_word". * - When regs.FPU fpsr is actually used, the value of "x86_status_word" * is translated. * QUOTIENT BYTE * - Updated by frem, fmod, frestore(null frame) * - Stored in "FPU fpsr.quotient" in correct bit position, combined when * regs.FPU fpsr is actually used. * EXCEPTION STATUS (BSUN,SNAN,OPERR,OVFL,UNFL,DZ,INEX2,INEX1) * - updated after each opcode, if needed. * - Saved in x86 form in "x86_status_word". * - When regs.FPU fpsr is actually used, the value of "x86_status_word" * is translated. * - Only fcc_op can set BSUN * ACCRUED EXCEPTION (ACCR_IOP,ACCR_OVFL,ACCR_UNFL,ACCR_DZ,ACCR_INEX) * - updated after each opcode, if needed. * - Logically OR'ed in x86 form to "x86_status_word_accrued". * - When regs.FPU fpsr is actually used, the value of * "x86_status_word_accrued" is translated. * * When "x86_status_word" and "x86_status_word_accrued" are stored, * all pending x86 FPU exceptions are cleared, if there are any. * * Writing to "regs.FPU fpsr" reverse-maps to x86 status/exception values and * stores the values in "x86_status_word", "x86_status_word_accrued" * and "FPU fpsr.quotient". * * So, "x86_status_word" and "x86_status_word_accrued" are not in * correct bit positions and have x86 values, but "FPU fpsr.quotient" is at * correct position. * * Note that it does not matter that the reverse-mapping is not exact * (both SW_IE and SW_DE are mapped to ACCR_IOP, but ACCR_IOP maps to * SW_IE only), the MacOS always sees the correct exception bits. * * Also note the usage of the fake BSUN flag SW_FAKE_BSUN. If you change * the x86 FPU code, you must make sure that you don't generate any FPU * stack faults. * * * x86 co-processor initialization: * * Bit Code Use * 0 IM Invalid operation exception mask 1 Disabled * 1 DM Denormalized operand exception mask 1 Disabled * 2 ZM Zerodivide exception mask 1 Disabled * 3 OM Overflow exception mask 1 Disabled * 4 UM Underflow exception mask 1 Disabled * 5 PM Precision exception mask 1 Disabled * 6 - - - - * 7 IEM Interrupt enable mask 0 Enabled * 8 PC Precision control\ 1 - 64 bits * 9 PC Precision control/ 1 / * 10 RC Rounding control\ 0 - Nearest even * 11 RC Rounding control/ 0 / * 12 IC Infinity control 1 Affine * 13 - - - - * 14 - - - - * 15 - - - - * * * TODO: * - Exceptions are not implemented. * - All tbyte variables should be aligned to 16-byte boundaries. * (for best efficiency). * - FTRAPcc code looks like broken. * - If USE_3_BIT_QUOTIENT is 0, exceptions should be checked after * float -> int rounding (frem,fmod). * - The speed can be greatly improved. Do this only after you are sure * that there are no major bugs. * - Support for big-endian byte order (but all assembly code needs to * be rewritten anyway) * I have some non-portable code like *((uae_u16 *)&m68k_dreg(regs, reg)) = newv; * Sorry about that, you need to change these. I could do it myself, but better * not, I would have no way to test them out. * I tried to mark all spots with a comment TODO_BIGENDIAN. * - to_double() may need renormalization code. Or then again, maybe not. * - Signaling NANs should be handled better. The current mapping of * signaling nan exception to denormalized operand exception is only * based on the idea that the (possible) handler sees that "something * seriously wrong" and takes the same action. Should not really get (m)any * of those since normalization is handled on to_exten() * */ #include #include #include #include "sysdeps.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" #define FPU_IMPLEMENTATION #include "fpu/fpu.h" #include "fpu/fpu_x86.h" #include "fpu/fpu_x86_asm.h" /* Global FPU context */ fpu_t fpu; /* -------------------------------------------------------------------------- */ /* --- Native Support --- */ /* -------------------------------------------------------------------------- */ #include "fpu/flags.h" #include "fpu/exceptions.h" #include "fpu/rounding.h" #include "fpu/impl.h" #include "fpu/flags.cpp" #include "fpu/exceptions.cpp" #include "fpu/rounding.cpp" /* -------------------------------------------------------------------------- */ /* --- Scopes Definition --- */ /* -------------------------------------------------------------------------- */ #undef PUBLIC #define PUBLIC /**/ #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* ---------------------------- Compatibility ---------------------------- */ #define BYTE uint8 #define WORD uint16 #define DWORD uint32 #define min(a, b) (((a) < (b)) ? (a) : (b)) /* ---------------------------- Configuration ---------------------------- */ /* If USE_3_BIT_QUOTIENT is set to 1, FREM and FMOD use a faster version with only 3 quotient bits (those provided by the x86 FPU). If set to 0, they calculate the same 7 bits that m68k does. It seems (as for now) that 3 bits suffice for all Mac programs I have tried. If you decide that you need all 7 bits (USE_3_BIT_QUOTIENT is 0), consider checking the host exception flags after FISTP (search for "TODO:Quotient". The result may be too large to fit into a dword. */ /* gb-- I only tested the following configurations: USE_3_BIT_QUOTIENT 1 -- still changes to apply if no 3-bit quotient FPU_DEBUG 1 or 0 USE_CONSISTENCY_CHECKING 0 I3_ON_ILLEGAL_FPU_OP 0 -- and this won't change I3_ON_FTRAPCC 0 -- and this won't change */ #define USE_3_BIT_QUOTIENT 1 //#define FPU_DEBUG 0 -- now defined in "fpu/fpu.h" #define USE_CONSISTENCY_CHECKING 0 #define I3_ON_ILLEGAL_FPU_OP 0 #define I3_ON_FTRAPCC 0 /* ---------------------------- Debugging ---------------------------- */ PUBLIC void FFPU fpu_dump_registers(void) { for (int i = 0; i < 8; i++){ printf ("FP%d: %g ", i, fpu_get_register(i)); if ((i & 3) == 3) printf ("\n"); } } PUBLIC void FFPU fpu_dump_flags(void) { printf ("N=%d Z=%d I=%d NAN=%d\n", (get_fpsr() & FPSR_CCB_NEGATIVE) != 0, (get_fpsr() & FPSR_CCB_ZERO)!= 0, (get_fpsr() & FPSR_CCB_INFINITY) != 0, (get_fpsr() & FPSR_CCB_NAN) != 0); } #include "debug.h" #if FPU_DEBUG #undef __inline__ #define __inline__ PRIVATE void FFPU dump_first_bytes_buf(char *b, uae_u8* buf, uae_s32 actual) { char bb[10]; int32 i, bytes = min(actual,100); *b = 0; for (i=0; i= 10) _ix = 0; sprintf( _s[_ix], "%.04f", (float)f ); return( _s[_ix] ); } PUBLIC void FFPU dump_registers(const char *s) { char b[512]; sprintf( b, "%s: %s, %s, %s, %s, %s, %s, %s, %s\r\n", s, etos(FPU registers[0]), etos(FPU registers[1]), etos(FPU registers[2]), etos(FPU registers[3]), etos(FPU registers[4]), etos(FPU registers[5]), etos(FPU registers[6]), etos(FPU registers[7]) ); D(bug((char*)b)); } #else PUBLIC void FFPU dump_registers(const char *) { } PUBLIC void FFPU dump_first_bytes(uae_u8 *, uae_s32) { } #endif /* ---------------------------- FPU consistency ---------------------------- */ #if USE_CONSISTENCY_CHECKING PRIVATE void FFPU FPU_CONSISTENCY_CHECK_START(void) { /* _asm { FNSTSW checked_sw_atstart } */ __asm__ __volatile__("fnstsw %0" : "=m" (checked_sw_atstart)); } PRIVATE void FFPU FPU_CONSISTENCY_CHECK_STOP(const char *name) { uae_u16 checked_sw_atend; // _asm FNSTSW checked_sw_atend __asm__ __volatile__("fnstsw %0" : "=m" (checked_sw_attend)); char msg[256]; // Check for FPU stack overflows/underflows. if( (checked_sw_atend & 0x3800) != (checked_sw_atstart & 0x3800) ) { wsprintf( msg, "FPU stack leak at %s, %X, %X\r\n", name, (int)(checked_sw_atstart & 0x3800) >> 11, (int)(checked_sw_atend & 0x3800) >> 11 ); OutputDebugString(msg); } // Observe status mapping. /* if(checked_sw_atstart != 0x400 || checked_sw_atend != 0x400) { wsprintf( msg, "Op %s, x86_status_word before=%X, x86_status_word after=%X\r\n", name, (int)checked_sw_atstart, (int)checked_sw_atend ); OutputDebugString(msg); } */ } #else PRIVATE void FFPU FPU_CONSISTENCY_CHECK_START(void) { } PRIVATE void FFPU FPU_CONSISTENCY_CHECK_STOP(const char *) { } #endif /* ---------------------------- Status byte ---------------------------- */ // Map x86 FXAM codes -> m68k fpu status byte #define SW_Z_I_NAN_MASK (SW_C0|SW_C2|SW_C3) #define SW_Z (SW_C3) #define SW_I (SW_C0|SW_C2) #define SW_NAN (SW_C0) #define SW_FINITE (SW_C2) #define SW_EMPTY_REGISTER (SW_C0|SW_C3) #define SW_DENORMAL (SW_C2|SW_C3) #define SW_UNSUPPORTED (0) #define SW_N (SW_C1) // Initial state after boot, reset and frestore(null frame) #define SW_INITIAL SW_FINITE /* ---------------------------- Status functions ---------------------------- */ PRIVATE void __inline__ FFPU SET_BSUN_ON_NAN () { if( (x86_status_word & (SW_Z_I_NAN_MASK)) == SW_NAN ) { x86_status_word |= SW_FAKE_BSUN; x86_status_word_accrued |= SW_IE; } } PRIVATE void __inline__ FFPU build_ex_status () { if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } } // TODO_BIGENDIAN; all of these. /* ---------------------------- Type functions ---------------------------- */ /* When the FPU creates a NAN, the NAN always contains the same bit pattern in the mantissa. All bits of the mantissa are ones for any precision. When the user creates a NAN, any nonzero bit pattern can be stored in the mantissa. */ PRIVATE __inline__ void FFPU MAKE_NAN (fpu_register & f) { // Make it non-signaling. uae_u8 * p = (uae_u8 *) &f; memset( p, 0xFF, sizeof(fpu_register) - 1 ); p[9] = 0x7F; } /* For single- and double-precision infinities the fraction is a zero. For extended-precision infinities, the mantissa’s MSB, the explicit integer bit, can be either one or zero. */ PRIVATE __inline__ uae_u32 FFPU IS_INFINITY (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { if ((*((uae_u32 *)&p[0]) == 0) && ((*((uae_u32 *)&p[4]) & 0x7FFFFFFF) == 0)) return(1); } return(0); } PRIVATE __inline__ uae_u32 FFPU IS_NAN (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; if( ((p[9] & 0x7F) == 0x7F) && p[8] == 0xFF ) { if ((*((uae_u32 *)&p[0]) == 0) && ((*((uae_u32 *)&p[4]) & 0x7FFFFFFF) != 0)) return(1); } return(0); } PRIVATE __inline__ uae_u32 FFPU IS_ZERO (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; return *((uae_u32 *)p) == 0 && *((uae_u32 *)&p[4]) == 0 && ( *((uae_u16 *)&p[8]) & 0x7FFF ) == 0; } PRIVATE __inline__ void FFPU MAKE_INF_POSITIVE (fpu_register & f) { uae_u8 * p = (uae_u8 *) &f; memset( p, 0, sizeof(fpu_register)-2 ); *((uae_u16 *)&p[8]) = 0x7FFF; } PRIVATE __inline__ void FFPU MAKE_INF_NEGATIVE (fpu_register & f) { uae_u8 * p = (uae_u8 *) &f; memset( p, 0, sizeof(fpu_register)-2 ); *((uae_u16 *)&p[8]) = 0xFFFF; } PRIVATE __inline__ void FFPU MAKE_ZERO_POSITIVE (fpu_register & f) { uae_u32 * const p = (uae_u32 *) &f; memset( p, 0, sizeof(fpu_register) ); } PRIVATE __inline__ void FFPU MAKE_ZERO_NEGATIVE (fpu_register & f) { uae_u32 * const p = (uae_u32 *) &f; memset( p, 0, sizeof(fpu_register) ); *((uae_u32 *)&p[4]) = 0x80000000; } PRIVATE __inline__ uae_u32 FFPU IS_NEGATIVE (fpu_register const & f) { uae_u8 * p = (uae_u8 *) &f; return( (p[9] & 0x80) != 0 ); } /* ---------------------------- Conversions ---------------------------- */ PRIVATE void FFPU signed_to_extended ( uae_s32 x, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [f] FILD DWORD PTR [x] FSTP TBYTE PTR [ESI] } */ __asm__ __volatile__("fildl %1\n\tfstpt %0" : "=m" (f) : "m" (x)); D(bug("signed_to_extended (%X) = %s\r\n",(int)x,etos(f))); FPU_CONSISTENCY_CHECK_STOP("signed_to_extended"); } PRIVATE uae_s32 FFPU extended_to_signed_32 ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_s32 tmp; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FISTP DWORD PTR tmp FNSTSW sw_temp } */ __asm__ __volatile__( "fldt %2\n" "fistpl %0\n" "fnstsw %1\n" : "=m" (tmp), "=m" (sw_temp) : "m" (f) ); if(sw_temp & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; // Setting the value to zero might not be the right way to go, // but I'll leave it like this for now. tmp = 0; } if(sw_temp & SW_PE) { x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } } D(bug("extended_to_signed_32 (%s) = %X\r\n",etos(f),(int)tmp)); FPU_CONSISTENCY_CHECK_STOP("extended_to_signed_32"); return tmp; } PRIVATE uae_s16 FFPU extended_to_signed_16 ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_s16 tmp; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FISTP WORD PTR tmp FNSTSW sw_temp } */ __asm__ __volatile__( "fldt %2\n" "fistp %0\n" "fnstsw %1\n" : "=m" (tmp), "=m" (sw_temp) : "m" (f) ); if(sw_temp & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; tmp = 0; } if(sw_temp & SW_PE) { x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } } D(bug("extended_to_signed_16 (%s) = %X\r\n",etos(f),(int)tmp)); FPU_CONSISTENCY_CHECK_STOP("extended_to_signed_16"); return tmp; } PRIVATE uae_s8 FFPU extended_to_signed_8 ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_s16 tmp; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FISTP WORD PTR tmp FNSTSW sw_temp } */ __asm__ __volatile__( "fldt %2\n" "fistp %0\n" "fnstsw %1\n" : "=m" (tmp), "=m" (sw_temp) : "m" (f) ); if(sw_temp & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); if(sw_temp & (SW_OE|SW_UE|SW_DE|SW_IE)) { // Map SW_OE to OPERR. x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; tmp = 0; } if(sw_temp & SW_PE) { x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } } if(tmp > 127 || tmp < -128) { // OPERR x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; } D(bug("extended_to_signed_8 (%s) = %X\r\n",etos(f),(int)tmp)); FPU_CONSISTENCY_CHECK_STOP("extended_to_signed_8"); return (uae_s8)tmp; } PRIVATE void FFPU double_to_extended ( double x, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV EDI, [f] FLD QWORD PTR [x] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldl %1\n" "fstpt %0\n" : "=m" (f) : "m" (x) ); FPU_CONSISTENCY_CHECK_STOP("double_to_extended"); } PRIVATE fpu_double FFPU extended_to_double( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); double result; /* _asm { MOV ESI, [f] FLD TBYTE PTR [ESI] FSTP QWORD PTR result } */ __asm__ __volatile__( "fldt %1\n" "fstpl %0\n" : "=m" (result) : "m" (f) ); FPU_CONSISTENCY_CHECK_STOP("extended_to_double"); return result; } PRIVATE void FFPU to_single ( uae_u32 src, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [f] FLD DWORD PTR src FSTP TBYTE PTR [ESI] } */ __asm__ __volatile__( "flds %1\n" "fstpt %0\n" : "=m" (f) : "m" (src) ); D(bug("to_single (%X) = %s\r\n",src,etos(f))); FPU_CONSISTENCY_CHECK_STOP("to_single"); } // TODO_BIGENDIAN PRIVATE void FFPU to_exten_no_normalize ( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); uae_u32 *p = (uae_u32 *)&f; uae_u32 sign = (wrd1 & 0x80000000) >> 16; uae_u32 exp = (wrd1 >> 16) & 0x7fff; p[0] = wrd3; p[1] = wrd2; *((uae_u16 *)&p[2]) = (uae_u16)(sign | exp); D(bug("to_exten_no_normalize (%X,%X,%X) = %s\r\n",wrd1,wrd2,wrd3,etos(f))); FPU_CONSISTENCY_CHECK_STOP("to_exten_no_normalize"); } PRIVATE void FFPU to_exten ( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); uae_u32 *p = (uae_u32 *)&f; uae_u32 sign = (wrd1 & 0x80000000) >> 16; uae_u32 exp = (wrd1 >> 16) & 0x7fff; // The explicit integer bit is not set, must normalize. // Don't do it for zeroes, infinities or nans. if( (wrd2 & 0x80000000) == 0 && exp != 0 && exp != 0x7FFF ) { D(bug("to_exten denormalized mantissa (%X,%X,%X)\r\n",wrd1,wrd2,wrd3)); if( wrd2 | wrd3 ) { // mantissa, not fraction. uae_u64 man = ((uae_u64)wrd2 << 32) | wrd3; while( exp > 0 && (man & UVAL64(0x8000000000000000)) == 0 ) { man <<= 1; exp--; } wrd2 = (uae_u32)( man >> 32 ); wrd3 = (uae_u32)( man & 0xFFFFFFFF ); if( exp == 0 || (wrd2 & 0x80000000) == 0 ) { // underflow wrd2 = wrd3 = exp = 0; sign = 0; } } else { if(exp != 0x7FFF && exp != 0) { // Make a non-signaling nan. exp = 0x7FFF; sign = 0; wrd2 = 0x80000000; } } } p[0] = wrd3; p[1] = wrd2; *((uae_u16 *)&p[2]) = (uae_u16)(sign | exp); D(bug("to_exten (%X,%X,%X) = %s\r\n",wrd1,wrd2,wrd3,etos(f))); FPU_CONSISTENCY_CHECK_STOP("to_exten"); } PRIVATE void FFPU to_double ( uae_u32 wrd1, uae_u32 wrd2, fpu_register & f ) { FPU_CONSISTENCY_CHECK_START(); // gb-- make GCC happy union { uae_u64 q; uae_u32 l[2]; } src; // Should renormalize if needed. I'm not sure that x86 and m68k FPU's // do it the sama way. This should be extremely rare however. // to_exten() is often called with denormalized values. src.l[0] = wrd2; src.l[1] = wrd1; /* _asm { FLD QWORD PTR src MOV EDI, [f] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldl %1\n" "fstpt %0\n" : "=m" (f) : "m" (src.q) ); D(bug("to_double (%X,%X) = %s\r\n",wrd1,wrd2,etos(f))); FPU_CONSISTENCY_CHECK_STOP("to_double"); } PRIVATE uae_u32 FFPU from_single ( fpu_register const & f ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_u32 dest; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FSTP DWORD PTR dest FNSTSW sw_temp } */ __asm__ __volatile__( "fldt %2\n" "fstps %0\n" "fnstsw %1\n" : "=m" (dest), "=m" (sw_temp) : "m" (f) ); sw_temp &= SW_EXCEPTION_MASK; if(sw_temp) { // _asm FNCLEX asm("fnclex"); x86_status_word = (x86_status_word & ~SW_EXCEPTION_MASK) | sw_temp; x86_status_word_accrued |= sw_temp; } D(bug("from_single (%s) = %X\r\n",etos(f),dest)); FPU_CONSISTENCY_CHECK_STOP("from_single"); return dest; } // TODO_BIGENDIAN PRIVATE void FFPU from_exten ( fpu_register const & f, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3 ) { FPU_CONSISTENCY_CHECK_START(); uae_u32 *p = (uae_u32 *)&f; *wrd3 = p[0]; *wrd2 = p[1]; *wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16; D(bug("from_exten (%s) = %X,%X,%X\r\n",etos(f),*wrd1,*wrd2,*wrd3)); FPU_CONSISTENCY_CHECK_STOP("from_exten"); } PRIVATE void FFPU from_double ( fpu_register const & f, uae_u32 *wrd1, uae_u32 *wrd2 ) { FPU_CONSISTENCY_CHECK_START(); volatile uae_u32 dest[2]; volatile WORD sw_temp; /* _asm { MOV EDI, [f] FLD TBYTE PTR [EDI] FSTP QWORD PTR dest FNSTSW sw_temp } */ __asm__ __volatile__( "fldt %2\n" "fstpl %0\n" "fnstsw %1\n" : "=m" (dest), "=m" (sw_temp) : "m" (f) ); sw_temp &= SW_EXCEPTION_MASK; if(sw_temp) { // _asm FNCLEX asm("fnclex"); x86_status_word = (x86_status_word & ~SW_EXCEPTION_MASK) | sw_temp; x86_status_word_accrued |= sw_temp; } // TODO: There is a partial memory stall, nothing happens until FSTP retires. // On PIII, could use MMX move w/o any penalty. *wrd2 = dest[0]; *wrd1 = dest[1]; D(bug("from_double (%s) = %X,%X\r\n",etos(f),dest[1],dest[0])); FPU_CONSISTENCY_CHECK_STOP("from_double"); } PRIVATE void FFPU do_fmove ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); FPU_CONSISTENCY_CHECK_STOP("do_fmove"); } /* PRIVATE void FFPU do_fmove_no_status ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FSTP TBYTE PTR [EDI] } FPU_CONSISTENCY_CHECK_STOP("do_fmove_no_status"); } */ /* ---------------------------- Operations ---------------------------- */ PRIVATE void FFPU do_fint ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FRNDINT FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "frndint\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fint"); } PRIVATE void FFPU do_fintrz ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); WORD cw_temp; /* _asm { MOV ESI, [src] MOV EDI, [dest] FSTCW cw_temp and cw_temp, ~X86_ROUNDING_MODE or cw_temp, CW_RC_ZERO FLDCW cw_temp FLD TBYTE PTR [ESI] FRNDINT FXAM FNSTSW x86_status_word FLDCW x86_control_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fstcw %0\n" "andl $(~X86_ROUNDING_MODE), %0\n" "orl $CW_RC_ZERO, %0\n" "fldcw %0\n" "fldt %3\n" "frndint\n" "fxam \n" "fnstsw %1\n" "fldcw %4\n" "fstpt %2\n" : "+m" (cw_temp), "=m" (x86_status_word), "=m" (dest) : "m" (src), "m" (x86_control_word) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fintrz"); } PRIVATE void FFPU do_fsqrt ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FSQRT FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fsqrt \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsqrt"); } PRIVATE void FFPU do_ftst ( fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] FLD TBYTE PTR [ESI] FXAM FNSTSW x86_status_word FSTP ST(0) } */ __asm__ __volatile__( "fldt %1\n" "fxam \n" "fnstsw %0\n" "fstp %%st(0)\n" : "=m" (x86_status_word) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_ftst"); } // These functions are calculated in 53 bits accuracy only. // Exception checking is not complete. PRIVATE void FFPU do_fsinh ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = sinh(x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_fsinh"); } PRIVATE void FFPU do_flognp1 ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = log (x + 1.0); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_flognp1"); } PRIVATE void FFPU do_fetoxm1 ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = exp (x) - 1.0; double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_fetoxm1"); } PRIVATE void FFPU do_ftanh ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = tanh (x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_ftanh"); } PRIVATE void FFPU do_fatan ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = atan (x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_fatan"); } PRIVATE void FFPU do_fasin ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = asin (x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_fasin"); } PRIVATE void FFPU do_fatanh ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = log ((1 + x) / (1 - x)) / 2; double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_fatanh"); } PRIVATE void FFPU do_fetox ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = exp (x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_fetox"); } PRIVATE void FFPU do_ftwotox ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = pow(2.0, x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_ftwotox"); } PRIVATE void FFPU do_ftentox ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = pow(10.0, x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_ftentox"); } PRIVATE void FFPU do_flogn ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = log (x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_flogn"); } PRIVATE void FFPU do_flog10 ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = log10 (x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_flog10"); } PRIVATE void FFPU do_flog2 ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = log (x) / log (2.0); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_flog2"); } PRIVATE void FFPU do_facos ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = acos(x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_facos"); } PRIVATE void FFPU do_fcosh ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); double x, y; x = extended_to_double( src ); y = cosh(x); double_to_extended( y, dest ); do_ftst( dest ); FPU_CONSISTENCY_CHECK_STOP("do_fcosh"); } PRIVATE void FFPU do_fsin ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FSIN FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fsin \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsin"); } // TODO: Should check for out-of-range condition (partial tangent) PRIVATE void FFPU do_ftan ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FPTAN FSTP ST(0) ; pop 1.0 (the 8087/287 compatibility thing) FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fptan \n" "fstp %%st(0)\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE - SW_UE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_ftan"); } PRIVATE void FFPU do_fabs ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FABS FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fabs \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); // x86 fabs should not rise any exceptions (except stack underflow) if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fabs"); } PRIVATE void FFPU do_fneg ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FCHS FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fchs \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); // x86 fchs should not rise any exceptions (except stack underflow) if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fneg"); } PRIVATE void FFPU do_fcos ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FCOS FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fcos \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fcos"); } PRIVATE void FFPU do_fgetexp ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FXTRACT FSTP ST(0) ; pop mantissa FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fxtract\n" "fstp %%st(0)\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fgetexp"); } PRIVATE void FFPU do_fgetman ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FXTRACT FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) ; pop exponent } */ __asm__ __volatile__( "fldt %2\n" "fxtract\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "=m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fgetman"); } PRIVATE void FFPU do_fdiv ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FDIV ST(0),ST(1) FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fdiv %%st(1), %%st(0)\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fdiv"); } // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. // Quotient Byte is loaded with the sign and least significant // seven bits of the quotient. PRIVATE void FFPU do_fmod ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; #if !USE_3_BIT_QUOTIENT WORD cw_temp; #endif uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[9]) & 0x80; /* _asm { MOV ESI, [src] MOV EDI, [dest] #if !USE_3_BIT_QUOTIENT MOV CX, x86_control_word AND CX, ~X86_ROUNDING_MODE OR CX, CW_RC_ZERO MOV cw_temp, CX FLDCW cw_temp FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FDIV ST(0),ST(1) FABS FISTP DWORD PTR quot FSTP ST(0) FLDCW x86_control_word // TODO:Quotient // Should clear any possible exceptions here #endif FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] // loop until the remainder is not partial any more. partial_loop: FPREM FNSTSW status TEST status, SW_C2 JNE partial_loop FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ #if !USE_3_BIT_QUOTIENT __asm__ __volatile__( "movl %6, %%ecx\n" // %6: x86_control_word (read) "andl $(~X86_ROUNDING_MODE), %%ecx\n" "orl $CW_RC_ZERO, %%ecx\n" "movl %%ecx, %0\n" // %0: cw_temp (read/write) "fldcw %0\n" "fldt %5\n" "fldt %4\n" "fdiv %%st(1), %%st(0)\n" "fabs \n" "fistpl %1\n" // %1: quot (read/write) "fstp %%st(0)\n" "fldcw %6\n" "fldt %5\n" "fldt %4\n" "0:\n" // partial_loop "fprem \n" "fnstsw %2\n" // %2: status (read/write) "testl $SW_C2, %2\n" "jne 0b\n" "fxam \n" "fnstsw %3\n" // %3: x86_status_word (write) "fstpt %4\n" "fstp %%st(0)\n" : "+m" (cw_temp), "+m" (quot), "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_control_word) : "ecx" ); #else __asm__ __volatile__( "fldt %3\n" "fldt %2\n" "0:\n" // partial_loop "fprem \n" "fnstsw %0\n" // %0: status (read/write) "testl $SW_C2, %0\n" "jne 0b\n" "fxam \n" "fnstsw %1\n" // %1: x86_status_word (write) "fstpt %2\n" "fstp %%st(0)\n" : "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src) ); #endif if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } #if USE_3_BIT_QUOTIENT // SW_C1 Set to least significant bit of quotient (Q0). // SW_C3 Set to bit 1 (Q1) of the quotient. // SW_C0 Set to bit 2 (Q2) of the quotient. quot = ((status & SW_C0) >> 6) | ((status & SW_C3) >> 13) | ((status & SW_C1) >> 9); FPU fpsr.quotient = (sign | quot) << 16; #else FPU fpsr.quotient = (sign | (quot&0x7F)) << 16; #endif FPU_CONSISTENCY_CHECK_STOP("do_fmod"); } PRIVATE void FFPU do_frem ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; #if !USE_3_BIT_QUOTIENT WORD cw_temp; #endif uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[9]) & 0x80; /* _asm { MOV ESI, [src] MOV EDI, [dest] #if !USE_3_BIT_QUOTIENT MOV CX, x86_control_word AND CX, ~X86_ROUNDING_MODE OR CX, CW_RC_NEAR MOV cw_temp, CX FLDCW cw_temp FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FDIV ST(0),ST(1) FABS FISTP DWORD PTR quot FSTP ST(0) FLDCW x86_control_word // TODO:Quotient // Should clear any possible exceptions here #endif FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] // loop until the remainder is not partial any more. partial_loop: FPREM1 FNSTSW status TEST status, SW_C2 JNE partial_loop FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ #if !USE_3_BIT_QUOTIENT __asm__ __volatile__( "movl %6, %%ecx\n" // %6: x86_control_word (read) "andl $(~X86_ROUNDING_MODE), %%ecx\n" "orl $CW_RC_NEAR, %%ecx\n" "movl %%ecx, %0\n" // %0: cw_temp (read/write) "fldcw %0\n" "fldt %5\n" "fldt %4\n" "fdiv %%st(1), %%st(0)\n" "fabs \n" "fistpl %1\n" // %1: quot (read/write) "fstp %%st(0)\n" "fldcw %6\n" "fldt %5\n" "fldt %4\n" "0:\n" // partial_loop "fprem1 \n" "fnstsw %2\n" // %2: status (read/write) "testl $SW_C2, %2\n" "jne 0b\n" "fxam \n" "fnstsw %3\n" // %3: x86_status_word (write) "fstpt %4\n" "fstp %%st(0)\n" : "+m" (cw_temp), "+m" (quot), "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_control_word) : "ecx" ); #else __asm__ __volatile__( "fldt %3\n" "fldt %2\n" "0:\n" // partial_loop "fprem1 \n" "fnstsw %0\n" // %0: status (read/write) "testl $SW_C2, %0\n" "jne 0b\n" "fxam \n" "fnstsw %1\n" // %1: x86_status_word (write) "fstpt %2\n" "fstp %%st(0)\n" : "+m" (status), "=m" (x86_status_word), "+m" (dest) : "m" (src) ); #endif if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } #if USE_3_BIT_QUOTIENT // SW_C1 Set to least significant bit of quotient (Q0). // SW_C3 Set to bit 1 (Q1) of the quotient. // SW_C0 Set to bit 2 (Q2) of the quotient. quot = ((status & SW_C0) >> 6) | ((status & SW_C3) >> 13) | ((status & SW_C1) >> 9); FPU fpsr.quotient = (sign | quot) << 16; #else FPU fpsr.quotient = (sign | (quot&0x7F)) << 16; #endif FPU_CONSISTENCY_CHECK_STOP("do_frem"); } // Faster versions. The current rounding mode is already correct. #if !USE_3_BIT_QUOTIENT PRIVATE void FFPU do_fmod_dont_set_cw ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[9]) & 0x80; _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FDIV ST(0),ST(1) FABS FISTP DWORD PTR quot FSTP ST(0) // TODO:Quotient // Should clear any possible exceptions here FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] // loop until the remainder is not partial any more. partial_loop: FPREM FNSTSW status TEST status, SW_C2 JNE partial_loop FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } if(x86_status_word & SW_EXCEPTION_MASK) { _asm FNCLEX x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } FPU fpsr.quotient = (sign | (quot&0x7F)) << 16; FPU_CONSISTENCY_CHECK_STOP("do_fmod_dont_set_cw"); } PRIVATE void FFPU do_frem_dont_set_cw ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); volatile uint16 status; uae_u32 quot; uae_u8 * dest_p = (uae_u8 *)&dest; uae_u8 * src_p = (uae_u8 *)&src; uae_u32 sign = (dest_p[9] ^ src_p[9]) & 0x80; _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FDIV ST(0),ST(1) FABS FISTP DWORD PTR quot FSTP ST(0) // TODO:Quotient // Should clear any possible exceptions here FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] // loop until the remainder is not partial any more. partial_loop: FPREM1 FNSTSW status TEST status, SW_C2 JNE partial_loop FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } if(x86_status_word & SW_EXCEPTION_MASK) { _asm FNCLEX x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE); x86_status_word_accrued |= x86_status_word; } FPU fpsr.quotient = (sign | (quot&0x7F)) << 16; FPU_CONSISTENCY_CHECK_STOP("do_frem_dont_set_cw"); } #endif //USE_3_BIT_QUOTIENT PRIVATE void FFPU do_fadd ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FADD FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fadd \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fadd"); } PRIVATE void FFPU do_fmul ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FMUL FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fmul \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fmul"); } PRIVATE void FFPU do_fsgldiv ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); WORD cw_temp; /* _asm { FSTCW cw_temp and cw_temp, ~X86_ROUNDING_PRECISION or cw_temp, PRECISION_CONTROL_SINGLE FLDCW cw_temp MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FDIV ST(0),ST(1) FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) FLDCW x86_control_word } */ __asm__ __volatile__( "fstcw %0\n" "andl $(~X86_ROUNDING_PRECISION), %0\n" "orl $PRECISION_CONTROL_SINGLE, %0\n" "fldcw %0\n" "fldt %3\n" "fldt %2\n" "fdiv %%st(1), %%st(0)\n" "fxam \n" "fnstsw %1\n" "fstpt %2\n" "fstp %%st(0)\n" "fldcw %4\n" : "+m" (cw_temp), "=m" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_control_word) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsgldiv"); } PRIVATE void FFPU do_fscale ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FSCALE FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fscale \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_UE - SW_OE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fscale"); } PRIVATE void FFPU do_fsglmul ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); WORD cw_temp; /* _asm { FSTCW cw_temp and cw_temp, ~X86_ROUNDING_PRECISION or cw_temp, PRECISION_CONTROL_SINGLE FLDCW cw_temp MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FMUL FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FLDCW x86_control_word } */ __asm__ __volatile__( "fstcw %0\n" "andl $(~X86_ROUNDING_PRECISION), %0\n" "orl $PRECISION_CONTROL_SINGLE, %0\n" "fldcw %0\n" "fldt %3\n" "fldt %2\n" "fmul \n" "fxam \n" "fnstsw %1\n" "fstpt %2\n" "fldcw %4\n" : "+m" (cw_temp), "=m" (x86_status_word), "+m" (dest) : "m" (src), "m" (x86_status_word) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsglmul"); } PRIVATE void FFPU do_fsub ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FSUB ST(0),ST(1) FXAM FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fsub %%st(1), %%st(0)\n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "+m" (dest) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_OE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsub"); } PRIVATE void FFPU do_fsincos ( fpu_register & dest_sin, fpu_register & dest_cos, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest_cos] FLD TBYTE PTR [ESI] FSINCOS FSTP TBYTE PTR [EDI] FXAM MOV EDI, [dest_sin] FNSTSW x86_status_word FSTP TBYTE PTR [EDI] FSTP ST(0) } */ __asm__ __volatile__( "fldt %3\n" "fsincos\n" "fstpt %1\n" "fxam \n" "fnstsw %0\n" "fstpt %2\n" "fstp %%st(0)\n" : "=m" (x86_status_word), "=m" (dest_cos), "=m" (dest_sin) : "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~(SW_EXCEPTION_MASK - SW_IE - SW_UE - SW_PE); x86_status_word_accrued |= x86_status_word; } FPU_CONSISTENCY_CHECK_STOP("do_fsincos"); } PRIVATE void FFPU do_fcmp ( fpu_register & dest, fpu_register const & src ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { MOV ESI, [src] MOV EDI, [dest] FLD TBYTE PTR [ESI] FLD TBYTE PTR [EDI] FSUB ST(0),ST(1) FXAM FNSTSW x86_status_word FSTP ST(0) FSTP ST(0) } */ __asm__ __volatile__( "fldt %2\n" "fldt %1\n" "fsub %%st(1), %%st(0)\n" "fxam \n" "fnstsw %0\n" "fstp %%st(0)\n" "fstp %%st(0)\n" : "=m" (x86_status_word) : "m" (dest), "m" (src) ); if(x86_status_word & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); x86_status_word &= ~SW_EXCEPTION_MASK; } FPU_CONSISTENCY_CHECK_STOP("do_fcmp"); } // More or less original. Should be reviewed. PRIVATE fpu_double FFPU to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { FPU_CONSISTENCY_CHECK_START(); double d; char *cp; char str[100]; cp = str; if (wrd1 & 0x80000000) *cp++ = '-'; *cp++ = (char)((wrd1 & 0xf) + '0'); *cp++ = '.'; *cp++ = (char)(((wrd2 >> 28) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 16) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 12) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 8) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 4) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 0) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 28) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 16) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 12) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 8) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 4) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 0) & 0xf) + '0'); *cp++ = 'E'; if (wrd1 & 0x40000000) *cp++ = '-'; *cp++ = (char)(((wrd1 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd1 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd1 >> 16) & 0xf) + '0'); *cp = 0; sscanf(str, "%le", &d); D(bug("to_pack str = %s\r\n",str)); D(bug("to_pack(%X,%X,%X) = %.04f\r\n",wrd1,wrd2,wrd3,(float)d)); FPU_CONSISTENCY_CHECK_STOP("to_pack"); return d; } // More or less original. Should be reviewed. PRIVATE void FFPU from_pack (fpu_double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { FPU_CONSISTENCY_CHECK_START(); int i; int t; char *cp; char str[100]; int exponent_digit_count = 0; sprintf(str, "%.16e", src); D(bug("from_pack(%.04f,%s)\r\n",(float)src,str)); cp = str; *wrd1 = *wrd2 = *wrd3 = 0; if (*cp == '-') { cp++; *wrd1 = 0x80000000; } if (*cp == '+') cp++; *wrd1 |= (*cp++ - '0'); if (*cp == '.') cp++; for (i = 0; i < 8; i++) { *wrd2 <<= 4; if (*cp >= '0' && *cp <= '9') *wrd2 |= *cp++ - '0'; } for (i = 0; i < 8; i++) { *wrd3 <<= 4; if (*cp >= '0' && *cp <= '9') *wrd3 |= *cp++ - '0'; } if (*cp == 'e' || *cp == 'E') { cp++; if (*cp == '-') { cp++; *wrd1 |= 0x40000000; } if (*cp == '+') cp++; t = 0; for (i = 0; i < 3; i++) { if (*cp >= '0' && *cp <= '9') { t = (t << 4) | (*cp++ - '0'); exponent_digit_count++; } } *wrd1 |= t << 16; } D(bug("from_pack(%.04f) = %X,%X,%X\r\n",(float)src,*wrd1,*wrd2,*wrd3)); WORD sw_temp; // _asm FNSTSW sw_temp __asm__ __volatile__("fnstsw %0" : "=m" (sw_temp)); if(sw_temp & SW_EXCEPTION_MASK) { // _asm FNCLEX __asm__ __volatile__("fnclex"); if(sw_temp & SW_PE) { x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } } /* OPERR is set if the k-factor > + 17 or the magnitude of the decimal exponent exceeds three digits; cleared otherwise. */ if(exponent_digit_count > 3) { x86_status_word |= SW_IE; x86_status_word_accrued |= SW_IE; } FPU_CONSISTENCY_CHECK_STOP("from_pack"); } PRIVATE int FFPU get_fp_value (uae_u32 opcode, uae_u32 extra, fpu_register & src) { static const int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static const int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // D(bug("get_fp_value(%X,%X)\r\n",(int)opcode,(int)extra)); // dump_first_bytes( regs.pc_p-4, 16 ); if ((extra & 0x4000) == 0) { memcpy( &src, &FPU registers[(extra >> 10) & 7], sizeof(fpu_register) ); // do_fmove_no_status( src, FPU registers[(extra >> 10) & 7] ); return 1; } int mode = (opcode >> 3) & 7; int reg = opcode & 7; int size = (extra >> 10) & 7; uae_u32 ad = 0; // D(bug("get_fp_value mode=%d, reg=%d, size=%d\r\n",(int)mode,(int)reg,(int)size)); switch ((uae_u8)mode) { case 0: switch ((uae_u8)size) { case 6: signed_to_extended( (uae_s32)(uae_s8) m68k_dreg (regs, reg), src ); break; case 4: signed_to_extended( (uae_s32)(uae_s16) m68k_dreg (regs, reg), src ); break; case 0: signed_to_extended( (uae_s32) m68k_dreg (regs, reg), src ); break; case 1: to_single( m68k_dreg (regs, reg), src ); break; default: return 0; } return 1; case 1: return 0; case 2: ad = m68k_areg (regs, reg); break; case 3: ad = m68k_areg (regs, reg); m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ad = m68k_areg (regs, reg); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch ((uae_u8)reg) { case 0: ad = (uae_s32) (uae_s16) next_iword(); break; case 1: ad = next_ilong(); break; case 2: ad = m68k_getpc (); ad += (uae_s32) (uae_s16) next_iword(); break; case 3: { uaecptr tmppc = m68k_getpc (); uae_u16 tmp = (uae_u16)next_iword(); ad = get_disp_ea_020 (tmppc, tmp); } break; case 4: ad = m68k_getpc (); m68k_setpc (ad + sz2[size]); /* +0000 000004 FSCALE.B #$01,FP2 | F23C 5926 0001 F23C 1111001000111100 5926 0101100100100110 0001 0000000000000001 mode = 7 reg = 4 size = 6 */ // Immediate addressing mode && Operation Length == Byte -> // Use the low-order byte of the extension word. if(size == 6) ad++; // May be faster on a PII(I), sz2[size] is already in register // ad += sz2[size] - sz1[size]; break; default: return 0; } } switch ((uae_u8)size) { case 0: signed_to_extended( (uae_s32) get_long (ad), src ); break; case 1: to_single( get_long (ad), src ); break; case 2:{ uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); to_exten( wrd1, wrd2, wrd3, src ); } break; case 3:{ uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); double_to_extended( to_pack(wrd1, wrd2, wrd3), src ); } break; case 4: signed_to_extended( (uae_s32)(uae_s16) get_word(ad), src ); break; case 5:{ uae_u32 wrd1, wrd2; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); to_double(wrd1, wrd2, src); } break; case 6: signed_to_extended( (uae_s32)(uae_s8) get_byte(ad), src ); break; default: return 0; } // D(bug("get_fp_value result = %.04f\r\n",(float)src)); return 1; } PRIVATE int FFPU put_fp_value (fpu_register const & value, uae_u32 opcode, uae_u32 extra) { static const int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static const int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // D(bug("put_fp_value(%.04f,%X,%X)\r\n",(float)value,(int)opcode,(int)extra)); if ((extra & 0x4000) == 0) { int dest_reg = (extra >> 10) & 7; do_fmove( FPU registers[dest_reg], value ); build_ex_status(); return 1; } int mode = (opcode >> 3) & 7; int reg = opcode & 7; int size = (extra >> 10) & 7; uae_u32 ad = 0xffffffff; // Clear exception status x86_status_word &= ~SW_EXCEPTION_MASK; switch ((uae_u8)mode) { case 0: switch ((uae_u8)size) { case 6: *((uae_u8 *)&m68k_dreg(regs, reg)) = extended_to_signed_8(value); break; case 4: // TODO_BIGENDIAN *((uae_u16 *)&m68k_dreg(regs, reg)) = extended_to_signed_16(value); break; case 0: m68k_dreg (regs, reg) = extended_to_signed_32(value); break; case 1: m68k_dreg (regs, reg) = from_single(value); break; default: return 0; } return 1; case 1: return 0; case 2: ad = m68k_areg (regs, reg); break; case 3: ad = m68k_areg (regs, reg); m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ad = m68k_areg (regs, reg); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch ((uae_u8)reg) { case 0: ad = (uae_s32) (uae_s16) next_iword(); break; case 1: ad = next_ilong(); break; case 2: ad = m68k_getpc (); ad += (uae_s32) (uae_s16) next_iword(); break; case 3: { uaecptr tmppc = m68k_getpc (); uae_u16 tmp = (uae_u16)next_iword(); ad = get_disp_ea_020 (tmppc, tmp); } break; case 4: ad = m68k_getpc (); m68k_setpc (ad + sz2[size]); break; default: return 0; } } switch ((uae_u8)size) { case 0: put_long (ad, (uae_s32) extended_to_signed_32(value)); break; case 1: put_long (ad, from_single(value)); break; case 2: { uae_u32 wrd1, wrd2, wrd3; from_exten(value, &wrd1, &wrd2, &wrd3); x86_status_word &= ~SW_EXCEPTION_MASK; if(wrd3) { // TODO: not correct! Just a "smart" guess. x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); } break; case 3: { uae_u32 wrd1, wrd2, wrd3; from_pack(extended_to_double(value), &wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); } break; case 4: put_word(ad, extended_to_signed_16(value)); break; case 5:{ uae_u32 wrd1, wrd2; from_double(value, &wrd1, &wrd2); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); } break; case 6: put_byte(ad, extended_to_signed_8(value)); break; default: return 0; } return 1; } PRIVATE int FFPU get_fp_ad(uae_u32 opcode, uae_u32 * ad) { int mode = (opcode >> 3) & 7; int reg = opcode & 7; switch ( (uae_u8)mode ) { case 0: case 1: if( (opcode & 0xFF00) == 0xF300 ) { // fsave, frestore m68k_setpc (m68k_getpc () - 2); } else { m68k_setpc (m68k_getpc () - 4); } op_illg (opcode); dump_registers( "END "); return 0; case 2: *ad = m68k_areg (regs, reg); break; case 3: *ad = m68k_areg (regs, reg); break; case 4: *ad = m68k_areg (regs, reg); break; case 5: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch ( (uae_u8)reg ) { case 0: *ad = (uae_s32) (uae_s16) next_iword(); break; case 1: *ad = next_ilong(); break; case 2: *ad = m68k_getpc (); *ad += (uae_s32) (uae_s16) next_iword(); break; case 3: { uaecptr tmppc = m68k_getpc (); uae_u16 tmp = (uae_u16)next_iword(); *ad = get_disp_ea_020 (tmppc, tmp); } break; default: if( (opcode & 0xFF00) == 0xF300 ) { // fsave, frestore m68k_setpc (m68k_getpc () - 2); } else { m68k_setpc (m68k_getpc () - 4); } op_illg (opcode); dump_registers( "END "); return 0; } } return 1; } #if FPU_DEBUG #define CONDRET(s,x) D(bug("fpp_cond %s = %d\r\n",s,(uint32)(x))); return (x) #else #define CONDRET(s,x) return (x) #endif PRIVATE int FFPU fpp_cond(uae_u32 opcode, int condition) { #define N (x86_status_word & SW_N) #define Z ((x86_status_word & (SW_Z_I_NAN_MASK)) == SW_Z) #define I ((x86_status_word & (SW_Z_I_NAN_MASK)) == (SW_I)) #define NotANumber ((x86_status_word & (SW_Z_I_NAN_MASK)) == SW_NAN) switch (condition) { // Common Tests, no BSUN case 0x01: CONDRET("Equal",Z); case 0x0e: CONDRET("Not Equal",!Z); // IEEE Nonaware Tests, BSUN case 0x12: SET_BSUN_ON_NAN(); CONDRET("Greater Than",!(NotANumber || Z || N)); case 0x1d: SET_BSUN_ON_NAN(); CONDRET("Not Greater Than",NotANumber || Z || N); case 0x13: SET_BSUN_ON_NAN(); CONDRET("Greater Than or Equal",Z || !(NotANumber || N)); case 0x1c: SET_BSUN_ON_NAN(); CONDRET("Not Greater Than or Equal",!Z && (NotANumber || N)); case 0x14: SET_BSUN_ON_NAN(); CONDRET("Less Than",N && !(NotANumber || Z)); case 0x1b: SET_BSUN_ON_NAN(); CONDRET("Not Less Than",NotANumber || Z || !N); case 0x15: SET_BSUN_ON_NAN(); CONDRET("Less Than or Equal",Z || (N && !NotANumber)); case 0x1a: SET_BSUN_ON_NAN(); CONDRET("Not Less Than or Equal",NotANumber || !(N || Z)); case 0x16: SET_BSUN_ON_NAN(); CONDRET("Greater or Less Than",!(NotANumber || Z)); case 0x19: SET_BSUN_ON_NAN(); CONDRET("Not Greater or Less Than",NotANumber || Z); case 0x17: CONDRET("Greater, Less or Equal",!NotANumber); case 0x18: SET_BSUN_ON_NAN(); CONDRET("Not Greater, Less or Equal",NotANumber); // IEEE Aware Tests, no BSUN case 0x02: CONDRET("Ordered Greater Than",!(NotANumber || Z || N)); case 0x0d: CONDRET("Unordered or Less or Equal",NotANumber || Z || N); case 0x03: CONDRET("Ordered Greater Than or Equal",Z || !(NotANumber || N)); case 0x0c: CONDRET("Unordered or Less Than",NotANumber || (N && !Z)); case 0x04: CONDRET("Ordered Less Than",N && !(NotANumber || Z)); case 0x0b: CONDRET("Unordered or Greater or Equal",NotANumber || Z || !N); case 0x05: CONDRET("Ordered Less Than or Equal",Z || (N && !NotANumber)); case 0x0a: CONDRET("Unordered or Greater Than",NotANumber || !(N || Z)); case 0x06: CONDRET("Ordered Greater or Less Than",!(NotANumber || Z)); case 0x09: CONDRET("Unordered or Equal",NotANumber || Z); case 0x07: CONDRET("Ordered",!NotANumber); case 0x08: CONDRET("Unordered",NotANumber); // Miscellaneous Tests, no BSUN case 0x00: CONDRET("False",0); case 0x0f: CONDRET("True",1); // Miscellaneous Tests, BSUN case 0x10: SET_BSUN_ON_NAN(); CONDRET("Signaling False",0); case 0x1f: SET_BSUN_ON_NAN(); CONDRET("Signaling True",1); case 0x11: SET_BSUN_ON_NAN(); CONDRET("Signaling Equal",Z); case 0x1e: SET_BSUN_ON_NAN(); CONDRET("Signaling Not Equal",!Z); } CONDRET("",-1); #undef N #undef Z #undef I #undef NotANumber } PUBLIC void REGPARAM2 FFPU fpuop_dbcc(uae_u32 opcode, uae_u32 extra) { uaecptr pc = (uae_u32) m68k_getpc (); uae_s32 disp = (uae_s32) (uae_s16) next_iword(); int cc; D(bug("fdbcc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); cc = fpp_cond(opcode, extra & 0x3f); if (cc < 0) { m68k_setpc (pc - 4); op_illg (opcode); } else if (!cc) { int reg = opcode & 0x7; // TODO_BIGENDIAN uae_u16 newv = (uae_u16)(m68k_dreg (regs, reg) & 0xffff) - 1; *((uae_u16 *)&m68k_dreg(regs, reg)) = newv; if (newv != 0xffff) m68k_setpc (pc + disp); } } PUBLIC void REGPARAM2 FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra) { uae_u32 ad; int cc; D(bug("fscc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); cc = fpp_cond(opcode, extra & 0x3f); if (cc < 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } else if ((opcode & 0x38) == 0) { // TODO_BIGENDIAN m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00); } else { if (get_fp_ad(opcode, &ad)) { put_byte(ad, cc ? 0xff : 0x00); } } } PUBLIC void REGPARAM2 FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) { int cc; D(bug("ftrapcc_opp %X at %08lx\r\n", (uae_u32)opcode, m68k_getpc ())); #if I3_ON_FTRAPCC #error "FIXME: _asm int 3" _asm int 3 #endif // This must be broken. cc = fpp_cond(opcode, opcode & 0x3f); if (cc < 0) { m68k_setpc (oldpc); op_illg (opcode); } else if (cc) Exception(7, oldpc - 2); } // NOTE that we get here also when there is a FNOP (nontrapping false, displ 0) PUBLIC void REGPARAM2 FFPU fpuop_bcc(uae_u32 opcode, uaecptr pc, uae_u32 extra) { int cc; D(bug("fbcc_opp %X, %X at %08lx, jumpto=%X\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc (), extra )); cc = fpp_cond(opcode, opcode & 0x3f); if (cc < 0) { m68k_setpc (pc); op_illg (opcode); } else if (cc) { if ((opcode & 0x40) == 0) extra = (uae_s32) (uae_s16) extra; m68k_setpc (pc + extra); } } // FSAVE has no post-increment // 0x1f180000 == IDLE state frame, coprocessor version number 1F PUBLIC void REGPARAM2 FFPU fpuop_save(uae_u32 opcode) { uae_u32 ad; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; int i; D(bug("fsave_opp at %08lx\r\n", m68k_getpc ())); if (get_fp_ad(opcode, &ad)) { if (FPU is_integral) { // Put 4 byte 68040 IDLE frame. if (incr < 0) { ad -= 4; put_long (ad, 0x41000000); } else { put_long (ad, 0x41000000); ad += 4; } } else { // Put 28 byte 68881 IDLE frame. if (incr < 0) { D(bug("fsave_opp pre-decrement\r\n")); ad -= 4; // What's this? Some BIU flags, or (incorrectly placed) command/condition? put_long (ad, 0x70000000); for (i = 0; i < 5; i++) { ad -= 4; put_long (ad, 0x00000000); } ad -= 4; put_long (ad, 0x1f180000); // IDLE, vers 1f } else { put_long (ad, 0x1f180000); // IDLE, vers 1f ad += 4; for (i = 0; i < 5; i++) { put_long (ad, 0x00000000); ad += 4; } // What's this? Some BIU flags, or (incorrectly placed) command/condition? put_long (ad, 0x70000000); ad += 4; } } if ((opcode & 0x38) == 0x18) { m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 D(bug("PROBLEM: fsave_opp post-increment\r\n")); } if ((opcode & 0x38) == 0x20) { m68k_areg (regs, opcode & 7) = ad; D(bug("fsave_opp pre-decrement %X -> A%d\r\n",ad,opcode & 7)); } } } PRIVATE void FFPU do_null_frestore () { // A null-restore operation sets FP7-FP0 positive, nonsignaling NANs. for( int i=0; i<8; i++ ) { MAKE_NAN( FPU registers[i] ); } FPU instruction_address = 0; set_fpcr(0); set_fpsr(0); x86_status_word = SW_INITIAL; x86_status_word_accrued = 0; FPU fpsr.quotient = 0; x86_control_word = CW_INITIAL; /* _asm FLDCW x86_control_word _asm FNCLEX */ __asm__ __volatile__("fldcw %0\n\tfnclex" : : "m" (x86_control_word)); } // FSAVE has no pre-decrement PUBLIC void REGPARAM2 FFPU fpuop_restore(uae_u32 opcode) { uae_u32 ad; uae_u32 d; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; D(bug("frestore_opp at %08lx\r\n", m68k_getpc ())); if (get_fp_ad(opcode, &ad)) { if (FPU is_integral) { // 68040 if (incr < 0) { D(bug("PROBLEM: frestore_opp incr < 0\r\n")); // this may be wrong, but it's never called. ad -= 4; d = get_long (ad); if ((d & 0xff000000) == 0) { // NULL D(bug("frestore_opp found NULL frame at %X\r\n",ad-4)); do_null_frestore(); } else if ((d & 0x00ff0000) == 0) { // IDLE D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP D(bug("PROBLEM: frestore_opp found UNIMP frame at %X\r\n",ad-4)); ad -= 44; } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4)); ad -= 92; } else { D(bug("PROBLEM: frestore_opp did not find a frame at %X, d=%X\r\n",ad-4,d)); } } else { d = get_long (ad); D(bug("frestore_opp frame at %X = %X\r\n",ad,d)); ad += 4; if ((d & 0xff000000) == 0) { // NULL D(bug("frestore_opp found NULL frame at %X\r\n",ad-4)); do_null_frestore(); } else if ((d & 0x00ff0000) == 0) { // IDLE D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP D(bug("PROBLEM: frestore_opp found UNIMP frame at %X\r\n",ad-4)); ad += 44; } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4)); ad += 92; } else { D(bug("PROBLEM: frestore_opp did not find a frame at %X, d=%X\r\n",ad-4,d)); } } } else { // 68881 if (incr < 0) { D(bug("PROBLEM: frestore_opp incr < 0\r\n")); // this may be wrong, but it's never called. ad -= 4; d = get_long (ad); if ((d & 0xff000000) == 0) { // NULL do_null_frestore(); } else if ((d & 0x00ff0000) == 0x00180000) { ad -= 6 * 4; } else if ((d & 0x00ff0000) == 0x00380000) { ad -= 14 * 4; } else if ((d & 0x00ff0000) == 0x00b40000) { ad -= 45 * 4; } } else { d = get_long (ad); D(bug("frestore_opp frame at %X = %X\r\n",ad,d)); ad += 4; if ((d & 0xff000000) == 0) { // NULL D(bug("frestore_opp found NULL frame at %X\r\n",ad-4)); do_null_frestore(); } else if ((d & 0x00ff0000) == 0x00180000) { // IDLE D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4)); ad += 6 * 4; } else if ((d & 0x00ff0000) == 0x00380000) {// UNIMP? shouldn't it be 3C? ad += 14 * 4; D(bug("PROBLEM: frestore_opp found UNIMP? frame at %X\r\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00b40000) {// BUSY D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4)); ad += 45 * 4; } else { D(bug("PROBLEM: frestore_opp did not find a frame at %X, d=%X\r\n",ad-4,d)); } } } if ((opcode & 0x38) == 0x18) { m68k_areg (regs, opcode & 7) = ad; D(bug("frestore_opp post-increment %X -> A%d\r\n",ad,opcode & 7)); } if ((opcode & 0x38) == 0x20) { m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 D(bug("PROBLEM: frestore_opp pre-decrement\r\n")); } } } /* ---------------------------- Old-style interface ---------------------------- */ // #ifndef OPTIMIZED_8BIT_MEMORY_ACCESS PUBLIC void REGPARAM2 FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) { uae_u32 mask = (extra & 0xFC7F) | ((opcode & 0x0038) << 4); (*fpufunctbl[mask])(opcode,extra); } // #endif /* ---------------------------- Illegal ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_illg( uae_u32 opcode, uae_u32 extra ) { D(bug("ILLEGAL F OP 2 %X\r\n",opcode)); #if I3_ON_ILLEGAL_FPU_OP #error "FIXME: asm int 3" _asm int 3 #endif m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); } /* ---------------------------- FPP -> ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmove_2_ea( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVE -> \r\n")); if (put_fp_value (FPU registers[(extra >> 7) & 7], opcode, extra) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } /* Needed (among other things) by some Pack5/Elems68k transcendental functions, they require the ACCR_INEX flag after a "MOVE.D, Dreg". However, now put_fp_value() is responsible of clearing the exceptions and merging statuses. */ /* WORD sw_temp; _asm FNSTSW sw_temp if(sw_temp & SW_PE) { _asm FNCLEX x86_status_word |= SW_PE; x86_status_word_accrued |= SW_PE; } */ dump_registers( "END "); } /* ---------------------------- CONTROL REGS -> Dreg ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM control(none) -> D%d\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> D%d\r\n", get_fpcr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> D%d\r\n", get_fpsr(), opcode & 7)); m68k_dreg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> D%d\r\n", FPU instruction_address, opcode & 7)); m68k_dreg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } /* ---------------------------- Dreg -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_none( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM D%d -> control(none)\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpiar( uae_u32 opcode, uae_u32 extra ) { FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_dreg (regs, opcode & 7) ); D(bug("FMOVEM D%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_dreg (regs, opcode & 7); D(bug("FMOVEM D%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } /* ---------------------------- CONTROL REGS -> Areg ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM control(none) -> A%d\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM regs.FPU fpcr (%X) -> A%d\r\n", get_fpcr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpcr(); D(bug("FMOVEM regs.FPU fpsr (%X) -> A%d\r\n", get_fpsr(), opcode & 7)); m68k_areg (regs, opcode & 7) = get_fpsr(); D(bug("FMOVEM FPU instruction_address (%X) -> A%d\r\n", FPU instruction_address, opcode & 7)); m68k_areg (regs, opcode & 7) = FPU instruction_address; dump_registers( "END "); } /* ---------------------------- Areg -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_none( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM A%d -> control(none)\r\n", opcode & 7)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpiar( uae_u32 opcode, uae_u32 extra ) { FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpsr( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ) { set_fpcr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpcr\r\n", opcode & 7, get_fpcr())); set_fpsr( m68k_areg (regs, opcode & 7) ); D(bug("FMOVEM A%d (%X) -> regs.FPU fpsr\r\n", opcode & 7, get_fpsr())); FPU instruction_address = m68k_areg (regs, opcode & 7); D(bug("FMOVEM A%d (%X) -> FPU instruction_address\r\n", opcode & 7, FPU instruction_address)); dump_registers( "END "); } /* ---------------------------- CONTROL REGS -> --MEMORY---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Control regs (none) -> mem\r\n" )); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; put_long (ad, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 12; put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); put_long (ad+8, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+8 )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } /* ---------------------------- CONTROL REGS -> MEMORY++ ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Control regs (none) -> mem\r\n" )); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { dump_registers( "END "); uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); m68k_areg (regs, opcode & 7) = ad+8; } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); put_long (ad+8, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+8 )); m68k_areg (regs, opcode & 7) = ad+12; dump_registers( "END "); } } /* ---------------------------- CONTROL REGS -> MEMORY ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Control regs (none) -> mem\r\n" )); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+4 )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { put_long (ad, get_fpcr()); D(bug("FMOVEM regs.FPU fpcr (%X) -> mem %X\r\n", get_fpcr(), ad )); put_long (ad+4, get_fpsr()); D(bug("FMOVEM regs.FPU fpsr (%X) -> mem %X\r\n", get_fpsr(), ad+4 )); put_long (ad+8, FPU instruction_address); D(bug("FMOVEM FPU instruction_address (%X) -> mem %X\r\n", FPU instruction_address, ad+8 )); dump_registers( "END "); } } /* ---------------------------- --MEMORY -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_predecrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM --Mem -> control(none)\r\n")); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; FPU instruction_address = get_long (ad); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 4; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 8; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { ad -= 12; set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); FPU instruction_address = get_long (ad+8); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+8, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } /* ---------------------------- CONTROL REGS -> MEMORY++ ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_postincrement( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Mem++ -> control(none)\r\n")); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { FPU instruction_address = get_long (ad); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); m68k_areg (regs, opcode & 7) = ad+4; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); m68k_areg (regs, opcode & 7) = ad+8; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); FPU instruction_address = get_long (ad+8); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+8, FPU instruction_address )); m68k_areg (regs, opcode & 7) = ad+12; dump_registers( "END "); } } /* ---------------------------- MEMORY -> CONTROL REGS ---------------------------- */ /* ---------------------------- and ---------------------------- */ /* ---------------------------- IMMEDIATE -> CONTROL REGS ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_2_Mem( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVEM Mem -> control(none)\r\n")); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { FPU instruction_address = get_long (ad); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad, FPU instruction_address )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpsr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad, get_fpsr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); FPU instruction_address = get_long (ad+4); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+4, FPU instruction_address )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); } } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ) { if ((opcode & 0x3f) == 0x3c) { set_fpcr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpcr\r\n", get_fpcr())); set_fpsr( next_ilong() ); D(bug("FMOVEM #<%X> -> regs.FPU fpsr\r\n", get_fpsr())); FPU instruction_address = next_ilong(); D(bug("FMOVEM #<%X> -> FPU instruction_address\r\n", FPU instruction_address)); } else { uae_u32 ad; if (get_fp_ad(opcode, &ad)) { set_fpcr( get_long (ad) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpcr\r\n", ad, get_fpcr() )); set_fpsr( get_long (ad+4) ); D(bug("FMOVEM mem %X (%X) -> regs.FPU fpsr\r\n", ad+4, get_fpsr() )); FPU instruction_address = get_long (ad+8); D(bug("FMOVEM mem %X (%X) -> FPU instruction_address\r\n", ad+8, FPU instruction_address )); } } dump_registers( "END "); } /* ---------------------------- FMOVEM MEMORY -> FPP ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM memory->FPP\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; to_exten_no_normalize (wrd1, wrd2, wrd3,FPU registers[reg]); } list <<= 1; } dump_registers( "END "); } } /* ---------------------------- FPP -> FMOVEM MEMORY ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=7; reg>=0; reg-- ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = extra & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_postincrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_predecrement( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } m68k_areg (regs, opcode & 7) = ad; dump_registers( "END "); } } PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc( uae_u32 opcode, uae_u32 extra ) { uae_u32 ad, list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; D(bug("FMOVEM FPP->memory\r\n")); if (get_fp_ad(opcode, &ad)) { for( int reg=0; reg<8; reg++ ) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { from_exten(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } dump_registers( "END "); } } /* ---------------------------- FMOVEM CONSTANT ROM -> FPP ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_do_fldpi( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Pi\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_pi, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldlg2( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Log 10 (2)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_lg2, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_e( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: e\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_e, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldl2e( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Log 2 (e)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_l2e, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_log_10_e( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: Log 10 (e)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_log_10_e, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldz( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: zero\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_z, sizeof(fpu_register) ); x86_status_word = SW_Z; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fldln2( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: ln(2)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_ln2, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_ln_10( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: ln(10)\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_ln_10, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fld1( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e0\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e1( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e1\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e1, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e2( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e2\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e2, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e4( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e4\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e4, sizeof(fpu_register) ); x86_status_word = SW_FINITE; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e8( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e8\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e8, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; // Is it really FPSR_EXCEPTION_INEX2? dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e16( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e16\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e16, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e32( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e32\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e32, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e64( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e64\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e64, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e128( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e128\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e128, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e256( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e256\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e256, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e512( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e512\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e512, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e1024( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e1024\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e1024, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e2048( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e2048\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e2048, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e4096( uae_u32 opcode, uae_u32 extra ) { D(bug("FMOVECR memory->FPP FP const: 1.0e4096\r\n")); memcpy( &FPU registers[(extra>>7) & 7], &const_1e4096, sizeof(fpu_register) ); x86_status_word = SW_FINITE | FPSR_EXCEPTION_INEX2; dump_registers( "END "); } /* ---------------------------- ALU ---------------------------- */ PRIVATE void REGPARAM2 FFPU fpuop_do_fmove( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FMOVE %s\r\n",etos(src))); do_fmove( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fint( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FINT %s, opcode=%X, extra=%X, ta %X\r\n",etos(src),opcode,extra,m68k_getpc())); do_fint( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsinh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSINH %s\r\n",etos(src))); do_fsinh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fintrz( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FINTRZ %s\r\n",etos(src))); do_fintrz( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsqrt( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSQRT %s\r\n",etos(src))); do_fsqrt( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flognp1( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOGNP1 %s\r\n",etos(src))); do_flognp1( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fetoxm1( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FETOXM1 %s\r\n",etos(src))); do_fetoxm1( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftanh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTANH %s\r\n",etos(src))); do_ftanh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fatan( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FATAN %s\r\n",etos(src))); do_fatan( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fasin( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FASIN %s\r\n",etos(src))); do_fasin( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fatanh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FATANH %s\r\n",etos(src))); do_fatanh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsin( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSIN %s\r\n",etos(src))); do_fsin( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftan( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTAN %s\r\n",etos(src))); do_ftan( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fetox( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FETOX %s\r\n",etos(src))); do_fetox( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftwotox( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTWOTOX %s\r\n",etos(src))); do_ftwotox( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftentox( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTENTOX %s\r\n",etos(src))); do_ftentox( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flogn( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOGN %s\r\n",etos(src))); do_flogn( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flog10( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOG10 %s\r\n",etos(src))); do_flog10( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_flog2( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FLOG2 %s\r\n",etos(src))); do_flog2( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fabs( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FABS %s\r\n",etos(src))); do_fabs( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fcosh( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FCOSH %s\r\n",etos(src))); do_fcosh( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fneg( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FNEG %s\r\n",etos(src))); do_fneg( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_facos( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FACOS %s\r\n",etos(src))); do_facos( FPU registers[reg], src ); build_ex_status(); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fcos( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FCOS %s\r\n",etos(src))); do_fcos( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fgetexp( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FGETEXP %s\r\n",etos(src))); if( IS_INFINITY(src) ) { MAKE_NAN( FPU registers[reg] ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { do_fgetexp( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fgetman( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FGETMAN %s\r\n",etos(src))); if( IS_INFINITY(src) ) { MAKE_NAN( FPU registers[reg] ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { do_fgetman( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fdiv( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FDIV %s\r\n",etos(src))); do_fdiv( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fmod( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FMOD %s\r\n",etos(src))); #if USE_3_BIT_QUOTIENT do_fmod( FPU registers[reg], src ); #else if( (x86_control_word & X86_ROUNDING_MODE) == CW_RC_ZERO ) { do_fmod_dont_set_cw( FPU registers[reg], src ); } else { do_fmod( FPU registers[reg], src ); } #endif dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_frem( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FREM %s\r\n",etos(src))); #if USE_3_BIT_QUOTIENT do_frem( FPU registers[reg], src ); #else if( (x86_control_word & X86_ROUNDING_MODE) == CW_RC_NEAR ) { do_frem_dont_set_cw( FPU registers[reg], src ); } else { do_frem( FPU registers[reg], src ); } #endif dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fadd( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FADD %s\r\n",etos(src))); do_fadd( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fmul( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FMUL %s\r\n",etos(src))); do_fmul( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsgldiv( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSGLDIV %s\r\n",etos(src))); do_fsgldiv( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fscale( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSCALE %s, opcode=%X, extra=%X, ta %X\r\n",etos(src),opcode,extra,m68k_getpc())); if( IS_INFINITY(FPU registers[reg]) ) { MAKE_NAN( FPU registers[reg] ); do_ftst( FPU registers[reg] ); x86_status_word |= SW_IE; } else { // When the absolute value of the source operand is >= 2^14, // an overflow or underflow always results. do_fscale( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsglmul( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSGLMUL %s\r\n",etos(src))); do_fsglmul( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsub( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSUB %s\r\n",etos(src))); do_fsub( FPU registers[reg], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fsincos( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FSINCOS %s\r\n",etos(src))); do_fsincos( FPU registers[reg], FPU registers[extra & 7], src ); dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_fcmp( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FCMP %s\r\n",etos(src))); if( IS_INFINITY(src) ) { if( IS_NEGATIVE(src) ) { if( IS_INFINITY(FPU registers[reg]) && IS_NEGATIVE(FPU registers[reg]) ) { x86_status_word = SW_Z | SW_N; D(bug("-INF FCMP -INF -> NZ\r\n")); } else { x86_status_word = SW_FINITE; D(bug("X FCMP -INF -> None\r\n")); } } else { if( IS_INFINITY(FPU registers[reg]) && !IS_NEGATIVE(FPU registers[reg]) ) { x86_status_word = SW_Z; D(bug("+INF FCMP +INF -> Z\r\n")); } else { x86_status_word = SW_N; D(bug("X FCMP +INF -> N\r\n")); } } } else if( IS_INFINITY(FPU registers[reg]) ) { if( IS_NEGATIVE(FPU registers[reg]) ) { x86_status_word = SW_N; D(bug("-INF FCMP X -> Negative\r\n")); } else { x86_status_word = SW_FINITE; D(bug("+INF FCMP X -> None\r\n")); } } else { do_fcmp( FPU registers[reg], src ); } dump_registers( "END "); } PRIVATE void REGPARAM2 FFPU fpuop_do_ftst( uae_u32 opcode, uae_u32 extra ) { int reg = (extra >> 7) & 7; fpu_register src; if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } D(bug("FTST %s\r\n",etos(src))); do_ftst( src ); build_ex_status(); dump_registers( "END "); } /* ---------------------------- SETUP TABLES ---------------------------- */ PRIVATE void FFPU build_fpp_opp_lookup_table () { for( uae_u32 opcode=0; opcode<=0x38; opcode+=8 ) { for( uae_u32 extra=0; extra<65536; extra++ ) { uae_u32 mask = (extra & 0xFC7F) | ((opcode & 0x0038) << 4); fpufunctbl[mask] = & FFPU fpuop_illg; switch ((extra >> 13) & 0x7) { case 3: fpufunctbl[mask] = & FFPU fpuop_fmove_2_ea; break; case 4: case 5: if ((opcode & 0x38) == 0) { if (extra & 0x2000) { // dr bit switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Dreg; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Dreg; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Dreg; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Dreg; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Dreg; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Dreg; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Dreg; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Dreg; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_none; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpiar; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpsr; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpsr_fpiar; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpcr; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpcr_fpiar; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr_fpiar; break; } } } else if ((opcode & 0x38) == 8) { if (extra & 0x2000) { // dr bit switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Areg; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Areg; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Areg; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Areg; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Areg; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Areg; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Areg; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Areg; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_none; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpiar; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpsr; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpsr_fpiar; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr_fpiar; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr_fpsr; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Areg_2_fpcr_fpsr_fpiar; break; } } } else if (extra & 0x2000) { if ((opcode & 0x38) == 0x20) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Mem_predecrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Mem_predecrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Mem_predecrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_predecrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Mem_predecrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_predecrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_predecrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_predecrement; break; } } else if ((opcode & 0x38) == 0x18) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Mem_postincrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Mem_postincrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Mem_postincrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_postincrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Mem_postincrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_postincrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_postincrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_postincrement; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_none_2_Mem; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpiar_2_Mem; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_2_Mem; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpsr_fpiar_2_Mem; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_2_Mem; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpiar_2_Mem; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_2_Mem; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem; break; } } } else { if ((opcode & 0x38) == 0x20) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_none_predecrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpiar_predecrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_predecrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_predecrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_predecrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_predecrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_predecrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_predecrement; break; } } else if ((opcode & 0x38) == 0x18) { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_none_postincrement; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpiar_postincrement; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_postincrement; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_postincrement; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_postincrement; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_postincrement; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_postincrement; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_postincrement; break; } } else { switch( extra & 0x1C00 ) { case 0x0000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_none_2_Mem; break; case 0x0400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpiar_2_Mem; break; case 0x0800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_2_Mem; break; case 0x0C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_2_Mem; break; case 0x1000: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_2_Mem; break; case 0x1400: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_2_Mem; break; case 0x1800: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_2_Mem; break; case 0x1C00: fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_2_Mem; break; } } break; case 6: switch ((extra >> 11) & 3) { case 0: /* static pred */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_pred; break; case 1: /* dynamic pred */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred; break; case 2: /* static postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_static_postinc; break; case 3: /* dynamic postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc; break; } break; case 7: switch ((extra >> 11) & 3) { case 0: /* static pred */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_pred; break; case 1: /* dynamic pred */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred; break; case 2: /* static postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_static_postinc; break; case 3: /* dynamic postinc */ if ((opcode & 0x38) == 0x18) // post-increment? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_postincrement; else if ((opcode & 0x38) == 0x20) // pre-decrement? fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_predecrement; else fpufunctbl[mask] = & FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc; break; } break; case 0: case 2: if ((extra & 0xfc00) == 0x5c00) { switch (extra & 0x7f) { case 0x00: fpufunctbl[mask] = & FFPU fpuop_do_fldpi; break; case 0x0b: fpufunctbl[mask] = & FFPU fpuop_do_fldlg2; break; case 0x0c: fpufunctbl[mask] = & FFPU fpuop_do_load_const_e; break; case 0x0d: fpufunctbl[mask] = & FFPU fpuop_do_fldl2e; break; case 0x0e: fpufunctbl[mask] = & FFPU fpuop_do_load_const_log_10_e; break; case 0x0f: fpufunctbl[mask] = & FFPU fpuop_do_fldz; break; case 0x30: fpufunctbl[mask] = & FFPU fpuop_do_fldln2; break; case 0x31: fpufunctbl[mask] = & FFPU fpuop_do_load_const_ln_10; break; case 0x32: fpufunctbl[mask] = & FFPU fpuop_do_fld1; break; case 0x33: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e1; break; case 0x34: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e2; break; case 0x35: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e4; break; case 0x36: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e8; break; case 0x37: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e16; break; case 0x38: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e32; break; case 0x39: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e64; break; case 0x3a: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e128; break; case 0x3b: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e256; break; case 0x3c: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e512; break; case 0x3d: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e1024; break; case 0x3e: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e2048; break; case 0x3f: fpufunctbl[mask] = & FFPU fpuop_do_load_const_1e4096; break; } break; } switch (extra & 0x7f) { case 0x00: fpufunctbl[mask] = & FFPU fpuop_do_fmove; break; case 0x01: fpufunctbl[mask] = & FFPU fpuop_do_fint; break; case 0x02: fpufunctbl[mask] = & FFPU fpuop_do_fsinh; break; case 0x03: fpufunctbl[mask] = & FFPU fpuop_do_fintrz; break; case 0x04: fpufunctbl[mask] = & FFPU fpuop_do_fsqrt; break; case 0x06: fpufunctbl[mask] = & FFPU fpuop_do_flognp1; break; case 0x08: fpufunctbl[mask] = & FFPU fpuop_do_fetoxm1; break; case 0x09: fpufunctbl[mask] = & FFPU fpuop_do_ftanh; break; case 0x0a: fpufunctbl[mask] = & FFPU fpuop_do_fatan; break; case 0x0c: fpufunctbl[mask] = & FFPU fpuop_do_fasin; break; case 0x0d: fpufunctbl[mask] = & FFPU fpuop_do_fatanh; break; case 0x0e: fpufunctbl[mask] = & FFPU fpuop_do_fsin; break; case 0x0f: fpufunctbl[mask] = & FFPU fpuop_do_ftan; break; case 0x10: fpufunctbl[mask] = & FFPU fpuop_do_fetox; break; case 0x11: fpufunctbl[mask] = & FFPU fpuop_do_ftwotox; break; case 0x12: fpufunctbl[mask] = & FFPU fpuop_do_ftentox; break; case 0x14: fpufunctbl[mask] = & FFPU fpuop_do_flogn; break; case 0x15: fpufunctbl[mask] = & FFPU fpuop_do_flog10; break; case 0x16: fpufunctbl[mask] = & FFPU fpuop_do_flog2; break; case 0x18: fpufunctbl[mask] = & FFPU fpuop_do_fabs; break; case 0x19: fpufunctbl[mask] = & FFPU fpuop_do_fcosh; break; case 0x1a: fpufunctbl[mask] = & FFPU fpuop_do_fneg; break; case 0x1c: fpufunctbl[mask] = & FFPU fpuop_do_facos; break; case 0x1d: fpufunctbl[mask] = & FFPU fpuop_do_fcos; break; case 0x1e: fpufunctbl[mask] = & FFPU fpuop_do_fgetexp; break; case 0x1f: fpufunctbl[mask] = & FFPU fpuop_do_fgetman; break; case 0x20: fpufunctbl[mask] = & FFPU fpuop_do_fdiv; break; case 0x21: fpufunctbl[mask] = & FFPU fpuop_do_fmod; break; case 0x22: fpufunctbl[mask] = & FFPU fpuop_do_fadd; break; case 0x23: fpufunctbl[mask] = & FFPU fpuop_do_fmul; break; case 0x24: fpufunctbl[mask] = & FFPU fpuop_do_fsgldiv; break; case 0x25: fpufunctbl[mask] = & FFPU fpuop_do_frem; break; case 0x26: fpufunctbl[mask] = & FFPU fpuop_do_fscale; break; case 0x27: fpufunctbl[mask] = & FFPU fpuop_do_fsglmul; break; case 0x28: fpufunctbl[mask] = & FFPU fpuop_do_fsub; break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: fpufunctbl[mask] = & FFPU fpuop_do_fsincos; break; case 0x38: fpufunctbl[mask] = & FFPU fpuop_do_fcmp; break; case 0x3a: fpufunctbl[mask] = & FFPU fpuop_do_ftst; break; } } } } } } /* ---------------------------- CONSTANTS ---------------------------- */ PRIVATE void FFPU set_constant ( fpu_register & f, char *name, double value, uae_s32 mult ) { FPU_CONSISTENCY_CHECK_START(); if(mult == 1) { /* _asm { MOV ESI, [f] FLD QWORD PTR [value] FSTP TBYTE PTR [ESI] } */ __asm__ __volatile__( "fldl %1\n" "fstpt %0\n" : "=m" (f) : "m" (value) ); } else { /* _asm { MOV ESI, [f] FILD DWORD PTR [mult] FLD QWORD PTR [value] FMUL FSTP TBYTE PTR [ESI] } */ __asm__ __volatile__( "fildl %2\n" "fldl %1\n" "fmul \n" "fstpt %0\n" : "=m" (f) : "m" (value), "m" (mult) ); } D(bug("set_constant (%s,%.04f) = %s\r\n",name,(float)value,etos(f))); FPU_CONSISTENCY_CHECK_STOP( mult==1 ? "set_constant(mult==1)" : "set_constant(mult>1)" ); } PRIVATE void FFPU do_fldpi ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDPI FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldpi \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldpi"); } PRIVATE void FFPU do_fldlg2 ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDLG2 FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldlg2 \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldlg2"); } PRIVATE void FFPU do_fldl2e ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDL2E FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldl2e \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldl2e"); } PRIVATE void FFPU do_fldz ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDZ FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldz \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldz"); } PRIVATE void FFPU do_fldln2 ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLDLN2 FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fldln2 \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fldln2"); } PRIVATE void FFPU do_fld1 ( fpu_register & dest ) { FPU_CONSISTENCY_CHECK_START(); /* _asm { FLD1 FXAM FNSTSW x86_status_word MOV EDI, [dest] FSTP TBYTE PTR [EDI] } */ __asm__ __volatile__( "fld1 \n" "fxam \n" "fnstsw %0\n" "fstpt %1\n" : "=m" (x86_status_word), "=m" (dest) ); FPU_CONSISTENCY_CHECK_STOP("do_fld1"); } /* ---------------------------- MAIN INIT ---------------------------- */ #ifdef HAVE_SIGACTION // Mega hackaround-that-happens-to-work: the following way to handle // SIGFPE just happens to make the "fsave" below in fpu_init() *NOT* // to abort with a floating point exception. However, we never // actually reach sigfpe_handler(). static void sigfpe_handler(int code, siginfo_t *sip, void *) { if (code == SIGFPE && sip->si_code == FPE_FLTINV) { fprintf(stderr, "Invalid floating point operation\n"); abort(); } } #endif PUBLIC void FFPU fpu_init( bool integral_68040 ) { static bool done_first_time_initialization = false; if (!done_first_time_initialization) { fpu_init_native_fflags(); fpu_init_native_exceptions(); fpu_init_native_accrued_exceptions(); #ifdef HAVE_SIGACTION struct sigaction fpe_sa; sigemptyset(&fpe_sa.sa_mask); fpe_sa.sa_sigaction = sigfpe_handler; fpe_sa.sa_flags = SA_SIGINFO; sigaction(SIGFPE, &fpe_sa, 0); #endif done_first_time_initialization = true; } __asm__ __volatile__("fsave %0" : "=m" (m_fpu_state_original)); FPU is_integral = integral_68040; FPU instruction_address = 0; set_fpcr(0); set_fpsr(0); x86_control_word = CW_INITIAL; x86_status_word = SW_INITIAL; x86_status_word_accrued = 0; FPU fpsr.quotient = 0; for( int i=0; i<8; i++ ) { MAKE_NAN( FPU registers[i] ); } build_fpp_opp_lookup_table(); __asm__ __volatile__("fninit\nfldcw %0" : : "m" (x86_control_word)); do_fldpi( const_pi ); do_fldlg2( const_lg2 ); do_fldl2e( const_l2e ); do_fldz( const_z ); do_fldln2( const_ln2 ); do_fld1( const_1 ); set_constant( const_e, "e", exp (1.0), 1 ); set_constant( const_log_10_e, "Log 10 (e)", log (exp (1.0)) / log (10.0), 1 ); set_constant( const_ln_10, "ln(10)", log (10.0), 1 ); set_constant( const_1e1, "1.0e1", 1.0e1, 1 ); set_constant( const_1e2, "1.0e2", 1.0e2, 1 ); set_constant( const_1e4, "1.0e4", 1.0e4, 1 ); set_constant( const_1e8, "1.0e8", 1.0e8, 1 ); set_constant( const_1e16, "1.0e16", 1.0e16, 1 ); set_constant( const_1e32, "1.0e32", 1.0e32, 1 ); set_constant( const_1e64, "1.0e64", 1.0e64, 1 ) ; set_constant( const_1e128, "1.0e128", 1.0e128, 1 ); set_constant( const_1e256, "1.0e256", 1.0e256, 1 ); set_constant( const_1e512, "1.0e512", 1.0e256, 10 ); set_constant( const_1e1024, "1.0e1024", 1.0e256, 100 ); set_constant( const_1e2048, "1.0e2048", 1.0e256, 1000 ); set_constant( const_1e4096, "1.0e4096", 1.0e256, 10000 ); // Just in case. __asm__ __volatile__("fninit\nfldcw %0" : : "m" (x86_control_word)); } PUBLIC void FFPU fpu_exit( void ) { __asm__ __volatile__("frstor %0" : : "m" (m_fpu_state_original)); } PUBLIC void FFPU fpu_reset( void ) { fpu_exit(); fpu_init(FPU is_integral); } BasiliskII/src/uae_cpu/fpu/impl.h0000644000175000017500000001172010736405224017061 0ustar centriscentris/* * fpu/impl.h - extra functions and inline implementations * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_IMPL_H #define FPU_IMPL_H /* NOTE: this file shall be included from fpu/core.h */ #undef PUBLIC #define PUBLIC /**/ #undef PRIVATE #define PRIVATE /**/ #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* -------------------------------------------------------------------------- */ /* --- X86 assembly fpu specific methods --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_X86 /* Return the floating-point status register in m68k format */ static inline uae_u32 FFPU get_fpsr(void) { return to_m68k_fpcond[(x86_status_word & 0x4700) >> 8] | FPU fpsr.quotient | exception_host2mac[x86_status_word & (SW_FAKE_BSUN|SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE)] | accrued_exception_host2mac[x86_status_word_accrued & (SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE)] ; } /* Set the floating-point status register from an m68k format */ static inline void FFPU set_fpsr(uae_u32 new_fpsr) { x86_status_word = to_host_fpcond[(new_fpsr & FPSR_CCB) >> 24 ] | exception_mac2host[(new_fpsr & FPSR_EXCEPTION_STATUS) >> 8]; x86_status_word_accrued = accrued_exception_mac2host[(new_fpsr & FPSR_ACCRUED_EXCEPTION) >> 3]; } #endif /* -------------------------------------------------------------------------- */ /* --- Original UAE and IEEE FPU core methods --- */ /* -------------------------------------------------------------------------- */ #ifndef FPU_X86 /* Return the floating-point status register in m68k format */ static inline uae_u32 FFPU get_fpsr(void) { uae_u32 condition_codes = get_fpccr(); uae_u32 exception_status = get_exception_status(); uae_u32 accrued_exception = get_accrued_exception(); uae_u32 quotient = FPU fpsr.quotient; return (condition_codes | quotient | exception_status | accrued_exception); } /* Set the floating-point status register from an m68k format */ static inline void FFPU set_fpsr(uae_u32 new_fpsr) { set_fpccr ( new_fpsr & FPSR_CCB ); set_exception_status ( new_fpsr & FPSR_EXCEPTION_STATUS ); set_accrued_exception ( new_fpsr & FPSR_ACCRUED_EXCEPTION ); FPU fpsr.quotient = new_fpsr & FPSR_QUOTIENT; } #endif /* -------------------------------------------------------------------------- */ /* --- Common routines for control word --- */ /* -------------------------------------------------------------------------- */ /* Return the floating-point control register in m68k format */ static inline uae_u32 FFPU get_fpcr(void) { uae_u32 rounding_precision = get_rounding_precision(); uae_u32 rounding_mode = get_rounding_mode(); return (rounding_precision | rounding_mode); } /* Set the floating-point control register from an m68k format */ static inline void FFPU set_fpcr(uae_u32 new_fpcr) { set_rounding_precision ( new_fpcr & FPCR_ROUNDING_PRECISION); set_rounding_mode ( new_fpcr & FPCR_ROUNDING_MODE ); set_host_control_word(); } /* -------------------------------------------------------------------------- */ /* --- Specific part to X86 assembly FPU --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_X86 /* Retrieve a floating-point register value and convert it to double precision */ static inline double FFPU fpu_get_register(int r) { double f; __asm__ __volatile__("fldt %1\n\tfstpl %0" : "=m" (f) : "m" (FPU registers[r])); return f; } #endif /* -------------------------------------------------------------------------- */ /* --- Specific to original UAE or new IEEE-based FPU core --- */ /* -------------------------------------------------------------------------- */ #if defined(FPU_UAE) || defined(FPU_IEEE) /* Retrieve a floating-point register value and convert it to double precision */ static inline double FFPU fpu_get_register(int r) { return FPU registers[r]; } #endif #endif /* FPU_IMPL_H */ BasiliskII/src/uae_cpu/fpu/fpu_x86.h0000644000175000017500000006120410736405224017421 0ustar centriscentris/* * fpu/fpu_x86.h - Extra Definitions for the X86 assembly FPU core * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_X86_H #define FPU_X86_H /* NOTE: this file shall be included from fpu/fpu_x86.cpp */ #undef PUBLIC #define PUBLIC extern #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. // Status word PRIVATE uae_u32 x86_status_word; PRIVATE uae_u32 x86_status_word_accrued; // FPU jump table typedef void REGPARAM2 ( *fpuop_func )( uae_u32, uae_u32 ); PRIVATE fpuop_func fpufunctbl[65536]; // FPU consistency PRIVATE uae_u32 checked_sw_atstart; // FMOVECR constants supported byt x86 FPU PRIVATE fpu_register const_pi; PRIVATE fpu_register const_lg2; PRIVATE fpu_register const_l2e; PRIVATE fpu_register const_z; PRIVATE fpu_register const_ln2; PRIVATE fpu_register const_1; // FMOVECR constants not not suported by x86 FPU PRIVATE fpu_register const_e; PRIVATE fpu_register const_log_10_e; PRIVATE fpu_register const_ln_10; PRIVATE fpu_register const_1e1; PRIVATE fpu_register const_1e2; PRIVATE fpu_register const_1e4; PRIVATE fpu_register const_1e8; PRIVATE fpu_register const_1e16; PRIVATE fpu_register const_1e32; PRIVATE fpu_register const_1e64; PRIVATE fpu_register const_1e128; PRIVATE fpu_register const_1e256; PRIVATE fpu_register const_1e512; PRIVATE fpu_register const_1e1024; PRIVATE fpu_register const_1e2048; PRIVATE fpu_register const_1e4096; // Saved host FPU state PRIVATE uae_u8 m_fpu_state_original[108]; // 90/94/108 /* -------------------------------------------------------------------------- */ /* --- Methods --- */ /* -------------------------------------------------------------------------- */ // Debug support functions PRIVATE void FFPU dump_first_bytes_buf(char *b, uae_u8* buf, uae_s32 actual); PRIVATE char * FFPU etos(fpu_register const & e) REGPARAM; // FPU consistency PRIVATE void FFPU FPU_CONSISTENCY_CHECK_START(void); PRIVATE void FFPU FPU_CONSISTENCY_CHECK_STOP(const char *name); // Get special floating-point value class PRIVATE __inline__ uae_u32 FFPU IS_INFINITY (fpu_register const & f); PRIVATE __inline__ uae_u32 FFPU IS_NAN (fpu_register const & f); PRIVATE __inline__ uae_u32 FFPU IS_ZERO (fpu_register const & f); PRIVATE __inline__ uae_u32 FFPU IS_NEGATIVE (fpu_register const & f); // Make a special floating-point value PRIVATE __inline__ void FFPU MAKE_NAN (fpu_register & f); PRIVATE __inline__ void FFPU MAKE_INF_POSITIVE (fpu_register & f); PRIVATE __inline__ void FFPU MAKE_INF_NEGATIVE (fpu_register & f); PRIVATE __inline__ void FFPU MAKE_ZERO_POSITIVE (fpu_register & f); PRIVATE __inline__ void FFPU MAKE_ZERO_NEGATIVE (fpu_register & f); // Conversion from extended floating-point values PRIVATE uae_s32 FFPU extended_to_signed_32 ( fpu_register const & f ) REGPARAM; PRIVATE uae_s16 FFPU extended_to_signed_16 ( fpu_register const & f ) REGPARAM; PRIVATE uae_s8 FFPU extended_to_signed_8 ( fpu_register const & f ) REGPARAM; PRIVATE fpu_double FFPU extended_to_double( fpu_register const & f ) REGPARAM; PRIVATE uae_u32 FFPU from_single ( fpu_register const & f ) REGPARAM; PRIVATE void FFPU from_exten ( fpu_register const & f, uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3 ) REGPARAM; PRIVATE void FFPU from_double ( fpu_register const & f, uae_u32 *wrd1, uae_u32 *wrd2 ) REGPARAM; PRIVATE void FFPU from_pack (fpu_double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) REGPARAM; // Conversion to extended floating-point values PRIVATE void FFPU signed_to_extended ( uae_s32 x, fpu_register & f ) REGPARAM; PRIVATE void FFPU double_to_extended ( double x, fpu_register & f ) REGPARAM; PRIVATE void FFPU to_single ( uae_u32 src, fpu_register & f ) REGPARAM; PRIVATE void FFPU to_exten_no_normalize ( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & f ) REGPARAM; PRIVATE void FFPU to_exten ( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & f ) REGPARAM; PRIVATE void FFPU to_double ( uae_u32 wrd1, uae_u32 wrd2, fpu_register & f ) REGPARAM; PRIVATE fpu_double FFPU to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) REGPARAM; // Atomic floating-point arithmetic operations PRIVATE void FFPU do_fmove ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fmove_no_status ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fint ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fintrz ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fsqrt ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_ftst ( fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fsinh ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_flognp1 ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fetoxm1 ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_ftanh ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fatan ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fasin ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fatanh ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fetox ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_ftwotox ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_ftentox ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_flogn ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_flog10 ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_flog2 ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_facos ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fcosh ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fsin ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_ftan ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fabs ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fneg ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fcos ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fgetexp ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fgetman ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fdiv ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fmod ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_frem ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fmod_dont_set_cw ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_frem_dont_set_cw ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fadd ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fmul ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fsgldiv ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fscale ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fsglmul ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fsub ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fsincos ( fpu_register & dest_sin, fpu_register & dest_cos, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fcmp ( fpu_register & dest, fpu_register const & src ) REGPARAM; PRIVATE void FFPU do_fldpi ( fpu_register & dest ) REGPARAM; PRIVATE void FFPU do_fldlg2 ( fpu_register & dest ) REGPARAM; PRIVATE void FFPU do_fldl2e ( fpu_register & dest ) REGPARAM; PRIVATE void FFPU do_fldz ( fpu_register & dest ) REGPARAM; PRIVATE void FFPU do_fldln2 ( fpu_register & dest ) REGPARAM; PRIVATE void FFPU do_fld1 ( fpu_register & dest ) REGPARAM; // Instructions handlers PRIVATE void REGPARAM2 FFPU fpuop_illg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmove_2_ea( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Dreg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_none( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpsr( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Dreg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Areg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_none( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpsr( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpsr( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Areg_2_fpcr_fpsr_fpiar( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_none_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_none_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpcr_fpsr_fpiar_2_Mem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_pred( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_pred( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_static_postinc( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_Mem_2_fpp_dynamic_postinc( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_pred( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_pred( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_static_postinc( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_postincrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc_predecrement( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_fmovem_fpp_2_Mem_dynamic_postinc( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fldpi( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fldlg2( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_e( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fldl2e( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_log_10_e( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fldz( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fldln2( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_ln_10( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fld1( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e1( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e2( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e4( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e8( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e16( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e32( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e64( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e128( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e256( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e512( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e1024( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e2048( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_load_const_1e4096( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fmove( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fint( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fsinh( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fintrz( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fsqrt( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_flognp1( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fetoxm1( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_ftanh( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fatan( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fasin( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fatanh( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fsin( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_ftan( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fetox( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_ftwotox( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_ftentox( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_flogn( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_flog10( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_flog2( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fabs( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fcosh( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fneg( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_facos( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fcos( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fgetexp( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fgetman( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fdiv( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fmod( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_frem( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fadd( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fmul( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fsgldiv( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fscale( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fsglmul( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fsub( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fsincos( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_fcmp( uae_u32 opcode, uae_u32 extra ); PRIVATE void REGPARAM2 FFPU fpuop_do_ftst( uae_u32 opcode, uae_u32 extra ); // Get & Put floating-point values PRIVATE int FFPU get_fp_value (uae_u32 opcode, uae_u32 extra, fpu_register & src) REGPARAM; PRIVATE int FFPU put_fp_value (fpu_register const & value, uae_u32 opcode, uae_u32 extra) REGPARAM; PRIVATE int FFPU get_fp_ad(uae_u32 opcode, uae_u32 * ad) REGPARAM; // Floating-point condition-based instruction handlers PRIVATE int FFPU fpp_cond(uae_u32 opcode, int condition) REGPARAM; // Misc functions PRIVATE void __inline__ FFPU set_host_fpu_control_word (); PRIVATE void __inline__ FFPU SET_BSUN_ON_NAN (); PRIVATE void __inline__ FFPU build_ex_status (); PRIVATE void FFPU do_null_frestore (); PRIVATE void FFPU build_fpp_opp_lookup_table (); PRIVATE void FFPU set_constant ( fpu_register & f, char *name, double value, uae_s32 mult ); #endif /* FPU_X86_H */ BasiliskII/src/uae_cpu/fpu/fpu_uae.h0000644000175000017500000001274610736405224017555 0ustar centriscentris/* * fpu/fpu_uae.h - Extra Definitions for the old UAE FPU core * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_UAE_H #define FPU_UAE_H // Only define if you have IEEE 64 bit doubles. #define FPU_HAVE_IEEE_DOUBLE 1 /* NOTE: this file shall be included from fpu/fpu_uae.cpp */ #undef PUBLIC #define PUBLIC extern #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. enum { #ifdef WORDS_BIGENDIAN FHI = 0, FLO = 1 #else FHI = 1, FLO = 0 #endif }; // Floating-point rounding support PRIVATE inline fpu_register round_to_zero(fpu_register const & x); PRIVATE inline fpu_register round_to_nearest(fpu_register const & x); #if FPU_HAVE_IEEE_DOUBLE // Lauri-- full words to avoid partial register stalls. struct double_flags { uae_u32 in_range; uae_u32 zero; uae_u32 infinity; uae_u32 nan; uae_u32 negative; }; PRIVATE double_flags fl_source; PRIVATE double_flags fl_dest; PRIVATE inline void FFPU get_dest_flags(fpu_register const & r); PRIVATE inline void FFPU get_source_flags(fpu_register const & r); PRIVATE inline bool FFPU do_isnan(fpu_register const & r); PRIVATE inline bool FFPU do_isinf(fpu_register const & r); PRIVATE inline bool FFPU do_isneg(fpu_register const & r); PRIVATE inline bool FFPU do_iszero(fpu_register const & r); PRIVATE inline void FFPU make_nan(fpu_register & r); PRIVATE inline void FFPU make_zero_positive(fpu_register & r); PRIVATE inline void FFPU make_zero_negative(fpu_register & r); PRIVATE inline void FFPU make_inf_positive(fpu_register & r); PRIVATE inline void FFPU make_inf_negative(fpu_register & r); PRIVATE inline void FFPU fast_scale(fpu_register & r, int add); PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r); // May be optimized for particular processors #ifndef FPU_USE_NATIVE_FLAGS PRIVATE inline void FFPU make_fpsr(fpu_register const & r); #endif // Normalize to range 1..2 PRIVATE inline void FFPU fast_remove_exponent(fpu_register & r); // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. PRIVATE inline uae_u32 FFPU get_quotient_sign( fpu_register const & ra, fpu_register const & rb ); // Quotient Byte is loaded with the sign and least significant // seven bits of the quotient. PRIVATE inline void FFPU make_quotient( fpu_register const & quotient, uae_u32 sign ); // to_single PRIVATE inline fpu_register FFPU make_single( uae_u32 value ); // from_single PRIVATE inline uae_u32 FFPU extract_single( fpu_register const & src ); // to_exten PRIVATE inline fpu_register FFPU make_extended( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3 ); /* Would be so much easier with full size floats :( ... this is so vague. */ // to_exten_no_normalize PRIVATE inline void FFPU make_extended_no_normalize( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & result ); // from_exten PRIVATE inline void FFPU extract_extended(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 ); // to_double PRIVATE inline fpu_register FFPU make_double( uae_u32 wrd1, uae_u32 wrd2 ); // from_double PRIVATE inline void FFPU extract_double(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2 ); #else /* !FPU_HAVE_IEEE_DOUBLE */ // FIXME: may be optimized for particular processors #ifndef FPU_USE_NATIVE_FLAGS PRIVATE inline void FFPU make_fpsr(fpu_register const & r); #endif // to_single PRIVATE inline fpu_register make_single( uae_u32 value ); // from_single PRIVATE inline uae_u32 FFPU extract_single( fpu_register const & src ); // to exten PRIVATE inline fpu_register FFPU make_extended( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3 ); // from_exten PRIVATE inline void FFPU extract_extended( fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 ); // to_double PRIVATE inline fpu_register FFPU make_double( uae_u32 wrd1, uae_u32 wrd2 ); // from_double PRIVATE inline void FFPU extract_double( fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2 ); #endif /* FPU_HAVE_IEEE_DOUBLE */ PRIVATE inline fpu_register FFPU make_packed( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3 ); PRIVATE inline void FFPU extract_packed( fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 ); PRIVATE inline int FFPU get_fp_value( uae_u32 opcode, uae_u16 extra, fpu_register & src ); PRIVATE inline int FFPU put_fp_value( uae_u32 opcode, uae_u16 extra, fpu_register const & value ); PRIVATE inline int FFPU get_fp_ad( uae_u32 opcode, uae_u32 * ad ); PRIVATE inline int FFPU fpp_cond( int condition ); #endif /* FPU_UAE_H */ BasiliskII/src/uae_cpu/fpu/rounding.h0000644000175000017500000001301010736405224017737 0ustar centriscentris/* * fpu/rounding.h - system-dependant FPU rounding mode and precision * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_ROUNDING_H #define FPU_ROUNDING_H /* NOTE: this file shall be included from fpu/fpu_*.cpp */ #undef PUBLIC #define PUBLIC extern #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* Defaults to generic rounding mode and precision handling */ #define FPU_USE_GENERIC_ROUNDING_MODE #define FPU_USE_GENERIC_ROUNDING_PRECISION /* -------------------------------------------------------------------------- */ /* --- Selection of floating-point rounding mode and precision --- */ /* -------------------------------------------------------------------------- */ /* Optimized i386 fpu core must use native rounding mode */ #if defined(FPU_X86) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_ROUNDING_MODE # define FPU_USE_X86_ROUNDING_MODE #endif /* Optimized i386 fpu core must use native rounding precision */ #if defined(FPU_X86) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_ROUNDING_PRECISION # define FPU_USE_X86_ROUNDING_PRECISION #endif #if 0 // gb-- FIXME: that doesn't work /* IEEE-based fpu core can have native rounding mode on i386 */ #if defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_ROUNDING_MODE # define FPU_USE_X86_ROUNDING_MODE #endif /* IEEE-based fpu core can have native rounding precision on i386 */ #if defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_ROUNDING_PRECISION # define FPU_USE_X86_ROUNDING_PRECISION #endif #endif /* -------------------------------------------------------------------------- */ /* --- Sanity checks --- */ /* -------------------------------------------------------------------------- */ /* X86 rounding mode and precision work together */ #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION) # define FPU_USE_X86_ROUNDING # define CW_INITIAL (CW_RESET|CW_X|CW_PC_EXTENDED|CW_RC_NEAR|CW_PM|CW_UM|CW_OM|CW_ZM|CW_DM|CW_IM) PRIVATE uae_u32 x86_control_word; #endif /* Control word -- rounding mode */ #ifdef FPU_USE_X86_ROUNDING_MODE PUBLIC const uae_u32 x86_control_word_rm_mac2host[]; #endif /* Control word -- rounding precision */ #ifdef FPU_USE_X86_ROUNDING_PRECISION PUBLIC const uae_u32 x86_control_word_rp_mac2host[]; #endif #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION) /* Set host control word for rounding mode and rounding precision */ PRIVATE inline void set_host_control_word(void) { /* Exception enable byte is ignored, but the same value is returned that was previously set. */ x86_control_word = (x86_control_word & ~(X86_ROUNDING_MODE|X86_ROUNDING_PRECISION)) | x86_control_word_rm_mac2host[(FPU fpcr.rounding_mode & FPCR_ROUNDING_MODE) >> 4] | x86_control_word_rp_mac2host[(FPU fpcr.rounding_precision & FPCR_ROUNDING_PRECISION) >> 6] ; __asm__ __volatile__("fldcw %0" : : "m" (x86_control_word)); } #endif /* -------------------------------------------------------------------------- */ /* --- Generic rounding mode and precision --- */ /* -------------------------------------------------------------------------- */ #if defined(FPU_USE_GENERIC_ROUNDING_MODE) && defined(FPU_USE_GENERIC_ROUNDING_PRECISION) /* Set host control word for rounding mode and rounding precision */ PRIVATE inline void set_host_control_word(void) { } #endif /* -------------------------------------------------------------------------- */ /* --- Common rounding mode and precision --- */ /* -------------------------------------------------------------------------- */ #if defined(FPU_USE_GENERIC_ROUNDING_MODE) || defined(FPU_USE_X86_ROUNDING_MODE) /* Return the current rounding mode in m68k format */ static inline uae_u32 FFPU get_rounding_mode(void) { return FPU fpcr.rounding_mode; } /* Convert and set to native rounding mode */ static inline void FFPU set_rounding_mode(uae_u32 new_rounding_mode) { FPU fpcr.rounding_mode = new_rounding_mode; } #endif #if defined(FPU_USE_GENERIC_ROUNDING_PRECISION) || defined(FPU_USE_X86_ROUNDING_PRECISION) /* Return the current rounding precision in m68k format */ static inline uae_u32 FFPU get_rounding_precision(void) { return FPU fpcr.rounding_precision; } /* Convert and set to native rounding precision */ static inline void FFPU set_rounding_precision(uae_u32 new_rounding_precision) { FPU fpcr.rounding_precision = new_rounding_precision; } #endif #endif /* FPU_ROUNDING_H */ BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp0000644000175000017500000016661111735673707020126 0ustar centriscentris/* * fpu/fpu_uae.cpp * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ /* * Following fixes by Lauri Pesonen, July 1999: * * FMOVEM list handling: * The lookup tables did not work correctly, rewritten. * FINT: * (int) cast does not work, fixed. * Further, now honors the FPU fpcr rounding modes. * FINTRZ: * (int) cast cannot be used, fixed. * FGETEXP: * Input argument value 0 returned erroneous value. * FMOD: * (int) cast cannot be used. Replaced by proper rounding. * Quotient byte handling was missing. * FREM: * (int) cast cannot be used. Replaced by proper rounding. * Quotient byte handling was missing. * FSCALE: * Input argument value 0 was not handled correctly. * FMOVEM Control Registers to/from address FPU registers An: * A bug caused the code never been called. * FMOVEM Control Registers pre-decrement: * Moving of control regs from memory to FPP was not handled properly, * if not all of the three FPU registers were moved. * Condition code "Not Greater Than or Equal": * Returned erroneous value. * FSINCOS: * Cosine must be loaded first if same register. * FMOVECR: * Status register was not updated (yes, this affects it). * FMOVE -> reg: * Status register was not updated (yes, this affects it). * FMOVE reg -> reg: * Status register was not updated. * FDBcc: * The loop termination condition was wrong. * Possible leak from int16 to int32 fixed. * get_fp_value: * Immediate addressing mode && Operation Length == Byte -> * Use the low-order byte of the extension word. * Now FPU fpcr high 16 bits are always read as zeroes, no matter what was * written to them. * * Other: * - Optimized single/double/extended to/from conversion functions. * Huge speed boost, but not (necessarily) portable to other systems. * Enabled/disabled by #define FPU_HAVE_IEEE_DOUBLE 1 * - Optimized versions of FSCALE, FGETEXP, FGETMAN * - Conversion routines now handle NaN and infinity better. * - Some constants precalculated. Not all compilers can optimize the * expressions previously used. * * TODO: * - Floating point exceptions. * - More Infinity/NaN/overflow/underflow checking. * - FPU instruction_address (only needed when exceptions are implemented) * - Should be written in assembly to support long doubles. * - Precision rounding single/double */ #include "sysdeps.h" #include #include #include "memory.h" #include "readcpu.h" #include "newcpu.h" #include "main.h" #define FPU_IMPLEMENTATION #include "fpu/fpu.h" #include "fpu/fpu_uae.h" /* Global FPU context */ fpu_t fpu; /* -------------------------------------------------------------------------- */ /* --- Native Support --- */ /* -------------------------------------------------------------------------- */ #include "fpu/flags.h" #include "fpu/exceptions.h" #include "fpu/rounding.h" #include "fpu/impl.h" #include "fpu/flags.cpp" #include "fpu/exceptions.cpp" /* -------------------------------------------------------------------------- */ /* --- Scopes Definition --- */ /* -------------------------------------------------------------------------- */ #undef PUBLIC #define PUBLIC /**/ #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* -------------------------------------------------------------------------- */ /* --- Debugging --- */ /* -------------------------------------------------------------------------- */ PUBLIC void FFPU fpu_dump_registers(void) { for (int i = 0; i < 8; i++){ printf ("FP%d: %g ", i, fpu_get_register(i)); if ((i & 3) == 3) printf ("\n"); } } PUBLIC void FFPU fpu_dump_flags(void) { printf ("N=%d Z=%d I=%d NAN=%d\n", (get_fpsr() & FPSR_CCB_NEGATIVE) != 0, (get_fpsr() & FPSR_CCB_ZERO)!= 0, (get_fpsr() & FPSR_CCB_INFINITY) != 0, (get_fpsr() & FPSR_CCB_NAN) != 0); } /* single : S 8*E 23*F */ /* double : S 11*E 52*F */ /* extended : S 15*E 64*F */ /* E = 0 & F = 0 -> 0 */ /* E = MAX & F = 0 -> Infin */ /* E = MAX & F # 0 -> NotANumber */ /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */ #if FPU_DEBUG PUBLIC void FFPU dump_registers(const char * str) { char temp_str[512]; sprintf(temp_str, "%s: %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f\n", str, get_register(0), get_register(1), get_register(2), get_register(3), get_register(4), get_register(5), get_register(6), get_register(7) ); fpu_debug((temp_str)); } PUBLIC void FFPU dump_first_bytes(uae_u8 * buffer, uae_s32 actual) { char temp_buf1[256], temp_buf2[10]; int bytes = sizeof(temp_buf1)/3-1-3; if (actual < bytes) bytes = actual; temp_buf1[0] = 0; for (int i = 0; i < bytes; i++) { sprintf(temp_buf2, "%02x ", (uae_u32)buffer[i]); strcat(temp_buf1, temp_buf2); } strcat(temp_buf1, "\n"); fpu_debug((temp_buf1)); } #else PUBLIC void FFPU dump_registers(const char *) { } PUBLIC void FFPU dump_first_bytes(uae_u8 *, uae_s32) { } #endif PRIVATE inline fpu_register FFPU round_to_zero(fpu_register const & x) { return (x < 0.0 ? ceil(x) : floor(x)); } PRIVATE inline fpu_register FFPU round_to_nearest(fpu_register const & x) { return floor(x + 0.5); } #if FPU_HAVE_IEEE_DOUBLE #ifndef HAVE_ISNAN #define isnan(x) do_isnan((x)) #endif PRIVATE inline bool FFPU do_isnan(fpu_register const & r) { uae_u32 * p = (uae_u32 *)&r; if ((p[FHI] & 0x7FF00000) == 0x7FF00000) { // logical or is faster here. if ((p[FHI] & 0x000FFFFF) || p[FLO]) { return true; } } return false; } #ifndef HAVE_ISINF #define isinf(x) do_isinf((x)) #endif PRIVATE inline bool FFPU do_isinf(fpu_register const & r) { uae_u32 * p = (uae_u32 *)&r; if (((p[FHI] & 0x7FF00000) == 0x7FF00000) && p[FLO] == 0) { return true; } return false; } #ifndef HAVE_ISNEG #define isneg(x) do_isneg((x)) #endif PRIVATE inline bool FFPU do_isneg(fpu_register const & r) { uae_u32 * p = (uae_u32 *)&r; return ((p[FHI] & 0x80000000) != 0); } #ifndef HAVE_ISZERO #define iszero(x) do_iszero((x)) #endif PRIVATE inline bool FFPU do_iszero(fpu_register const & r) { uae_u32 * p = (uae_u32 *)&r; return (((p[FHI] & 0x7FF00000) == 0) && p[FLO] == 0); } // May be optimized for particular processors #ifndef FPU_USE_NATIVE_FLAGS PRIVATE inline void FFPU make_fpsr(fpu_register const & r) { FPU fpsr.condition_codes = (iszero(r) ? NATIVE_FFLAG_ZERO : 0) | (isneg(r) ? NATIVE_FFLAG_NEGATIVE : 0) | (isnan(r) ? NATIVE_FFLAG_NAN : 0) | (isinf(r) ? NATIVE_FFLAG_INFINITY : 0) ; } #endif PRIVATE inline void FFPU get_dest_flags(fpu_register const & r) { fl_dest.negative = isneg(r); fl_dest.zero = iszero(r); fl_dest.infinity = isinf(r); fl_dest.nan = isnan(r); fl_dest.in_range = !fl_dest.zero && !fl_dest.infinity && !fl_dest.nan; } PRIVATE inline void FFPU get_source_flags(fpu_register const & r) { fl_source.negative = isneg(r); fl_source.zero = iszero(r); fl_source.infinity = isinf(r); fl_source.nan = isnan(r); fl_source.in_range = !fl_source.zero && !fl_source.infinity && !fl_source.nan; } PRIVATE inline void FFPU make_nan(fpu_register & r) { uae_u32 * const p = (uae_u32 *)&r; p[FLO] = 0xffffffff; p[FHI] = 0x7fffffff; } PRIVATE inline void FFPU make_zero_positive(fpu_register & r) { uae_u32 * const p = (uae_u32 *)&r; p[FLO] = p[FHI] = 0; } PRIVATE inline void FFPU make_zero_negative(fpu_register & r) { uae_u32 * const p = (uae_u32 *)&r; p[FLO] = 0; p[FHI] = 0x80000000; } PRIVATE inline void FFPU make_inf_positive(fpu_register & r) { uae_u32 * const p = (uae_u32 *)&r; p[FLO] = 0; p[FHI] = 0x7FF00000; } PRIVATE inline void FFPU make_inf_negative(fpu_register & r) { uae_u32 * const p = (uae_u32 *)&r; p[FLO] = 0; p[FHI] = 0xFFF00000; } PRIVATE inline void FFPU fast_scale(fpu_register & r, int add) { uae_u32 * const p = (uae_u32 *)&r; int exp = (p[FHI] & 0x7FF00000) >> 20; // TODO: overflow flags exp += add; if(exp >= 2047) { make_inf_positive(r); } else if(exp < 0) { // keep sign (+/- 0) p[FHI] &= 0x80000000; } else { p[FHI] = (p[FHI] & 0x800FFFFF) | ((uae_u32)exp << 20); } } PRIVATE inline fpu_register FFPU fast_fgetexp(fpu_register const & r) { uae_u32 * const p = (uae_u32 *)&r; int exp = (p[FHI] & 0x7FF00000) >> 20; return( exp - 1023 ); } // Normalize to range 1..2 PRIVATE inline void FFPU fast_remove_exponent(fpu_register & r) { uae_u32 * const p = (uae_u32 *)&r; p[FHI] = (p[FHI] & 0x800FFFFF) | 0x3FF00000; } // The sign of the quotient is the exclusive-OR of the sign bits // of the source and destination operands. PRIVATE inline uae_u32 FFPU get_quotient_sign(fpu_register const & ra, fpu_register const & rb) { uae_u32 * const a = (uae_u32 *)&ra; uae_u32 * const b = (uae_u32 *)&rb; return (((a[FHI] ^ b[FHI]) & 0x80000000) ? FPSR_QUOTIENT_SIGN : 0); } // Quotient Byte is loaded with the sign and least significant // seven bits of the quotient. PRIVATE inline void FFPU make_quotient(fpu_register const & quotient, uae_u32 sign) { uae_u32 lsb = (uae_u32)fabs(quotient) & 0x7f; FPU fpsr.quotient = sign | (lsb << 16); } // to_single PRIVATE inline fpu_register FFPU make_single(uae_u32 value) { if ((value & 0x7fffffff) == 0) return (0.0); fpu_register result; uae_u32 * p = (uae_u32 *)&result; uae_u32 sign = (value & 0x80000000); uae_u32 exp = ((value & 0x7F800000) >> 23) + 1023 - 127; p[FLO] = value << 29; p[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3); fpu_debug(("make_single (%X) = %.04f\n",value,(double)result)); return(result); } // from_single PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) { if (src == 0.0) return 0; uae_u32 result; uae_u32 *p = (uae_u32 *)&src; uae_u32 sign = (p[FHI] & 0x80000000); uae_u32 exp = (p[FHI] & 0x7FF00000) >> 20; if(exp + 127 < 1023) { exp = 0; } else if(exp > 1023 + 127) { exp = 255; } else { exp = exp + 127 - 1023; } result = sign | (exp << 23) | ((p[FHI] & 0x000FFFFF) << 3) | (p[FLO] >> 29); fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result)); return (result); } // to_exten PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) return 0.0; fpu_register result; uae_u32 *p = (uae_u32 *)&result; uae_u32 sign = wrd1 & 0x80000000; uae_u32 exp = (wrd1 >> 16) & 0x7fff; // The explicit integer bit is not set, must normalize. if((wrd2 & 0x80000000) == 0) { fpu_debug(("make_extended denormalized mantissa (%X,%X,%X)\n",wrd1,wrd2,wrd3)); if( wrd2 | wrd3 ) { // mantissa, not fraction. uae_u64 man = ((uae_u64)wrd2 << 32) | wrd3; while( exp > 0 && (man & UVAL64(0x8000000000000000)) == 0 ) { man <<= 1; exp--; } wrd2 = (uae_u32)( man >> 32 ); wrd3 = (uae_u32)( man & 0xFFFFFFFF ); } else { if(exp == 0x7FFF) { // Infinity. } else { // Zero exp = 16383 - 1023; } } } if(exp < 16383 - 1023) { // should set underflow. exp = 0; } else if(exp > 16383 + 1023) { // should set overflow. exp = 2047; } else { exp = exp + 1023 - 16383; } // drop the explicit integer bit. p[FLO] = (wrd2 << 21) | (wrd3 >> 11); p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); return(result); } /* Would be so much easier with full size floats :( ... this is so vague. */ // make_extended_no_normalize PRIVATE inline void FFPU make_extended_no_normalize( uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & result ) { // Is it zero? if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) { make_zero_positive(result); return; } // Is it NaN? if( (wrd1 & 0x7FFF0000) == 0x7FFF0000 ) { if( (wrd1 & 0x0000FFFF) || wrd2 || wrd3 ) { make_nan(result); return; } } uae_u32 sign = wrd1 & 0x80000000; uae_u32 exp = (wrd1 >> 16) & 0x7fff; if(exp < 16383 - 1023) { // should set underflow. exp = 0; } else if(exp > 16383 + 1023) { // should set overflow. exp = 2047; } else { exp = exp + 1023 - 16383; } // drop the explicit integer bit. uae_u32 *p = (uae_u32 *)&result; p[FLO] = (wrd2 << 21) | (wrd3 >> 11); p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11); fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(float)(*(double *)p))); } // from_exten PRIVATE inline void FFPU extract_extended(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3 ) { if (src == 0.0) { *wrd1 = *wrd2 = *wrd3 = 0; return; } uae_u32 *p = (uae_u32 *)&src; fpu_debug(("extract_extended (%X,%X)\n",p[FLO],p[FHI])); uae_u32 sign = p[FHI] & 0x80000000; uae_u32 exp = ((p[FHI] >> 20) & 0x7ff); // Check for maximum if(exp == 0x7FF) { exp = 0x7FFF; } else { exp += 16383 - 1023; } *wrd1 = sign | (exp << 16); // always set the explicit integer bit. *wrd2 = 0x80000000 | ((p[FHI] & 0x000FFFFF) << 11) | ((p[FLO] & 0xFFE00000) >> 21); *wrd3 = p[FLO] << 11; fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); } // to_double PRIVATE inline fpu_register FFPU make_double(uae_u32 wrd1, uae_u32 wrd2) { if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) return 0.0; fpu_register result; uae_u32 *p = (uae_u32 *)&result; p[FLO] = wrd2; p[FHI] = wrd1; fpu_debug(("make_double (%X,%X) = %.04f\n",wrd1,wrd2,(double)result)); return(result); } // from_double PRIVATE inline void FFPU extract_double(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2 ) { /* if (src == 0.0) { *wrd1 = *wrd2 = 0; return; } */ uae_u32 *p = (uae_u32 *)&src; *wrd2 = p[FLO]; *wrd1 = p[FHI]; fpu_debug(("extract_double (%.04f) = %X,%X\n",(double)src,*wrd1,*wrd2)); } #else // !FPU_HAVE_IEEE_DOUBLE #ifndef FPU_USE_NATIVE_FLAGS PRIVATE inline void FFPU make_fpsr(fpu_register const & r) { FPU fpsr.condition_codes = ((r == 0.0) ? NATIVE_FFLAG_ZERO : 0) | ((r < 0.0) ? NATIVE_FFLAG_NEGATIVE : 0) ; } #endif // make_single PRIVATE inline fpu_register FFPU make_single(uae_u32 value) { if ((value & 0x7fffffff) == 0) return (0.0); fpu_register frac = (fpu_register) ((value & 0x7fffff) | 0x800000) / 8388608.0; if (value & 0x80000000) frac = -frac; fpu_register result = ldexp (frac, (int)((value >> 23) & 0xff) - 127); fpu_debug(("make_single (%X) = %.04f\n",value,(double)result)); return (result); } // extract_single PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src) { int expon; uae_u32 tmp, result; fpu_register frac; #if FPU_DEBUG fpu_register src0 = src; #endif if (src == 0.0) return 0; if (src < 0) { tmp = 0x80000000; src = -src; } else { tmp = 0; } frac = frexp (src, &expon); frac += 0.5 / 16777216.0; if (frac >= 1.0) { frac /= 2.0; expon++; } result = tmp | (((expon + 127 - 1) & 0xff) << 23) | (((int) (frac * 16777216.0)) & 0x7fffff); // fpu_debug(("extract_single (%.04f) = %X\n",(float)src0,result)); return (result); } // to exten PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { fpu_register frac, result; if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) return 0.0; frac = (fpu_register) wrd2 / 2147483648.0 + (fpu_register) wrd3 / 9223372036854775808.0; if (wrd1 & 0x80000000) frac = -frac; result = ldexp (frac, (int)((wrd1 >> 16) & 0x7fff) - 16383); fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result)); return result; } // extract_extended PRIVATE inline void FFPU extract_extended(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { int expon; fpu_register frac; #if FPU_DEBUG fpu_register src0 = src; #endif if (src == 0.0) { *wrd1 = 0; *wrd2 = 0; *wrd3 = 0; return; } if (src < 0) { *wrd1 = 0x80000000; src = -src; } else { *wrd1 = 0; } frac = frexp (src, &expon); frac += 0.5 / 18446744073709551616.0; if (frac >= 1.0) { frac /= 2.0; expon++; } *wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16); *wrd2 = (uae_u32) (frac * 4294967296.0); *wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0); // fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(float)src0,*wrd1,*wrd2,*wrd3)); } // make_double PRIVATE inline fpu_register FFPU make_double(uae_u32 wrd1, uae_u32 wrd2) { if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) return 0.0; fpu_register frac = (fpu_register) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 + (fpu_register) wrd2 / 4503599627370496.0; if (wrd1 & 0x80000000) frac = -frac; fpu_register result = ldexp (frac, (int)((wrd1 >> 20) & 0x7ff) - 1023); fpu_debug(("make_double (%X,%X) = %.04f\n",wrd1,wrd2,(double)result)); return result; } // extract_double PRIVATE inline void FFPU extract_double(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2) { int expon; int tmp; fpu_register frac frac; #if FPU_DEBUG fpu_register src0 = src; #endif if (src == 0.0) { *wrd1 = 0; *wrd2 = 0; return; } if (src < 0) { *wrd1 = 0x80000000; src = -src; } else { *wrd1 = 0; } frac = frexp (src, &expon); frac += 0.5 / 9007199254740992.0; if (frac >= 1.0) { frac /= 2.0; expon++; } tmp = (uae_u32) (frac * 2097152.0); *wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff); *wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0); // fpu_debug(("extract_double (%.04f) = %X,%X\n",(float)src0,*wrd1,*wrd2)); } #endif // to_pack PRIVATE inline fpu_register FFPU make_packed(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3) { fpu_double d; char *cp; char str[100]; cp = str; if (wrd1 & 0x80000000) *cp++ = '-'; *cp++ = (char)((wrd1 & 0xf) + '0'); *cp++ = '.'; *cp++ = (char)(((wrd2 >> 28) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 16) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 12) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 8) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 4) & 0xf) + '0'); *cp++ = (char)(((wrd2 >> 0) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 28) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 16) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 12) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 8) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 4) & 0xf) + '0'); *cp++ = (char)(((wrd3 >> 0) & 0xf) + '0'); *cp++ = 'E'; if (wrd1 & 0x40000000) *cp++ = '-'; *cp++ = (char)(((wrd1 >> 24) & 0xf) + '0'); *cp++ = (char)(((wrd1 >> 20) & 0xf) + '0'); *cp++ = (char)(((wrd1 >> 16) & 0xf) + '0'); *cp = 0; sscanf(str, "%le", &d); fpu_debug(("make_packed str = %s\n",str)); fpu_debug(("make_packed(%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)d)); return d; } // from_pack PRIVATE inline void FFPU extract_packed(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3) { int i; int t; char *cp; char str[100]; sprintf(str, "%.16e", src); fpu_debug(("extract_packed(%.04f,%s)\n",(double)src,str)); cp = str; *wrd1 = *wrd2 = *wrd3 = 0; if (*cp == '-') { cp++; *wrd1 = 0x80000000; } if (*cp == '+') cp++; *wrd1 |= (*cp++ - '0'); if (*cp == '.') cp++; for (i = 0; i < 8; i++) { *wrd2 <<= 4; if (*cp >= '0' && *cp <= '9') *wrd2 |= *cp++ - '0'; } for (i = 0; i < 8; i++) { *wrd3 <<= 4; if (*cp >= '0' && *cp <= '9') *wrd3 |= *cp++ - '0'; } if (*cp == 'e' || *cp == 'E') { cp++; if (*cp == '-') { cp++; *wrd1 |= 0x40000000; } if (*cp == '+') cp++; t = 0; for (i = 0; i < 3; i++) { if (*cp >= '0' && *cp <= '9') t = (t << 4) | (*cp++ - '0'); } *wrd1 |= t << 16; } fpu_debug(("extract_packed(%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3)); } PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_register & src) { uaecptr tmppc; uae_u16 tmp; int size; int mode; int reg; uae_u32 ad = 0; static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // fpu_debug(("get_fp_value(%X,%X)\n",(int)opcode,(int)extra)); // dump_first_bytes( regs.pc_p-4, 16 ); if ((extra & 0x4000) == 0) { src = FPU registers[(extra >> 10) & 7]; return 1; } mode = (opcode >> 3) & 7; reg = opcode & 7; size = (extra >> 10) & 7; fpu_debug(("get_fp_value mode=%d, reg=%d, size=%d\n",(int)mode,(int)reg,(int)size)); switch (mode) { case 0: switch (size) { case 6: src = (fpu_register) (uae_s8) m68k_dreg (regs, reg); break; case 4: src = (fpu_register) (uae_s16) m68k_dreg (regs, reg); break; case 0: src = (fpu_register) (uae_s32) m68k_dreg (regs, reg); break; case 1: src = make_single(m68k_dreg (regs, reg)); break; default: return 0; } return 1; case 1: return 0; case 2: ad = m68k_areg (regs, reg); break; case 3: ad = m68k_areg (regs, reg); m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ad = m68k_areg (regs, reg); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch (reg) { case 0: ad = (uae_s32) (uae_s16) next_iword(); break; case 1: ad = next_ilong(); break; case 2: ad = m68k_getpc (); ad += (uae_s32) (uae_s16) next_iword(); fpu_debug(("get_fp_value next_iword()=%X\n",ad-m68k_getpc()-2)); break; case 3: tmppc = m68k_getpc (); tmp = (uae_u16)next_iword(); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: ad = m68k_getpc (); m68k_setpc (ad + sz2[size]); // Immediate addressing mode && Operation Length == Byte -> // Use the low-order byte of the extension word. if(size == 6) ad++; break; default: return 0; } } fpu_debug(("get_fp_value m68k_getpc()=%X\n",m68k_getpc())); fpu_debug(("get_fp_value ad=%X\n",ad)); fpu_debug(("get_fp_value get_long (ad)=%X\n",get_long (ad))); dump_first_bytes( get_real_address(ad)-64, 64 ); dump_first_bytes( get_real_address(ad), 64 ); switch (size) { case 0: src = (fpu_register) (uae_s32) get_long (ad); break; case 1: src = make_single(get_long (ad)); break; case 2: { uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); src = make_extended(wrd1, wrd2, wrd3); break; } case 3: { uae_u32 wrd1, wrd2, wrd3; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); src = make_packed(wrd1, wrd2, wrd3); break; } case 4: src = (fpu_register) (uae_s16) get_word(ad); break; case 5: { uae_u32 wrd1, wrd2; wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); src = make_double(wrd1, wrd2); break; } case 6: src = (fpu_register) (uae_s8) get_byte(ad); break; default: return 0; } // fpu_debug(("get_fp_value result = %.04f\n",(float)src)); return 1; } PRIVATE inline int FFPU put_fp_value (uae_u32 opcode, uae_u16 extra, fpu_register const & value) { uae_u16 tmp; uaecptr tmppc; int size; int mode; int reg; uae_u32 ad; static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0}; static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0}; // fpu_debug(("put_fp_value(%.04f,%X,%X)\n",(float)value,(int)opcode,(int)extra)); if ((extra & 0x4000) == 0) { int dest_reg = (extra >> 10) & 7; FPU registers[dest_reg] = value; make_fpsr(FPU registers[dest_reg]); return 1; } mode = (opcode >> 3) & 7; reg = opcode & 7; size = (extra >> 10) & 7; ad = 0xffffffff; switch (mode) { case 0: switch (size) { case 6: m68k_dreg (regs, reg) = (((uae_s32) value & 0xff) | (m68k_dreg (regs, reg) & ~0xff)); break; case 4: m68k_dreg (regs, reg) = (((uae_s32) value & 0xffff) | (m68k_dreg (regs, reg) & ~0xffff)); break; case 0: m68k_dreg (regs, reg) = (uae_s32) value; break; case 1: m68k_dreg (regs, reg) = extract_single(value); break; default: return 0; } return 1; case 1: return 0; case 2: ad = m68k_areg (regs, reg); break; case 3: ad = m68k_areg (regs, reg); m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size]; break; case 4: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size]; ad = m68k_areg (regs, reg); break; case 5: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch (reg) { case 0: ad = (uae_s32) (uae_s16) next_iword(); break; case 1: ad = next_ilong(); break; case 2: ad = m68k_getpc (); ad += (uae_s32) (uae_s16) next_iword(); break; case 3: tmppc = m68k_getpc (); tmp = (uae_u16)next_iword(); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: ad = m68k_getpc (); m68k_setpc (ad + sz2[size]); break; default: return 0; } } switch (size) { case 0: put_long (ad, (uae_s32) value); break; case 1: put_long (ad, extract_single(value)); break; case 2: { uae_u32 wrd1, wrd2, wrd3; extract_extended(value, &wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); break; } case 3: { uae_u32 wrd1, wrd2, wrd3; extract_packed(value, &wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); break; } case 4: put_word(ad, (uae_s16) value); break; case 5: { uae_u32 wrd1, wrd2; extract_double(value, &wrd1, &wrd2); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); break; } case 6: put_byte(ad, (uae_s8) value); break; default: return 0; } return 1; } PRIVATE inline int FFPU get_fp_ad(uae_u32 opcode, uae_u32 * ad) { uae_u16 tmp; uaecptr tmppc; int mode; int reg; mode = (opcode >> 3) & 7; reg = opcode & 7; switch (mode) { case 0: case 1: return 0; case 2: *ad = m68k_areg (regs, reg); break; case 3: *ad = m68k_areg (regs, reg); break; case 4: *ad = m68k_areg (regs, reg); break; case 5: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword(); break; case 6: *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword()); break; case 7: switch (reg) { case 0: *ad = (uae_s32) (uae_s16) next_iword(); break; case 1: *ad = next_ilong(); break; case 2: *ad = m68k_getpc (); *ad += (uae_s32) (uae_s16) next_iword(); break; case 3: tmppc = m68k_getpc (); tmp = (uae_u16)next_iword(); *ad = get_disp_ea_020 (tmppc, tmp); break; default: return 0; } } return 1; } #if FPU_DEBUG # define CONDRET(s,x) fpu_debug(("fpp_cond %s = %d\n",s,(uint32)(x))); return (x) #else # define CONDRET(s,x) return (x) #endif PRIVATE inline int FFPU fpp_cond(int condition) { #if 1 # define N ((FPU fpsr.condition_codes & NATIVE_FFLAG_NEGATIVE) == NATIVE_FFLAG_NEGATIVE) # define Z ((FPU fpsr.condition_codes & NATIVE_FFLAG_ZERO) == NATIVE_FFLAG_ZERO) # define I ((FPU fpsr.condition_codes & NATIVE_FFLAG_INFINITY) == NATIVE_FFLAG_INFINITY) # define NaN ((FPU fpsr.condition_codes & NATIVE_FFLAG_NAN) == NATIVE_FFLAG_NAN) #else # define N ((FPU fpsr.condition_codes & NATIVE_FFLAG_NEGATIVE) != 0) # define Z ((FPU fpsr.condition_codes & NATIVE_FFLAG_ZERO) != 0) # define I ((FPU fpsr.condition_codes & NATIVE_FFLAG_INFINITY) != 0) # define NaN ((FPU fpsr.condition_codes & NATIVE_FFLAG_NAN) != 0) #endif #if 0 return fpcctrue(condition); #else switch (condition) { case 0x00: CONDRET("False",0); case 0x01: CONDRET("Equal",Z); case 0x02: CONDRET("Ordered Greater Than",!(NaN || Z || N)); case 0x03: CONDRET("Ordered Greater Than or Equal",Z || !(NaN || N)); case 0x04: CONDRET("Ordered Less Than",N && !(NaN || Z)); case 0x05: CONDRET("Ordered Less Than or Equal",Z || (N && !NaN)); case 0x06: CONDRET("Ordered Greater or Less Than",!(NaN || Z)); case 0x07: CONDRET("Ordered",!NaN); case 0x08: CONDRET("Unordered",NaN); case 0x09: CONDRET("Unordered or Equal",NaN || Z); case 0x0a: CONDRET("Unordered or Greater Than",NaN || !(N || Z)); case 0x0b: CONDRET("Unordered or Greater or Equal",NaN || Z || !N); case 0x0c: CONDRET("Unordered or Less Than",NaN || (N && !Z)); case 0x0d: CONDRET("Unordered or Less or Equal",NaN || Z || N); case 0x0e: CONDRET("Not Equal",!Z); case 0x0f: CONDRET("True",1); case 0x10: CONDRET("Signaling False",0); case 0x11: CONDRET("Signaling Equal",Z); case 0x12: CONDRET("Greater Than",!(NaN || Z || N)); case 0x13: CONDRET("Greater Than or Equal",Z || !(NaN || N)); case 0x14: CONDRET("Less Than",N && !(NaN || Z)); case 0x15: CONDRET("Less Than or Equal",Z || (N && !NaN)); case 0x16: CONDRET("Greater or Less Than",!(NaN || Z)); case 0x17: CONDRET("Greater, Less or Equal",!NaN); case 0x18: CONDRET("Not Greater, Less or Equal",NaN); case 0x19: CONDRET("Not Greater or Less Than",NaN || Z); case 0x1a: CONDRET("Not Less Than or Equal",NaN || !(N || Z)); case 0x1b: CONDRET("Not Less Than",NaN || Z || !N); case 0x1c: CONDRET("Not Greater Than or Equal", NaN || (N && !Z)); // case 0x1c: CONDRET("Not Greater Than or Equal",!Z && (NaN || N)); case 0x1d: CONDRET("Not Greater Than",NaN || Z || N); case 0x1e: CONDRET("Signaling Not Equal",!Z); case 0x1f: CONDRET("Signaling True",1); default: CONDRET("",-1); } #endif # undef N # undef Z # undef I # undef NaN } void FFPU fpuop_dbcc(uae_u32 opcode, uae_u32 extra) { fpu_debug(("fdbcc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); uaecptr pc = (uae_u32) m68k_getpc (); uae_s32 disp = (uae_s32) (uae_s16) next_iword(); int cc = fpp_cond(extra & 0x3f); if (cc == -1) { m68k_setpc (pc - 4); op_illg (opcode); } else if (!cc) { int reg = opcode & 0x7; // this may have leaked. /* m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff) | ((m68k_dreg (regs, reg) - 1) & 0xffff)); */ m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000) | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff)); // condition reversed. // if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff) if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) m68k_setpc (pc + disp); } } void FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra) { fpu_debug(("fscc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ())); uae_u32 ad; int cc = fpp_cond(extra & 0x3f); if (cc == -1) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } else if ((opcode & 0x38) == 0) { m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00); } else if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } else put_byte(ad, cc ? 0xff : 0x00); } void FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc) { fpu_debug(("ftrapcc_opp %X at %08lx\n", (uae_u32)opcode, m68k_getpc ())); int cc = fpp_cond(opcode & 0x3f); if (cc == -1) { m68k_setpc (oldpc); op_illg (opcode); } if (cc) Exception(7, oldpc - 2); } // NOTE that we get here also when there is a FNOP (nontrapping false, displ 0) void FFPU fpuop_bcc(uae_u32 opcode, uaecptr pc, uae_u32 extra) { fpu_debug(("fbcc_opp %X, %X at %08lx, jumpto=%X\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc (), extra )); int cc = fpp_cond(opcode & 0x3f); if (cc == -1) { m68k_setpc (pc); op_illg (opcode); } else if (cc) { if ((opcode & 0x40) == 0) extra = (uae_s32) (uae_s16) extra; m68k_setpc (pc + extra); } } // FSAVE has no post-increment // 0x1f180000 == IDLE state frame, coprocessor version number 1F void FFPU fpuop_save(uae_u32 opcode) { fpu_debug(("fsave_opp at %08lx\n", m68k_getpc ())); uae_u32 ad; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; int i; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 2); op_illg (opcode); return; } if (CPUType == 4) { // Put 4 byte 68040 IDLE frame. if (incr < 0) { ad -= 4; put_long (ad, 0x41000000); } else { put_long (ad, 0x41000000); ad += 4; } } else { // Put 28 byte 68881 IDLE frame. if (incr < 0) { fpu_debug(("fsave_opp pre-decrement\n")); ad -= 4; // What's this? Some BIU flags, or (incorrectly placed) command/condition? put_long (ad, 0x70000000); for (i = 0; i < 5; i++) { ad -= 4; put_long (ad, 0x00000000); } ad -= 4; put_long (ad, 0x1f180000); // IDLE, vers 1f } else { put_long (ad, 0x1f180000); // IDLE, vers 1f ad += 4; for (i = 0; i < 5; i++) { put_long (ad, 0x00000000); ad += 4; } // What's this? Some BIU flags, or (incorrectly placed) command/condition? put_long (ad, 0x70000000); ad += 4; } } if ((opcode & 0x38) == 0x18) { m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 fpu_debug(("PROBLEM: fsave_opp post-increment\n")); } if ((opcode & 0x38) == 0x20) { m68k_areg (regs, opcode & 7) = ad; fpu_debug(("fsave_opp pre-decrement %X -> A%d\n",ad,opcode & 7)); } } // FRESTORE has no pre-decrement void FFPU fpuop_restore(uae_u32 opcode) { fpu_debug(("frestore_opp at %08lx\n", m68k_getpc ())); uae_u32 ad; uae_u32 d; int incr = (opcode & 0x38) == 0x20 ? -1 : 1; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 2); op_illg (opcode); return; } if (CPUType == 4) { // 68040 if (incr < 0) { fpu_debug(("PROBLEM: frestore_opp incr < 0\n")); // this may be wrong, but it's never called. ad -= 4; d = get_long (ad); if ((d & 0xff000000) != 0) { // Not a NULL frame? if ((d & 0x00ff0000) == 0) { // IDLE fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP fpu_debug(("PROBLEM: frestore_opp found UNIMP frame at %X\n",ad-4)); ad -= 44; } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4)); ad -= 92; } } } else { d = get_long (ad); fpu_debug(("frestore_opp frame at %X = %X\n",ad,d)); ad += 4; if ((d & 0xff000000) != 0) { // Not a NULL frame? if ((d & 0x00ff0000) == 0) { // IDLE fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP fpu_debug(("PROBLEM: frestore_opp found UNIMP frame at %X\n",ad-4)); ad += 44; } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4)); ad += 92; } } } } else { // 68881 if (incr < 0) { fpu_debug(("PROBLEM: frestore_opp incr < 0\n")); // this may be wrong, but it's never called. ad -= 4; d = get_long (ad); if ((d & 0xff000000) != 0) { if ((d & 0x00ff0000) == 0x00180000) ad -= 6 * 4; else if ((d & 0x00ff0000) == 0x00380000) ad -= 14 * 4; else if ((d & 0x00ff0000) == 0x00b40000) ad -= 45 * 4; } } else { d = get_long (ad); fpu_debug(("frestore_opp frame at %X = %X\n",ad,d)); ad += 4; if ((d & 0xff000000) != 0) { // Not a NULL frame? if ((d & 0x00ff0000) == 0x00180000) { // IDLE fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4)); ad += 6 * 4; } else if ((d & 0x00ff0000) == 0x00380000) {// UNIMP? shouldn't it be 3C? ad += 14 * 4; fpu_debug(("PROBLEM: frestore_opp found UNIMP? frame at %X\n",ad-4)); } else if ((d & 0x00ff0000) == 0x00b40000) {// BUSY fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4)); ad += 45 * 4; } } } } if ((opcode & 0x38) == 0x18) { m68k_areg (regs, opcode & 7) = ad; fpu_debug(("frestore_opp post-increment %X -> A%d\n",ad,opcode & 7)); } if ((opcode & 0x38) == 0x20) { m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881 fpu_debug(("PROBLEM: frestore_opp pre-decrement\n")); } } void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra) { int reg; fpu_register src; fpu_debug(("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff, m68k_getpc () - 4)); dump_registers( "START"); switch ((extra >> 13) & 0x7) { case 3: fpu_debug(("FMOVE -> \n")); if (put_fp_value (opcode, extra, FPU registers[(extra >> 7) & 7]) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); } dump_registers( "END "); return; case 4: case 5: if ((opcode & 0x38) == 0) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { // according to the manual, the msb bits are always zero. m68k_dreg (regs, opcode & 7) = get_fpcr() & 0xFFFF; fpu_debug(("FMOVEM FPU fpcr (%X) -> D%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { m68k_dreg (regs, opcode & 7) = get_fpsr(); fpu_debug(("FMOVEM FPU fpsr (%X) -> D%d\n", get_fpsr(), opcode & 7)); } if (extra & 0x0400) { m68k_dreg (regs, opcode & 7) = FPU instruction_address; fpu_debug(("FMOVEM FPU instruction_address (%X) -> D%d\n", FPU instruction_address, opcode & 7)); } } else { if (extra & 0x1000) { set_fpcr( m68k_dreg (regs, opcode & 7) ); fpu_debug(("FMOVEM D%d (%X) -> FPU fpcr\n", opcode & 7, get_fpcr())); } if (extra & 0x0800) { set_fpsr( m68k_dreg (regs, opcode & 7) ); fpu_debug(("FMOVEM D%d (%X) -> FPU fpsr\n", opcode & 7, get_fpsr())); } if (extra & 0x0400) { FPU instruction_address = m68k_dreg (regs, opcode & 7); fpu_debug(("FMOVEM D%d (%X) -> FPU instruction_address\n", opcode & 7, FPU instruction_address)); } } // } else if ((opcode & 0x38) == 1) { } else if ((opcode & 0x38) == 8) { if (extra & 0x2000) { // dr bit if (extra & 0x1000) { // according to the manual, the msb bits are always zero. m68k_areg (regs, opcode & 7) = get_fpcr() & 0xFFFF; fpu_debug(("FMOVEM FPU fpcr (%X) -> A%d\n", get_fpcr(), opcode & 7)); } if (extra & 0x0800) { m68k_areg (regs, opcode & 7) = get_fpsr(); fpu_debug(("FMOVEM FPU fpsr (%X) -> A%d\n", get_fpsr(), opcode & 7)); } if (extra & 0x0400) { m68k_areg (regs, opcode & 7) = FPU instruction_address; fpu_debug(("FMOVEM FPU instruction_address (%X) -> A%d\n", FPU instruction_address, opcode & 7)); } } else { if (extra & 0x1000) { set_fpcr( m68k_areg (regs, opcode & 7) ); fpu_debug(("FMOVEM A%d (%X) -> FPU fpcr\n", opcode & 7, get_fpcr())); } if (extra & 0x0800) { set_fpsr( m68k_areg (regs, opcode & 7) ); fpu_debug(("FMOVEM A%d (%X) -> FPU fpsr\n", opcode & 7, get_fpsr())); } if (extra & 0x0400) { FPU instruction_address = m68k_areg (regs, opcode & 7); fpu_debug(("FMOVEM A%d (%X) -> FPU instruction_address\n", opcode & 7, FPU instruction_address)); } } } else if ((opcode & 0x3f) == 0x3c) { if ((extra & 0x2000) == 0) { if (extra & 0x1000) { set_fpcr( next_ilong() ); fpu_debug(("FMOVEM #<%X> -> FPU fpcr\n", get_fpcr())); } if (extra & 0x0800) { set_fpsr( next_ilong() ); fpu_debug(("FMOVEM #<%X> -> FPU fpsr\n", get_fpsr())); } if (extra & 0x0400) { FPU instruction_address = next_ilong(); fpu_debug(("FMOVEM #<%X> -> FPU instruction_address\n", FPU instruction_address)); } } } else if (extra & 0x2000) { /* FMOVEM FPP->memory */ uae_u32 ad; int incr = 0; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } if ((opcode & 0x38) == 0x20) { if (extra & 0x1000) incr += 4; if (extra & 0x0800) incr += 4; if (extra & 0x0400) incr += 4; } ad -= incr; if (extra & 0x1000) { // according to the manual, the msb bits are always zero. put_long (ad, get_fpcr() & 0xFFFF); fpu_debug(("FMOVEM FPU fpcr (%X) -> mem %X\n", get_fpcr(), ad )); ad += 4; } if (extra & 0x0800) { put_long (ad, get_fpsr()); fpu_debug(("FMOVEM FPU fpsr (%X) -> mem %X\n", get_fpsr(), ad )); ad += 4; } if (extra & 0x0400) { put_long (ad, FPU instruction_address); fpu_debug(("FMOVEM FPU instruction_address (%X) -> mem %X\n", FPU instruction_address, ad )); ad += 4; } ad -= incr; if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? m68k_areg (regs, opcode & 7) = ad; } else { /* FMOVEM memory->FPP */ uae_u32 ad; if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } // ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad; int incr = 0; if((opcode & 0x38) == 0x20) { if (extra & 0x1000) incr += 4; if (extra & 0x0800) incr += 4; if (extra & 0x0400) incr += 4; ad = ad - incr; } if (extra & 0x1000) { set_fpcr( get_long (ad) ); fpu_debug(("FMOVEM mem %X (%X) -> FPU fpcr\n", ad, get_fpcr() )); ad += 4; } if (extra & 0x0800) { set_fpsr( get_long (ad) ); fpu_debug(("FMOVEM mem %X (%X) -> FPU fpsr\n", ad, get_fpsr() )); ad += 4; } if (extra & 0x0400) { FPU instruction_address = get_long (ad); fpu_debug(("FMOVEM mem %X (%X) -> FPU instruction_address\n", ad, FPU instruction_address )); ad += 4; } if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? // m68k_areg (regs, opcode & 7) = ad - 12; m68k_areg (regs, opcode & 7) = ad - incr; } dump_registers( "END "); return; case 6: case 7: { uae_u32 ad, list = 0; int incr = 0; if (extra & 0x2000) { /* FMOVEM FPP->memory */ fpu_debug(("FMOVEM FPP->memory\n")); if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } switch ((extra >> 11) & 3) { case 0: /* static pred */ list = extra & 0xff; incr = -1; break; case 1: /* dynamic pred */ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = -1; break; case 2: /* static postinc */ list = extra & 0xff; incr = 1; break; case 3: /* dynamic postinc */ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = 1; break; } if (incr < 0) { for(reg=7; reg>=0; reg--) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { extract_extended(FPU registers[reg],&wrd1, &wrd2, &wrd3); ad -= 4; put_long (ad, wrd3); ad -= 4; put_long (ad, wrd2); ad -= 4; put_long (ad, wrd1); } list <<= 1; } } else { for(reg=0; reg<8; reg++) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { extract_extended(FPU registers[reg],&wrd1, &wrd2, &wrd3); put_long (ad, wrd1); ad += 4; put_long (ad, wrd2); ad += 4; put_long (ad, wrd3); ad += 4; } list <<= 1; } } if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? m68k_areg (regs, opcode & 7) = ad; } else { /* FMOVEM memory->FPP */ fpu_debug(("FMOVEM memory->FPP\n")); if (get_fp_ad(opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } switch ((extra >> 11) & 3) { case 0: /* static pred */ fpu_debug(("memory->FMOVEM FPP not legal mode.\n")); list = extra & 0xff; incr = -1; break; case 1: /* dynamic pred */ fpu_debug(("memory->FMOVEM FPP not legal mode.\n")); list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = -1; break; case 2: /* static postinc */ list = extra & 0xff; incr = 1; break; case 3: /* dynamic postinc */ list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff; incr = 1; break; } /**/ if (incr < 0) { // not reached for(reg=7; reg>=0; reg--) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { ad -= 4; wrd3 = get_long (ad); ad -= 4; wrd2 = get_long (ad); ad -= 4; wrd1 = get_long (ad); // FPU registers[reg] = make_extended(wrd1, wrd2, wrd3); make_extended_no_normalize (wrd1, wrd2, wrd3, FPU registers[reg]); } list <<= 1; } } else { for(reg=0; reg<8; reg++) { uae_u32 wrd1, wrd2, wrd3; if( list & 0x80 ) { wrd1 = get_long (ad); ad += 4; wrd2 = get_long (ad); ad += 4; wrd3 = get_long (ad); ad += 4; // FPU registers[reg] = make_extended(wrd1, wrd2, wrd3); make_extended_no_normalize (wrd1, wrd2, wrd3, FPU registers[reg]); } list <<= 1; } } if ((opcode & 0x38) == 0x18) // post-increment? m68k_areg (regs, opcode & 7) = ad; if ((opcode & 0x38) == 0x20) // pre-decrement? m68k_areg (regs, opcode & 7) = ad; } dump_registers( "END "); return; } case 0: case 2: reg = (extra >> 7) & 7; if ((extra & 0xfc00) == 0x5c00) { fpu_debug(("FMOVECR memory->FPP\n")); switch (extra & 0x7f) { case 0x00: // FPU registers[reg] = 4.0 * atan(1.0); FPU registers[reg] = 3.1415926535897932384626433832795; fpu_debug(("FP const: Pi\n")); break; case 0x0b: // FPU registers[reg] = log10 (2.0); FPU registers[reg] = 0.30102999566398119521373889472449; fpu_debug(("FP const: Log 10 (2)\n")); break; case 0x0c: // FPU registers[reg] = exp (1.0); FPU registers[reg] = 2.7182818284590452353602874713527; fpu_debug(("FP const: e\n")); break; case 0x0d: // FPU registers[reg] = log (exp (1.0)) / log (2.0); FPU registers[reg] = 1.4426950408889634073599246810019; fpu_debug(("FP const: Log 2 (e)\n")); break; case 0x0e: // FPU registers[reg] = log (exp (1.0)) / log (10.0); FPU registers[reg] = 0.43429448190325182765112891891661; fpu_debug(("FP const: Log 10 (e)\n")); break; case 0x0f: FPU registers[reg] = 0.0; fpu_debug(("FP const: zero\n")); break; case 0x30: // FPU registers[reg] = log (2.0); FPU registers[reg] = 0.69314718055994530941723212145818; fpu_debug(("FP const: ln(2)\n")); break; case 0x31: // FPU registers[reg] = log (10.0); FPU registers[reg] = 2.3025850929940456840179914546844; fpu_debug(("FP const: ln(10)\n")); break; case 0x32: // ?? FPU registers[reg] = 1.0e0; fpu_debug(("FP const: 1.0e0\n")); break; case 0x33: FPU registers[reg] = 1.0e1; fpu_debug(("FP const: 1.0e1\n")); break; case 0x34: FPU registers[reg] = 1.0e2; fpu_debug(("FP const: 1.0e2\n")); break; case 0x35: FPU registers[reg] = 1.0e4; fpu_debug(("FP const: 1.0e4\n")); break; case 0x36: FPU registers[reg] = 1.0e8; fpu_debug(("FP const: 1.0e8\n")); break; case 0x37: FPU registers[reg] = 1.0e16; fpu_debug(("FP const: 1.0e16\n")); break; case 0x38: FPU registers[reg] = 1.0e32; fpu_debug(("FP const: 1.0e32\n")); break; case 0x39: FPU registers[reg] = 1.0e64; fpu_debug(("FP const: 1.0e64\n")); break; case 0x3a: FPU registers[reg] = 1.0e128; fpu_debug(("FP const: 1.0e128\n")); break; case 0x3b: FPU registers[reg] = 1.0e256; fpu_debug(("FP const: 1.0e256\n")); break; #if 0 case 0x3c: FPU registers[reg] = 1.0e512; fpu_debug(("FP const: 1.0e512\n")); break; case 0x3d: FPU registers[reg] = 1.0e1024; fpu_debug(("FP const: 1.0e1024\n")); break; case 0x3e: FPU registers[reg] = 1.0e2048; fpu_debug(("FP const: 1.0e2048\n")); break; case 0x3f: FPU registers[reg] = 1.0e4096; fpu_debug(("FP const: 1.0e4096\n")); break; #endif default: m68k_setpc (m68k_getpc () - 4); op_illg (opcode); break; } // these *do* affect the status reg make_fpsr(FPU registers[reg]); dump_registers( "END "); return; } if (get_fp_value (opcode, extra, src) == 0) { m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); return; } fpu_debug(("returned from get_fp_value m68k_getpc()=%X\n",m68k_getpc())); switch (extra & 0x7f) { case 0x00: /* FMOVE */ fpu_debug(("FMOVE %.04f\n",(double)src)); FPU registers[reg] = src; // -> reg DOES affect the status reg make_fpsr(FPU registers[reg]); break; case 0x01: /* FINT */ fpu_debug(("FINT %.04f\n",(double)src)); // FPU registers[reg] = (int) (src + 0.5); // FIXME: use native rounding mode flags switch (get_fpcr() & 0x30) { case FPCR_ROUND_ZERO: FPU registers[reg] = round_to_zero(src); break; case FPCR_ROUND_MINF: FPU registers[reg] = floor(src); break; case FPCR_ROUND_NEAR: FPU registers[reg] = round_to_nearest(src); break; case FPCR_ROUND_PINF: FPU registers[reg] = ceil(src); break; } make_fpsr(FPU registers[reg]); break; case 0x02: /* FSINH */ fpu_debug(("FSINH %.04f\n",(double)src)); FPU registers[reg] = sinh (src); make_fpsr(FPU registers[reg]); break; case 0x03: /* FINTRZ */ fpu_debug(("FINTRZ %.04f\n",(double)src)); // FPU registers[reg] = (int) src; FPU registers[reg] = round_to_zero(src); make_fpsr(FPU registers[reg]); break; case 0x04: /* FSQRT */ fpu_debug(("FSQRT %.04f\n",(double)src)); FPU registers[reg] = sqrt (src); make_fpsr(FPU registers[reg]); break; case 0x06: /* FLOGNP1 */ fpu_debug(("FLOGNP1 %.04f\n",(double)src)); FPU registers[reg] = log (src + 1.0); make_fpsr(FPU registers[reg]); break; case 0x08: /* FETOXM1 */ fpu_debug(("FETOXM1 %.04f\n",(double)src)); FPU registers[reg] = exp (src) - 1.0; make_fpsr(FPU registers[reg]); break; case 0x09: /* FTANH */ fpu_debug(("FTANH %.04f\n",(double)src)); FPU registers[reg] = tanh (src); make_fpsr(FPU registers[reg]); break; case 0x0a: /* FATAN */ fpu_debug(("FATAN %.04f\n",(double)src)); FPU registers[reg] = atan (src); make_fpsr(FPU registers[reg]); break; case 0x0c: /* FASIN */ fpu_debug(("FASIN %.04f\n",(double)src)); FPU registers[reg] = asin (src); make_fpsr(FPU registers[reg]); break; case 0x0d: /* FATANH */ fpu_debug(("FATANH %.04f\n",(double)src)); #if HAVE_ATANH FPU registers[reg] = atanh (src); #else /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */ FPU registers[reg] = log ((1 + src) / (1 - src)) / 2; #endif make_fpsr(FPU registers[reg]); break; case 0x0e: /* FSIN */ fpu_debug(("FSIN %.04f\n",(double)src)); FPU registers[reg] = sin (src); make_fpsr(FPU registers[reg]); break; case 0x0f: /* FTAN */ fpu_debug(("FTAN %.04f\n",(double)src)); FPU registers[reg] = tan (src); make_fpsr(FPU registers[reg]); break; case 0x10: /* FETOX */ fpu_debug(("FETOX %.04f\n",(double)src)); FPU registers[reg] = exp (src); make_fpsr(FPU registers[reg]); break; case 0x11: /* FTWOTOX */ fpu_debug(("FTWOTOX %.04f\n",(double)src)); FPU registers[reg] = pow(2.0, src); make_fpsr(FPU registers[reg]); break; case 0x12: /* FTENTOX */ fpu_debug(("FTENTOX %.04f\n",(double)src)); FPU registers[reg] = pow(10.0, src); make_fpsr(FPU registers[reg]); break; case 0x14: /* FLOGN */ fpu_debug(("FLOGN %.04f\n",(double)src)); FPU registers[reg] = log (src); make_fpsr(FPU registers[reg]); break; case 0x15: /* FLOG10 */ fpu_debug(("FLOG10 %.04f\n",(double)src)); FPU registers[reg] = log10 (src); make_fpsr(FPU registers[reg]); break; case 0x16: /* FLOG2 */ fpu_debug(("FLOG2 %.04f\n",(double)src)); FPU registers[reg] = log (src) / log (2.0); make_fpsr(FPU registers[reg]); break; case 0x18: /* FABS */ case 0x58: /* single precision rounding */ case 0x5C: /* double precision rounding */ fpu_debug(("FABS %.04f\n",(double)src)); FPU registers[reg] = src < 0 ? -src : src; make_fpsr(FPU registers[reg]); break; case 0x19: /* FCOSH */ fpu_debug(("FCOSH %.04f\n",(double)src)); FPU registers[reg] = cosh(src); make_fpsr(FPU registers[reg]); break; case 0x1a: /* FNEG */ fpu_debug(("FNEG %.04f\n",(double)src)); FPU registers[reg] = -src; make_fpsr(FPU registers[reg]); break; case 0x1c: /* FACOS */ fpu_debug(("FACOS %.04f\n",(double)src)); FPU registers[reg] = acos(src); make_fpsr(FPU registers[reg]); break; case 0x1d: /* FCOS */ fpu_debug(("FCOS %.04f\n",(double)src)); FPU registers[reg] = cos(src); make_fpsr(FPU registers[reg]); break; case 0x1e: /* FGETEXP */ fpu_debug(("FGETEXP %.04f\n",(double)src)); #if FPU_HAVE_IEEE_DOUBLE if( isinf(src) ) { make_nan( FPU registers[reg] ); } else { FPU registers[reg] = fast_fgetexp( src ); } #else if(src == 0) { FPU registers[reg] = (fpu_register)0; } else { int expon; frexp (src, &expon); FPU registers[reg] = (fpu_register) (expon - 1); } #endif make_fpsr(FPU registers[reg]); break; case 0x1f: /* FGETMAN */ fpu_debug(("FGETMAN %.04f\n",(double)src)); #if FPU_HAVE_IEEE_DOUBLE if( src == 0 ) { FPU registers[reg] = 0; } else if( isinf(src) ) { make_nan( FPU registers[reg] ); } else { FPU registers[reg] = src; fast_remove_exponent( FPU registers[reg] ); } #else { int expon; FPU registers[reg] = frexp (src, &expon) * 2.0; } #endif make_fpsr(FPU registers[reg]); break; case 0x20: /* FDIV */ fpu_debug(("FDIV %.04f\n",(double)src)); FPU registers[reg] /= src; make_fpsr(FPU registers[reg]); break; case 0x21: /* FMOD */ fpu_debug(("FMOD %.04f\n",(double)src)); // FPU registers[reg] = FPU registers[reg] - (fpu_register) ((int) (FPU registers[reg] / src)) * src; { fpu_register quot = round_to_zero(FPU registers[reg] / src); #if FPU_HAVE_IEEE_DOUBLE uae_u32 sign = get_quotient_sign(FPU registers[reg],src); #endif FPU registers[reg] = FPU registers[reg] - quot * src; make_fpsr(FPU registers[reg]); #if FPU_HAVE_IEEE_DOUBLE make_quotient(quot, sign); #endif } break; case 0x22: /* FADD */ case 0x62: /* single */ case 0x66: /* double */ fpu_debug(("FADD %.04f\n",(double)src)); FPU registers[reg] += src; make_fpsr(FPU registers[reg]); break; case 0x23: /* FMUL */ fpu_debug(("FMUL %.04f\n",(double)src)); #if FPU_HAVE_IEEE_DOUBLE get_dest_flags(FPU registers[reg]); get_source_flags(src); if(fl_dest.in_range && fl_source.in_range) { FPU registers[reg] *= src; } else if (fl_dest.nan || fl_source.nan || fl_dest.zero && fl_source.infinity || fl_dest.infinity && fl_source.zero ) { make_nan( FPU registers[reg] ); } else if (fl_dest.zero || fl_source.zero ) { if (fl_dest.negative && !fl_source.negative || !fl_dest.negative && fl_source.negative) { make_zero_negative(FPU registers[reg]); } else { make_zero_positive(FPU registers[reg]); } } else { if( fl_dest.negative && !fl_source.negative || !fl_dest.negative && fl_source.negative) { make_inf_negative(FPU registers[reg]); } else { make_inf_positive(FPU registers[reg]); } } #else fpu_debug(("FMUL %.04f\n",(double)src)); FPU registers[reg] *= src; #endif make_fpsr(FPU registers[reg]); break; case 0x24: /* FSGLDIV */ fpu_debug(("FSGLDIV %.04f\n",(double)src)); // TODO: round to float. FPU registers[reg] /= src; make_fpsr(FPU registers[reg]); break; case 0x25: /* FREM */ fpu_debug(("FREM %.04f\n",(double)src)); // FPU registers[reg] = FPU registers[reg] - (double) ((int) (FPU registers[reg] / src + 0.5)) * src; { fpu_register quot = round_to_nearest(FPU registers[reg] / src); #if FPU_HAVE_IEEE_DOUBLE uae_u32 sign = get_quotient_sign(FPU registers[reg],src); #endif FPU registers[reg] = FPU registers[reg] - quot * src; make_fpsr(FPU registers[reg]); #if FPU_HAVE_IEEE_DOUBLE make_quotient(quot,sign); #endif } break; case 0x26: /* FSCALE */ fpu_debug(("FSCALE %.04f\n",(double)src)); // TODO: // Overflow, underflow #if FPU_HAVE_IEEE_DOUBLE if( isinf(FPU registers[reg]) ) { make_nan( FPU registers[reg] ); } else { // When the absolute value of the source operand is >= 2^14, // an overflow or underflow always results. // Here (int) cast is okay. fast_scale( FPU registers[reg], (int)round_to_zero(src) ); } #else if (src != 0) { // Manual says: src==0 -> FPn FPU registers[reg] *= exp (log (2.0) * src); } #endif make_fpsr(FPU registers[reg]); break; case 0x27: /* FSGLMUL */ fpu_debug(("FSGLMUL %.04f\n",(double)src)); FPU registers[reg] *= src; make_fpsr(FPU registers[reg]); break; case 0x28: /* FSUB */ fpu_debug(("FSUB %.04f\n",(double)src)); FPU registers[reg] -= src; make_fpsr(FPU registers[reg]); break; case 0x30: /* FSINCOS */ case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: fpu_debug(("FSINCOS %.04f\n",(double)src)); // Cosine must be calculated first if same register FPU registers[extra & 7] = cos(src); FPU registers[reg] = sin (src); // Set FPU fpsr according to the sine result make_fpsr(FPU registers[reg]); break; case 0x38: /* FCMP */ fpu_debug(("FCMP %.04f\n",(double)src)); // The infinity bit is always cleared by the FCMP // instruction since it is not used by any of the // conditional predicate equations. #if FPU_HAVE_IEEE_DOUBLE if( isinf(src) ) { if( isneg(src) ) { // negative infinity if( isinf(FPU registers[reg]) && isneg(FPU registers[reg]) ) { // Zero, Negative FPU fpsr.condition_codes = NATIVE_FFLAG_ZERO | NATIVE_FFLAG_NEGATIVE; fpu_debug(("-INF cmp -INF -> NZ\n")); } else { // None FPU fpsr.condition_codes = 0; fpu_debug(("x cmp -INF -> None\n")); } } else { // positive infinity if( isinf(FPU registers[reg]) && !isneg(FPU registers[reg]) ) { // Zero FPU fpsr.condition_codes = NATIVE_FFLAG_ZERO; fpu_debug(("+INF cmp +INF -> Z\n")); } else { // Negative FPU fpsr.condition_codes = NATIVE_FFLAG_NEGATIVE; fpu_debug(("X cmp +INF -> N\n")); } } } else { fpu_register tmp = FPU registers[reg] - src; FPU fpsr.condition_codes = (iszero(tmp) ? NATIVE_FFLAG_ZERO : 0) | (isneg(tmp) ? NATIVE_FFLAG_NEGATIVE : 0) ; } #else { fpu_register tmp = FPU registers[reg] - src; make_fpsr(tmp); } #endif break; case 0x3a: /* FTST */ fpu_debug(("FTST %.04f\n",(double)src)); // make_fpsr(FPU registers[reg]); make_fpsr(src); break; default: fpu_debug(("ILLEGAL F OP %X\n",opcode)); m68k_setpc (m68k_getpc () - 4); op_illg (opcode); break; } fpu_debug(("END m68k_getpc()=%X\n",m68k_getpc())); dump_registers( "END "); return; } fpu_debug(("ILLEGAL F OP 2 %X\n",opcode)); m68k_setpc (m68k_getpc () - 4); op_illg (opcode); dump_registers( "END "); } /* -------------------------- Initialization -------------------------- */ void FFPU fpu_init (bool integral_68040) { fpu_debug(("fpu_init\n")); static bool initialized_lookup_tables = false; if (!initialized_lookup_tables) { fpu_init_native_fflags(); fpu_init_native_exceptions(); fpu_init_native_accrued_exceptions(); initialized_lookup_tables = true; } FPU is_integral = integral_68040; set_fpcr(0); set_fpsr(0); FPU instruction_address = 0; } void FFPU fpu_exit (void) { fpu_debug(("fpu_exit\n")); } void FFPU fpu_reset (void) { fpu_debug(("fpu_reset\n")); fpu_exit(); fpu_init(FPU is_integral); } BasiliskII/src/uae_cpu/fpu/types.h0000644000175000017500000001100010736405224017253 0ustar centriscentris/* * types.h - basic types for fpu registers * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_TYPES_H #define FPU_TYPES_H #include "sysdeps.h" /* Default behavior is *not* to use long doubles */ #undef USE_LONG_DOUBLE #undef USE_QUAD_DOUBLE /* -------------------------------------------------------------------------- */ /* --- Original UAE fpu core --- */ /* -------------------------------------------------------------------------- */ #if defined(FPU_UAE) /* 4-byte floats */ #if SIZEOF_FLOAT == 4 typedef float uae_f32; #elif SIZEOF_DOUBLE == 4 typedef double uae_f32; #else #error "No 4 byte float type, you lose." #endif /* 8-byte floats */ #if SIZEOF_DOUBLE == 8 typedef double uae_f64; #elif SIZEOF_LONG_DOUBLE == 8 typedef long double uae_f64; #else #error "No 8 byte float type, you lose." #endif /* Original UAE FPU registers are only 8 bytes long */ typedef uae_f64 fpu_register; typedef fpu_register fpu_extended; typedef uae_f64 fpu_double; typedef uae_f32 fpu_single; /* -------------------------------------------------------------------------- */ /* --- Optimized core for x86 --- */ /* -------------------------------------------------------------------------- */ #elif defined(FPU_X86) /* 4-byte floats */ #if SIZEOF_FLOAT == 4 typedef float uae_f32; #elif SIZEOF_DOUBLE == 4 typedef double uae_f32; #else #error "No 4 byte float type, you lose." #endif /* 8-byte floats */ #if SIZEOF_DOUBLE == 8 typedef float uae_f64; #elif SIZEOF_LONG_DOUBLE == 8 typedef double uae_f64; #else #error "No 8 byte float type, you lose." #endif /* At least 10-byte floats are required */ #if SIZEOF_LONG_DOUBLE >= 10 typedef long double fpu_register; #else #error "No float type at least 10 bytes long, you lose." #endif /* X86 FPU has a custom register type that maps to a native X86 register */ typedef fpu_register fpu_extended; typedef uae_f64 fpu_double; typedef uae_f32 fpu_single; /* -------------------------------------------------------------------------- */ /* --- C99 implementation --- */ /* -------------------------------------------------------------------------- */ #elif defined(FPU_IEEE) #if HOST_FLOAT_FORMAT != IEEE_FLOAT_FORMAT #error "No IEEE float format, you lose." #endif /* 4-byte floats */ #if SIZEOF_FLOAT == 4 typedef float uae_f32; #elif SIZEOF_DOUBLE == 4 typedef double uae_f32; #else #error "No 4 byte float type, you lose." #endif /* 8-byte floats */ #if SIZEOF_DOUBLE == 8 typedef double uae_f64; #elif SIZEOF_LONG_DOUBLE == 8 typedef long double uae_f64; #else #error "No 8 byte float type, you lose." #endif /* 12-byte or 16-byte floats */ #if SIZEOF_LONG_DOUBLE == 12 typedef long double uae_f96; typedef uae_f96 fpu_register; #define USE_LONG_DOUBLE 1 #elif SIZEOF_LONG_DOUBLE == 16 && (defined(__i386__) || defined(__x86_64__)) /* Long doubles on x86-64 are really held in old x87 FPU stack. */ typedef long double uae_f128; typedef uae_f128 fpu_register; #define USE_LONG_DOUBLE 1 #elif 0 /* Disable for now and probably for good as (i) the emulator implementation is not correct, (ii) I don't know of any CPU which handles this kind of format *natively* with conformance to IEEE. */ typedef long double uae_f128; typedef uae_f128 fpu_register; #define USE_QUAD_DOUBLE 1 #else typedef uae_f64 fpu_register; #endif /* We need all those floating-point types */ typedef fpu_register fpu_extended; typedef uae_f64 fpu_double; typedef uae_f32 fpu_single; #endif #endif /* FPU_TYPES_H */ BasiliskII/src/uae_cpu/fpu/mathlib.cpp0000644000175000017500000000541010736405224020072 0ustar centriscentris/* * fpu/mathlib.cpp - Floating-point math support library * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2001 Lauri Pesonen * New framework, copyright 2000-2001 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000-2001 * * 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 */ /* NOTE: this file shall be included only from fpu/fpu_*.cpp */ #undef PRIVATE #define PRIVATE static #undef PUBLIC #define PUBLIC /**/ #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. #if defined(FPU_IEEE) && defined(USE_X87_ASSEMBLY) PRIVATE fpu_extended fp_do_pow(fpu_extended x, fpu_extended y) { fpu_extended value, exponent; uae_s64 p = (uae_s64)y; if (x == 0.0) { if (y > 0.0) return (y == (double) p && (p & 1) != 0 ? x : 0.0); else if (y < 0.0) return (y == (double) p && (-p & 1) != 0 ? 1.0 / x : 1.0 / fp_fabs (x)); } if (y == (double) p) { fpu_extended r = 1.0; if (p == 0) return 1.0; if (p < 0) { p = -p; x = 1.0 / x; } while (1) { if (p & 1) r *= x; p >>= 1; if (p == 0) return r; x *= x; } } __asm__ __volatile__("fyl2x" : "=t" (value) : "0" (x), "u" (1.0) : "st(1)"); __asm__ __volatile__("fmul %%st(1) # y * log2(x)\n\t" "fst %%st(1)\n\t" "frndint # int(y * log2(x))\n\t" "fxch\n\t" "fsub %%st(1) # fract(y * log2(x))\n\t" "f2xm1 # 2^(fract(y * log2(x))) - 1\n\t" : "=t" (value), "=u" (exponent) : "0" (y), "1" (value)); value += 1.0; __asm__ __volatile__("fscale" : "=t" (value) : "0" (value), "u" (exponent)); return value; } PRIVATE fpu_extended fp_do_log1p(fpu_extended x) { // TODO: handle NaN and +inf/-inf fpu_extended value; // The fyl2xp1 can only be used for values in // -1 + sqrt(2) / 2 <= x <= 1 - sqrt(2) / 2 // 0.29 is a safe value. if (fp_fabs(x) <= 0.29) __asm__ __volatile__("fldln2; fxch; fyl2xp1" : "=t" (value) : "0" (x)); else __asm__ __volatile__("fldln2; fxch; fyl2x" : "=t" (value) : "0" (x + 1.0)); return value; } #endif BasiliskII/src/uae_cpu/fpu/exceptions.h0000644000175000017500000001232310736405224020301 0ustar centriscentris/* * fpu/exceptions.h - system-dependant FPU exceptions management * * Basilisk II (C) 1997-2008 Christian Bauer * * MC68881/68040 fpu emulation * * Original UAE FPU, copyright 1996 Herman ten Brugge * Rewrite for x86, copyright 1999-2000 Lauri Pesonen * New framework, copyright 2000 Gwenole Beauchesne * Adapted for JIT compilation (c) Bernd Meyer, 2000 * * 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 */ #ifndef FPU_EXCEPTIONS_H #define FPU_EXCEPTIONS_H /* NOTE: this file shall be included only from fpu/fpu_*.cpp */ #undef PUBLIC #define PUBLIC extern #undef PRIVATE #define PRIVATE static #undef FFPU #define FFPU /**/ #undef FPU #define FPU fpu. /* Defaults to generic exceptions */ #define FPU_USE_GENERIC_EXCEPTIONS #define FPU_USE_GENERIC_ACCRUED_EXCEPTIONS /* -------------------------------------------------------------------------- */ /* --- Selection of floating-point exceptions handling mode --- */ /* -------------------------------------------------------------------------- */ /* Optimized i386 fpu core must use native exceptions */ #if defined(FPU_X86) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_EXCEPTIONS # define FPU_USE_X86_EXCEPTIONS #endif /* Optimized i386 fpu core must use native accrued exceptions */ #if defined(FPU_X86) && defined(USE_X87_ASSEMBLY) # undef FPU_USE_GENERIC_ACCRUED_EXCEPTIONS # define FPU_USE_X86_ACCRUED_EXCEPTIONS #endif /* -------------------------------------------------------------------------- */ /* --- Native X86 Exceptions --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_X86_EXCEPTIONS /* Extend the SW_* codes */ #define SW_FAKE_BSUN SW_SF /* Shorthand */ #define SW_EXCEPTION_MASK (SW_ES|SW_SF|SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE) // #define SW_EXCEPTION_MASK (SW_SF|SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE) /* Lookup tables */ PRIVATE uae_u32 exception_host2mac[ 0x80 ]; PRIVATE uae_u32 exception_mac2host[ 0x100 ]; /* Initialize native exception management */ PUBLIC void FFPU fpu_init_native_exceptions(void); /* Return m68k floating-point exception status */ PRIVATE inline uae_u32 FFPU get_exception_status(void) { return exception_host2mac[FPU fpsr.exception_status & (SW_FAKE_BSUN|SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE)]; } /* Set new exception status. Assumes mask against FPSR_EXCEPTION to be already performed */ PRIVATE inline void FFPU set_exception_status(uae_u32 new_status) { FPU fpsr.exception_status = exception_mac2host[new_status >> 8]; } #endif /* FPU_USE_X86_EXCEPTIONS */ #ifdef FPU_USE_X86_ACCRUED_EXCEPTIONS /* Lookup tables */ PRIVATE uae_u32 accrued_exception_host2mac[ 0x40 ]; PRIVATE uae_u32 accrued_exception_mac2host[ 0x20 ]; /* Initialize native accrued exception management */ PUBLIC void FFPU fpu_init_native_accrued_exceptions(void); /* Return m68k accrued exception byte */ PRIVATE inline uae_u32 FFPU get_accrued_exception(void) { return accrued_exception_host2mac[FPU fpsr.accrued_exception & (SW_PE|SW_UE|SW_OE|SW_ZE|SW_DE|SW_IE)]; } /* Set new accrued exception byte */ PRIVATE inline void FFPU set_accrued_exception(uae_u32 new_status) { FPU fpsr.accrued_exception = accrued_exception_mac2host[(new_status & 0xF8) >> 3]; } #endif /* FPU_USE_X86_ACCRUED_EXCEPTIONS */ /* -------------------------------------------------------------------------- */ /* --- Default Exceptions Handling --- */ /* -------------------------------------------------------------------------- */ #ifdef FPU_USE_GENERIC_EXCEPTIONS /* Initialize native exception management */ static inline void FFPU fpu_init_native_exceptions(void) { } /* Return m68k floating-point exception status */ PRIVATE inline uae_u32 FFPU get_exception_status(void) { return FPU fpsr.exception_status; } /* Set new exception status. Assumes mask against FPSR_EXCEPTION to be already performed */ PRIVATE inline void FFPU set_exception_status(uae_u32 new_status) { FPU fpsr.exception_status = new_status; } #endif /* FPU_USE_GENERIC_EXCEPTIONS */ #ifdef FPU_USE_GENERIC_ACCRUED_EXCEPTIONS /* Initialize native accrued exception management */ PRIVATE inline void FFPU fpu_init_native_accrued_exceptions(void) { } /* Return m68k accrued exception byte */ PRIVATE inline uae_u32 FFPU get_accrued_exception(void) { return FPU fpsr.accrued_exception; } /* Set new accrued exception byte */ PRIVATE inline void FFPU set_accrued_exception(uae_u32 new_status) { FPU fpsr.accrued_exception = new_status; } #endif /* FPU_USE_GENERIC_ACCRUED_EXCEPTIONS */ #endif /* FPU_EXCEPTIONS_H */ BasiliskII/src/uae_cpu/fpu/fpu_x86_asm.h0000644000175000017500000000507707540357440020274 0ustar centriscentris#define DEFINE_X86_MACRO(name, value) \ asm(".local " #name "\n\t" #name " = " #value) DEFINE_X86_MACRO(BSUN, 0x00008000); DEFINE_X86_MACRO(SNAN, 0x00004000); DEFINE_X86_MACRO(OPERR, 0x00002000); DEFINE_X86_MACRO(OVFL, 0x00001000); DEFINE_X86_MACRO(UNFL, 0x00000800); DEFINE_X86_MACRO(DZ, 0x00000400); DEFINE_X86_MACRO(INEX2, 0x00000200); DEFINE_X86_MACRO(INEX1, 0x00000100); DEFINE_X86_MACRO(ACCR_IOP, 0x80); DEFINE_X86_MACRO(ACCR_OVFL, 0x40); DEFINE_X86_MACRO(ACCR_UNFL, 0x20); DEFINE_X86_MACRO(ACCR_DZ, 0x10); DEFINE_X86_MACRO(ACCR_INEX, 0x08); DEFINE_X86_MACRO(ROUND_CONTROL_MASK, 0x30); DEFINE_X86_MACRO(ROUND_TO_NEAREST, 0); DEFINE_X86_MACRO(ROUND_TO_ZERO, 0x10); DEFINE_X86_MACRO(ROUND_TO_NEGATIVE_INFINITY, 0x20); DEFINE_X86_MACRO(ROUND_TO_POSITIVE_INFINITY, 0x30); DEFINE_X86_MACRO(PRECISION_CONTROL_MASK, 0xC0); DEFINE_X86_MACRO(PRECISION_CONTROL_EXTENDED, 0); DEFINE_X86_MACRO(PRECISION_CONTROL_DOUBLE, 0x80); DEFINE_X86_MACRO(PRECISION_CONTROL_SINGLE, 0x40); DEFINE_X86_MACRO(PRECISION_CONTROL_UNDEFINED, 0xC0); DEFINE_X86_MACRO(CW_RESET, 0x0040); DEFINE_X86_MACRO(CW_FINIT, 0x037F); DEFINE_X86_MACRO(SW_RESET, 0x0000); DEFINE_X86_MACRO(SW_FINIT, 0x0000); DEFINE_X86_MACRO(TW_RESET, 0x5555); DEFINE_X86_MACRO(TW_FINIT, 0x0FFF); DEFINE_X86_MACRO(CW_X, 0x1000); DEFINE_X86_MACRO(CW_RC_ZERO, 0x0C00); DEFINE_X86_MACRO(CW_RC_UP, 0x0800); DEFINE_X86_MACRO(CW_RC_DOWN, 0x0400); DEFINE_X86_MACRO(CW_RC_NEAR, 0x0000); DEFINE_X86_MACRO(CW_PC_EXTENDED, 0x0300); DEFINE_X86_MACRO(CW_PC_DOUBLE, 0x0200); DEFINE_X86_MACRO(CW_PC_RESERVED, 0x0100); DEFINE_X86_MACRO(CW_PC_SINGLE, 0x0000); DEFINE_X86_MACRO(CW_PM, 0x0020); DEFINE_X86_MACRO(CW_UM, 0x0010); DEFINE_X86_MACRO(CW_OM, 0x0008); DEFINE_X86_MACRO(CW_ZM, 0x0004); DEFINE_X86_MACRO(CW_DM, 0x0002); DEFINE_X86_MACRO(CW_IM, 0x0001); DEFINE_X86_MACRO(SW_B, 0x8000); DEFINE_X86_MACRO(SW_C3, 0x4000); DEFINE_X86_MACRO(SW_TOP_7, 0x3800); DEFINE_X86_MACRO(SW_TOP_6, 0x3000); DEFINE_X86_MACRO(SW_TOP_5, 0x2800); DEFINE_X86_MACRO(SW_TOP_4, 0x2000); DEFINE_X86_MACRO(SW_TOP_3, 0x1800); DEFINE_X86_MACRO(SW_TOP_2, 0x1000); DEFINE_X86_MACRO(SW_TOP_1, 0x0800); DEFINE_X86_MACRO(SW_TOP_0, 0x0000); DEFINE_X86_MACRO(SW_C2, 0x0400); DEFINE_X86_MACRO(SW_C1, 0x0200); DEFINE_X86_MACRO(SW_C0, 0x0100); DEFINE_X86_MACRO(SW_ES, 0x0080); DEFINE_X86_MACRO(SW_SF, 0x0040); DEFINE_X86_MACRO(SW_PE, 0x0020); DEFINE_X86_MACRO(SW_UE, 0x0010); DEFINE_X86_MACRO(SW_OE, 0x0008); DEFINE_X86_MACRO(SW_ZE, 0x0004); DEFINE_X86_MACRO(SW_DE, 0x0002); DEFINE_X86_MACRO(SW_IE, 0x0001); DEFINE_X86_MACRO(X86_ROUNDING_MODE, 0x0C00); DEFINE_X86_MACRO(X86_ROUNDING_PRECISION, 0x0300); #undef DEFINE_X86_MACRO BasiliskII/src/uae_cpu/cpuopti.c0000644000175000017500000001560411735673707017026 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * cpuopti.c - Small optimizer for cpu*.s files * Based on work by Tauno Taipaleenmaki * * Copyright 1996 Bernd Schmidt * * 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 */ #include #include #include #include "sysdeps.h" struct line { struct line *next, *prev; int delet; char *data; }; struct func { struct line *first_line, *last_line; int initial_offset; }; static void oops(void) { fprintf(stderr, "Don't know how to optimize this file.\n"); exit(1); } static char * match(struct line *l, const char *m) { char *str = l->data; int len = strlen(m); while (isspace(*str)) str++; if (strncmp(str, m, len) != 0) return NULL; return str + len; } static int insn_references_reg (struct line *l, char *reg) { if (reg[0] != 'e') { fprintf(stderr, "Unknown register?!?\n"); exit(1); } if (strstr (l->data, reg) != 0) return 1; if (strstr (l->data, reg+1) != 0) return 1; if (strcmp (reg, "eax") == 0 && (strstr (l->data, "%al") != 0 || strstr (l->data, "%ah") != 0)) return 1; if (strcmp (reg, "ebx") == 0 && (strstr (l->data, "%bl") != 0 || strstr (l->data, "%bh") != 0)) return 1; if (strcmp (reg, "ecx") == 0 && (strstr (l->data, "%cl") != 0 || strstr (l->data, "%ch") != 0)) return 1; if (strcmp (reg, "edx") == 0 && (strstr (l->data, "%dl") != 0 || strstr (l->data, "%dh") != 0)) return 1; return 0; } static void do_function(struct func *f) { int v; int pops_at_end = 0; struct line *l, *l1, *fl, *l2; char *s, *s2; int in_pop_area = 1; f->initial_offset = 0; l = f->last_line; fl = f->first_line; if (match(l,".LFE")) l = l->prev; if (!match(l,"ret")) oops(); while (!match(fl, "op_")) fl = fl->next; fl = fl->next; /* Try reordering the insns at the end of the function so that the * pops are all at the end. */ l2 = l->prev; /* Tolerate one stack adjustment */ if (match (l2, "addl $") && strstr(l2->data, "esp") != 0) l2 = l2->prev; for (;;) { char *forbidden_reg; struct line *l3, *l4; while (match (l2, "popl %")) l2 = l2->prev; l3 = l2; for (;;) { forbidden_reg = match (l3, "popl %"); if (forbidden_reg) break; if (l3 == fl) goto reordered; /* Jumps and labels put an end to our attempts... */ if (strstr (l3->data, ".L") != 0) goto reordered; /* Likewise accesses to the stack pointer... */ if (strstr (l3->data, "esp") != 0) goto reordered; /* Function calls... */ if (strstr (l3->data, "call") != 0) goto reordered; l3 = l3->prev; } if (l3 == l2) exit(1); for (l4 = l2; l4 != l3; l4 = l4->prev) { /* The register may not be referenced by any of the insns that we * move the popl past */ if (insn_references_reg (l4, forbidden_reg)) goto reordered; } l3->prev->next = l3->next; l3->next->prev = l3->prev; l2->next->prev = l3; l3->next = l2->next; l2->next = l3; l3->prev = l2; } reordered: l = l->prev; s = match (l, "addl $"); s2 = match (fl, "subl $"); l1 = l; if (s == 0) { char *t = match (l, "popl %"); if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) { s = "4,%esp"; l = l->prev; t = match (l, "popl %"); if (t != 0 && (strcmp (t, "ecx") == 0 || strcmp (t, "edx") == 0)) { s = "8,%esp"; l = l->prev; } } } else { l = l->prev; } if (s && s2) { int v = 0; if (strcmp (s, s2) != 0) { fprintf (stderr, "Stack adjustment not matching.\n"); return; } while (isdigit(*s)) { v = v * 10 + (*s) - '0'; s++; } if (strcmp (s, ",%esp") != 0) { fprintf (stderr, "Not adjusting the stack pointer.\n"); return; } f->initial_offset = v; fl->delet = 3; fl = fl->next; l1->delet = 2; l1 = l1->prev; while (l1 != l) { l1->delet = 1; l1 = l1->prev; } } while (in_pop_area) { char *popm, *pushm; popm = match (l, "popl %"); pushm = match (fl, "pushl %"); if (popm && pushm && strcmp(pushm, popm) == 0) { pops_at_end++; fl->delet = l->delet = 1; } else in_pop_area = 0; l = l->prev; fl = fl->next; } if (f->initial_offset) f->initial_offset += 4 * pops_at_end; } static void output_function(struct func *f) { struct line *l = f->first_line; while (l) { switch (l->delet) { case 1: break; case 0: printf("%s\n", l->data); break; case 2: if (f->initial_offset) printf("\taddl $%d,%%esp\n", f->initial_offset); break; case 3: if (f->initial_offset) printf("\tsubl $%d,%%esp\n", f->initial_offset); break; } l = l->next; } } int main(int argc, char **argv) { FILE *infile = stdin; char tmp[4096]; #ifdef __mc68000__ if(system("perl machdep/cpuopti")==-1) { perror("perl machdep/cpuopti"); return 10; } else return 0; #endif /* For debugging... */ if (argc == 2) infile = fopen (argv[1], "r"); for(;;) { char *s; if ((fgets(tmp, 4095, infile)) == NULL) break; s = strchr (tmp, '\n'); if (s != NULL) *s = 0; if (strncmp(tmp, ".globl op_", 10) == 0) { struct line *first_line = NULL, *prev = NULL; struct line **nextp = &first_line; struct func f; int nr_rets = 0; int can_opt = 1; do { struct line *current; if (strcmp (tmp, "#APP") != 0 && strcmp (tmp, "#NO_APP") != 0) { current = *nextp = (struct line *)malloc(sizeof (struct line)); nextp = ¤t->next; current->prev = prev; prev = current; current->next = NULL; current->delet = 0; current->data = strdup (tmp); if (match (current, "movl %esp,%ebp") || match (current, "enter")) { fprintf (stderr, "GCC failed to eliminate fp: %s\n", first_line->data); can_opt = 0; } if (match (current, "ret")) nr_rets++; } if ((fgets(tmp, 4095, infile)) == NULL) oops(); s = strchr (tmp, '\n'); if (s != NULL) *s = 0; } while (strncmp (tmp,".Lfe", 4) != 0); f.first_line = first_line; f.last_line = prev; if (nr_rets == 1 && can_opt) do_function(&f); /*else fprintf(stderr, "Too many RET instructions: %s\n", first_line->data);*/ output_function(&f); } printf("%s\n", tmp); } return 0; } BasiliskII/src/uae_cpu/memory.cpp0000644000175000017500000003476411735673707017223 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * Memory management * * (c) 1995 Bernd Schmidt * * 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 */ #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "video.h" #include "m68k.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" #if !REAL_ADDRESSING && !DIRECT_ADDRESSING static bool illegal_mem = false; #ifdef SAVE_MEMORY_BANKS addrbank *mem_banks[65536]; #else addrbank mem_banks[65536]; #endif #ifdef WORDS_BIGENDIAN # define swap_words(X) (X) #else # define swap_words(X) (((X) >> 16) | ((X) << 16)) #endif #ifdef NO_INLINE_MEMORY_ACCESS uae_u32 longget (uaecptr addr) { return call_mem_get_func (get_mem_bank (addr).lget, addr); } uae_u32 wordget (uaecptr addr) { return call_mem_get_func (get_mem_bank (addr).wget, addr); } uae_u32 byteget (uaecptr addr) { return call_mem_get_func (get_mem_bank (addr).bget, addr); } void longput (uaecptr addr, uae_u32 l) { call_mem_put_func (get_mem_bank (addr).lput, addr, l); } void wordput (uaecptr addr, uae_u32 w) { call_mem_put_func (get_mem_bank (addr).wput, addr, w); } void byteput (uaecptr addr, uae_u32 b) { call_mem_put_func (get_mem_bank (addr).bput, addr, b); } #endif /* A dummy bank that only contains zeros */ static uae_u32 REGPARAM2 dummy_lget (uaecptr) REGPARAM; static uae_u32 REGPARAM2 dummy_wget (uaecptr) REGPARAM; static uae_u32 REGPARAM2 dummy_bget (uaecptr) REGPARAM; static void REGPARAM2 dummy_lput (uaecptr, uae_u32) REGPARAM; static void REGPARAM2 dummy_wput (uaecptr, uae_u32) REGPARAM; static void REGPARAM2 dummy_bput (uaecptr, uae_u32) REGPARAM; uae_u32 REGPARAM2 dummy_lget (uaecptr addr) { if (illegal_mem) write_log ("Illegal lget at %08lx\n", addr); return 0; } uae_u32 REGPARAM2 dummy_wget (uaecptr addr) { if (illegal_mem) write_log ("Illegal wget at %08lx\n", addr); return 0; } uae_u32 REGPARAM2 dummy_bget (uaecptr addr) { if (illegal_mem) write_log ("Illegal bget at %08lx\n", addr); return 0; } void REGPARAM2 dummy_lput (uaecptr addr, uae_u32 l) { if (illegal_mem) write_log ("Illegal lput at %08lx\n", addr); } void REGPARAM2 dummy_wput (uaecptr addr, uae_u32 w) { if (illegal_mem) write_log ("Illegal wput at %08lx\n", addr); } void REGPARAM2 dummy_bput (uaecptr addr, uae_u32 b) { if (illegal_mem) write_log ("Illegal bput at %08lx\n", addr); } /* Mac RAM (32 bit addressing) */ static uae_u32 REGPARAM2 ram_lget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 ram_wget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 ram_bget(uaecptr) REGPARAM; static void REGPARAM2 ram_lput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 ram_wput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 ram_bput(uaecptr, uae_u32) REGPARAM; static uae_u8 *REGPARAM2 ram_xlate(uaecptr addr) REGPARAM; static uintptr RAMBaseDiff; // RAMBaseHost - RAMBaseMac uae_u32 REGPARAM2 ram_lget(uaecptr addr) { uae_u32 *m; m = (uae_u32 *)(RAMBaseDiff + addr); return do_get_mem_long(m); } uae_u32 REGPARAM2 ram_wget(uaecptr addr) { uae_u16 *m; m = (uae_u16 *)(RAMBaseDiff + addr); return do_get_mem_word(m); } uae_u32 REGPARAM2 ram_bget(uaecptr addr) { return (uae_u32)*(uae_u8 *)(RAMBaseDiff + addr); } void REGPARAM2 ram_lput(uaecptr addr, uae_u32 l) { uae_u32 *m; m = (uae_u32 *)(RAMBaseDiff + addr); do_put_mem_long(m, l); } void REGPARAM2 ram_wput(uaecptr addr, uae_u32 w) { uae_u16 *m; m = (uae_u16 *)(RAMBaseDiff + addr); do_put_mem_word(m, w); } void REGPARAM2 ram_bput(uaecptr addr, uae_u32 b) { *(uae_u8 *)(RAMBaseDiff + addr) = b; } uae_u8 *REGPARAM2 ram_xlate(uaecptr addr) { return (uae_u8 *)(RAMBaseDiff + addr); } /* Mac RAM (24 bit addressing) */ static uae_u32 REGPARAM2 ram24_lget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 ram24_wget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 ram24_bget(uaecptr) REGPARAM; static void REGPARAM2 ram24_lput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 ram24_wput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 ram24_bput(uaecptr, uae_u32) REGPARAM; static uae_u8 *REGPARAM2 ram24_xlate(uaecptr addr) REGPARAM; uae_u32 REGPARAM2 ram24_lget(uaecptr addr) { uae_u32 *m; m = (uae_u32 *)(RAMBaseDiff + (addr & 0xffffff)); return do_get_mem_long(m); } uae_u32 REGPARAM2 ram24_wget(uaecptr addr) { uae_u16 *m; m = (uae_u16 *)(RAMBaseDiff + (addr & 0xffffff)); return do_get_mem_word(m); } uae_u32 REGPARAM2 ram24_bget(uaecptr addr) { return (uae_u32)*(uae_u8 *)(RAMBaseDiff + (addr & 0xffffff)); } void REGPARAM2 ram24_lput(uaecptr addr, uae_u32 l) { uae_u32 *m; m = (uae_u32 *)(RAMBaseDiff + (addr & 0xffffff)); do_put_mem_long(m, l); } void REGPARAM2 ram24_wput(uaecptr addr, uae_u32 w) { uae_u16 *m; m = (uae_u16 *)(RAMBaseDiff + (addr & 0xffffff)); do_put_mem_word(m, w); } void REGPARAM2 ram24_bput(uaecptr addr, uae_u32 b) { *(uae_u8 *)(RAMBaseDiff + (addr & 0xffffff)) = b; } uae_u8 *REGPARAM2 ram24_xlate(uaecptr addr) { return (uae_u8 *)(RAMBaseDiff + (addr & 0xffffff)); } /* Mac ROM (32 bit addressing) */ static uae_u32 REGPARAM2 rom_lget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 rom_wget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 rom_bget(uaecptr) REGPARAM; static void REGPARAM2 rom_lput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 rom_wput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 rom_bput(uaecptr, uae_u32) REGPARAM; static uae_u8 *REGPARAM2 rom_xlate(uaecptr addr) REGPARAM; static uintptr ROMBaseDiff; // ROMBaseHost - ROMBaseMac uae_u32 REGPARAM2 rom_lget(uaecptr addr) { uae_u32 *m; m = (uae_u32 *)(ROMBaseDiff + addr); return do_get_mem_long(m); } uae_u32 REGPARAM2 rom_wget(uaecptr addr) { uae_u16 *m; m = (uae_u16 *)(ROMBaseDiff + addr); return do_get_mem_word(m); } uae_u32 REGPARAM2 rom_bget(uaecptr addr) { return (uae_u32)*(uae_u8 *)(ROMBaseDiff + addr); } void REGPARAM2 rom_lput(uaecptr addr, uae_u32 b) { if (illegal_mem) write_log ("Illegal ROM lput at %08lx\n", addr); } void REGPARAM2 rom_wput(uaecptr addr, uae_u32 b) { if (illegal_mem) write_log ("Illegal ROM wput at %08lx\n", addr); } void REGPARAM2 rom_bput(uaecptr addr, uae_u32 b) { if (illegal_mem) write_log ("Illegal ROM bput at %08lx\n", addr); } uae_u8 *REGPARAM2 rom_xlate(uaecptr addr) { return (uae_u8 *)(ROMBaseDiff + addr); } /* Mac ROM (24 bit addressing) */ static uae_u32 REGPARAM2 rom24_lget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 rom24_wget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 rom24_bget(uaecptr) REGPARAM; static uae_u8 *REGPARAM2 rom24_xlate(uaecptr addr) REGPARAM; uae_u32 REGPARAM2 rom24_lget(uaecptr addr) { uae_u32 *m; m = (uae_u32 *)(ROMBaseDiff + (addr & 0xffffff)); return do_get_mem_long(m); } uae_u32 REGPARAM2 rom24_wget(uaecptr addr) { uae_u16 *m; m = (uae_u16 *)(ROMBaseDiff + (addr & 0xffffff)); return do_get_mem_word(m); } uae_u32 REGPARAM2 rom24_bget(uaecptr addr) { return (uae_u32)*(uae_u8 *)(ROMBaseDiff + (addr & 0xffffff)); } uae_u8 *REGPARAM2 rom24_xlate(uaecptr addr) { return (uae_u8 *)(ROMBaseDiff + (addr & 0xffffff)); } /* Frame buffer */ static uae_u32 REGPARAM2 frame_direct_lget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 frame_direct_wget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 frame_direct_bget(uaecptr) REGPARAM; static void REGPARAM2 frame_direct_lput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 frame_direct_wput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 frame_direct_bput(uaecptr, uae_u32) REGPARAM; static uae_u32 REGPARAM2 frame_host_555_lget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 frame_host_555_wget(uaecptr) REGPARAM; static void REGPARAM2 frame_host_555_lput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 frame_host_555_wput(uaecptr, uae_u32) REGPARAM; static uae_u32 REGPARAM2 frame_host_565_lget(uaecptr) REGPARAM; static uae_u32 REGPARAM2 frame_host_565_wget(uaecptr) REGPARAM; static void REGPARAM2 frame_host_565_lput(uaecptr, uae_u32) REGPARAM; static void REGPARAM2 frame_host_565_wput(uaecptr, uae_u32) REGPARAM; static uae_u32 REGPARAM2 frame_host_888_lget(uaecptr) REGPARAM; static void REGPARAM2 frame_host_888_lput(uaecptr, uae_u32) REGPARAM; static uae_u8 *REGPARAM2 frame_xlate(uaecptr addr) REGPARAM; static uintptr FrameBaseDiff; // MacFrameBaseHost - MacFrameBaseMac uae_u32 REGPARAM2 frame_direct_lget(uaecptr addr) { uae_u32 *m; m = (uae_u32 *)(FrameBaseDiff + addr); return do_get_mem_long(m); } uae_u32 REGPARAM2 frame_direct_wget(uaecptr addr) { uae_u16 *m; m = (uae_u16 *)(FrameBaseDiff + addr); return do_get_mem_word(m); } uae_u32 REGPARAM2 frame_direct_bget(uaecptr addr) { return (uae_u32)*(uae_u8 *)(FrameBaseDiff + addr); } void REGPARAM2 frame_direct_lput(uaecptr addr, uae_u32 l) { uae_u32 *m; m = (uae_u32 *)(FrameBaseDiff + addr); do_put_mem_long(m, l); } void REGPARAM2 frame_direct_wput(uaecptr addr, uae_u32 w) { uae_u16 *m; m = (uae_u16 *)(FrameBaseDiff + addr); do_put_mem_word(m, w); } void REGPARAM2 frame_direct_bput(uaecptr addr, uae_u32 b) { *(uae_u8 *)(FrameBaseDiff + addr) = b; } uae_u32 REGPARAM2 frame_host_555_lget(uaecptr addr) { uae_u32 *m, l; m = (uae_u32 *)(FrameBaseDiff + addr); l = *m; return swap_words(l); } uae_u32 REGPARAM2 frame_host_555_wget(uaecptr addr) { uae_u16 *m; m = (uae_u16 *)(FrameBaseDiff + addr); return *m; } void REGPARAM2 frame_host_555_lput(uaecptr addr, uae_u32 l) { uae_u32 *m; m = (uae_u32 *)(FrameBaseDiff + addr); *m = swap_words(l); } void REGPARAM2 frame_host_555_wput(uaecptr addr, uae_u32 w) { uae_u16 *m; m = (uae_u16 *)(FrameBaseDiff + addr); *m = w; } uae_u32 REGPARAM2 frame_host_565_lget(uaecptr addr) { uae_u32 *m, l; m = (uae_u32 *)(FrameBaseDiff + addr); l = *m; l = (l & 0x001f001f) | ((l >> 1) & 0x7fe07fe0); return swap_words(l); } uae_u32 REGPARAM2 frame_host_565_wget(uaecptr addr) { uae_u16 *m, w; m = (uae_u16 *)(FrameBaseDiff + addr); w = *m; return (w & 0x1f) | ((w >> 1) & 0x7fe0); } void REGPARAM2 frame_host_565_lput(uaecptr addr, uae_u32 l) { uae_u32 *m; m = (uae_u32 *)(FrameBaseDiff + addr); l = (l & 0x001f001f) | ((l << 1) & 0xffc0ffc0); *m = swap_words(l); } void REGPARAM2 frame_host_565_wput(uaecptr addr, uae_u32 w) { uae_u16 *m; m = (uae_u16 *)(FrameBaseDiff + addr); *m = (w & 0x1f) | ((w << 1) & 0xffc0); } uae_u32 REGPARAM2 frame_host_888_lget(uaecptr addr) { uae_u32 *m, l; m = (uae_u32 *)(FrameBaseDiff + addr); return *m; } void REGPARAM2 frame_host_888_lput(uaecptr addr, uae_u32 l) { uae_u32 *m; m = (uae_u32 *)(MacFrameBaseHost + addr - MacFrameBaseMac); *m = l; } uae_u8 *REGPARAM2 frame_xlate(uaecptr addr) { return (uae_u8 *)(FrameBaseDiff + addr); } /* Default memory access functions */ uae_u8 *REGPARAM2 default_xlate (uaecptr a) { write_log("Your Mac program just did something terribly stupid\n"); return NULL; } /* Address banks */ addrbank dummy_bank = { dummy_lget, dummy_wget, dummy_bget, dummy_lput, dummy_wput, dummy_bput, default_xlate }; addrbank ram_bank = { ram_lget, ram_wget, ram_bget, ram_lput, ram_wput, ram_bput, ram_xlate }; addrbank ram24_bank = { ram24_lget, ram24_wget, ram24_bget, ram24_lput, ram24_wput, ram24_bput, ram24_xlate }; addrbank rom_bank = { rom_lget, rom_wget, rom_bget, rom_lput, rom_wput, rom_bput, rom_xlate }; addrbank rom24_bank = { rom24_lget, rom24_wget, rom24_bget, rom_lput, rom_wput, rom_bput, rom24_xlate }; addrbank frame_direct_bank = { frame_direct_lget, frame_direct_wget, frame_direct_bget, frame_direct_lput, frame_direct_wput, frame_direct_bput, frame_xlate }; addrbank frame_host_555_bank = { frame_host_555_lget, frame_host_555_wget, frame_direct_bget, frame_host_555_lput, frame_host_555_wput, frame_direct_bput, frame_xlate }; addrbank frame_host_565_bank = { frame_host_565_lget, frame_host_565_wget, frame_direct_bget, frame_host_565_lput, frame_host_565_wput, frame_direct_bput, frame_xlate }; addrbank frame_host_888_bank = { frame_host_888_lget, frame_direct_wget, frame_direct_bget, frame_host_888_lput, frame_direct_wput, frame_direct_bput, frame_xlate }; void memory_init(void) { for(long i=0; i<65536; i++) put_mem_bank(i<<16, &dummy_bank); // Limit RAM size to not overlap ROM uint32 ram_size = RAMSize > ROMBaseMac ? ROMBaseMac : RAMSize; RAMBaseDiff = (uintptr)RAMBaseHost - (uintptr)RAMBaseMac; ROMBaseDiff = (uintptr)ROMBaseHost - (uintptr)ROMBaseMac; FrameBaseDiff = (uintptr)MacFrameBaseHost - (uintptr)MacFrameBaseMac; // Map RAM and ROM if (TwentyFourBitAddressing) { map_banks(&ram24_bank, RAMBaseMac >> 16, ram_size >> 16); map_banks(&rom24_bank, ROMBaseMac >> 16, ROMSize >> 16); } else { map_banks(&ram_bank, RAMBaseMac >> 16, ram_size >> 16); map_banks(&rom_bank, ROMBaseMac >> 16, ROMSize >> 16); } // Map frame buffer switch (MacFrameLayout) { case FLAYOUT_DIRECT: map_banks(&frame_direct_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); break; case FLAYOUT_HOST_555: map_banks(&frame_host_555_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); break; case FLAYOUT_HOST_565: map_banks(&frame_host_565_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); break; case FLAYOUT_HOST_888: map_banks(&frame_host_888_bank, MacFrameBaseMac >> 16, (MacFrameSize >> 16) + 1); break; } } void map_banks(addrbank *bank, int start, int size) { int bnr; unsigned long int hioffs = 0, endhioffs = 0x100; if (start >= 0x100) { for (bnr = start; bnr < start + size; bnr++) put_mem_bank (bnr << 16, bank); return; } if (TwentyFourBitAddressing) endhioffs = 0x10000; for (hioffs = 0; hioffs < endhioffs; hioffs += 0x100) for (bnr = start; bnr < start+size; bnr++) put_mem_bank((bnr + hioffs) << 16, bank); } #endif /* !REAL_ADDRESSING && !DIRECT_ADDRESSING */ BasiliskII/src/uae_cpu/noflags.h0000644000175000017500000000741307534427571016776 0ustar centriscentris#ifndef NOFLAGS_H #define NOFLAGS_H /* Undefine everything that will *set* flags. Note: Leave *reading* flags alone ;-). We assume that nobody does something like SET_ZFLG(a=b+c), i.e. expect side effects of the macros. That would be a stupid thing to do when using macros. */ /* Gwenole Beauchesne pointed out that CAS and CAS2 use flag_cmp to set flags that are then used internally, and that thus the noflags versions of those instructions were broken. Oops! Easy fix: Leave flag_cmp alone. It is only used by CMP* and CAS* instructions. For CAS*, noflags is a bad idea. For CMP*, which has setting flags as its only function, the noflags version is kinda pointless, anyway. Note that this will only work while using the optflag_* routines --- as we do on all (one ;-) platforms that will ever use the noflags versions, anyway. However, if you try to compile without optimized flags, the "SET_ZFLAG" macro will be left unchanged, to make CAS and CAS2 work right. Of course, this is contrary to the whole idea of noflags, but better be right than be fast. Another problem exists with one of the bitfield operations. Once again, one of the operations sets a flag, and looks at it later. And the CHK2 instruction does so as well. For those, a different solution is possible. the *_ALWAYS versions of the SET_?FLG macros shall remain untouched by the redefinitions in this file. Unfortunately, they are defined in terms of the macros we *do* redefine. So here comes a bit of trickery.... */ #define NOFLAGS_CMP 0 #undef SET_NFLG_ALWAYS static __inline__ void SET_NFLG_ALWAYS(uae_u32 x) { SET_NFLG(x); /* This has not yet been redefined */ } #undef SET_CFLG_ALWAYS static __inline__ void SET_CFLG_ALWAYS(uae_u32 x) { SET_CFLG(x); /* This has not yet been redefined */ } #undef CPUFUNC #define CPUFUNC(x) x##_nf #ifndef OPTIMIZED_FLAGS #undef SET_ZFLG #define SET_ZFLG(y) do {uae_u32 dummy=(y); } while (0) #endif #undef SET_CFLG #define SET_CFLG(y) do {uae_u32 dummy=(y); } while (0) #undef SET_VFLG #define SET_VFLG(y) do {uae_u32 dummy=(y); } while (0) #undef SET_NFLG #define SET_NFLG(y) do {uae_u32 dummy=(y); } while (0) #undef SET_XFLG #define SET_XFLG(y) do {uae_u32 dummy=(y); } while (0) #undef CLEAR_CZNV #define CLEAR_CZNV #undef IOR_CZNV #define IOR_CZNV(y) do {uae_u32 dummy=(y); } while (0) #undef SET_CZNV #define SET_CZNV(y) do {uae_u32 dummy=(y); } while (0) #undef COPY_CARRY #define COPY_CARRY #ifdef optflag_testl #undef optflag_testl #endif #ifdef optflag_testw #undef optflag_testw #endif #ifdef optflag_testb #undef optflag_testb #endif #ifdef optflag_addl #undef optflag_addl #endif #ifdef optflag_addw #undef optflag_addw #endif #ifdef optflag_addb #undef optflag_addb #endif #ifdef optflag_subl #undef optflag_subl #endif #ifdef optflag_subw #undef optflag_subw #endif #ifdef optflag_subb #undef optflag_subb #endif #if NOFLAGS_CMP #ifdef optflag_cmpl #undef optflag_cmpl #endif #ifdef optflag_cmpw #undef optflag_cmpw #endif #ifdef optflag_cmpb #undef optflag_cmpb #endif #endif #define optflag_testl(v) do { } while (0) #define optflag_testw(v) do { } while (0) #define optflag_testb(v) do { } while (0) #define optflag_addl(v, s, d) (v = (uae_s32)(d) + (uae_s32)(s)) #define optflag_addw(v, s, d) (v = (uae_s16)(d) + (uae_s16)(s)) #define optflag_addb(v, s, d) (v = (uae_s8)(d) + (uae_s8)(s)) #define optflag_subl(v, s, d) (v = (uae_s32)(d) - (uae_s32)(s)) #define optflag_subw(v, s, d) (v = (uae_s16)(d) - (uae_s16)(s)) #define optflag_subb(v, s, d) (v = (uae_s8)(d) - (uae_s8)(s)) #if NOFLAGS_CMP /* These are just for completeness sake */ #define optflag_cmpl(s, d) do { } while (0) #define optflag_cmpw(s, d) do { } while (0) #define optflag_cmpb(s, d) do { } while (0) #endif #endif BasiliskII/src/uae_cpu/gencpu.c0000644000175000017500000024657611735673707016642 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * MC68000 emulation generator * * This is a fairly stupid program that generates a lot of case labels that * can be #included in a switch statement. * As an alternative, it can generate functions that handle specific * MC68000 instructions, plus a prototype header file and a function pointer * array to look up the function for an opcode. * Error checking is bad, an illegal table68k file will cause the program to * call abort(). * The generated code is sometimes sub-optimal, an optimizing compiler should * take care of this. * * Copyright 1995, 1996 Bernd Schmidt * * 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 * */ #include #include #include #include #include "sysdeps.h" #include "readcpu.h" #if defined(SPARC_V8_ASSEMBLY) || defined(SPARC_V9_ASSEMBLY) #define SPARC_ASSEMBLY 0 #endif #define BOOL_TYPE "int" /* Define the minimal 680x0 where NV flags are not affected by xBCD instructions. */ #define xBCD_KEEPS_NV_FLAGS 4 static FILE *headerfile; static FILE *stblfile; static int using_prefetch; static int using_exception_3; static int cpu_level; /* For the current opcode, the next lower level that will have different code. * Initialized to -1 for each opcode. If it remains unchanged, indicates we * are done with that opcode. */ static int next_cpu_level; static int *opcode_map; static int *opcode_next_clev; static int *opcode_last_postfix; static unsigned long *counts; static void read_counts (void) { FILE *file; unsigned long opcode, count, total; char name[20]; int nr = 0; memset (counts, 0, 65536 * sizeof *counts); file = fopen ("frequent.68k", "r"); if (file) { fscanf (file, "Total: %lu\n", &total); while (fscanf (file, "%lx: %lu %s\n", &opcode, &count, name) == 3) { opcode_next_clev[nr] = 4; opcode_last_postfix[nr] = -1; opcode_map[nr++] = opcode; counts[opcode] = count; } fclose (file); } if (nr == nr_cpuop_funcs) return; for (opcode = 0; opcode < 0x10000; opcode++) { if (table68k[opcode].handler == -1 && table68k[opcode].mnemo != i_ILLG && counts[opcode] == 0) { opcode_next_clev[nr] = 4; opcode_last_postfix[nr] = -1; opcode_map[nr++] = opcode; counts[opcode] = count; } } if (nr != nr_cpuop_funcs) abort (); } static char endlabelstr[80]; static int endlabelno = 0; static int need_endlabel; static int n_braces = 0; static int m68k_pc_offset = 0; static int insn_n_cycles; static void start_brace (void) { n_braces++; printf ("{"); } static void close_brace (void) { assert (n_braces > 0); n_braces--; printf ("}"); } static void finish_braces (void) { while (n_braces > 0) close_brace (); } static void pop_braces (int to) { while (n_braces > to) close_brace (); } static int bit_size (int size) { switch (size) { case sz_byte: return 8; case sz_word: return 16; case sz_long: return 32; default: abort (); } return 0; } static const char *bit_mask (int size) { switch (size) { case sz_byte: return "0xff"; case sz_word: return "0xffff"; case sz_long: return "0xffffffff"; default: abort (); } return 0; } static const char *gen_nextilong (void) { static char buffer[80]; int r = m68k_pc_offset; m68k_pc_offset += 4; insn_n_cycles += 4; if (using_prefetch) sprintf (buffer, "get_ilong_prefetch(%d)", r); else sprintf (buffer, "get_ilong(%d)", r); return buffer; } static const char *gen_nextiword (void) { static char buffer[80]; int r = m68k_pc_offset; m68k_pc_offset += 2; insn_n_cycles += 2; if (using_prefetch) sprintf (buffer, "get_iword_prefetch(%d)", r); else sprintf (buffer, "get_iword(%d)", r); return buffer; } static const char *gen_nextibyte (void) { static char buffer[80]; int r = m68k_pc_offset; m68k_pc_offset += 2; insn_n_cycles += 2; if (using_prefetch) sprintf (buffer, "get_ibyte_prefetch(%d)", r); else sprintf (buffer, "get_ibyte(%d)", r); return buffer; } static void fill_prefetch_0 (void) { if (using_prefetch) printf ("fill_prefetch_0 ();\n"); } static void fill_prefetch_2 (void) { if (using_prefetch) printf ("fill_prefetch_2 ();\n"); } static void swap_opcode (void) { printf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); printf ("\topcode = ((opcode << 8) & 0xFF00) | ((opcode >> 8) & 0xFF);\n"); printf ("#endif\n"); } static void sync_m68k_pc (void) { if (m68k_pc_offset == 0) return; printf ("m68k_incpc(%d);\n", m68k_pc_offset); switch (m68k_pc_offset) { case 0: /*fprintf (stderr, "refilling prefetch at 0\n"); */ break; case 2: fill_prefetch_2 (); break; default: fill_prefetch_0 (); break; } m68k_pc_offset = 0; } /* getv == 1: fetch data; getv != 0: check for odd address. If movem != 0, * the calling routine handles Apdi and Aipi modes. * gb-- movem == 2 means the same thing but for a MOVE16 instruction */ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem) { start_brace (); switch (mode) { case Dreg: if (movem) abort (); if (getv == 1) switch (size) { case sz_byte: #if defined(AMIGA) && !defined(WARPUP) /* sam: I don't know why gcc.2.7.2.1 produces a code worse */ /* if it is not done like that: */ printf ("\tuae_s8 %s = ((uae_u8*)&m68k_dreg(regs, %s))[3];\n", name, reg); #else printf ("\tuae_s8 %s = m68k_dreg(regs, %s);\n", name, reg); #endif break; case sz_word: #if defined(AMIGA) && !defined(WARPUP) printf ("\tuae_s16 %s = ((uae_s16*)&m68k_dreg(regs, %s))[1];\n", name, reg); #else printf ("\tuae_s16 %s = m68k_dreg(regs, %s);\n", name, reg); #endif break; case sz_long: printf ("\tuae_s32 %s = m68k_dreg(regs, %s);\n", name, reg); break; default: abort (); } return; case Areg: if (movem) abort (); if (getv == 1) switch (size) { case sz_word: printf ("\tuae_s16 %s = m68k_areg(regs, %s);\n", name, reg); break; case sz_long: printf ("\tuae_s32 %s = m68k_areg(regs, %s);\n", name, reg); break; default: abort (); } return; case Aind: printf ("\tuaecptr %sa = m68k_areg(regs, %s);\n", name, reg); break; case Aipi: printf ("\tuaecptr %sa = m68k_areg(regs, %s);\n", name, reg); break; case Apdi: switch (size) { case sz_byte: if (movem) printf ("\tuaecptr %sa = m68k_areg(regs, %s);\n", name, reg); else printf ("\tuaecptr %sa = m68k_areg(regs, %s) - areg_byteinc[%s];\n", name, reg, reg); break; case sz_word: printf ("\tuaecptr %sa = m68k_areg(regs, %s) - %d;\n", name, reg, movem ? 0 : 2); break; case sz_long: printf ("\tuaecptr %sa = m68k_areg(regs, %s) - %d;\n", name, reg, movem ? 0 : 4); break; default: abort (); } break; case Ad16: printf ("\tuaecptr %sa = m68k_areg(regs, %s) + (uae_s32)(uae_s16)%s;\n", name, reg, gen_nextiword ()); break; case Ad8r: if (cpu_level > 1) { if (next_cpu_level < 1) next_cpu_level = 1; sync_m68k_pc (); start_brace (); printf ("\tuaecptr %sa = get_disp_ea_020(m68k_areg(regs, %s), next_iword());\n", name, reg); } else printf ("\tuaecptr %sa = get_disp_ea_000(m68k_areg(regs, %s), %s);\n", name, reg, gen_nextiword ()); break; case PC16: printf ("\tuaecptr %sa = m68k_getpc () + %d;\n", name, m68k_pc_offset); printf ("\t%sa += (uae_s32)(uae_s16)%s;\n", name, gen_nextiword ()); break; case PC8r: if (cpu_level > 1) { if (next_cpu_level < 1) next_cpu_level = 1; sync_m68k_pc (); start_brace (); printf ("\tuaecptr tmppc = m68k_getpc();\n"); printf ("\tuaecptr %sa = get_disp_ea_020(tmppc, next_iword());\n", name); } else { printf ("\tuaecptr tmppc = m68k_getpc() + %d;\n", m68k_pc_offset); printf ("\tuaecptr %sa = get_disp_ea_000(tmppc, %s);\n", name, gen_nextiword ()); } break; case absw: printf ("\tuaecptr %sa = (uae_s32)(uae_s16)%s;\n", name, gen_nextiword ()); break; case absl: printf ("\tuaecptr %sa = %s;\n", name, gen_nextilong ()); break; case imm: if (getv != 1) abort (); switch (size) { case sz_byte: printf ("\tuae_s8 %s = %s;\n", name, gen_nextibyte ()); break; case sz_word: printf ("\tuae_s16 %s = %s;\n", name, gen_nextiword ()); break; case sz_long: printf ("\tuae_s32 %s = %s;\n", name, gen_nextilong ()); break; default: abort (); } return; case imm0: if (getv != 1) abort (); printf ("\tuae_s8 %s = %s;\n", name, gen_nextibyte ()); return; case imm1: if (getv != 1) abort (); printf ("\tuae_s16 %s = %s;\n", name, gen_nextiword ()); return; case imm2: if (getv != 1) abort (); printf ("\tuae_s32 %s = %s;\n", name, gen_nextilong ()); return; case immi: if (getv != 1) abort (); printf ("\tuae_u32 %s = %s;\n", name, reg); return; default: abort (); } /* We get here for all non-reg non-immediate addressing modes to * actually fetch the value. */ if (using_exception_3 && getv != 0 && size != sz_byte) { printf ("\tif ((%sa & 1) != 0) {\n", name); printf ("\t\tlast_fault_for_exception_3 = %sa;\n", name); printf ("\t\tlast_op_for_exception_3 = opcode;\n"); printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + %d;\n", m68k_pc_offset); printf ("\t\tException(3, 0);\n"); printf ("\t\tgoto %s;\n", endlabelstr); printf ("\t}\n"); need_endlabel = 1; start_brace (); } if (getv == 1) { switch (size) { case sz_byte: insn_n_cycles += 2; break; case sz_word: insn_n_cycles += 2; break; case sz_long: insn_n_cycles += 4; break; default: abort (); } start_brace (); switch (size) { case sz_byte: printf ("\tuae_s8 %s = get_byte(%sa);\n", name, name); break; case sz_word: printf ("\tuae_s16 %s = get_word(%sa);\n", name, name); break; case sz_long: printf ("\tuae_s32 %s = get_long(%sa);\n", name, name); break; default: abort (); } } /* We now might have to fix up the register for pre-dec or post-inc * addressing modes. */ if (!movem) switch (mode) { case Aipi: switch (size) { case sz_byte: printf ("\tm68k_areg(regs, %s) += areg_byteinc[%s];\n", reg, reg); break; case sz_word: printf ("\tm68k_areg(regs, %s) += 2;\n", reg); break; case sz_long: printf ("\tm68k_areg(regs, %s) += 4;\n", reg); break; default: abort (); } break; case Apdi: printf ("\tm68k_areg (regs, %s) = %sa;\n", reg, name); break; default: break; } } static void genastore (char *from, amodes mode, char *reg, wordsizes size, char *to) { switch (mode) { case Dreg: switch (size) { case sz_byte: printf ("\tm68k_dreg(regs, %s) = (m68k_dreg(regs, %s) & ~0xff) | ((%s) & 0xff);\n", reg, reg, from); break; case sz_word: printf ("\tm68k_dreg(regs, %s) = (m68k_dreg(regs, %s) & ~0xffff) | ((%s) & 0xffff);\n", reg, reg, from); break; case sz_long: printf ("\tm68k_dreg(regs, %s) = (%s);\n", reg, from); break; default: abort (); } break; case Areg: switch (size) { case sz_word: fprintf (stderr, "Foo\n"); printf ("\tm68k_areg(regs, %s) = (uae_s32)(uae_s16)(%s);\n", reg, from); break; case sz_long: printf ("\tm68k_areg(regs, %s) = (%s);\n", reg, from); break; default: abort (); } break; case Aind: case Aipi: case Apdi: case Ad16: case Ad8r: case absw: case absl: case PC16: case PC8r: if (using_prefetch) sync_m68k_pc (); switch (size) { case sz_byte: insn_n_cycles += 2; printf ("\tput_byte(%sa,%s);\n", to, from); break; case sz_word: insn_n_cycles += 2; if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) abort (); printf ("\tput_word(%sa,%s);\n", to, from); break; case sz_long: insn_n_cycles += 4; if (cpu_level < 2 && (mode == PC16 || mode == PC8r)) abort (); printf ("\tput_long(%sa,%s);\n", to, from); break; default: abort (); } break; case imm: case imm0: case imm1: case imm2: case immi: abort (); break; default: abort (); } } static void genmovemel (uae_u16 opcode) { char getcode[100]; int size = table68k[opcode].size == sz_long ? 4 : 2; if (table68k[opcode].size == sz_long) { strcpy (getcode, "get_long(srca)"); } else { strcpy (getcode, "(uae_s32)(uae_s16)get_word(srca)"); } printf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); printf ("\tunsigned int dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); start_brace (); printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = %s; srca += %d; dmask = movem_next[dmask]; }\n", getcode, size); printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = %s; srca += %d; amask = movem_next[amask]; }\n", getcode, size); if (table68k[opcode].dmode == Aipi) printf ("\tm68k_areg(regs, dstreg) = srca;\n"); } static void genmovemle (uae_u16 opcode) { char putcode[100]; int size = table68k[opcode].size == sz_long ? 4 : 2; if (table68k[opcode].size == sz_long) { strcpy (putcode, "put_long(srca,"); } else { strcpy (putcode, "put_word(srca,"); } printf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); if (using_prefetch) sync_m68k_pc (); start_brace (); if (table68k[opcode].dmode == Apdi) { printf ("\tuae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n"); printf ("\twhile (amask) { srca -= %d; %s m68k_areg(regs, movem_index2[amask])); amask = movem_next[amask]; }\n", size, putcode); printf ("\twhile (dmask) { srca -= %d; %s m68k_dreg(regs, movem_index2[dmask])); dmask = movem_next[dmask]; }\n", size, putcode); printf ("\tm68k_areg(regs, dstreg) = srca;\n"); } else { printf ("\tuae_u16 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); printf ("\twhile (dmask) { %s m68k_dreg(regs, movem_index1[dmask])); srca += %d; dmask = movem_next[dmask]; }\n", putcode, size); printf ("\twhile (amask) { %s m68k_areg(regs, movem_index1[amask])); srca += %d; amask = movem_next[amask]; }\n", putcode, size); } } static void duplicate_carry (void) { printf ("\tCOPY_CARRY;\n"); } typedef enum { flag_logical_noclobber, flag_logical, flag_add, flag_sub, flag_cmp, flag_addx, flag_subx, flag_z, flag_zn, flag_av, flag_sv } flagtypes; static void genflags_normal (flagtypes type, wordsizes size, char *value, char *src, char *dst) { char vstr[100], sstr[100], dstr[100]; char usstr[100], udstr[100]; char unsstr[100], undstr[100]; switch (size) { case sz_byte: strcpy (vstr, "((uae_s8)("); strcpy (usstr, "((uae_u8)("); break; case sz_word: strcpy (vstr, "((uae_s16)("); strcpy (usstr, "((uae_u16)("); break; case sz_long: strcpy (vstr, "((uae_s32)("); strcpy (usstr, "((uae_u32)("); break; default: abort (); } strcpy (unsstr, usstr); strcpy (sstr, vstr); strcpy (dstr, vstr); strcat (vstr, value); strcat (vstr, "))"); strcat (dstr, dst); strcat (dstr, "))"); strcat (sstr, src); strcat (sstr, "))"); strcpy (udstr, usstr); strcat (udstr, dst); strcat (udstr, "))"); strcat (usstr, src); strcat (usstr, "))"); strcpy (undstr, unsstr); strcat (unsstr, "-"); strcat (undstr, "~"); strcat (undstr, dst); strcat (undstr, "))"); strcat (unsstr, src); strcat (unsstr, "))"); switch (type) { case flag_logical_noclobber: case flag_logical: case flag_z: case flag_zn: case flag_av: case flag_sv: case flag_addx: case flag_subx: break; case flag_add: start_brace (); printf ("uae_u32 %s = %s + %s;\n", value, dstr, sstr); break; case flag_sub: case flag_cmp: start_brace (); printf ("uae_u32 %s = %s - %s;\n", value, dstr, sstr); break; } switch (type) { case flag_logical_noclobber: case flag_logical: case flag_z: case flag_zn: break; case flag_add: case flag_sub: case flag_addx: case flag_subx: case flag_cmp: case flag_av: case flag_sv: start_brace (); printf ("\t" BOOL_TYPE " flgs = %s < 0;\n", sstr); printf ("\t" BOOL_TYPE " flgo = %s < 0;\n", dstr); printf ("\t" BOOL_TYPE " flgn = %s < 0;\n", vstr); break; } switch (type) { case flag_logical: printf ("\tCLEAR_CZNV;\n"); printf ("\tSET_ZFLG (%s == 0);\n", vstr); printf ("\tSET_NFLG (%s < 0);\n", vstr); break; case flag_logical_noclobber: printf ("\tSET_ZFLG (%s == 0);\n", vstr); printf ("\tSET_NFLG (%s < 0);\n", vstr); break; case flag_av: printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); break; case flag_sv: printf ("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n"); break; case flag_z: printf ("\tSET_ZFLG (GET_ZFLG & (%s == 0));\n", vstr); break; case flag_zn: printf ("\tSET_ZFLG (GET_ZFLG & (%s == 0));\n", vstr); printf ("\tSET_NFLG (%s < 0);\n", vstr); break; case flag_add: printf ("\tSET_ZFLG (%s == 0);\n", vstr); printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); printf ("\tSET_CFLG (%s < %s);\n", undstr, usstr); duplicate_carry (); printf ("\tSET_NFLG (flgn != 0);\n"); break; case flag_sub: printf ("\tSET_ZFLG (%s == 0);\n", vstr); printf ("\tSET_VFLG ((flgs ^ flgo) & (flgn ^ flgo));\n"); printf ("\tSET_CFLG (%s > %s);\n", usstr, udstr); duplicate_carry (); printf ("\tSET_NFLG (flgn != 0);\n"); break; case flag_addx: printf ("\tSET_VFLG ((flgs ^ flgn) & (flgo ^ flgn));\n"); /* minterm SON: 0x42 */ printf ("\tSET_CFLG (flgs ^ ((flgs ^ flgo) & (flgo ^ flgn)));\n"); /* minterm SON: 0xD4 */ duplicate_carry (); break; case flag_subx: printf ("\tSET_VFLG ((flgs ^ flgo) & (flgo ^ flgn));\n"); /* minterm SON: 0x24 */ printf ("\tSET_CFLG (flgs ^ ((flgs ^ flgn) & (flgo ^ flgn)));\n"); /* minterm SON: 0xB2 */ duplicate_carry (); break; case flag_cmp: printf ("\tSET_ZFLG (%s == 0);\n", vstr); printf ("\tSET_VFLG ((flgs != flgo) && (flgn != flgo));\n"); printf ("\tSET_CFLG (%s > %s);\n", usstr, udstr); printf ("\tSET_NFLG (flgn != 0);\n"); break; } } static void genflags (flagtypes type, wordsizes size, char *value, char *src, char *dst) { /* Temporarily deleted 68k/ARM flag optimizations. I'd prefer to have them in the appropriate m68k.h files and use just one copy of this code here. The API can be changed if necessary. */ #ifdef OPTIMIZED_FLAGS switch (type) { case flag_add: case flag_sub: start_brace (); printf ("\tuae_u32 %s;\n", value); break; default: break; } /* At least some of those casts are fairly important! */ switch (type) { case flag_logical_noclobber: printf ("\t{uae_u32 oldcznv = GET_CZNV & ~(FLAGVAL_Z | FLAGVAL_N);\n"); if (strcmp (value, "0") == 0) { printf ("\tSET_CZNV (olcznv | FLAGVAL_Z);\n"); } else { switch (size) { case sz_byte: printf ("\toptflag_testb ((uae_s8)(%s));\n", value); break; case sz_word: printf ("\toptflag_testw ((uae_s16)(%s));\n", value); break; case sz_long: printf ("\toptflag_testl ((uae_s32)(%s));\n", value); break; } printf ("\tIOR_CZNV (oldcznv);\n"); } printf ("\t}\n"); return; case flag_logical: if (strcmp (value, "0") == 0) { printf ("\tSET_CZNV (FLAGVAL_Z);\n"); } else { switch (size) { case sz_byte: printf ("\toptflag_testb ((uae_s8)(%s));\n", value); break; case sz_word: printf ("\toptflag_testw ((uae_s16)(%s));\n", value); break; case sz_long: printf ("\toptflag_testl ((uae_s32)(%s));\n", value); break; } } return; case flag_add: switch (size) { case sz_byte: printf ("\toptflag_addb (%s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break; case sz_word: printf ("\toptflag_addw (%s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; case sz_long: printf ("\toptflag_addl (%s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; } return; case flag_sub: switch (size) { case sz_byte: printf ("\toptflag_subb (%s, (uae_s8)(%s), (uae_s8)(%s));\n", value, src, dst); break; case sz_word: printf ("\toptflag_subw (%s, (uae_s16)(%s), (uae_s16)(%s));\n", value, src, dst); break; case sz_long: printf ("\toptflag_subl (%s, (uae_s32)(%s), (uae_s32)(%s));\n", value, src, dst); break; } return; case flag_cmp: switch (size) { case sz_byte: printf ("\toptflag_cmpb ((uae_s8)(%s), (uae_s8)(%s));\n", src, dst); break; case sz_word: printf ("\toptflag_cmpw ((uae_s16)(%s), (uae_s16)(%s));\n", src, dst); break; case sz_long: printf ("\toptflag_cmpl ((uae_s32)(%s), (uae_s32)(%s));\n", src, dst); break; } return; default: break; } #endif genflags_normal (type, size, value, src, dst); } static void force_range_for_rox (const char *var, wordsizes size) { /* Could do a modulo operation here... which one is faster? */ switch (size) { case sz_long: printf ("\tif (%s >= 33) %s -= 33;\n", var, var); break; case sz_word: printf ("\tif (%s >= 34) %s -= 34;\n", var, var); printf ("\tif (%s >= 17) %s -= 17;\n", var, var); break; case sz_byte: printf ("\tif (%s >= 36) %s -= 36;\n", var, var); printf ("\tif (%s >= 18) %s -= 18;\n", var, var); printf ("\tif (%s >= 9) %s -= 9;\n", var, var); break; } } static const char *cmask (wordsizes size) { switch (size) { case sz_byte: return "0x80"; case sz_word: return "0x8000"; case sz_long: return "0x80000000"; default: abort (); } } static int source_is_imm1_8 (struct instr *i) { return i->stype == 3; } static void gen_opcode (unsigned long int opcode) { struct instr *curi = table68k + opcode; insn_n_cycles = 2; start_brace (); #if 0 printf ("uae_u8 *m68k_pc = regs.pc_p;\n"); #endif m68k_pc_offset = 2; switch (curi->plev) { case 0: /* not privileged */ break; case 1: /* unprivileged only on 68000 */ if (cpu_level == 0) break; if (next_cpu_level < 0) next_cpu_level = 0; /* fall through */ case 2: /* priviledged */ printf ("if (!regs.s) { Exception(8,0); goto %s; }\n", endlabelstr); need_endlabel = 1; start_brace (); break; case 3: /* privileged if size == word */ if (curi->size == sz_byte) break; printf ("if (!regs.s) { Exception(8,0); goto %s; }\n", endlabelstr); need_endlabel = 1; start_brace (); break; } switch (curi->mnemo) { case i_OR: case i_AND: case i_EOR: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); printf ("\tsrc %c= dst;\n", curi->mnemo == i_OR ? '|' : curi->mnemo == i_AND ? '&' : '^'); genflags (flag_logical, curi->size, "src", "", ""); genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); break; case i_ORSR: case i_EORSR: printf ("\tMakeSR();\n"); genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); if (curi->size == sz_byte) { printf ("\tsrc &= 0xFF;\n"); } printf ("\tregs.sr %c= src;\n", curi->mnemo == i_EORSR ? '^' : '|'); printf ("\tMakeFromSR();\n"); break; case i_ANDSR: printf ("\tMakeSR();\n"); genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); if (curi->size == sz_byte) { printf ("\tsrc |= 0xFF00;\n"); } printf ("\tregs.sr &= src;\n"); printf ("\tMakeFromSR();\n"); break; case i_SUB: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); genflags (flag_sub, curi->size, "newv", "src", "dst"); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); break; case i_SUBA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); start_brace (); printf ("\tuae_u32 newv = dst - src;\n"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); break; case i_SUBX: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); printf ("\tuae_u32 newv = dst - src - (GET_XFLG ? 1 : 0);\n"); genflags (flag_subx, curi->size, "newv", "src", "dst"); genflags (flag_zn, curi->size, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); break; case i_SBCD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); printf ("\tuae_u16 newv_lo = (dst & 0xF) - (src & 0xF) - (GET_XFLG ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = (dst & 0xF0) - (src & 0xF0);\n"); printf ("\tuae_u16 newv, tmp_newv;\n"); printf ("\tint bcd = 0;\n"); printf ("\tnewv = tmp_newv = newv_hi + newv_lo;\n"); printf ("\tif (newv_lo & 0xF0) { newv -= 6; bcd = 6; };\n"); printf ("\tif ((((dst & 0xFF) - (src & 0xFF) - (GET_XFLG ? 1 : 0)) & 0x100) > 0xFF) { newv -= 0x60; }\n"); printf ("\tSET_CFLG ((((dst & 0xFF) - (src & 0xFF) - bcd - (GET_XFLG ? 1 : 0)) & 0x300) > 0xFF);\n"); duplicate_carry (); /* Manual says bits NV are undefined though a real 68040 don't change them */ if (cpu_level >= xBCD_KEEPS_NV_FLAGS) { if (next_cpu_level < xBCD_KEEPS_NV_FLAGS) next_cpu_level = xBCD_KEEPS_NV_FLAGS - 1; genflags (flag_z, curi->size, "newv", "", ""); } else { genflags (flag_zn, curi->size, "newv", "", ""); printf ("\tSET_VFLG ((tmp_newv & 0x80) != 0 && (newv & 0x80) == 0);\n"); } genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); break; case i_ADD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); genflags (flag_add, curi->size, "newv", "src", "dst"); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); break; case i_ADDA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); start_brace (); printf ("\tuae_u32 newv = dst + src;\n"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); break; case i_ADDX: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); printf ("\tuae_u32 newv = dst + src + (GET_XFLG ? 1 : 0);\n"); genflags (flag_addx, curi->size, "newv", "src", "dst"); genflags (flag_zn, curi->size, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); break; case i_ABCD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); printf ("\tuae_u16 newv_lo = (src & 0xF) + (dst & 0xF) + (GET_XFLG ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = (src & 0xF0) + (dst & 0xF0);\n"); printf ("\tuae_u16 newv, tmp_newv;\n"); printf ("\tint cflg;\n"); printf ("\tnewv = tmp_newv = newv_hi + newv_lo;\n"); printf ("\tif (newv_lo > 9) { newv += 6; }\n"); printf ("\tcflg = (newv & 0x3F0) > 0x90;\n"); printf ("\tif (cflg) newv += 0x60;\n"); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry (); /* Manual says bits NV are undefined though a real 68040 don't change them */ if (cpu_level >= xBCD_KEEPS_NV_FLAGS) { if (next_cpu_level < xBCD_KEEPS_NV_FLAGS) next_cpu_level = xBCD_KEEPS_NV_FLAGS - 1; genflags (flag_z, curi->size, "newv", "", ""); } else { genflags (flag_zn, curi->size, "newv", "", ""); printf ("\tSET_VFLG ((tmp_newv & 0x80) == 0 && (newv & 0x80) != 0);\n"); } genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); break; case i_NEG: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); genflags (flag_sub, curi->size, "dst", "src", "0"); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); break; case i_NEGX: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); printf ("\tuae_u32 newv = 0 - src - (GET_XFLG ? 1 : 0);\n"); genflags (flag_subx, curi->size, "newv", "src", "0"); genflags (flag_zn, curi->size, "newv", "", ""); genastore ("newv", curi->smode, "srcreg", curi->size, "src"); break; case i_NBCD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); printf ("\tuae_u16 newv_lo = - (src & 0xF) - (GET_XFLG ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = - (src & 0xF0);\n"); printf ("\tuae_u16 newv;\n"); printf ("\tint cflg;\n"); printf ("\tif (newv_lo > 9) { newv_lo -= 6; }\n"); printf ("\tnewv = newv_hi + newv_lo;\n"); printf ("\tcflg = (newv & 0x1F0) > 0x90;\n"); printf ("\tif (cflg) newv -= 0x60;\n"); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry(); /* Manual says bits NV are undefined though a real 68040 don't change them */ if (cpu_level >= xBCD_KEEPS_NV_FLAGS) { if (next_cpu_level < xBCD_KEEPS_NV_FLAGS) next_cpu_level = xBCD_KEEPS_NV_FLAGS - 1; genflags (flag_z, curi->size, "newv", "", ""); } else { genflags (flag_zn, curi->size, "newv", "", ""); } genastore ("newv", curi->smode, "srcreg", curi->size, "src"); break; case i_CLR: genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); genflags (flag_logical, curi->size, "0", "", ""); genastore ("0", curi->smode, "srcreg", curi->size, "src"); break; case i_NOT: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); printf ("\tuae_u32 dst = ~src;\n"); genflags (flag_logical, curi->size, "dst", "", ""); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); break; case i_TST: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genflags (flag_logical, curi->size, "src", "", ""); break; case i_BTST: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else printf ("\tsrc &= 31;\n"); printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); break; case i_BCHG: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else printf ("\tsrc &= 31;\n"); printf ("\tdst ^= (1 << src);\n"); printf ("\tSET_ZFLG (((uae_u32)dst & (1 << src)) >> src);\n"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_BCLR: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else printf ("\tsrc &= 31;\n"); printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); printf ("\tdst &= ~(1 << src);\n"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_BSET: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); if (curi->size == sz_byte) printf ("\tsrc &= 7;\n"); else printf ("\tsrc &= 31;\n"); printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); printf ("\tdst |= (1 << src);\n"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_CMPM: case i_CMP: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); genflags (flag_cmp, curi->size, "newv", "src", "dst"); break; case i_CMPA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); start_brace (); genflags (flag_cmp, sz_long, "newv", "src", "dst"); break; /* The next two are coded a little unconventional, but they are doing * weird things... */ case i_MVPRM: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tuaecptr memp = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword ()); if (curi->size == sz_word) { printf ("\tput_byte(memp, src >> 8); put_byte(memp + 2, src);\n"); } else { printf ("\tput_byte(memp, src >> 24); put_byte(memp + 2, src >> 16);\n"); printf ("\tput_byte(memp + 4, src >> 8); put_byte(memp + 6, src);\n"); } break; case i_MVPMR: printf ("\tuaecptr memp = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword ()); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); if (curi->size == sz_word) { printf ("\tuae_u16 val = (get_byte(memp) << 8) + get_byte(memp + 2);\n"); } else { printf ("\tuae_u32 val = (get_byte(memp) << 24) + (get_byte(memp + 2) << 16)\n"); printf (" + (get_byte(memp + 4) << 8) + get_byte(memp + 6);\n"); } genastore ("val", curi->dmode, "dstreg", curi->size, "dst"); break; case i_MOVE: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); genflags (flag_logical, curi->size, "src", "", ""); genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); break; case i_MOVEA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); if (curi->size == sz_word) { printf ("\tuae_u32 val = (uae_s32)(uae_s16)src;\n"); } else { printf ("\tuae_u32 val = src;\n"); } genastore ("val", curi->dmode, "dstreg", sz_long, "dst"); break; case i_MVSR2: genamode (curi->smode, "srcreg", sz_word, "src", 2, 0); printf ("\tMakeSR();\n"); if (curi->size == sz_byte) genastore ("regs.sr & 0xff", curi->smode, "srcreg", sz_word, "src"); else genastore ("regs.sr", curi->smode, "srcreg", sz_word, "src"); break; case i_MV2SR: genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); if (curi->size == sz_byte) printf ("\tMakeSR();\n\tregs.sr &= 0xFF00;\n\tregs.sr |= src & 0xFF;\n"); else { printf ("\tregs.sr = src;\n"); } printf ("\tMakeFromSR();\n"); break; case i_SWAP: genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); start_brace (); printf ("\tuae_u32 dst = ((src >> 16)&0xFFFF) | ((src&0xFFFF)<<16);\n"); genflags (flag_logical, sz_long, "dst", "", ""); genastore ("dst", curi->smode, "srcreg", sz_long, "src"); break; case i_EXG: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); break; case i_EXT: genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 dst = (uae_s32)(uae_s8)src;\n"); break; case sz_word: printf ("\tuae_u16 dst = (uae_s16)(uae_s8)src;\n"); break; case sz_long: printf ("\tuae_u32 dst = (uae_s32)(uae_s16)src;\n"); break; default: abort (); } genflags (flag_logical, curi->size == sz_word ? sz_word : sz_long, "dst", "", ""); genastore ("dst", curi->smode, "srcreg", curi->size == sz_word ? sz_word : sz_long, "src"); break; case i_MVMEL: genmovemel (opcode); break; case i_MVMLE: genmovemle (opcode); break; case i_TRAP: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); sync_m68k_pc (); printf ("\tException(src+32,0);\n"); m68k_pc_offset = 0; break; case i_MVR2USP: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tregs.usp = src;\n"); break; case i_MVUSP2R: genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); genastore ("regs.usp", curi->smode, "srcreg", curi->size, "src"); break; case i_RESET: break; case i_NOP: break; case i_STOP: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tregs.sr = src;\n"); printf ("\tMakeFromSR();\n"); printf ("\tm68k_setstopped(1);\n"); break; case i_RTE: if (cpu_level == 0) { genamode (Aipi, "7", sz_word, "sr", 1, 0); genamode (Aipi, "7", sz_long, "pc", 1, 0); printf ("\tregs.sr = sr; m68k_setpc_rte(pc);\n"); fill_prefetch_0 (); printf ("\tMakeFromSR();\n"); } else { int old_brace_level = n_braces; if (next_cpu_level < 0) next_cpu_level = 0; printf ("\tuae_u16 newsr; uae_u32 newpc; for (;;) {\n"); genamode (Aipi, "7", sz_word, "sr", 1, 0); genamode (Aipi, "7", sz_long, "pc", 1, 0); genamode (Aipi, "7", sz_word, "format", 1, 0); printf ("\tnewsr = sr; newpc = pc;\n"); printf ("\tif ((format & 0xF000) == 0x0000) { break; }\n"); printf ("\telse if ((format & 0xF000) == 0x1000) { ; }\n"); printf ("\telse if ((format & 0xF000) == 0x2000) { m68k_areg(regs, 7) += 4; break; }\n"); /* gb-- the next two lines are deleted in Bernie's gencpu.c */ printf ("\telse if ((format & 0xF000) == 0x3000) { m68k_areg(regs, 7) += 4; break; }\n"); printf ("\telse if ((format & 0xF000) == 0x7000) { m68k_areg(regs, 7) += 52; break; }\n"); printf ("\telse if ((format & 0xF000) == 0x8000) { m68k_areg(regs, 7) += 50; break; }\n"); printf ("\telse if ((format & 0xF000) == 0x9000) { m68k_areg(regs, 7) += 12; break; }\n"); printf ("\telse if ((format & 0xF000) == 0xa000) { m68k_areg(regs, 7) += 24; break; }\n"); printf ("\telse if ((format & 0xF000) == 0xb000) { m68k_areg(regs, 7) += 84; break; }\n"); printf ("\telse { Exception(14,0); goto %s; }\n", endlabelstr); printf ("\tregs.sr = newsr; MakeFromSR();\n}\n"); pop_braces (old_brace_level); printf ("\tregs.sr = newsr; MakeFromSR();\n"); printf ("\tm68k_setpc_rte(newpc);\n"); fill_prefetch_0 (); need_endlabel = 1; } /* PC is set and prefetch filled. */ m68k_pc_offset = 0; break; case i_RTD: genamode (Aipi, "7", sz_long, "pc", 1, 0); genamode (curi->smode, "srcreg", curi->size, "offs", 1, 0); printf ("\tm68k_areg(regs, 7) += offs;\n"); printf ("\tm68k_setpc_rte(pc);\n"); fill_prefetch_0 (); /* PC is set and prefetch filled. */ m68k_pc_offset = 0; break; case i_LINK: genamode (Apdi, "7", sz_long, "old", 2, 0); genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); genastore ("src", Apdi, "7", sz_long, "old"); genastore ("m68k_areg(regs, 7)", curi->smode, "srcreg", sz_long, "src"); genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0); printf ("\tm68k_areg(regs, 7) += offs;\n"); break; case i_UNLK: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tm68k_areg(regs, 7) = src;\n"); genamode (Aipi, "7", sz_long, "old", 1, 0); genastore ("old", curi->smode, "srcreg", curi->size, "src"); break; case i_RTS: printf ("\tm68k_do_rts();\n"); fill_prefetch_0 (); m68k_pc_offset = 0; break; case i_TRAPV: sync_m68k_pc (); printf ("\tif (GET_VFLG) { Exception(7,m68k_getpc()); goto %s; }\n", endlabelstr); need_endlabel = 1; break; case i_RTR: printf ("\tMakeSR();\n"); genamode (Aipi, "7", sz_word, "sr", 1, 0); genamode (Aipi, "7", sz_long, "pc", 1, 0); printf ("\tregs.sr &= 0xFF00; sr &= 0xFF;\n"); printf ("\tregs.sr |= sr; m68k_setpc(pc);\n"); fill_prefetch_0 (); printf ("\tMakeFromSR();\n"); m68k_pc_offset = 0; break; case i_JSR: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); printf ("\tm68k_do_jsr(m68k_getpc() + %d, srca);\n", m68k_pc_offset); fill_prefetch_0 (); m68k_pc_offset = 0; break; case i_JMP: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); printf ("\tm68k_setpc(srca);\n"); fill_prefetch_0 (); m68k_pc_offset = 0; break; case i_BSR: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tuae_s32 s = (uae_s32)src + 2;\n"); if (using_exception_3) { printf ("\tif (src & 1) {\n"); printf ("\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); printf ("\t\tlast_fault_for_exception_3 = m68k_getpc() + s;\n"); printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); printf ("\t}\n"); need_endlabel = 1; } printf ("\tm68k_do_bsr(m68k_getpc() + %d, s);\n", m68k_pc_offset); fill_prefetch_0 (); m68k_pc_offset = 0; break; case i_Bcc: if (0 && !using_prefetch && !using_exception_3 && (cpu_level >= 2)) { /* gb-- variant probably more favorable to compiler optimizations also assumes no prefetch buffer is used Hmm, that would make sense with processors capable of conditional moves */ if (curi->size == sz_long && next_cpu_level < 1) next_cpu_level = 1; genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tm68k_incpc (cctrue(%d) ? ((uae_s32)src + 2) : %d);\n", curi->cc, m68k_pc_offset); m68k_pc_offset = 0; } else { /* original code for branch instructions */ if (curi->size == sz_long) { if (cpu_level < 2) { printf ("\tm68k_incpc(2);\n"); printf ("\tif (!cctrue(%d)) goto %s;\n", curi->cc, endlabelstr); printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); printf ("\t\tlast_fault_for_exception_3 = m68k_getpc() + 1;\n"); printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); need_endlabel = 1; } else { if (next_cpu_level < 1) next_cpu_level = 1; } } genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tif (!cctrue(%d)) goto didnt_jump;\n", curi->cc); if (using_exception_3) { printf ("\tif (src & 1) {\n"); printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); printf ("\t\tlast_fault_for_exception_3 = m68k_getpc() + 2 + (uae_s32)src;\n"); printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); printf ("\t}\n"); need_endlabel = 1; } printf ("\tm68k_incpc ((uae_s32)src + 2);\n"); fill_prefetch_0 (); printf ("return;\n"); printf ("didnt_jump:;\n"); need_endlabel = 1; } break; case i_LEA: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); genastore ("srca", curi->dmode, "dstreg", curi->size, "dst"); break; case i_PEA: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); genamode (Apdi, "7", sz_long, "dst", 2, 0); genastore ("srca", Apdi, "7", sz_long, "dst"); break; case i_DBcc: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0); printf ("\tif (!cctrue(%d)) {\n", curi->cc); genastore ("(src-1)", curi->smode, "srcreg", curi->size, "src"); printf ("\t\tif (src) {\n"); if (using_exception_3) { printf ("\t\t\tif (offs & 1) {\n"); printf ("\t\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); printf ("\t\t\tlast_fault_for_exception_3 = m68k_getpc() + 2 + (uae_s32)offs + 2;\n"); printf ("\t\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); printf ("\t\t}\n"); need_endlabel = 1; } printf ("\t\t\tm68k_incpc((uae_s32)offs + 2);\n"); fill_prefetch_0 (); printf ("return;\n"); printf ("\t\t}\n"); printf ("\t}\n"); need_endlabel = 1; break; case i_Scc: genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); start_brace (); printf ("\tint val = cctrue(%d) ? 0xff : 0;\n", curi->cc); genastore ("val", curi->smode, "srcreg", curi->size, "src"); break; case i_DIVU: printf ("\tuaecptr oldpc = m68k_getpc();\n"); genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); sync_m68k_pc (); /* Clear V flag when dividing by zero - Alcatraz Odyssey demo depends * on this (actually, it's doing a DIVS). */ printf ("\tif (src == 0) { SET_VFLG (0); Exception (5, oldpc); goto %s; } else {\n", endlabelstr); printf ("\tuae_u32 newv = (uae_u32)dst / (uae_u32)(uae_u16)src;\n"); printf ("\tuae_u32 rem = (uae_u32)dst %% (uae_u32)(uae_u16)src;\n"); /* The N flag appears to be set each time there is an overflow. * Weird. */ printf ("\tif (newv > 0xffff) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else\n\t{\n"); genflags (flag_logical, sz_word, "newv", "", ""); printf ("\tnewv = (newv & 0xffff) | ((uae_u32)rem << 16);\n"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); printf ("\t}\n"); printf ("\t}\n"); insn_n_cycles += 68; need_endlabel = 1; break; case i_DIVS: printf ("\tuaecptr oldpc = m68k_getpc();\n"); genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); sync_m68k_pc (); printf ("\tif (src == 0) { SET_VFLG (0); Exception(5,oldpc); goto %s; } else {\n", endlabelstr); printf ("\tuae_s32 newv = (uae_s32)dst / (uae_s32)(uae_s16)src;\n"); printf ("\tuae_u16 rem = (uae_s32)dst %% (uae_s32)(uae_s16)src;\n"); printf ("\tif ((newv & 0xffff8000) != 0 && (newv & 0xffff8000) != 0xffff8000) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else\n\t{\n"); printf ("\tif (((uae_s16)rem < 0) != ((uae_s32)dst < 0)) rem = -rem;\n"); genflags (flag_logical, sz_word, "newv", "", ""); printf ("\tnewv = (newv & 0xffff) | ((uae_u32)rem << 16);\n"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); printf ("\t}\n"); printf ("\t}\n"); insn_n_cycles += 72; need_endlabel = 1; break; case i_MULU: genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0); start_brace (); printf ("\tuae_u32 newv = (uae_u32)(uae_u16)dst * (uae_u32)(uae_u16)src;\n"); genflags (flag_logical, sz_long, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); insn_n_cycles += 32; break; case i_MULS: genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0); start_brace (); printf ("\tuae_u32 newv = (uae_s32)(uae_s16)dst * (uae_s32)(uae_s16)src;\n"); genflags (flag_logical, sz_long, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); insn_n_cycles += 32; break; case i_CHK: printf ("\tuaecptr oldpc = m68k_getpc();\n"); genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); printf ("\tif ((uae_s32)dst < 0) { SET_NFLG (1); Exception(6,oldpc); goto %s; }\n", endlabelstr); printf ("\telse if (dst > src) { SET_NFLG (0); Exception(6,oldpc); goto %s; }\n", endlabelstr); need_endlabel = 1; break; case i_CHK2: printf ("\tuaecptr oldpc = m68k_getpc();\n"); genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); printf ("\t{uae_s32 upper,lower,reg = regs.regs[(extra >> 12) & 15];\n"); switch (curi->size) { case sz_byte: printf ("\tlower=(uae_s32)(uae_s8)get_byte(dsta); upper = (uae_s32)(uae_s8)get_byte(dsta+1);\n"); printf ("\tif ((extra & 0x8000) == 0) reg = (uae_s32)(uae_s8)reg;\n"); break; case sz_word: printf ("\tlower=(uae_s32)(uae_s16)get_word(dsta); upper = (uae_s32)(uae_s16)get_word(dsta+2);\n"); printf ("\tif ((extra & 0x8000) == 0) reg = (uae_s32)(uae_s16)reg;\n"); break; case sz_long: printf ("\tlower=get_long(dsta); upper = get_long(dsta+4);\n"); break; default: abort (); } printf ("\tSET_ZFLG (upper == reg || lower == reg);\n"); printf ("\tSET_CFLG_ALWAYS (lower <= upper ? reg < lower || reg > upper : reg > upper || reg < lower);\n"); printf ("\tif ((extra & 0x800) && GET_CFLG) { Exception(6,oldpc); goto %s; }\n}\n", endlabelstr); need_endlabel = 1; break; case i_ASR: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 sign = (%s & val) >> %d;\n", cmask (curi->size), bit_size (curi->size) - 1); printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tval = %s & (uae_u32)-sign;\n", bit_mask (curi->size)); printf ("\t\tSET_CFLG (sign);\n"); duplicate_carry (); if (source_is_imm1_8 (curi)) printf ("\t} else {\n"); else printf ("\t} else if (cnt > 0) {\n"); printf ("\t\tval >>= cnt - 1;\n"); printf ("\t\tSET_CFLG (val & 1);\n"); duplicate_carry (); printf ("\t\tval >>= 1;\n"); printf ("\t\tval |= (%s << (%d - cnt)) & (uae_u32)-sign;\n", bit_mask (curi->size), bit_size (curi->size)); printf ("\t\tval &= %s;\n", bit_mask (curi->size)); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_ASL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tSET_VFLG (val != 0);\n"); printf ("\t\tSET_CFLG (cnt == %d ? val & 1 : 0);\n", bit_size (curi->size)); duplicate_carry (); printf ("\t\tval = 0;\n"); if (source_is_imm1_8 (curi)) printf ("\t} else {\n"); else printf ("\t} else if (cnt > 0) {\n"); printf ("\t\tuae_u32 mask = (%s << (%d - cnt)) & %s;\n", bit_mask (curi->size), bit_size (curi->size) - 1, bit_mask (curi->size)); printf ("\t\tSET_VFLG ((val & mask) != mask && (val & mask) != 0);\n"); printf ("\t\tval <<= cnt - 1;\n"); printf ("\t\tSET_CFLG ((val & %s) >> %d);\n", cmask (curi->size), bit_size (curi->size) - 1); duplicate_carry (); printf ("\t\tval <<= 1;\n"); printf ("\t\tval &= %s;\n", bit_mask (curi->size)); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_LSR: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tSET_CFLG ((cnt == %d) & (val >> %d));\n", bit_size (curi->size), bit_size (curi->size) - 1); duplicate_carry (); printf ("\t\tval = 0;\n"); if (source_is_imm1_8 (curi)) printf ("\t} else {\n"); else printf ("\t} else if (cnt > 0) {\n"); printf ("\t\tval >>= cnt - 1;\n"); printf ("\t\tSET_CFLG (val & 1);\n"); duplicate_carry (); printf ("\t\tval >>= 1;\n"); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_LSL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tSET_CFLG (cnt == %d ? val & 1 : 0);\n", bit_size (curi->size)); duplicate_carry (); printf ("\t\tval = 0;\n"); if (source_is_imm1_8 (curi)) printf ("\t} else {\n"); else printf ("\t} else if (cnt > 0) {\n"); printf ("\t\tval <<= (cnt - 1);\n"); printf ("\t\tSET_CFLG ((val & %s) >> %d);\n", cmask (curi->size), bit_size (curi->size) - 1); duplicate_carry (); printf ("\t\tval <<= 1;\n"); printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_ROL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); else printf ("\tif (cnt > 0) {\n"); printf ("\tuae_u32 loval;\n"); printf ("\tcnt &= %d;\n", bit_size (curi->size) - 1); printf ("\tloval = val >> (%d - cnt);\n", bit_size (curi->size)); printf ("\tval <<= cnt;\n"); printf ("\tval |= loval;\n"); printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\tSET_CFLG (val & 1);\n"); printf ("}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_ROR: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); else printf ("\tif (cnt > 0) {"); printf ("\tuae_u32 hival;\n"); printf ("\tcnt &= %d;\n", bit_size (curi->size) - 1); printf ("\thival = val << (%d - cnt);\n", bit_size (curi->size)); printf ("\tval >>= cnt;\n"); printf ("\tval |= hival;\n"); printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\tSET_CFLG ((val & %s) >> %d);\n", cmask (curi->size), bit_size (curi->size) - 1); printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_ROXL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); else { force_range_for_rox ("cnt", curi->size); printf ("\tif (cnt > 0) {\n"); } printf ("\tcnt--;\n"); printf ("\t{\n\tuae_u32 carry;\n"); printf ("\tuae_u32 loval = val >> (%d - cnt);\n", bit_size (curi->size) - 1); printf ("\tcarry = loval & 1;\n"); printf ("\tval = (((val << 1) | GET_XFLG) << cnt) | (loval >> 1);\n"); printf ("\tSET_XFLG (carry);\n"); printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\t} }\n"); printf ("\tSET_CFLG (GET_XFLG);\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_ROXR: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tcnt &= 63;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); else { force_range_for_rox ("cnt", curi->size); printf ("\tif (cnt > 0) {\n"); } printf ("\tcnt--;\n"); printf ("\t{\n\tuae_u32 carry;\n"); printf ("\tuae_u32 hival = (val << 1) | GET_XFLG;\n"); printf ("\thival <<= (%d - cnt);\n", bit_size (curi->size) - 1); printf ("\tval >>= cnt;\n"); printf ("\tcarry = val & 1;\n"); printf ("\tval >>= 1;\n"); printf ("\tval |= hival;\n"); printf ("\tSET_XFLG (carry);\n"); printf ("\tval &= %s;\n", bit_mask (curi->size)); printf ("\t} }\n"); printf ("\tSET_CFLG (GET_XFLG);\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); break; case i_ASRW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 sign = %s & val;\n", cmask (curi->size)); printf ("\tuae_u32 cflg = val & 1;\n"); printf ("\tval = (val >> 1) | sign;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry (); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_ASLW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 sign = %s & val;\n", cmask (curi->size)); printf ("\tuae_u32 sign2;\n"); printf ("\tval <<= 1;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("\tsign2 = %s & val;\n", cmask (curi->size)); printf ("\tSET_CFLG (sign != 0);\n"); duplicate_carry (); printf ("\tSET_VFLG (GET_VFLG | (sign2 != sign));\n"); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_LSRW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u32 val = (uae_u8)data;\n"); break; case sz_word: printf ("\tuae_u32 val = (uae_u16)data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 carry = val & 1;\n"); printf ("\tval >>= 1;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry);\n"); duplicate_carry (); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_LSLW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; case sz_word: printf ("\tuae_u16 val = data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 carry = val & %s;\n", cmask (curi->size)); printf ("\tval <<= 1;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); duplicate_carry (); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_ROLW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; case sz_word: printf ("\tuae_u16 val = data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 carry = val & %s;\n", cmask (curi->size)); printf ("\tval <<= 1;\n"); printf ("\tif (carry) val |= 1;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_RORW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; case sz_word: printf ("\tuae_u16 val = data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 carry = val & 1;\n"); printf ("\tval >>= 1;\n"); printf ("\tif (carry) val |= %s;\n", cmask (curi->size)); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry);\n"); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_ROXLW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; case sz_word: printf ("\tuae_u16 val = data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 carry = val & %s;\n", cmask (curi->size)); printf ("\tval <<= 1;\n"); printf ("\tif (GET_XFLG) val |= 1;\n"); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1); duplicate_carry (); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_ROXRW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); start_brace (); switch (curi->size) { case sz_byte: printf ("\tuae_u8 val = data;\n"); break; case sz_word: printf ("\tuae_u16 val = data;\n"); break; case sz_long: printf ("\tuae_u32 val = data;\n"); break; default: abort (); } printf ("\tuae_u32 carry = val & 1;\n"); printf ("\tval >>= 1;\n"); printf ("\tif (GET_XFLG) val |= %s;\n", cmask (curi->size)); genflags (flag_logical, curi->size, "val", "", ""); printf ("SET_CFLG (carry);\n"); duplicate_carry (); genastore ("val", curi->smode, "srcreg", curi->size, "data"); break; case i_MOVEC2: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); printf ("\tint regno = (src >> 12) & 15;\n"); printf ("\tuae_u32 *regp = regs.regs + regno;\n"); printf ("\tif (! m68k_movec2(src & 0xFFF, regp)) goto %s;\n", endlabelstr); break; case i_MOVE2C: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); printf ("\tint regno = (src >> 12) & 15;\n"); printf ("\tuae_u32 *regp = regs.regs + regno;\n"); printf ("\tif (! m68k_move2c(src & 0xFFF, regp)) goto %s;\n", endlabelstr); break; case i_CAS: { int old_brace_level; genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); printf ("\tint ru = (src >> 6) & 7;\n"); printf ("\tint rc = src & 7;\n"); genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, rc)", "dst"); printf ("\tif (GET_ZFLG)"); old_brace_level = n_braces; start_brace (); genastore ("(m68k_dreg(regs, ru))", curi->dmode, "dstreg", curi->size, "dst"); pop_braces (old_brace_level); printf ("else"); start_brace (); printf ("m68k_dreg(regs, rc) = dst;\n"); pop_braces (old_brace_level); } break; case i_CAS2: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); printf ("\tuae_u32 rn1 = regs.regs[(extra >> 28) & 15];\n"); printf ("\tuae_u32 rn2 = regs.regs[(extra >> 12) & 15];\n"); if (curi->size == sz_word) { int old_brace_level = n_braces; printf ("\tuae_u16 dst1 = get_word(rn1), dst2 = get_word(rn2);\n"); genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, (extra >> 16) & 7)", "dst1"); printf ("\tif (GET_ZFLG) {\n"); genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, extra & 7)", "dst2"); printf ("\tif (GET_ZFLG) {\n"); printf ("\tput_word(rn1, m68k_dreg(regs, (extra >> 22) & 7));\n"); printf ("\tput_word(rn1, m68k_dreg(regs, (extra >> 6) & 7));\n"); printf ("\t}}\n"); pop_braces (old_brace_level); printf ("\tif (! GET_ZFLG) {\n"); printf ("\tm68k_dreg(regs, (extra >> 22) & 7) = (m68k_dreg(regs, (extra >> 22) & 7) & ~0xffff) | (dst1 & 0xffff);\n"); printf ("\tm68k_dreg(regs, (extra >> 6) & 7) = (m68k_dreg(regs, (extra >> 6) & 7) & ~0xffff) | (dst2 & 0xffff);\n"); printf ("\t}\n"); } else { int old_brace_level = n_braces; printf ("\tuae_u32 dst1 = get_long(rn1), dst2 = get_long(rn2);\n"); genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, (extra >> 16) & 7)", "dst1"); printf ("\tif (GET_ZFLG) {\n"); genflags (flag_cmp, curi->size, "newv", "m68k_dreg(regs, extra & 7)", "dst2"); printf ("\tif (GET_ZFLG) {\n"); printf ("\tput_long(rn1, m68k_dreg(regs, (extra >> 22) & 7));\n"); printf ("\tput_long(rn1, m68k_dreg(regs, (extra >> 6) & 7));\n"); printf ("\t}}\n"); pop_braces (old_brace_level); printf ("\tif (! GET_ZFLG) {\n"); printf ("\tm68k_dreg(regs, (extra >> 22) & 7) = dst1;\n"); printf ("\tm68k_dreg(regs, (extra >> 6) & 7) = dst2;\n"); printf ("\t}\n"); } break; case i_MOVES: /* ignore DFC and SFC because we have no MMU */ { int old_brace_level; genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); printf ("\tif (extra & 0x800)\n"); old_brace_level = n_braces; start_brace (); printf ("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n"); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); pop_braces (old_brace_level); printf ("else"); start_brace (); genamode (curi->dmode, "dstreg", curi->size, "src", 1, 0); printf ("\tif (extra & 0x8000) {\n"); switch (curi->size) { case sz_byte: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s8)src;\n"); break; case sz_word: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s16)src;\n"); break; case sz_long: printf ("\tm68k_areg(regs, (extra >> 12) & 7) = src;\n"); break; default: abort (); } printf ("\t} else {\n"); genastore ("src", Dreg, "(extra >> 12) & 7", curi->size, ""); printf ("\t}\n"); pop_braces (old_brace_level); } break; case i_BKPT: /* only needed for hardware emulators */ sync_m68k_pc (); printf ("\top_illg(opcode);\n"); break; case i_CALLM: /* not present in 68030 */ sync_m68k_pc (); printf ("\top_illg(opcode);\n"); break; case i_RTM: /* not present in 68030 */ sync_m68k_pc (); printf ("\top_illg(opcode);\n"); break; case i_TRAPcc: if (curi->smode != am_unknown && curi->smode != am_illg) genamode (curi->smode, "srcreg", curi->size, "dummy", 1, 0); printf ("\tif (cctrue(%d)) { Exception(7,m68k_getpc()); goto %s; }\n", curi->cc, endlabelstr); need_endlabel = 1; break; case i_DIVL: sync_m68k_pc (); start_brace (); printf ("\tuaecptr oldpc = m68k_getpc();\n"); genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); sync_m68k_pc (); printf ("\tm68k_divl(opcode, dst, extra, oldpc);\n"); break; case i_MULL: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); sync_m68k_pc (); printf ("\tm68k_mull(opcode, dst, extra);\n"); break; case i_BFTST: case i_BFEXTU: case i_BFCHG: case i_BFEXTS: case i_BFCLR: case i_BFFFO: case i_BFSET: case i_BFINS: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 2, 0); start_brace (); printf ("\tuae_s32 offset = extra & 0x800 ? m68k_dreg(regs, (extra >> 6) & 7) : (extra >> 6) & 0x1f;\n"); printf ("\tint width = (((extra & 0x20 ? m68k_dreg(regs, extra & 7) : extra) -1) & 0x1f) +1;\n"); if (curi->dmode == Dreg) { printf ("\tuae_u32 tmp = m68k_dreg(regs, dstreg) << (offset & 0x1f);\n"); } else { printf ("\tuae_u32 tmp,bf0,bf1;\n"); printf ("\tdsta += (offset >> 3) | (offset & 0x80000000 ? ~0x1fffffff : 0);\n"); printf ("\tbf0 = get_long(dsta);bf1 = get_byte(dsta+4) & 0xff;\n"); printf ("\ttmp = (bf0 << (offset & 7)) | (bf1 >> (8 - (offset & 7)));\n"); } printf ("\ttmp >>= (32 - width);\n"); printf ("\tSET_NFLG_ALWAYS (tmp & (1 << (width-1)) ? 1 : 0);\n"); printf ("\tSET_ZFLG (tmp == 0); SET_VFLG (0); SET_CFLG (0);\n"); switch (curi->mnemo) { case i_BFTST: break; case i_BFEXTU: printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = tmp;\n"); break; case i_BFCHG: printf ("\ttmp = ~tmp;\n"); break; case i_BFEXTS: printf ("\tif (GET_NFLG) tmp |= width == 32 ? 0 : (-1 << width);\n"); printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = tmp;\n"); break; case i_BFCLR: printf ("\ttmp = 0;\n"); break; case i_BFFFO: printf ("\t{ uae_u32 mask = 1 << (width-1);\n"); printf ("\twhile (mask) { if (tmp & mask) break; mask >>= 1; offset++; }}\n"); printf ("\tm68k_dreg(regs, (extra >> 12) & 7) = offset;\n"); break; case i_BFSET: printf ("\ttmp = 0xffffffff;\n"); break; case i_BFINS: printf ("\ttmp = m68k_dreg(regs, (extra >> 12) & 7);\n"); printf ("\tSET_NFLG_ALWAYS (tmp & (1 << (width - 1)) ? 1 : 0);\n"); printf ("\tSET_ZFLG (tmp == 0);\n"); break; default: break; } if (curi->mnemo == i_BFCHG || curi->mnemo == i_BFCLR || curi->mnemo == i_BFSET || curi->mnemo == i_BFINS) { printf ("\ttmp <<= (32 - width);\n"); if (curi->dmode == Dreg) { printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & ((offset & 0x1f) == 0 ? 0 :\n"); printf ("\t\t(0xffffffff << (32 - (offset & 0x1f))))) |\n"); printf ("\t\t(tmp >> (offset & 0x1f)) |\n"); printf ("\t\t(((offset & 0x1f) + width) >= 32 ? 0 :\n"); printf (" (m68k_dreg(regs, dstreg) & ((uae_u32)0xffffffff >> ((offset & 0x1f) + width))));\n"); } else { printf ("\tbf0 = (bf0 & (0xff000000 << (8 - (offset & 7)))) |\n"); printf ("\t\t(tmp >> (offset & 7)) |\n"); printf ("\t\t(((offset & 7) + width) >= 32 ? 0 :\n"); printf ("\t\t (bf0 & ((uae_u32)0xffffffff >> ((offset & 7) + width))));\n"); printf ("\tput_long(dsta,bf0 );\n"); printf ("\tif (((offset & 7) + width) > 32) {\n"); printf ("\t\tbf1 = (bf1 & (0xff >> (width - 32 + (offset & 7)))) |\n"); printf ("\t\t\t(tmp << (8 - (offset & 7)));\n"); printf ("\t\tput_byte(dsta+4,bf1);\n"); printf ("\t}\n"); } } break; case i_PACK: if (curi->smode == Dreg) { printf ("\tuae_u16 val = m68k_dreg(regs, srcreg) + %s;\n", gen_nextiword ()); printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & 0xffffff00) | ((val >> 4) & 0xf0) | (val & 0xf);\n"); } else { printf ("\tuae_u16 val;\n"); printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n"); printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg));\n"); printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n"); printf ("\tval = (val | ((uae_u16)get_byte(m68k_areg(regs, srcreg)) << 8)) + %s;\n", gen_nextiword ()); printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n"); printf ("\tput_byte(m68k_areg(regs, dstreg),((val >> 4) & 0xf0) | (val & 0xf));\n"); } break; case i_UNPK: if (curi->smode == Dreg) { printf ("\tuae_u16 val = m68k_dreg(regs, srcreg);\n"); printf ("\tval = (((val << 4) & 0xf00) | (val & 0xf)) + %s;\n", gen_nextiword ()); printf ("\tm68k_dreg(regs, dstreg) = (m68k_dreg(regs, dstreg) & 0xffff0000) | (val & 0xffff);\n"); } else { printf ("\tuae_u16 val;\n"); printf ("\tm68k_areg(regs, srcreg) -= areg_byteinc[srcreg];\n"); printf ("\tval = (uae_u16)get_byte(m68k_areg(regs, srcreg));\n"); printf ("\tval = (((val << 4) & 0xf00) | (val & 0xf)) + %s;\n", gen_nextiword ()); printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n"); printf ("\tput_byte(m68k_areg(regs, dstreg),val);\n"); printf ("\tm68k_areg(regs, dstreg) -= areg_byteinc[dstreg];\n"); printf ("\tput_byte(m68k_areg(regs, dstreg),val >> 8);\n"); } break; case i_TAS: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genflags (flag_logical, curi->size, "src", "", ""); printf ("\tsrc |= 0x80;\n"); genastore ("src", curi->smode, "srcreg", curi->size, "src"); break; case i_FPP: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_arithmetic(opcode, extra);\n"); break; case i_FDBcc: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_dbcc(opcode, extra);\n"); break; case i_FScc: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_scc(opcode,extra);\n"); break; case i_FTRAPcc: sync_m68k_pc (); start_brace (); printf ("\tuaecptr oldpc = m68k_getpc();\n"); if (curi->smode != am_unknown && curi->smode != am_illg) genamode (curi->smode, "srcreg", curi->size, "dummy", 1, 0); sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_trapcc(opcode,oldpc);\n"); break; case i_FBcc: sync_m68k_pc (); start_brace (); printf ("\tuaecptr pc = m68k_getpc();\n"); genamode (curi->dmode, "srcreg", curi->size, "extra", 1, 0); sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_bcc(opcode,pc,extra);\n"); break; case i_FSAVE: sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_save(opcode);\n"); break; case i_FRESTORE: sync_m68k_pc (); swap_opcode (); printf ("\tfpuop_restore(opcode);\n"); break; case i_CINVL: case i_CINVP: case i_CINVA: /* gb-- srcreg now contains the cache field */ printf ("\tif (srcreg&0x2)\n"); printf ("\t\tflush_icache(%d);\n", 30 + ((opcode >> 3) & 3)); break; case i_CPUSHL: case i_CPUSHP: case i_CPUSHA: /* gb-- srcreg now contains the cache field */ printf ("\tif (srcreg&0x2)\n"); printf ("\t\tflush_icache(%d);\n", 40 + ((opcode >> 3) & 3)); break; case i_MOVE16: if ((opcode & 0xfff8) == 0xf620) { /* MOVE16 (Ax)+,(Ay)+ */ printf ("\tuaecptr mems = m68k_areg(regs, srcreg) & ~15, memd;\n"); printf ("\tdstreg = (%s >> 12) & 7;\n", gen_nextiword()); printf ("\tmemd = m68k_areg(regs, dstreg) & ~15;\n"); printf ("\tput_long(memd, get_long(mems));\n"); printf ("\tput_long(memd+4, get_long(mems+4));\n"); printf ("\tput_long(memd+8, get_long(mems+8));\n"); printf ("\tput_long(memd+12, get_long(mems+12));\n"); printf ("\tif (srcreg != dstreg)\n"); printf ("\tm68k_areg(regs, srcreg) += 16;\n"); printf ("\tm68k_areg(regs, dstreg) += 16;\n"); } else { /* Other variants */ genamode (curi->smode, "srcreg", curi->size, "mems", 0, 2); genamode (curi->dmode, "dstreg", curi->size, "memd", 0, 2); printf ("\tmemsa &= ~15;\n"); printf ("\tmemda &= ~15;\n"); printf ("\tput_long(memda, get_long(memsa));\n"); printf ("\tput_long(memda+4, get_long(memsa+4));\n"); printf ("\tput_long(memda+8, get_long(memsa+8));\n"); printf ("\tput_long(memda+12, get_long(memsa+12));\n"); if ((opcode & 0xfff8) == 0xf600) printf ("\tm68k_areg(regs, srcreg) += 16;\n"); else if ((opcode & 0xfff8) == 0xf608) printf ("\tm68k_areg(regs, dstreg) += 16;\n"); } break; case i_MMUOP: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); sync_m68k_pc (); swap_opcode (); printf ("\tmmu_op(opcode,extra);\n"); break; case i_EMULOP_RETURN: printf ("\tm68k_emulop_return();\n"); m68k_pc_offset = 0; break; case i_EMULOP: printf ("\n"); swap_opcode (); printf ("\tm68k_emulop(opcode);\n"); break; default: abort (); break; } finish_braces (); sync_m68k_pc (); } static void generate_includes (FILE * f) { fprintf (f, "#include \"sysdeps.h\"\n"); fprintf (f, "#include \"m68k.h\"\n"); fprintf (f, "#include \"memory.h\"\n"); fprintf (f, "#include \"readcpu.h\"\n"); fprintf (f, "#include \"newcpu.h\"\n"); fprintf (f, "#include \"compiler/compemu.h\"\n"); fprintf (f, "#include \"fpu/fpu.h\"\n"); fprintf (f, "#include \"cputbl.h\"\n"); fprintf (f, "#define SET_CFLG_ALWAYS(x) SET_CFLG(x)\n"); fprintf (f, "#define SET_NFLG_ALWAYS(x) SET_NFLG(x)\n"); fprintf (f, "#define CPUFUNC_FF(x) x##_ff\n"); fprintf (f, "#define CPUFUNC_NF(x) x##_nf\n"); fprintf (f, "#define CPUFUNC(x) CPUFUNC_FF(x)\n"); fprintf (f, "#ifdef NOFLAGS\n"); fprintf (f, "# include \"noflags.h\"\n"); fprintf (f, "#endif\n"); } static int postfix; static void generate_one_opcode (int rp) { uae_u16 smsk, dmsk; long int opcode = opcode_map[rp]; const char *opcode_str; if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level) return; if (table68k[opcode].handler != -1) return; opcode_str = get_instruction_string (opcode); if (opcode_next_clev[rp] != cpu_level) { if (table68k[opcode].flagdead == 0) /* force to the "ff" variant since the instruction doesn't set at all the condition codes */ fprintf (stblfile, "{ CPUFUNC_FF(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, opcode_last_postfix[rp], opcode, opcode_str); else fprintf (stblfile, "{ CPUFUNC(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, opcode_last_postfix[rp], opcode, opcode_str); return; } if (table68k[opcode].flagdead == 0) /* force to the "ff" variant since the instruction doesn't set at all the condition codes */ fprintf (stblfile, "{ CPUFUNC_FF(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, postfix, opcode, opcode_str); else fprintf (stblfile, "{ CPUFUNC(op_%lx_%d), 0, %ld }, /* %s */\n", opcode, postfix, opcode, opcode_str); fprintf (headerfile, "extern cpuop_func op_%lx_%d_nf;\n", opcode, postfix); fprintf (headerfile, "extern cpuop_func op_%lx_%d_ff;\n", opcode, postfix); /* gb-- The "nf" variant for an instruction that doesn't set the condition codes at all is the same as the "ff" variant, so we don't need the "nf" variant to be compiled since it is mapped to the "ff" variant in the smalltbl. */ if (table68k[opcode].flagdead == 0) printf ("#ifndef NOFLAGS\n"); printf ("void REGPARAM2 CPUFUNC(op_%lx_%d)(uae_u32 opcode) /* %s */\n{\n", opcode, postfix, opcode_str); printf ("\tcpuop_begin();\n"); switch (table68k[opcode].stype) { case 0: smsk = 7; break; case 1: smsk = 255; break; case 2: smsk = 15; break; case 3: smsk = 7; break; case 4: smsk = 7; break; case 5: smsk = 63; break; case 6: smsk = 255; break; case 7: smsk = 3; break; default: abort (); } dmsk = 7; next_cpu_level = -1; if (table68k[opcode].suse && table68k[opcode].smode != imm && table68k[opcode].smode != imm0 && table68k[opcode].smode != imm1 && table68k[opcode].smode != imm2 && table68k[opcode].smode != absw && table68k[opcode].smode != absl && table68k[opcode].smode != PC8r && table68k[opcode].smode != PC16 /* gb-- We don't want to fetch the EmulOp code since the EmulOp() routine uses the whole opcode value. Maybe all the EmulOps could be expanded out but I don't think it is an improvement */ && table68k[opcode].stype != 6 ) { if (table68k[opcode].spos == -1) { if (((int) table68k[opcode].sreg) >= 128) printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].sreg); else printf ("\tuae_u32 srcreg = %d;\n", (int) table68k[opcode].sreg); } else { char source[100]; int pos = table68k[opcode].spos; #if 0 /* Check that we can do the little endian optimization safely. */ if (pos < 8 && (smsk >> (8 - pos)) != 0) abort (); #endif printf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); if (pos < 8 && (smsk >> (8 - pos)) != 0) sprintf (source, "(((opcode >> %d) | (opcode << %d)) & %d)", pos ^ 8, 8 - pos, dmsk); else if (pos != 8) sprintf (source, "((opcode >> %d) & %d)", pos ^ 8, smsk); else sprintf (source, "(opcode & %d)", smsk); if (table68k[opcode].stype == 3) printf ("\tuae_u32 srcreg = imm8_table[%s];\n", source); else if (table68k[opcode].stype == 1) printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%s;\n", source); else printf ("\tuae_u32 srcreg = %s;\n", source); printf ("#else\n"); if (pos) sprintf (source, "((opcode >> %d) & %d)", pos, smsk); else sprintf (source, "(opcode & %d)", smsk); if (table68k[opcode].stype == 3) printf ("\tuae_u32 srcreg = imm8_table[%s];\n", source); else if (table68k[opcode].stype == 1) printf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%s;\n", source); else printf ("\tuae_u32 srcreg = %s;\n", source); printf ("#endif\n"); } } if (table68k[opcode].duse /* Yes, the dmode can be imm, in case of LINK or DBcc */ && table68k[opcode].dmode != imm && table68k[opcode].dmode != imm0 && table68k[opcode].dmode != imm1 && table68k[opcode].dmode != imm2 && table68k[opcode].dmode != absw && table68k[opcode].dmode != absl) { if (table68k[opcode].dpos == -1) { if (((int) table68k[opcode].dreg) >= 128) printf ("\tuae_u32 dstreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].dreg); else printf ("\tuae_u32 dstreg = %d;\n", (int) table68k[opcode].dreg); } else { int pos = table68k[opcode].dpos; #if 0 /* Check that we can do the little endian optimization safely. */ if (pos < 8 && (dmsk >> (8 - pos)) != 0) abort (); #endif printf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); if (pos < 8 && (dmsk >> (8 - pos)) != 0) printf ("\tuae_u32 dstreg = ((opcode >> %d) | (opcode << %d)) & %d;\n", pos ^ 8, 8 - pos, dmsk); else if (pos != 8) printf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n", pos ^ 8, dmsk); else printf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk); printf ("#else\n"); if (pos) printf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n", pos, dmsk); else printf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk); printf ("#endif\n"); } } need_endlabel = 0; endlabelno++; sprintf (endlabelstr, "endlabel%d", endlabelno); gen_opcode (opcode); if (need_endlabel) printf ("%s: ;\n", endlabelstr); printf ("\tcpuop_end();\n"); printf ("}\n"); if (table68k[opcode].flagdead == 0) printf ("\n#endif\n"); opcode_next_clev[rp] = next_cpu_level; opcode_last_postfix[rp] = postfix; } static void generate_func (void) { int i, j, rp; using_prefetch = 0; using_exception_3 = 0; #if !USE_PREFETCH_BUFFER /* gb-- No need for a prefetch buffer, nor exception 3 handling */ /* Anyway, Basilisk2 does not use the op_smalltbl_5 table... */ for (i = 0; i <= 4; i++) { #else for (i = 0; i < 6; i++) { #endif cpu_level = 4 - i; if (i == 5) { cpu_level = 0; using_prefetch = 1; using_exception_3 = 1; for (rp = 0; rp < nr_cpuop_funcs; rp++) opcode_next_clev[rp] = 0; } postfix = i; fprintf (stblfile, "struct cputbl CPUFUNC(op_smalltbl_%d)[] = {\n", postfix); /* sam: this is for people with low memory (eg. me :)) */ printf ("\n" "#if !defined(PART_1) && !defined(PART_2) && " "!defined(PART_3) && !defined(PART_4) && " "!defined(PART_5) && !defined(PART_6) && " "!defined(PART_7) && !defined(PART_8)" "\n" "#define PART_1 1\n" "#define PART_2 1\n" "#define PART_3 1\n" "#define PART_4 1\n" "#define PART_5 1\n" "#define PART_6 1\n" "#define PART_7 1\n" "#define PART_8 1\n" "#endif\n\n"); rp = 0; for(j=1;j<=8;++j) { int k = (j*nr_cpuop_funcs)/8; printf ("#ifdef PART_%d\n",j); for (; rp < k; rp++) generate_one_opcode (rp); printf ("#endif\n\n"); } fprintf (stblfile, "{ 0, 0, 0 }};\n"); } } int main (int argc, char **argv) { FILE *out; read_table68k (); do_merges (); opcode_map = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_last_postfix = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_next_clev = (int *) malloc (sizeof (int) * nr_cpuop_funcs); counts = (unsigned long *) malloc (65536 * sizeof (unsigned long)); read_counts (); /* It would be a lot nicer to put all in one file (we'd also get rid of * cputbl.h that way), but cpuopti can't cope. That could be fixed, but * I don't dare to touch the 68k version. */ headerfile = fopen ("cputbl.h", "w"); stblfile = fopen ("cpustbl.cpp", "w"); out = freopen ("cpuemu.cpp", "w", stdout); generate_includes (stdout); generate_includes (stblfile); generate_func (); free (table68k); fclose (headerfile); fclose (stblfile); fflush (out); return 0; } BasiliskII/src/uae_cpu/build68k.c0000644000175000017500000001501511735673707016767 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * Read 68000 CPU specs from file "table68k" and build table68k.c * * Copyright 1995,1996 Bernd Schmidt * * 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 */ #include #include #include #include "sysdeps.h" #include "readcpu.h" static FILE *tablef; static int nextch = 0; static void getnextch(void) { do { nextch = fgetc(tablef); if (nextch == '%') { do { nextch = fgetc(tablef); } while (nextch != EOF && nextch != '\n'); } } while (nextch != EOF && isspace(nextch)); } static int nextchtohex(void) { switch (isupper (nextch) ? tolower (nextch) : nextch) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; default: abort(); } } int main(int argc, char **argv) { int no_insns = 0; printf ("#include \"sysdeps.h\"\n"); printf ("#include \"readcpu.h\"\n"); printf ("struct instr_def defs68k[] = {\n"); #ifdef WIN32 tablef = fopen(argc > 1 ? argv[1] : "table68k","r"); if (tablef == NULL) { fprintf(stderr, "table68k not found\n"); exit(1); } #else tablef = stdin; #endif getnextch(); while (nextch != EOF) { int cpulevel, plevel, sduse; int i; char patbits[16]; char opcstr[256]; int bitpos[16]; int flagset[5], flaguse[5]; char cflow; unsigned int bitmask,bitpattern; int n_variable; n_variable = 0; bitmask = bitpattern = 0; memset (bitpos, 0, sizeof(bitpos)); for(i=0; i<16; i++) { int currbit; bitmask <<= 1; bitpattern <<= 1; switch (nextch) { case '0': currbit = bit0; bitmask |= 1; break; case '1': currbit = bit1; bitmask |= 1; bitpattern |= 1; break; case 'c': currbit = bitc; break; case 'C': currbit = bitC; break; case 'f': currbit = bitf; break; case 'i': currbit = biti; break; case 'I': currbit = bitI; break; case 'j': currbit = bitj; break; case 'J': currbit = bitJ; break; case 'k': currbit = bitk; break; case 'K': currbit = bitK; break; case 's': currbit = bits; break; case 'S': currbit = bitS; break; case 'd': currbit = bitd; break; case 'D': currbit = bitD; break; case 'r': currbit = bitr; break; case 'R': currbit = bitR; break; case 'z': currbit = bitz; break; case 'E': currbit = bitE; break; case 'p': currbit = bitp; break; default: abort(); } if (!(bitmask & 1)) { bitpos[n_variable] = currbit; n_variable++; } if (nextch == '0' || nextch == '1') bitmask |= 1; if (nextch == '1') bitpattern |= 1; patbits[i] = nextch; getnextch(); } while (isspace(nextch) || nextch == ':') /* Get CPU and privilege level */ getnextch(); switch (nextch) { case '0': cpulevel = 0; break; case '1': cpulevel = 1; break; case '2': cpulevel = 2; break; case '3': cpulevel = 3; break; case '4': cpulevel = 4; break; case '5': cpulevel = 5; break; default: abort(); } getnextch(); switch (nextch) { case '0': plevel = 0; break; case '1': plevel = 1; break; case '2': plevel = 2; break; case '3': plevel = 3; break; default: abort(); } getnextch(); while (isspace(nextch)) /* Get flag set information */ getnextch(); if (nextch != ':') abort(); for(i = 0; i < 5; i++) { getnextch(); switch(nextch){ case '-': flagset[i] = fa_unset; break; case '0': flagset[i] = fa_zero; break; case '1': flagset[i] = fa_one; break; case 'x': flagset[i] = fa_dontcare; break; case '?': flagset[i] = fa_unknown; break; default: flagset[i] = fa_set; break; } } getnextch(); while (isspace(nextch)) getnextch(); if (nextch != ':') /* Get flag used information */ abort(); for(i = 0; i < 5; i++) { getnextch(); switch(nextch){ case '-': flaguse[i] = fu_unused; break; case '?': flaguse[i] = fu_unknown; break; default: flaguse[i] = fu_used; break; } } getnextch(); while (isspace(nextch)) getnextch(); if (nextch != ':') /* Get control flow information */ abort(); cflow = 0; for(i = 0; i < 2; i++) { getnextch(); switch(nextch){ case '-': break; case 'R': cflow |= fl_return; break; case 'B': cflow |= fl_branch; break; case 'J': cflow |= fl_jump; break; case 'T': cflow |= fl_trap; break; default: abort(); } } getnextch(); while (isspace(nextch)) getnextch(); if (nextch != ':') /* Get source/dest usage information */ abort(); getnextch(); sduse = nextchtohex() << 4; getnextch(); sduse |= nextchtohex(); getnextch(); while (isspace(nextch)) getnextch(); if (nextch != ':') abort(); fgets(opcstr, 250, tablef); getnextch(); { int j; /* Remove superfluous spaces from the string */ char *opstrp = opcstr, *osendp; int slen = 0; while (isspace(*opstrp)) opstrp++; osendp = opstrp; while (*osendp) { if (!isspace (*osendp)) slen = osendp - opstrp + 1; osendp++; } opstrp[slen] = 0; if (no_insns > 0) printf(",\n"); no_insns++; printf("{ %d, %d, {", bitpattern, n_variable); for (j = 0; j < 16; j++) { printf("%d", bitpos[j]); if (j < 15) printf(","); } printf ("}, %d, %d, %d, { ", bitmask, cpulevel, plevel); for(i = 0; i < 5; i++) { printf("{ %d, %d }%c ", flaguse[i], flagset[i], i == 4 ? ' ' : ','); } printf("}, %d, %d, \"%s\"}", cflow, sduse, opstrp); } } printf("};\nint n_defs68k = %d;\n", no_insns); fflush(stdout); return 0; } BasiliskII/src/uae_cpu/compiler/0000755000175000017500000000000011735674761017004 5ustar centriscentrisBasiliskII/src/uae_cpu/compiler/compemu.h0000644000175000017500000004510110736405223020604 0ustar centriscentris/* * compiler/compemu.h - Public interface and definitions * * Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer * * Adaptation for Basilisk II and improvements, copyright 2000-2005 * Gwenole Beauchesne * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef COMPEMU_H #define COMPEMU_H #include "newcpu.h" #if USE_JIT #if defined __i386__ || defined __x86_64__ #include "flags_x86.h" #else #error "Unsupported JIT compiler for this architecture" #endif #if JIT_DEBUG /* dump some information (m68k block, x86 block addresses) about the compiler state */ extern void compiler_dumpstate(void); #endif /* Now that we do block chaining, and also have linked lists on each tag, TAGMASK can be much smaller and still do its job. Saves several megs of memory! */ #define TAGMASK 0x0000ffff #define TAGSIZE (TAGMASK+1) #define MAXRUN 1024 #define cacheline(x) (((uintptr)x)&TAGMASK) extern uae_u8* start_pc_p; extern uae_u32 start_pc; struct blockinfo_t; struct cpu_history { uae_u16 * location; }; union cacheline { cpuop_func * handler; blockinfo_t * bi; }; /* Use new spill/reload strategy when calling external functions */ #define USE_OPTIMIZED_CALLS 0 #if USE_OPTIMIZED_CALLS #error implementation in progress #endif /* (gb) When on, this option can save save up to 30% compilation time * when many lazy flushes occur (e.g. apps in MacOS 8.x). */ #define USE_SEPARATE_BIA 1 /* Use chain of checksum_info_t to compute the block checksum */ #define USE_CHECKSUM_INFO 1 /* Use code inlining, aka follow-up of constant jumps */ #define USE_INLINING 1 /* Inlining requires the chained checksuming information */ #if USE_INLINING #undef USE_CHECKSUM_INFO #define USE_CHECKSUM_INFO 1 #endif /* Does flush_icache_range() only check for blocks falling in the requested range? */ #define LAZY_FLUSH_ICACHE_RANGE 0 #define USE_F_ALIAS 1 #define USE_OFFSET 1 #define COMP_DEBUG 1 #if COMP_DEBUG #define Dif(x) if (x) #else #define Dif(x) if (0) #endif #define SCALE 2 #define BYTES_PER_INST 10240 /* paranoid ;-) */ #define LONGEST_68K_INST 16 /* The number of bytes the longest possible 68k instruction takes */ #define MAX_CHECKSUM_LEN 2048 /* The maximum size we calculate checksums for. Anything larger will be flushed unconditionally even with SOFT_FLUSH */ #define MAX_HOLD_BI 3 /* One for the current block, and up to two for jump targets */ #define INDIVIDUAL_INST 0 #if 1 // gb-- my format from readcpu.cpp is not the same #define FLAG_X 0x0010 #define FLAG_N 0x0008 #define FLAG_Z 0x0004 #define FLAG_V 0x0002 #define FLAG_C 0x0001 #else #define FLAG_C 0x0010 #define FLAG_V 0x0008 #define FLAG_Z 0x0004 #define FLAG_N 0x0002 #define FLAG_X 0x0001 #endif #define FLAG_CZNV (FLAG_C | FLAG_Z | FLAG_N | FLAG_V) #define FLAG_ZNV (FLAG_Z | FLAG_N | FLAG_V) #define KILLTHERAT 1 /* Set to 1 to avoid some partial_rat_stalls */ #if defined(__x86_64__) #define N_REGS 16 /* really only 15, but they are numbered 0-3,5-15 */ #else #define N_REGS 8 /* really only 7, but they are numbered 0,1,2,3,5,6,7 */ #endif #define N_FREGS 6 /* That leaves us two positions on the stack to play with */ /* Functions exposed to newcpu, or to what was moved from newcpu.c to * compemu_support.c */ extern void compiler_init(void); extern void compiler_exit(void); extern bool compiler_use_jit(void); extern void init_comp(void); extern void flush(int save_regs); extern void small_flush(int save_regs); extern void set_target(uae_u8* t); extern uae_u8* get_target(void); extern void freescratch(void); extern void build_comp(void); extern void set_cache_state(int enabled); extern int get_cache_state(void); extern uae_u32 get_jitted_size(void); extern void (*flush_icache)(int n); extern void alloc_cache(void); extern int check_for_cache_miss(void); /* JIT FPU compilation */ extern void comp_fpp_opp (uae_u32 opcode, uae_u16 extra); extern void comp_fbcc_opp (uae_u32 opcode); extern void comp_fscc_opp (uae_u32 opcode, uae_u16 extra); extern uae_u32 needed_flags; extern cacheline cache_tags[]; extern uae_u8* comp_pc_p; extern void* pushall_call_handler; #define VREGS 32 #define VFREGS 16 #define INMEM 1 #define CLEAN 2 #define DIRTY 3 #define UNDEF 4 #define ISCONST 5 typedef struct { uae_u32* mem; uae_u32 val; uae_u8 is_swapped; uae_u8 status; uae_s8 realreg; /* gb-- realreg can hold -1 */ uae_u8 realind; /* The index in the holds[] array */ uae_u8 needflush; uae_u8 validsize; uae_u8 dirtysize; uae_u8 dummy; } reg_status; typedef struct { uae_u32* mem; double val; uae_u8 status; uae_s8 realreg; /* gb-- realreg can hold -1 */ uae_u8 realind; uae_u8 needflush; } freg_status; #define PC_P 16 #define FLAGX 17 #define FLAGTMP 18 #define NEXT_HANDLER 19 #define S1 20 #define S2 21 #define S3 22 #define S4 23 #define S5 24 #define S6 25 #define S7 26 #define S8 27 #define S9 28 #define S10 29 #define S11 30 #define S12 31 #define FP_RESULT 8 #define FS1 9 #define FS2 10 #define FS3 11 typedef struct { uae_u32 touched; uae_s8 holds[VREGS]; uae_u8 nholds; uae_u8 canbyte; uae_u8 canword; uae_u8 locked; } n_status; typedef struct { uae_u32 touched; uae_s8 holds[VFREGS]; uae_u8 nholds; uae_u8 locked; } fn_status; /* For flag handling */ #define NADA 1 #define TRASH 2 #define VALID 3 /* needflush values */ #define NF_SCRATCH 0 #define NF_TOMEM 1 #define NF_HANDLER 2 typedef struct { /* Integer part */ reg_status state[VREGS]; n_status nat[N_REGS]; uae_u32 flags_on_stack; uae_u32 flags_in_flags; uae_u32 flags_are_important; /* FPU part */ freg_status fate[VFREGS]; fn_status fat[N_FREGS]; /* x86 FPU part */ uae_s8 spos[N_FREGS]; uae_s8 onstack[6]; uae_s8 tos; } bigstate; typedef struct { /* Integer part */ char virt[VREGS]; char nat[N_REGS]; } smallstate; extern bigstate live; extern int touchcnt; #define IMM uae_s32 #define R1 uae_u32 #define R2 uae_u32 #define R4 uae_u32 #define W1 uae_u32 #define W2 uae_u32 #define W4 uae_u32 #define RW1 uae_u32 #define RW2 uae_u32 #define RW4 uae_u32 #define MEMR uae_u32 #define MEMW uae_u32 #define MEMRW uae_u32 #define FW uae_u32 #define FR uae_u32 #define FRW uae_u32 #define MIDFUNC(nargs,func,args) void func args #define MENDFUNC(nargs,func,args) #define COMPCALL(func) func #define LOWFUNC(flags,mem,nargs,func,args) static __inline__ void func args #define LENDFUNC(flags,mem,nargs,func,args) /* What we expose to the outside */ #define DECLARE_MIDFUNC(func) extern void func DECLARE_MIDFUNC(bt_l_ri(R4 r, IMM i)); DECLARE_MIDFUNC(bt_l_rr(R4 r, R4 b)); DECLARE_MIDFUNC(btc_l_ri(RW4 r, IMM i)); DECLARE_MIDFUNC(btc_l_rr(RW4 r, R4 b)); DECLARE_MIDFUNC(bts_l_ri(RW4 r, IMM i)); DECLARE_MIDFUNC(bts_l_rr(RW4 r, R4 b)); DECLARE_MIDFUNC(btr_l_ri(RW4 r, IMM i)); DECLARE_MIDFUNC(btr_l_rr(RW4 r, R4 b)); DECLARE_MIDFUNC(mov_l_rm(W4 d, IMM s)); DECLARE_MIDFUNC(call_r(R4 r)); DECLARE_MIDFUNC(sub_l_mi(IMM d, IMM s)); DECLARE_MIDFUNC(mov_l_mi(IMM d, IMM s)); DECLARE_MIDFUNC(mov_w_mi(IMM d, IMM s)); DECLARE_MIDFUNC(mov_b_mi(IMM d, IMM s)); DECLARE_MIDFUNC(rol_b_ri(RW1 r, IMM i)); DECLARE_MIDFUNC(rol_w_ri(RW2 r, IMM i)); DECLARE_MIDFUNC(rol_l_ri(RW4 r, IMM i)); DECLARE_MIDFUNC(rol_l_rr(RW4 d, R1 r)); DECLARE_MIDFUNC(rol_w_rr(RW2 d, R1 r)); DECLARE_MIDFUNC(rol_b_rr(RW1 d, R1 r)); DECLARE_MIDFUNC(shll_l_rr(RW4 d, R1 r)); DECLARE_MIDFUNC(shll_w_rr(RW2 d, R1 r)); DECLARE_MIDFUNC(shll_b_rr(RW1 d, R1 r)); DECLARE_MIDFUNC(ror_b_ri(R1 r, IMM i)); DECLARE_MIDFUNC(ror_w_ri(R2 r, IMM i)); DECLARE_MIDFUNC(ror_l_ri(R4 r, IMM i)); DECLARE_MIDFUNC(ror_l_rr(R4 d, R1 r)); DECLARE_MIDFUNC(ror_w_rr(R2 d, R1 r)); DECLARE_MIDFUNC(ror_b_rr(R1 d, R1 r)); DECLARE_MIDFUNC(shrl_l_rr(RW4 d, R1 r)); DECLARE_MIDFUNC(shrl_w_rr(RW2 d, R1 r)); DECLARE_MIDFUNC(shrl_b_rr(RW1 d, R1 r)); DECLARE_MIDFUNC(shra_l_rr(RW4 d, R1 r)); DECLARE_MIDFUNC(shra_w_rr(RW2 d, R1 r)); DECLARE_MIDFUNC(shra_b_rr(RW1 d, R1 r)); DECLARE_MIDFUNC(shll_l_ri(RW4 r, IMM i)); DECLARE_MIDFUNC(shll_w_ri(RW2 r, IMM i)); DECLARE_MIDFUNC(shll_b_ri(RW1 r, IMM i)); DECLARE_MIDFUNC(shrl_l_ri(RW4 r, IMM i)); DECLARE_MIDFUNC(shrl_w_ri(RW2 r, IMM i)); DECLARE_MIDFUNC(shrl_b_ri(RW1 r, IMM i)); DECLARE_MIDFUNC(shra_l_ri(RW4 r, IMM i)); DECLARE_MIDFUNC(shra_w_ri(RW2 r, IMM i)); DECLARE_MIDFUNC(shra_b_ri(RW1 r, IMM i)); DECLARE_MIDFUNC(setcc(W1 d, IMM cc)); DECLARE_MIDFUNC(setcc_m(IMM d, IMM cc)); DECLARE_MIDFUNC(cmov_b_rr(RW1 d, R1 s, IMM cc)); DECLARE_MIDFUNC(cmov_w_rr(RW2 d, R2 s, IMM cc)); DECLARE_MIDFUNC(cmov_l_rr(RW4 d, R4 s, IMM cc)); DECLARE_MIDFUNC(cmov_l_rm(RW4 d, IMM s, IMM cc)); DECLARE_MIDFUNC(bsf_l_rr(W4 d, R4 s)); DECLARE_MIDFUNC(pop_m(IMM d)); DECLARE_MIDFUNC(push_m(IMM d)); DECLARE_MIDFUNC(pop_l(W4 d)); DECLARE_MIDFUNC(push_l_i(IMM i)); DECLARE_MIDFUNC(push_l(R4 s)); DECLARE_MIDFUNC(clear_16(RW4 r)); DECLARE_MIDFUNC(clear_8(RW4 r)); DECLARE_MIDFUNC(sign_extend_16_rr(W4 d, R2 s)); DECLARE_MIDFUNC(sign_extend_8_rr(W4 d, R1 s)); DECLARE_MIDFUNC(zero_extend_16_rr(W4 d, R2 s)); DECLARE_MIDFUNC(zero_extend_8_rr(W4 d, R1 s)); DECLARE_MIDFUNC(imul_64_32(RW4 d, RW4 s)); DECLARE_MIDFUNC(mul_64_32(RW4 d, RW4 s)); DECLARE_MIDFUNC(imul_32_32(RW4 d, R4 s)); DECLARE_MIDFUNC(mul_32_32(RW4 d, R4 s)); DECLARE_MIDFUNC(mov_b_rr(W1 d, R1 s)); DECLARE_MIDFUNC(mov_w_rr(W2 d, R2 s)); DECLARE_MIDFUNC(mov_l_rrm_indexed(W4 d,R4 baser, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_w_rrm_indexed(W2 d, R4 baser, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_b_rrm_indexed(W1 d, R4 baser, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_l_mrr_indexed(R4 baser, R4 index, IMM factor, R4 s)); DECLARE_MIDFUNC(mov_w_mrr_indexed(R4 baser, R4 index, IMM factor, R2 s)); DECLARE_MIDFUNC(mov_b_mrr_indexed(R4 baser, R4 index, IMM factor, R1 s)); DECLARE_MIDFUNC(mov_l_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R4 s)); DECLARE_MIDFUNC(mov_w_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R2 s)); DECLARE_MIDFUNC(mov_b_bmrr_indexed(IMM base, R4 baser, R4 index, IMM factor, R1 s)); DECLARE_MIDFUNC(mov_l_brrm_indexed(W4 d, IMM base, R4 baser, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_w_brrm_indexed(W2 d, IMM base, R4 baser, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_b_brrm_indexed(W1 d, IMM base, R4 baser, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_l_rm_indexed(W4 d, IMM base, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_l_rR(W4 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_w_rR(W2 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_b_rR(W1 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_l_brR(W4 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_w_brR(W2 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_b_brR(W1 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_l_Ri(R4 d, IMM i, IMM offset)); DECLARE_MIDFUNC(mov_w_Ri(R4 d, IMM i, IMM offset)); DECLARE_MIDFUNC(mov_b_Ri(R4 d, IMM i, IMM offset)); DECLARE_MIDFUNC(mov_l_Rr(R4 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_w_Rr(R4 d, R2 s, IMM offset)); DECLARE_MIDFUNC(mov_b_Rr(R4 d, R1 s, IMM offset)); DECLARE_MIDFUNC(lea_l_brr(W4 d, R4 s, IMM offset)); DECLARE_MIDFUNC(lea_l_brr_indexed(W4 d, R4 s, R4 index, IMM factor, IMM offset)); DECLARE_MIDFUNC(lea_l_rr_indexed(W4 d, R4 s, R4 index, IMM factor)); DECLARE_MIDFUNC(mov_l_bRr(R4 d, R4 s, IMM offset)); DECLARE_MIDFUNC(mov_w_bRr(R4 d, R2 s, IMM offset)); DECLARE_MIDFUNC(mov_b_bRr(R4 d, R1 s, IMM offset)); DECLARE_MIDFUNC(bswap_32(RW4 r)); DECLARE_MIDFUNC(bswap_16(RW2 r)); DECLARE_MIDFUNC(mov_l_rr(W4 d, R4 s)); DECLARE_MIDFUNC(mov_l_mr(IMM d, R4 s)); DECLARE_MIDFUNC(mov_w_mr(IMM d, R2 s)); DECLARE_MIDFUNC(mov_w_rm(W2 d, IMM s)); DECLARE_MIDFUNC(mov_b_mr(IMM d, R1 s)); DECLARE_MIDFUNC(mov_b_rm(W1 d, IMM s)); DECLARE_MIDFUNC(mov_l_ri(W4 d, IMM s)); DECLARE_MIDFUNC(mov_w_ri(W2 d, IMM s)); DECLARE_MIDFUNC(mov_b_ri(W1 d, IMM s)); DECLARE_MIDFUNC(add_l_mi(IMM d, IMM s) ); DECLARE_MIDFUNC(add_w_mi(IMM d, IMM s) ); DECLARE_MIDFUNC(add_b_mi(IMM d, IMM s) ); DECLARE_MIDFUNC(test_l_ri(R4 d, IMM i)); DECLARE_MIDFUNC(test_l_rr(R4 d, R4 s)); DECLARE_MIDFUNC(test_w_rr(R2 d, R2 s)); DECLARE_MIDFUNC(test_b_rr(R1 d, R1 s)); DECLARE_MIDFUNC(and_l_ri(RW4 d, IMM i)); DECLARE_MIDFUNC(and_l(RW4 d, R4 s)); DECLARE_MIDFUNC(and_w(RW2 d, R2 s)); DECLARE_MIDFUNC(and_b(RW1 d, R1 s)); DECLARE_MIDFUNC(or_l_rm(RW4 d, IMM s)); DECLARE_MIDFUNC(or_l_ri(RW4 d, IMM i)); DECLARE_MIDFUNC(or_l(RW4 d, R4 s)); DECLARE_MIDFUNC(or_w(RW2 d, R2 s)); DECLARE_MIDFUNC(or_b(RW1 d, R1 s)); DECLARE_MIDFUNC(adc_l(RW4 d, R4 s)); DECLARE_MIDFUNC(adc_w(RW2 d, R2 s)); DECLARE_MIDFUNC(adc_b(RW1 d, R1 s)); DECLARE_MIDFUNC(add_l(RW4 d, R4 s)); DECLARE_MIDFUNC(add_w(RW2 d, R2 s)); DECLARE_MIDFUNC(add_b(RW1 d, R1 s)); DECLARE_MIDFUNC(sub_l_ri(RW4 d, IMM i)); DECLARE_MIDFUNC(sub_w_ri(RW2 d, IMM i)); DECLARE_MIDFUNC(sub_b_ri(RW1 d, IMM i)); DECLARE_MIDFUNC(add_l_ri(RW4 d, IMM i)); DECLARE_MIDFUNC(add_w_ri(RW2 d, IMM i)); DECLARE_MIDFUNC(add_b_ri(RW1 d, IMM i)); DECLARE_MIDFUNC(sbb_l(RW4 d, R4 s)); DECLARE_MIDFUNC(sbb_w(RW2 d, R2 s)); DECLARE_MIDFUNC(sbb_b(RW1 d, R1 s)); DECLARE_MIDFUNC(sub_l(RW4 d, R4 s)); DECLARE_MIDFUNC(sub_w(RW2 d, R2 s)); DECLARE_MIDFUNC(sub_b(RW1 d, R1 s)); DECLARE_MIDFUNC(cmp_l(R4 d, R4 s)); DECLARE_MIDFUNC(cmp_l_ri(R4 r, IMM i)); DECLARE_MIDFUNC(cmp_w(R2 d, R2 s)); DECLARE_MIDFUNC(cmp_b(R1 d, R1 s)); DECLARE_MIDFUNC(xor_l(RW4 d, R4 s)); DECLARE_MIDFUNC(xor_w(RW2 d, R2 s)); DECLARE_MIDFUNC(xor_b(RW1 d, R1 s)); DECLARE_MIDFUNC(live_flags(void)); DECLARE_MIDFUNC(dont_care_flags(void)); DECLARE_MIDFUNC(duplicate_carry(void)); DECLARE_MIDFUNC(restore_carry(void)); DECLARE_MIDFUNC(start_needflags(void)); DECLARE_MIDFUNC(end_needflags(void)); DECLARE_MIDFUNC(make_flags_live(void)); DECLARE_MIDFUNC(call_r_11(R4 r, W4 out1, R4 in1, IMM osize, IMM isize)); DECLARE_MIDFUNC(call_r_02(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2)); DECLARE_MIDFUNC(forget_about(W4 r)); DECLARE_MIDFUNC(nop(void)); DECLARE_MIDFUNC(f_forget_about(FW r)); DECLARE_MIDFUNC(fmov_pi(FW r)); DECLARE_MIDFUNC(fmov_log10_2(FW r)); DECLARE_MIDFUNC(fmov_log2_e(FW r)); DECLARE_MIDFUNC(fmov_loge_2(FW r)); DECLARE_MIDFUNC(fmov_1(FW r)); DECLARE_MIDFUNC(fmov_0(FW r)); DECLARE_MIDFUNC(fmov_rm(FW r, MEMR m)); DECLARE_MIDFUNC(fmovi_rm(FW r, MEMR m)); DECLARE_MIDFUNC(fmovi_mr(MEMW m, FR r)); DECLARE_MIDFUNC(fmovs_rm(FW r, MEMR m)); DECLARE_MIDFUNC(fmovs_mr(MEMW m, FR r)); DECLARE_MIDFUNC(fmov_mr(MEMW m, FR r)); DECLARE_MIDFUNC(fmov_ext_mr(MEMW m, FR r)); DECLARE_MIDFUNC(fmov_ext_rm(FW r, MEMR m)); DECLARE_MIDFUNC(fmov_rr(FW d, FR s)); DECLARE_MIDFUNC(fldcw_m_indexed(R4 index, IMM base)); DECLARE_MIDFUNC(ftst_r(FR r)); DECLARE_MIDFUNC(dont_care_fflags(void)); DECLARE_MIDFUNC(fsqrt_rr(FW d, FR s)); DECLARE_MIDFUNC(fabs_rr(FW d, FR s)); DECLARE_MIDFUNC(frndint_rr(FW d, FR s)); DECLARE_MIDFUNC(fsin_rr(FW d, FR s)); DECLARE_MIDFUNC(fcos_rr(FW d, FR s)); DECLARE_MIDFUNC(ftwotox_rr(FW d, FR s)); DECLARE_MIDFUNC(fetox_rr(FW d, FR s)); DECLARE_MIDFUNC(flog2_rr(FW d, FR s)); DECLARE_MIDFUNC(fneg_rr(FW d, FR s)); DECLARE_MIDFUNC(fadd_rr(FRW d, FR s)); DECLARE_MIDFUNC(fsub_rr(FRW d, FR s)); DECLARE_MIDFUNC(fmul_rr(FRW d, FR s)); DECLARE_MIDFUNC(frem_rr(FRW d, FR s)); DECLARE_MIDFUNC(frem1_rr(FRW d, FR s)); DECLARE_MIDFUNC(fdiv_rr(FRW d, FR s)); DECLARE_MIDFUNC(fcmp_rr(FR d, FR s)); DECLARE_MIDFUNC(fflags_into_flags(W2 tmp)); #undef DECLARE_MIDFUNC extern int failure; #define FAIL(x) do { failure|=x; } while (0) /* Convenience functions exposed to gencomp */ extern uae_u32 m68k_pc_offset; extern void readbyte(int address, int dest, int tmp); extern void readword(int address, int dest, int tmp); extern void readlong(int address, int dest, int tmp); extern void writebyte(int address, int source, int tmp); extern void writeword(int address, int source, int tmp); extern void writelong(int address, int source, int tmp); extern void writeword_clobber(int address, int source, int tmp); extern void writelong_clobber(int address, int source, int tmp); extern void get_n_addr(int address, int dest, int tmp); extern void get_n_addr_jmp(int address, int dest, int tmp); extern void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp); /* Set native Z flag only if register is zero */ extern void set_zero(int r, int tmp); extern int kill_rodent(int r); extern void sync_m68k_pc(void); extern uae_u32 get_const(int r); extern int is_const(int r); extern void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond); #define comp_get_ibyte(o) do_get_mem_byte((uae_u8 *)(comp_pc_p + (o) + 1)) #define comp_get_iword(o) do_get_mem_word((uae_u16 *)(comp_pc_p + (o))) #define comp_get_ilong(o) do_get_mem_long((uae_u32 *)(comp_pc_p + (o))) struct blockinfo_t; typedef struct dep_t { uae_u32* jmp_off; struct blockinfo_t* target; struct blockinfo_t* source; struct dep_t** prev_p; struct dep_t* next; } dependency; typedef struct checksum_info_t { uae_u8 *start_p; uae_u32 length; struct checksum_info_t *next; } checksum_info; typedef struct blockinfo_t { uae_s32 count; cpuop_func* direct_handler_to_use; cpuop_func* handler_to_use; /* The direct handler does not check for the correct address */ cpuop_func* handler; cpuop_func* direct_handler; cpuop_func* direct_pen; cpuop_func* direct_pcc; uae_u8* pc_p; uae_u32 c1; uae_u32 c2; #if USE_CHECKSUM_INFO checksum_info *csi; #else uae_u32 len; uae_u32 min_pcp; #endif struct blockinfo_t* next_same_cl; struct blockinfo_t** prev_same_cl_p; struct blockinfo_t* next; struct blockinfo_t** prev_p; uae_u8 optlevel; uae_u8 needed_flags; uae_u8 status; uae_u8 havestate; dependency dep[2]; /* Holds things we depend on */ dependency* deplist; /* List of things that depend on this */ smallstate env; #if JIT_DEBUG /* (gb) size of the compiled block (direct handler) */ uae_u32 direct_handler_size; #endif } blockinfo; #define BI_INVALID 0 #define BI_ACTIVE 1 #define BI_NEED_RECOMP 2 #define BI_NEED_CHECK 3 #define BI_CHECKING 4 #define BI_COMPILING 5 #define BI_FINALIZING 6 void execute_normal(void); void exec_nostats(void); void do_nothing(void); #else static __inline__ void flush_icache(int) { } static __inline__ void build_comp() { } #endif /* !USE_JIT */ #endif /* COMPEMU_H */ BasiliskII/src/uae_cpu/compiler/codegen_x86.cpp0000644000175000017500000032720610755660144021622 0ustar centriscentris/* * compiler/codegen_x86.cpp - IA-32 code generator * * Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer * * Adaptation for Basilisk II and improvements, copyright 2000-2005 * Gwenole Beauchesne * * Basilisk II (C) 1997-2008 Christian Bauer * * Portions related to CPU detection come from linux/arch/i386/kernel/setup.c * * 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 */ /* This should eventually end up in machdep/, but for now, x86 is the only target, and it's easier this way... */ #include "flags_x86.h" /************************************************************************* * Some basic information about the the target CPU * *************************************************************************/ #define EAX_INDEX 0 #define ECX_INDEX 1 #define EDX_INDEX 2 #define EBX_INDEX 3 #define ESP_INDEX 4 #define EBP_INDEX 5 #define ESI_INDEX 6 #define EDI_INDEX 7 #if defined(__x86_64__) #define R8_INDEX 8 #define R9_INDEX 9 #define R10_INDEX 10 #define R11_INDEX 11 #define R12_INDEX 12 #define R13_INDEX 13 #define R14_INDEX 14 #define R15_INDEX 15 #endif /* XXX this has to match X86_Reg8H_Base + 4 */ #define AH_INDEX (0x10+4+EAX_INDEX) #define CH_INDEX (0x10+4+ECX_INDEX) #define DH_INDEX (0x10+4+EDX_INDEX) #define BH_INDEX (0x10+4+EBX_INDEX) /* The register in which subroutines return an integer return value */ #define REG_RESULT EAX_INDEX /* The registers subroutines take their first and second argument in */ #if defined( _MSC_VER ) && !defined( USE_NORMAL_CALLING_CONVENTION ) /* Handle the _fastcall parameters of ECX and EDX */ #define REG_PAR1 ECX_INDEX #define REG_PAR2 EDX_INDEX #elif defined(__x86_64__) #define REG_PAR1 EDI_INDEX #define REG_PAR2 ESI_INDEX #else #define REG_PAR1 EAX_INDEX #define REG_PAR2 EDX_INDEX #endif #define REG_PC_PRE EAX_INDEX /* The register we use for preloading regs.pc_p */ #if defined( _MSC_VER ) && !defined( USE_NORMAL_CALLING_CONVENTION ) #define REG_PC_TMP EAX_INDEX #else #define REG_PC_TMP ECX_INDEX /* Another register that is not the above */ #endif #define SHIFTCOUNT_NREG ECX_INDEX /* Register that can be used for shiftcount. -1 if any reg will do */ #define MUL_NREG1 EAX_INDEX /* %eax will hold the low 32 bits after a 32x32 mul */ #define MUL_NREG2 EDX_INDEX /* %edx will hold the high 32 bits */ #define STACK_ALIGN 16 #define STACK_OFFSET sizeof(void *) uae_s8 always_used[]={4,-1}; #if defined(__x86_64__) uae_s8 can_byte[]={0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,-1}; uae_s8 can_word[]={0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,-1}; #else uae_s8 can_byte[]={0,1,2,3,-1}; uae_s8 can_word[]={0,1,2,3,5,6,7,-1}; #endif #if USE_OPTIMIZED_CALLS /* Make sure interpretive core does not use cpuopti */ uae_u8 call_saved[]={0,0,0,1,1,1,1,1}; #error FIXME: code not ready #else /* cpuopti mutate instruction handlers to assume registers are saved by the caller */ uae_u8 call_saved[]={0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0}; #endif /* This *should* be the same as call_saved. But: - We might not really know which registers are saved, and which aren't, so we need to preserve some, but don't want to rely on everyone else also saving those registers - Special registers (such like the stack pointer) should not be "preserved" by pushing, even though they are "saved" across function calls */ #if defined(__x86_64__) /* callee-saved registers as defined by Linux AMD64 ABI: rbx, rbp, rsp, r12 - r15 */ /* preserve r11 because it's generally used to hold pointers to functions */ static const uae_u8 need_to_preserve[]={0,0,0,1,0,1,0,0,0,0,0,1,1,1,1,1}; #else /* callee-saved registers as defined by System V IA-32 ABI: edi, esi, ebx, ebp */ static const uae_u8 need_to_preserve[]={0,0,0,1,0,1,1,1}; #endif /* Whether classes of instructions do or don't clobber the native flags */ #define CLOBBER_MOV #define CLOBBER_LEA #define CLOBBER_CMOV #define CLOBBER_POP #define CLOBBER_PUSH #define CLOBBER_SUB clobber_flags() #define CLOBBER_SBB clobber_flags() #define CLOBBER_CMP clobber_flags() #define CLOBBER_ADD clobber_flags() #define CLOBBER_ADC clobber_flags() #define CLOBBER_AND clobber_flags() #define CLOBBER_OR clobber_flags() #define CLOBBER_XOR clobber_flags() #define CLOBBER_ROL clobber_flags() #define CLOBBER_ROR clobber_flags() #define CLOBBER_SHLL clobber_flags() #define CLOBBER_SHRL clobber_flags() #define CLOBBER_SHRA clobber_flags() #define CLOBBER_TEST clobber_flags() #define CLOBBER_CL16 #define CLOBBER_CL8 #define CLOBBER_SE32 #define CLOBBER_SE16 #define CLOBBER_SE8 #define CLOBBER_ZE32 #define CLOBBER_ZE16 #define CLOBBER_ZE8 #define CLOBBER_SW16 clobber_flags() #define CLOBBER_SW32 #define CLOBBER_SETCC #define CLOBBER_MUL clobber_flags() #define CLOBBER_BT clobber_flags() #define CLOBBER_BSF clobber_flags() /* The older code generator is now deprecated. */ #define USE_NEW_RTASM 1 #if USE_NEW_RTASM #if defined(__x86_64__) #define X86_TARGET_64BIT 1 /* The address override prefix causes a 5 cycles penalty on Intel Core processors. Another solution would be to decompose the load in an LEA, MOV (to zero-extend), MOV (from memory): is it better? */ #define ADDR32 x86_emit_byte(0x67), #else #define ADDR32 /**/ #endif #define X86_FLAT_REGISTERS 0 #define X86_OPTIMIZE_ALU 1 #define X86_OPTIMIZE_ROTSHI 1 #include "codegen_x86.h" #define x86_emit_byte(B) emit_byte(B) #define x86_emit_word(W) emit_word(W) #define x86_emit_long(L) emit_long(L) #define x86_emit_quad(Q) emit_quad(Q) #define x86_get_target() get_target() #define x86_emit_failure(MSG) jit_fail(MSG, __FILE__, __LINE__, __FUNCTION__) static void jit_fail(const char *msg, const char *file, int line, const char *function) { fprintf(stderr, "JIT failure in function %s from file %s at line %d: %s\n", function, file, line, msg); abort(); } LOWFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) { #if defined(__x86_64__) PUSHQr(r); #else PUSHLr(r); #endif } LENDFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) LOWFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) { #if defined(__x86_64__) POPQr(r); #else POPLr(r); #endif } LENDFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) LOWFUNC(NONE,READ,1,raw_pop_l_m,(MEMW d)) { #if defined(__x86_64__) POPQm(d, X86_NOREG, X86_NOREG, 1); #else POPLm(d, X86_NOREG, X86_NOREG, 1); #endif } LENDFUNC(NONE,READ,1,raw_pop_l_m,(MEMW d)) LOWFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) { BTLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) { BTLrr(b, r); } LENDFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) { BTCLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) { BTCLrr(b, r); } LENDFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) { BTRLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) { BTRLrr(b, r); } LENDFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) { BTSLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) { BTSLrr(b, r); } LENDFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) { SUBWir(i, d); } LENDFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) LOWFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) { MOVLmr(s, X86_NOREG, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) LOWFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) { MOVLim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) { MOVWim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) { MOVBim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) { ROLBim(i, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) { ROLBir(i, r); } LENDFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) { ROLWir(i, r); } LENDFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) { ROLLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) { ROLLrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) { ROLWrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) { ROLBrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) { SHLLrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) { SHLWrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) { SHLBrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) { RORBir(i, r); } LENDFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) { RORWir(i, r); } LENDFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,READ,2,raw_or_l_rm,(RW4 d, MEMR s)) { ORLmr(s, X86_NOREG, X86_NOREG, 1, d); } LENDFUNC(WRITE,READ,2,raw_or_l_rm,(RW4 d, MEMR s)) LOWFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) { RORLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) { RORLrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) { RORWrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) { RORBrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) { SHRLrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) { SHRWrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) { SHRBrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) { SARLrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) { SARWrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) { SARBrr(r, d); } LENDFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) { SHLLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) { SHLWir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) { SHLBir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) { SHRLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) { SHRWir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) { SHRBir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) { SARLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) { SARWir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) { SARBir(i, r); } LENDFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) { SAHF(); } LENDFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) LOWFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) { CPUID(); } LENDFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) LOWFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) { LAHF(); } LENDFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) LOWFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) { SETCCir(cc, d); } LENDFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) LOWFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) { SETCCim(cc, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) LOWFUNC(READ,NONE,3,raw_cmov_b_rr,(RW1 d, R1 s, IMM cc)) { /* replacement using branch and mov */ int8 *target_p = (int8 *)x86_get_target() + 1; JCCSii(cc^1, 0); MOVBrr(s, d); *target_p = (uintptr)x86_get_target() - ((uintptr)target_p + 1); } LENDFUNC(READ,NONE,3,raw_cmov_b_rr,(RW1 d, R1 s, IMM cc)) LOWFUNC(READ,NONE,3,raw_cmov_w_rr,(RW2 d, R2 s, IMM cc)) { if (have_cmov) CMOVWrr(cc, s, d); else { /* replacement using branch and mov */ int8 *target_p = (int8 *)x86_get_target() + 1; JCCSii(cc^1, 0); MOVWrr(s, d); *target_p = (uintptr)x86_get_target() - ((uintptr)target_p + 1); } } LENDFUNC(READ,NONE,3,raw_cmov_w_rr,(RW2 d, R2 s, IMM cc)) LOWFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) { if (have_cmov) CMOVLrr(cc, s, d); else { /* replacement using branch and mov */ int8 *target_p = (int8 *)x86_get_target() + 1; JCCSii(cc^1, 0); MOVLrr(s, d); *target_p = (uintptr)x86_get_target() - ((uintptr)target_p + 1); } } LENDFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) LOWFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) { BSFLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_sign_extend_32_rr,(W4 d, R4 s)) { MOVSLQrr(s, d); } LENDFUNC(NONE,NONE,2,raw_sign_extend_32_rr,(W4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) { MOVSWLrr(s, d); } LENDFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) LOWFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) { MOVSBLrr(s, d); } LENDFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) { MOVZWLrr(s, d); } LENDFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) LOWFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) { MOVZBLrr(s, d); } LENDFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) { IMULLrr(s, d); } LENDFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) { if (d!=MUL_NREG1 || s!=MUL_NREG2) { write_log("Bad register in IMUL: d=%d, s=%d\n",d,s); abort(); } IMULLr(s); } LENDFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) LOWFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) { if (d!=MUL_NREG1 || s!=MUL_NREG2) { write_log("Bad register in MUL: d=%d, s=%d\n",d,s); abort(); } MULLr(s); } LENDFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) LOWFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) { abort(); /* %^$&%^$%#^ x86! */ } LENDFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) { MOVBrr(s, d); } LENDFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) { MOVWrr(s, d); } LENDFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) LOWFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) { ADDR32 MOVLmr(0, baser, index, factor, d); } LENDFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) { ADDR32 MOVWmr(0, baser, index, factor, d); } LENDFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) { ADDR32 MOVBmr(0, baser, index, factor, d); } LENDFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) { ADDR32 MOVLrm(s, 0, baser, index, factor); } LENDFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) LOWFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) { ADDR32 MOVWrm(s, 0, baser, index, factor); } LENDFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) LOWFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) { ADDR32 MOVBrm(s, 0, baser, index, factor); } LENDFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) LOWFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) { ADDR32 MOVLrm(s, base, baser, index, factor); } LENDFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) LOWFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) { ADDR32 MOVWrm(s, base, baser, index, factor); } LENDFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) LOWFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) { ADDR32 MOVBrm(s, base, baser, index, factor); } LENDFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) LOWFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) { ADDR32 MOVLmr(base, baser, index, factor, d); } LENDFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) { ADDR32 MOVWmr(base, baser, index, factor, d); } LENDFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) { ADDR32 MOVBmr(base, baser, index, factor, d); } LENDFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) { ADDR32 MOVLmr(base, X86_NOREG, index, factor, d); } LENDFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) { if (have_cmov) ADDR32 CMOVLmr(cond, base, X86_NOREG, index, factor, d); else { /* replacement using branch and mov */ int8 *target_p = (int8 *)x86_get_target() + 1; JCCSii(cond^1, 0); ADDR32 MOVLmr(base, X86_NOREG, index, factor, d); *target_p = (uintptr)x86_get_target() - ((uintptr)target_p + 1); } } LENDFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) LOWFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) { if (have_cmov) CMOVLmr(cond, mem, X86_NOREG, X86_NOREG, 1, d); else { /* replacement using branch and mov */ int8 *target_p = (int8 *)x86_get_target() + 1; JCCSii(cond^1, 0); MOVLmr(mem, X86_NOREG, X86_NOREG, 1, d); *target_p = (uintptr)x86_get_target() - ((uintptr)target_p + 1); } } LENDFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) LOWFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) { ADDR32 MOVLmr(offset, s, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) { ADDR32 MOVWmr(offset, s, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) { ADDR32 MOVBmr(offset, s, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) { ADDR32 MOVLmr(offset, s, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) { ADDR32 MOVWmr(offset, s, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) { ADDR32 MOVBmr(offset, s, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) { ADDR32 MOVLim(i, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) { ADDR32 MOVWim(i, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) { ADDR32 MOVBim(i, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) { ADDR32 MOVLrm(s, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) { ADDR32 MOVWrm(s, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) { ADDR32 MOVBrm(s, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) LOWFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) { LEALmr(offset, s, X86_NOREG, 1, d); } LENDFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) { LEALmr(offset, s, index, factor, d); } LENDFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) LOWFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) { LEALmr(0, s, index, factor, d); } LENDFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) LOWFUNC(NONE,NONE,4,raw_lea_l_r_scaled,(W4 d, R4 index, IMM factor)) { LEALmr(0, X86_NOREG, index, factor, d); } LENDFUNC(NONE,NONE,4,raw_lea_l_r_scaled,(W4 d, R4 index, IMM factor)) LOWFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) { ADDR32 MOVLrm(s, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) { ADDR32 MOVWrm(s, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) { ADDR32 MOVBrm(s, offset, d, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) LOWFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) { BSWAPLr(r); } LENDFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) LOWFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) { ROLWir(8, r); } LENDFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) LOWFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) { MOVLrr(s, d); } LENDFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) LOWFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) { MOVLrm(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) LOWFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) { MOVWrm(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) LOWFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) { MOVWmr(s, X86_NOREG, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) { MOVBrm(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) LOWFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) { MOVBmr(s, X86_NOREG, X86_NOREG, 1, d); } LENDFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) { MOVLir(s, d); } LENDFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) { MOVWir(s, d); } LENDFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) { MOVBir(s, d); } LENDFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) LOWFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) { ADCLim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) { ADDLim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) { ADDWim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) { ADDBim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) LOWFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) { TESTLir(i, d); } LENDFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) { TESTLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) { TESTWrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) { TESTBrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_xor_l_ri,(RW4 d, IMM i)) { XORLir(i, d); } LENDFUNC(WRITE,NONE,2,raw_xor_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) { ANDLir(i, d); } LENDFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) { ANDWir(i, d); } LENDFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) { ANDLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) { ANDWrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) { ANDBrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) { ORLir(i, d); } LENDFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) { ORLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) { ORWrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) { ORBrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) LOWFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) { ADCLrr(s, d); } LENDFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) LOWFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) { ADCWrr(s, d); } LENDFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) LOWFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) { ADCBrr(s, d); } LENDFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) { ADDLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) { ADDWrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) { ADDBrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) { SUBLir(i, d); } LENDFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) { SUBBir(i, d); } LENDFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) { ADDLir(i, d); } LENDFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) { ADDWir(i, d); } LENDFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) { ADDBir(i, d); } LENDFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) LOWFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) { SBBLrr(s, d); } LENDFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) LOWFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) { SBBWrr(s, d); } LENDFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) LOWFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) { SBBBrr(s, d); } LENDFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) { SUBLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) { SUBWrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) { SUBBrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) { CMPLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) { CMPLir(i, r); } LENDFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) { CMPWrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) LOWFUNC(WRITE,READ,2,raw_cmp_b_mi,(MEMR d, IMM s)) { CMPBim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) LOWFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) { CMPBir(i, d); } LENDFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) { CMPBrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) LOWFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) { ADDR32 CMPLmr(offset, X86_NOREG, index, factor, d); } LENDFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) LOWFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) { XORLrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) { XORWrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) { XORBrr(s, d); } LENDFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) LOWFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) { SUBLim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) LOWFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) { CMPLim(s, d, X86_NOREG, X86_NOREG, 1); } LENDFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) LOWFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) { XCHGLrr(r2, r1); } LENDFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) LOWFUNC(NONE,NONE,2,raw_xchg_b_rr,(RW4 r1, RW4 r2)) { XCHGBrr(r2, r1); } LENDFUNC(NONE,NONE,2,raw_xchg_b_rr,(RW4 r1, RW4 r2)) LOWFUNC(READ,WRITE,0,raw_pushfl,(void)) { PUSHF(); } LENDFUNC(READ,WRITE,0,raw_pushfl,(void)) LOWFUNC(WRITE,READ,0,raw_popfl,(void)) { POPF(); } LENDFUNC(WRITE,READ,0,raw_popfl,(void)) /* Generate floating-point instructions */ static inline void x86_fadd_m(MEMR s) { FADDDm(s,X86_NOREG,X86_NOREG,1); } #else const bool optimize_accum = true; const bool optimize_imm8 = true; const bool optimize_shift_once = true; /************************************************************************* * Actual encoding of the instructions on the target CPU * *************************************************************************/ static __inline__ int isaccum(int r) { return (r == EAX_INDEX); } static __inline__ int isbyte(uae_s32 x) { return (x>=-128 && x<=127); } static __inline__ int isword(uae_s32 x) { return (x>=-32768 && x<=32767); } LOWFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) { emit_byte(0x50+r); } LENDFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) LOWFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) { emit_byte(0x58+r); } LENDFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) LOWFUNC(NONE,READ,1,raw_pop_l_m,(MEMW d)) { emit_byte(0x8f); emit_byte(0x05); emit_long(d); } LENDFUNC(NONE,READ,1,raw_pop_l_m,(MEMW d)) LOWFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xe0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xa3); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xf8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xbb); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xf0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xb3); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xe8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xab); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) { emit_byte(0x66); if (isbyte(i)) { emit_byte(0x83); emit_byte(0xe8+d); emit_byte(i); } else { if (optimize_accum && isaccum(d)) emit_byte(0x2d); else { emit_byte(0x81); emit_byte(0xe8+d); } emit_word(i); } } LENDFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) LOWFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) { emit_byte(0x8b); emit_byte(0x05+8*d); emit_long(s); } LENDFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) LOWFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) { emit_byte(0xc7); emit_byte(0x05); emit_long(d); emit_long(s); } LENDFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) { emit_byte(0x66); emit_byte(0xc7); emit_byte(0x05); emit_long(d); emit_word(s); } LENDFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) { emit_byte(0xc6); emit_byte(0x05); emit_long(d); emit_byte(s); } LENDFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd0); emit_byte(0x05); emit_long(d); } else { emit_byte(0xc0); emit_byte(0x05); emit_long(d); emit_byte(i); } } LENDFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd0); emit_byte(0xc0+r); } else { emit_byte(0xc0); emit_byte(0xc0+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xc0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd1); emit_byte(0xc0+r); } else { emit_byte(0xc1); emit_byte(0xc0+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xc0+d); } LENDFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xc0+d); } LENDFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xc0+d); } LENDFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xe0+d); } LENDFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xe0+d); } LENDFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xe0+d); } LENDFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd0); emit_byte(0xc8+r); } else { emit_byte(0xc0); emit_byte(0xc8+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xc8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) // gb-- used for making an fpcr value in compemu_fpp.cpp LOWFUNC(WRITE,READ,2,raw_or_l_rm,(RW4 d, MEMR s)) { emit_byte(0x0b); emit_byte(0x05+8*d); emit_long(s); } LENDFUNC(WRITE,READ,2,raw_or_l_rm,(RW4 d, MEMR s)) LOWFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd1); emit_byte(0xc8+r); } else { emit_byte(0xc1); emit_byte(0xc8+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xc8+d); } LENDFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xc8+d); } LENDFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xc8+d); } LENDFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xe8+d); } LENDFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xe8+d); } LENDFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xe8+d); } LENDFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xf8+d); } LENDFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xf8+d); } LENDFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xf8+d); } LENDFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd1); emit_byte(0xe0+r); } else { emit_byte(0xc1); emit_byte(0xe0+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xe0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd0); emit_byte(0xe0+r); } else { emit_byte(0xc0); emit_byte(0xe0+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd1); emit_byte(0xe8+r); } else { emit_byte(0xc1); emit_byte(0xe8+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xe8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd0); emit_byte(0xe8+r); } else { emit_byte(0xc0); emit_byte(0xe8+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd1); emit_byte(0xf8+r); } else { emit_byte(0xc1); emit_byte(0xf8+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xf8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) { if (optimize_shift_once && (i == 1)) { emit_byte(0xd0); emit_byte(0xf8+r); } else { emit_byte(0xc0); emit_byte(0xf8+r); emit_byte(i); } } LENDFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) { emit_byte(0x9e); } LENDFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) LOWFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) { emit_byte(0x0f); emit_byte(0xa2); } LENDFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) LOWFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) { emit_byte(0x9f); } LENDFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) LOWFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) { emit_byte(0x0f); emit_byte(0x90+cc); emit_byte(0xc0+d); } LENDFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) LOWFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) { emit_byte(0x0f); emit_byte(0x90+cc); emit_byte(0x05); emit_long(d); } LENDFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) LOWFUNC(READ,NONE,3,raw_cmov_b_rr,(RW1 d, R1 s, IMM cc)) { /* replacement using branch and mov */ int uncc=(cc^1); emit_byte(0x70+uncc); emit_byte(3); /* skip next 2 bytes if not cc=true */ emit_byte(0x88); emit_byte(0xc0+8*s+d); } LENDFUNC(READ,NONE,3,raw_cmov_b_rr,(RW1 d, R1 s, IMM cc)) LOWFUNC(READ,NONE,3,raw_cmov_w_rr,(RW2 d, R2 s, IMM cc)) { if (have_cmov) { emit_byte(0x66); emit_byte(0x0f); emit_byte(0x40+cc); emit_byte(0xc0+8*d+s); } else { /* replacement using branch and mov */ int uncc=(cc^1); emit_byte(0x70+uncc); emit_byte(3); /* skip next 3 bytes if not cc=true */ emit_byte(0x66); emit_byte(0x89); emit_byte(0xc0+8*s+d); } } LENDFUNC(READ,NONE,3,raw_cmov_w_rr,(RW2 d, R2 s, IMM cc)) LOWFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) { if (have_cmov) { emit_byte(0x0f); emit_byte(0x40+cc); emit_byte(0xc0+8*d+s); } else { /* replacement using branch and mov */ int uncc=(cc^1); emit_byte(0x70+uncc); emit_byte(2); /* skip next 2 bytes if not cc=true */ emit_byte(0x89); emit_byte(0xc0+8*s+d); } } LENDFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) LOWFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) { emit_byte(0x0f); emit_byte(0xbc); emit_byte(0xc0+8*d+s); } LENDFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) { emit_byte(0x0f); emit_byte(0xbf); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) LOWFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) { emit_byte(0x0f); emit_byte(0xbe); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) { emit_byte(0x0f); emit_byte(0xb7); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) LOWFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) { emit_byte(0x0f); emit_byte(0xb6); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) { emit_byte(0x0f); emit_byte(0xaf); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) { if (d!=MUL_NREG1 || s!=MUL_NREG2) abort(); emit_byte(0xf7); emit_byte(0xea); } LENDFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) LOWFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) { if (d!=MUL_NREG1 || s!=MUL_NREG2) { printf("Bad register in MUL: d=%d, s=%d\n",d,s); abort(); } emit_byte(0xf7); emit_byte(0xe2); } LENDFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) LOWFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) { abort(); /* %^$&%^$%#^ x86! */ emit_byte(0x0f); emit_byte(0xaf); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) { emit_byte(0x88); emit_byte(0xc0+8*s+d); } LENDFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) { emit_byte(0x66); emit_byte(0x89); emit_byte(0xc0+8*s+d); } LENDFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) LOWFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) { int isebp=(baser==5)?0x40:0; int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8b); emit_byte(0x04+8*d+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x66); emit_byte(0x8b); emit_byte(0x04+8*d+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x8a); emit_byte(0x04+8*d+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x89); emit_byte(0x04+8*s+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) LOWFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x66); emit_byte(0x89); emit_byte(0x04+8*s+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) LOWFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x88); emit_byte(0x04+8*s+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) LOWFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x89); emit_byte(0x84+8*s); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) LOWFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x66); emit_byte(0x89); emit_byte(0x84+8*s); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) LOWFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x88); emit_byte(0x84+8*s); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) LOWFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8b); emit_byte(0x84+8*d); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x66); emit_byte(0x8b); emit_byte(0x84+8*d); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8a); emit_byte(0x84+8*d); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: fprintf(stderr,"Bad factor %d in mov_l_rm_indexed!\n",factor); abort(); } emit_byte(0x8b); emit_byte(0x04+8*d); emit_byte(0x05+8*index+64*fi); emit_long(base); } LENDFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: fprintf(stderr,"Bad factor %d in mov_l_rm_indexed!\n",factor); abort(); } if (have_cmov) { emit_byte(0x0f); emit_byte(0x40+cond); emit_byte(0x04+8*d); emit_byte(0x05+8*index+64*fi); emit_long(base); } else { /* replacement using branch and mov */ int uncc=(cond^1); emit_byte(0x70+uncc); emit_byte(7); /* skip next 7 bytes if not cc=true */ emit_byte(0x8b); emit_byte(0x04+8*d); emit_byte(0x05+8*index+64*fi); emit_long(base); } } LENDFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) LOWFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) { if (have_cmov) { emit_byte(0x0f); emit_byte(0x40+cond); emit_byte(0x05+8*d); emit_long(mem); } else { /* replacement using branch and mov */ int uncc=(cond^1); emit_byte(0x70+uncc); emit_byte(6); /* skip next 6 bytes if not cc=true */ emit_byte(0x8b); emit_byte(0x05+8*d); emit_long(mem); } } LENDFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) LOWFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0x8b); emit_byte(0x40+8*d+s); emit_byte(offset); } LENDFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0x66); emit_byte(0x8b); emit_byte(0x40+8*d+s); emit_byte(offset); } LENDFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0x8a); emit_byte(0x40+8*d+s); emit_byte(offset); } LENDFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) { emit_byte(0x8b); emit_byte(0x80+8*d+s); emit_long(offset); } LENDFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) { emit_byte(0x66); emit_byte(0x8b); emit_byte(0x80+8*d+s); emit_long(offset); } LENDFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) { emit_byte(0x8a); emit_byte(0x80+8*d+s); emit_long(offset); } LENDFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0xc7); emit_byte(0x40+d); emit_byte(offset); emit_long(i); } LENDFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0x66); emit_byte(0xc7); emit_byte(0x40+d); emit_byte(offset); emit_word(i); } LENDFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0xc6); emit_byte(0x40+d); emit_byte(offset); emit_byte(i); } LENDFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0x89); emit_byte(0x40+8*s+d); emit_byte(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0x66); emit_byte(0x89); emit_byte(0x40+8*s+d); emit_byte(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) { Dif(!isbyte(offset)) abort(); emit_byte(0x88); emit_byte(0x40+8*s+d); emit_byte(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) LOWFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) { if (optimize_imm8 && isbyte(offset)) { emit_byte(0x8d); emit_byte(0x40+8*d+s); emit_byte(offset); } else { emit_byte(0x8d); emit_byte(0x80+8*d+s); emit_long(offset); } } LENDFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } if (optimize_imm8 && isbyte(offset)) { emit_byte(0x8d); emit_byte(0x44+8*d); emit_byte(0x40*fi+8*index+s); emit_byte(offset); } else { emit_byte(0x8d); emit_byte(0x84+8*d); emit_byte(0x40*fi+8*index+s); emit_long(offset); } } LENDFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) LOWFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) { int isebp=(s==5)?0x40:0; int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8d); emit_byte(0x04+8*d+isebp); emit_byte(0x40*fi+8*index+s); if (isebp) emit_byte(0); } LENDFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) LOWFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) { if (optimize_imm8 && isbyte(offset)) { emit_byte(0x89); emit_byte(0x40+8*s+d); emit_byte(offset); } else { emit_byte(0x89); emit_byte(0x80+8*s+d); emit_long(offset); } } LENDFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) { emit_byte(0x66); emit_byte(0x89); emit_byte(0x80+8*s+d); emit_long(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) { if (optimize_imm8 && isbyte(offset)) { emit_byte(0x88); emit_byte(0x40+8*s+d); emit_byte(offset); } else { emit_byte(0x88); emit_byte(0x80+8*s+d); emit_long(offset); } } LENDFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) LOWFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) { emit_byte(0x0f); emit_byte(0xc8+r); } LENDFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) LOWFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xc0+r); emit_byte(0x08); } LENDFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) LOWFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) { emit_byte(0x89); emit_byte(0xc0+8*s+d); } LENDFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) LOWFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) { emit_byte(0x89); emit_byte(0x05+8*s); emit_long(d); } LENDFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) LOWFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) { emit_byte(0x66); emit_byte(0x89); emit_byte(0x05+8*s); emit_long(d); } LENDFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) LOWFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) { emit_byte(0x66); emit_byte(0x8b); emit_byte(0x05+8*d); emit_long(s); } LENDFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) { emit_byte(0x88); emit_byte(0x05+8*(s&0xf)); /* XXX this handles %ah case (defined as 0x10+4) and others */ emit_long(d); } LENDFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) LOWFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) { emit_byte(0x8a); emit_byte(0x05+8*d); emit_long(s); } LENDFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) { emit_byte(0xb8+d); emit_long(s); } LENDFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) { emit_byte(0x66); emit_byte(0xb8+d); emit_word(s); } LENDFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) { emit_byte(0xb0+d); emit_byte(s); } LENDFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) LOWFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) { emit_byte(0x81); emit_byte(0x15); emit_long(d); emit_long(s); } LENDFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) { if (optimize_imm8 && isbyte(s)) { emit_byte(0x83); emit_byte(0x05); emit_long(d); emit_byte(s); } else { emit_byte(0x81); emit_byte(0x05); emit_long(d); emit_long(s); } } LENDFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) { emit_byte(0x66); emit_byte(0x81); emit_byte(0x05); emit_long(d); emit_word(s); } LENDFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) { emit_byte(0x80); emit_byte(0x05); emit_long(d); emit_byte(s); } LENDFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) LOWFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) { if (optimize_accum && isaccum(d)) emit_byte(0xa9); else { emit_byte(0xf7); emit_byte(0xc0+d); } emit_long(i); } LENDFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) { emit_byte(0x85); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) { emit_byte(0x66); emit_byte(0x85); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) { emit_byte(0x84); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_xor_l_ri,(RW4 d, IMM i)) { emit_byte(0x81); emit_byte(0xf0+d); emit_long(i); } LENDFUNC(WRITE,NONE,2,raw_xor_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) { if (optimize_imm8 && isbyte(i)) { emit_byte(0x83); emit_byte(0xe0+d); emit_byte(i); } else { if (optimize_accum && isaccum(d)) emit_byte(0x25); else { emit_byte(0x81); emit_byte(0xe0+d); } emit_long(i); } } LENDFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) { emit_byte(0x66); if (optimize_imm8 && isbyte(i)) { emit_byte(0x83); emit_byte(0xe0+d); emit_byte(i); } else { if (optimize_accum && isaccum(d)) emit_byte(0x25); else { emit_byte(0x81); emit_byte(0xe0+d); } emit_word(i); } } LENDFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) { emit_byte(0x21); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x21); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) { emit_byte(0x20); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) { if (optimize_imm8 && isbyte(i)) { emit_byte(0x83); emit_byte(0xc8+d); emit_byte(i); } else { if (optimize_accum && isaccum(d)) emit_byte(0x0d); else { emit_byte(0x81); emit_byte(0xc8+d); } emit_long(i); } } LENDFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) { emit_byte(0x09); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x09); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) { emit_byte(0x08); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) LOWFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) { emit_byte(0x11); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) LOWFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x11); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) LOWFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) { emit_byte(0x10); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) { emit_byte(0x01); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x01); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) { emit_byte(0x00); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) { if (isbyte(i)) { emit_byte(0x83); emit_byte(0xe8+d); emit_byte(i); } else { if (optimize_accum && isaccum(d)) emit_byte(0x2d); else { emit_byte(0x81); emit_byte(0xe8+d); } emit_long(i); } } LENDFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) { if (optimize_accum && isaccum(d)) emit_byte(0x2c); else { emit_byte(0x80); emit_byte(0xe8+d); } emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) { if (isbyte(i)) { emit_byte(0x83); emit_byte(0xc0+d); emit_byte(i); } else { if (optimize_accum && isaccum(d)) emit_byte(0x05); else { emit_byte(0x81); emit_byte(0xc0+d); } emit_long(i); } } LENDFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) { emit_byte(0x66); if (isbyte(i)) { emit_byte(0x83); emit_byte(0xc0+d); emit_byte(i); } else { if (optimize_accum && isaccum(d)) emit_byte(0x05); else { emit_byte(0x81); emit_byte(0xc0+d); } emit_word(i); } } LENDFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) { if (optimize_accum && isaccum(d)) emit_byte(0x04); else { emit_byte(0x80); emit_byte(0xc0+d); } emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) LOWFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) { emit_byte(0x19); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) LOWFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x19); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) LOWFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) { emit_byte(0x18); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) { emit_byte(0x29); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x29); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) { emit_byte(0x28); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) { emit_byte(0x39); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) { if (optimize_imm8 && isbyte(i)) { emit_byte(0x83); emit_byte(0xf8+r); emit_byte(i); } else { if (optimize_accum && isaccum(r)) emit_byte(0x3d); else { emit_byte(0x81); emit_byte(0xf8+r); } emit_long(i); } } LENDFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) { emit_byte(0x66); emit_byte(0x39); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) LOWFUNC(WRITE,READ,2,raw_cmp_b_mi,(MEMR d, IMM s)) { emit_byte(0x80); emit_byte(0x3d); emit_long(d); emit_byte(s); } LENDFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) LOWFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) { if (optimize_accum && isaccum(d)) emit_byte(0x3c); else { emit_byte(0x80); emit_byte(0xf8+d); } emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) { emit_byte(0x38); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) LOWFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x39); emit_byte(0x04+8*d); emit_byte(5+8*index+0x40*fi); emit_long(offset); } LENDFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) LOWFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) { emit_byte(0x31); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x31); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) { emit_byte(0x30); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) LOWFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) { if (optimize_imm8 && isbyte(s)) { emit_byte(0x83); emit_byte(0x2d); emit_long(d); emit_byte(s); } else { emit_byte(0x81); emit_byte(0x2d); emit_long(d); emit_long(s); } } LENDFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) LOWFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) { if (optimize_imm8 && isbyte(s)) { emit_byte(0x83); emit_byte(0x3d); emit_long(d); emit_byte(s); } else { emit_byte(0x81); emit_byte(0x3d); emit_long(d); emit_long(s); } } LENDFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) LOWFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) { emit_byte(0x87); emit_byte(0xc0+8*r1+r2); } LENDFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) LOWFUNC(NONE,NONE,2,raw_xchg_b_rr,(RW4 r1, RW4 r2)) { emit_byte(0x86); emit_byte(0xc0+8*(r1&0xf)+(r2&0xf)); /* XXX this handles upper-halves registers (e.g. %ah defined as 0x10+4) */ } LENDFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) /************************************************************************* * FIXME: mem access modes probably wrong * *************************************************************************/ LOWFUNC(READ,WRITE,0,raw_pushfl,(void)) { emit_byte(0x9c); } LENDFUNC(READ,WRITE,0,raw_pushfl,(void)) LOWFUNC(WRITE,READ,0,raw_popfl,(void)) { emit_byte(0x9d); } LENDFUNC(WRITE,READ,0,raw_popfl,(void)) /* Generate floating-point instructions */ static inline void x86_fadd_m(MEMR s) { emit_byte(0xdc); emit_byte(0x05); emit_long(s); } #endif /************************************************************************* * Unoptimizable stuff --- jump * *************************************************************************/ static __inline__ void raw_call_r(R4 r) { #if USE_NEW_RTASM CALLsr(r); #else emit_byte(0xff); emit_byte(0xd0+r); #endif } static __inline__ void raw_call_m_indexed(uae_u32 base, uae_u32 r, uae_u32 m) { #if USE_NEW_RTASM CALLsm(base, X86_NOREG, r, m); #else int mu; switch(m) { case 1: mu=0; break; case 2: mu=1; break; case 4: mu=2; break; case 8: mu=3; break; default: abort(); } emit_byte(0xff); emit_byte(0x14); emit_byte(0x05+8*r+0x40*mu); emit_long(base); #endif } static __inline__ void raw_jmp_r(R4 r) { #if USE_NEW_RTASM JMPsr(r); #else emit_byte(0xff); emit_byte(0xe0+r); #endif } static __inline__ void raw_jmp_m_indexed(uae_u32 base, uae_u32 r, uae_u32 m) { #if USE_NEW_RTASM JMPsm(base, X86_NOREG, r, m); #else int mu; switch(m) { case 1: mu=0; break; case 2: mu=1; break; case 4: mu=2; break; case 8: mu=3; break; default: abort(); } emit_byte(0xff); emit_byte(0x24); emit_byte(0x05+8*r+0x40*mu); emit_long(base); #endif } static __inline__ void raw_jmp_m(uae_u32 base) { emit_byte(0xff); emit_byte(0x25); emit_long(base); } static __inline__ void raw_call(uae_u32 t) { #if USE_NEW_RTASM CALLm(t); #else emit_byte(0xe8); emit_long(t-(uae_u32)target-4); #endif } static __inline__ void raw_jmp(uae_u32 t) { #if USE_NEW_RTASM JMPm(t); #else emit_byte(0xe9); emit_long(t-(uae_u32)target-4); #endif } static __inline__ void raw_jl(uae_u32 t) { emit_byte(0x0f); emit_byte(0x8c); emit_long(t-(uintptr)target-4); } static __inline__ void raw_jz(uae_u32 t) { emit_byte(0x0f); emit_byte(0x84); emit_long(t-(uintptr)target-4); } static __inline__ void raw_jnz(uae_u32 t) { emit_byte(0x0f); emit_byte(0x85); emit_long(t-(uintptr)target-4); } static __inline__ void raw_jnz_l_oponly(void) { emit_byte(0x0f); emit_byte(0x85); } static __inline__ void raw_jcc_l_oponly(int cc) { emit_byte(0x0f); emit_byte(0x80+cc); } static __inline__ void raw_jnz_b_oponly(void) { emit_byte(0x75); } static __inline__ void raw_jz_b_oponly(void) { emit_byte(0x74); } static __inline__ void raw_jcc_b_oponly(int cc) { emit_byte(0x70+cc); } static __inline__ void raw_jmp_l_oponly(void) { emit_byte(0xe9); } static __inline__ void raw_jmp_b_oponly(void) { emit_byte(0xeb); } static __inline__ void raw_ret(void) { emit_byte(0xc3); } static __inline__ void raw_nop(void) { emit_byte(0x90); } static __inline__ void raw_emit_nop_filler(int nbytes) { /* Source: GNU Binutils 2.12.90.0.15 */ /* Various efficient no-op patterns for aligning code labels. Note: Don't try to assemble the instructions in the comments. 0L and 0w are not legal. */ static const uae_u8 f32_1[] = {0x90}; /* nop */ static const uae_u8 f32_2[] = {0x89,0xf6}; /* movl %esi,%esi */ static const uae_u8 f32_3[] = {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ static const uae_u8 f32_4[] = {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ static const uae_u8 f32_5[] = {0x90, /* nop */ 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ static const uae_u8 f32_6[] = {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ static const uae_u8 f32_7[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ static const uae_u8 f32_8[] = {0x90, /* nop */ 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ static const uae_u8 f32_9[] = {0x89,0xf6, /* movl %esi,%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_10[] = {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_11[] = {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_12[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ static const uae_u8 f32_13[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_14[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_15[] = {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; static const uae_u8 f32_16[] = {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; static const uae_u8 *const f32_patt[] = { f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 }; static const uae_u8 prefixes[4] = { 0x66, 0x66, 0x66, 0x66 }; #if defined(__x86_64__) /* The recommended way to pad 64bit code is to use NOPs preceded by maximally four 0x66 prefixes. Balance the size of nops. */ if (nbytes == 0) return; int i; int nnops = (nbytes + 3) / 4; int len = nbytes / nnops; int remains = nbytes - nnops * len; for (i = 0; i < remains; i++) { emit_block(prefixes, len); raw_nop(); } for (; i < nnops; i++) { emit_block(prefixes, len - 1); raw_nop(); } #else int nloops = nbytes / 16; while (nloops-- > 0) emit_block(f32_16, sizeof(f32_16)); nbytes %= 16; if (nbytes) emit_block(f32_patt[nbytes - 1], nbytes); #endif } /************************************************************************* * Flag handling, to and fro UAE flag register * *************************************************************************/ static __inline__ void raw_flags_evicted(int r) { //live.state[FLAGTMP].status=CLEAN; live.state[FLAGTMP].status=INMEM; live.state[FLAGTMP].realreg=-1; /* We just "evicted" FLAGTMP. */ if (live.nat[r].nholds!=1) { /* Huh? */ abort(); } live.nat[r].nholds=0; } #define FLAG_NREG1_FLAGREG 0 /* Set to -1 if any register will do */ static __inline__ void raw_flags_to_reg_FLAGREG(int r) { raw_lahf(0); /* Most flags in AH */ //raw_setcc(r,0); /* V flag in AL */ raw_setcc_m((uintptr)live.state[FLAGTMP].mem,0); #if 1 /* Let's avoid those nasty partial register stalls */ //raw_mov_b_mr((uintptr)live.state[FLAGTMP].mem,r); raw_mov_b_mr(((uintptr)live.state[FLAGTMP].mem)+1,AH_INDEX); raw_flags_evicted(r); #endif } #define FLAG_NREG2_FLAGREG 0 /* Set to -1 if any register will do */ static __inline__ void raw_reg_to_flags_FLAGREG(int r) { raw_cmp_b_ri(r,-127); /* set V */ raw_sahf(0); } #define FLAG_NREG3_FLAGREG 0 /* Set to -1 if any register will do */ static __inline__ void raw_flags_set_zero_FLAGREG(int s, int tmp) { raw_mov_l_rr(tmp,s); raw_lahf(s); /* flags into ah */ raw_and_l_ri(s,0xffffbfff); raw_and_l_ri(tmp,0x00004000); raw_xor_l_ri(tmp,0x00004000); raw_or_l(s,tmp); raw_sahf(s); } static __inline__ void raw_flags_init_FLAGREG(void) { } #define FLAG_NREG1_FLAGSTK -1 /* Set to -1 if any register will do */ static __inline__ void raw_flags_to_reg_FLAGSTK(int r) { raw_pushfl(); raw_pop_l_r(r); raw_mov_l_mr((uintptr)live.state[FLAGTMP].mem,r); raw_flags_evicted(r); } #define FLAG_NREG2_FLAGSTK -1 /* Set to -1 if any register will do */ static __inline__ void raw_reg_to_flags_FLAGSTK(int r) { raw_push_l_r(r); raw_popfl(); } #define FLAG_NREG3_FLAGSTK -1 /* Set to -1 if any register will do */ static __inline__ void raw_flags_set_zero_FLAGSTK(int s, int tmp) { raw_mov_l_rr(tmp,s); raw_pushfl(); raw_pop_l_r(s); raw_and_l_ri(s,0xffffffbf); raw_and_l_ri(tmp,0x00000040); raw_xor_l_ri(tmp,0x00000040); raw_or_l(s,tmp); raw_push_l_r(s); raw_popfl(); } static __inline__ void raw_flags_init_FLAGSTK(void) { } #if defined(__x86_64__) /* Try to use the LAHF/SETO method on x86_64 since it is faster. This can't be the default because some older CPUs don't support LAHF/SAHF in long mode. */ static int FLAG_NREG1_FLAGGEN = 0; static __inline__ void raw_flags_to_reg_FLAGGEN(int r) { if (have_lahf_lm) { // NOTE: the interpreter uses the normal EFLAGS layout // pushf/popf CF(0) ZF( 6) SF( 7) OF(11) // sahf/lahf CF(8) ZF(14) SF(15) OF( 0) assert(r == 0); raw_setcc(r,0); /* V flag in AL */ raw_lea_l_r_scaled(0,0,8); /* move it to its EFLAGS location */ raw_mov_b_mr(((uintptr)live.state[FLAGTMP].mem)+1,0); raw_lahf(0); /* most flags in AH */ raw_mov_b_mr((uintptr)live.state[FLAGTMP].mem,AH_INDEX); raw_flags_evicted(r); } else raw_flags_to_reg_FLAGSTK(r); } static int FLAG_NREG2_FLAGGEN = 0; static __inline__ void raw_reg_to_flags_FLAGGEN(int r) { if (have_lahf_lm) { raw_xchg_b_rr(0,AH_INDEX); raw_cmp_b_ri(r,-120); /* set V */ raw_sahf(0); } else raw_reg_to_flags_FLAGSTK(r); } static int FLAG_NREG3_FLAGGEN = 0; static __inline__ void raw_flags_set_zero_FLAGGEN(int s, int tmp) { if (have_lahf_lm) raw_flags_set_zero_FLAGREG(s, tmp); else raw_flags_set_zero_FLAGSTK(s, tmp); } static __inline__ void raw_flags_init_FLAGGEN(void) { if (have_lahf_lm) { FLAG_NREG1_FLAGGEN = FLAG_NREG1_FLAGREG; FLAG_NREG2_FLAGGEN = FLAG_NREG2_FLAGREG; FLAG_NREG1_FLAGGEN = FLAG_NREG3_FLAGREG; } else { FLAG_NREG1_FLAGGEN = FLAG_NREG1_FLAGSTK; FLAG_NREG2_FLAGGEN = FLAG_NREG2_FLAGSTK; FLAG_NREG1_FLAGGEN = FLAG_NREG3_FLAGSTK; } } #endif #ifdef SAHF_SETO_PROFITABLE #define FLAG_SUFFIX FLAGREG #elif defined __x86_64__ #define FLAG_SUFFIX FLAGGEN #else #define FLAG_SUFFIX FLAGSTK #endif #define FLAG_GLUE_2(x, y) x ## _ ## y #define FLAG_GLUE_1(x, y) FLAG_GLUE_2(x, y) #define FLAG_GLUE(x) FLAG_GLUE_1(x, FLAG_SUFFIX) #define raw_flags_init FLAG_GLUE(raw_flags_init) #define FLAG_NREG1 FLAG_GLUE(FLAG_NREG1) #define raw_flags_to_reg FLAG_GLUE(raw_flags_to_reg) #define FLAG_NREG2 FLAG_GLUE(FLAG_NREG2) #define raw_reg_to_flags FLAG_GLUE(raw_reg_to_flags) #define FLAG_NREG3 FLAG_GLUE(FLAG_NREG3) #define raw_flags_set_zero FLAG_GLUE(raw_flags_set_zero) /* Apparently, there are enough instructions between flag store and flag reload to avoid the partial memory stall */ static __inline__ void raw_load_flagreg(uae_u32 target, uae_u32 r) { #if 1 raw_mov_l_rm(target,(uintptr)live.state[r].mem); #else raw_mov_b_rm(target,(uintptr)live.state[r].mem); raw_mov_b_rm(target+4,((uintptr)live.state[r].mem)+1); #endif } /* FLAGX is byte sized, and we *do* write it at that size */ static __inline__ void raw_load_flagx(uae_u32 target, uae_u32 r) { if (live.nat[target].canbyte) raw_mov_b_rm(target,(uintptr)live.state[r].mem); else if (live.nat[target].canword) raw_mov_w_rm(target,(uintptr)live.state[r].mem); else raw_mov_l_rm(target,(uintptr)live.state[r].mem); } static __inline__ void raw_dec_sp(int off) { if (off) raw_sub_l_ri(ESP_INDEX,off); } static __inline__ void raw_inc_sp(int off) { if (off) raw_add_l_ri(ESP_INDEX,off); } /************************************************************************* * Handling mistaken direct memory access * *************************************************************************/ // gb-- I don't need that part for JIT Basilisk II #if defined(NATMEM_OFFSET) && 0 #include #include #define SIG_READ 1 #define SIG_WRITE 2 static int in_handler=0; static uae_u8 veccode[256]; static void vec(int x, struct sigcontext sc) { uae_u8* i=(uae_u8*)sc.eip; uae_u32 addr=sc.cr2; int r=-1; int size=4; int dir=-1; int len=0; int j; write_log("fault address is %08x at %08x\n",sc.cr2,sc.eip); if (!canbang) write_log("Not happy! Canbang is 0 in SIGSEGV handler!\n"); if (in_handler) write_log("Argh --- Am already in a handler. Shouldn't happen!\n"); if (canbang && i>=compiled_code && i<=current_compile_p) { if (*i==0x66) { i++; size=2; len++; } switch(i[0]) { case 0x8a: if ((i[1]&0xc0)==0x80) { r=(i[1]>>3)&7; dir=SIG_READ; size=1; len+=6; break; } break; case 0x88: if ((i[1]&0xc0)==0x80) { r=(i[1]>>3)&7; dir=SIG_WRITE; size=1; len+=6; break; } break; case 0x8b: if ((i[1]&0xc0)==0x80) { r=(i[1]>>3)&7; dir=SIG_READ; len+=6; break; } if ((i[1]&0xc0)==0x40) { r=(i[1]>>3)&7; dir=SIG_READ; len+=3; break; } break; case 0x89: if ((i[1]&0xc0)==0x80) { r=(i[1]>>3)&7; dir=SIG_WRITE; len+=6; break; } if ((i[1]&0xc0)==0x40) { r=(i[1]>>3)&7; dir=SIG_WRITE; len+=3; break; } break; } } if (r!=-1) { void* pr=NULL; write_log("register was %d, direction was %d, size was %d\n",r,dir,size); switch(r) { case 0: pr=&(sc.eax); break; case 1: pr=&(sc.ecx); break; case 2: pr=&(sc.edx); break; case 3: pr=&(sc.ebx); break; case 4: pr=(size>1)?NULL:(((uae_u8*)&(sc.eax))+1); break; case 5: pr=(size>1)? (void*)(&(sc.ebp)): (void*)(((uae_u8*)&(sc.ecx))+1); break; case 6: pr=(size>1)? (void*)(&(sc.esi)): (void*)(((uae_u8*)&(sc.edx))+1); break; case 7: pr=(size>1)? (void*)(&(sc.edi)): (void*)(((uae_u8*)&(sc.ebx))+1); break; default: abort(); } if (pr) { blockinfo* bi; if (currprefs.comp_oldsegv) { addr-=NATMEM_OFFSET; if ((addr>=0x10000000 && addr<0x40000000) || (addr>=0x50000000)) { write_log("Suspicious address in %x SEGV handler.\n",addr); } if (dir==SIG_READ) { switch(size) { case 1: *((uae_u8*)pr)=get_byte(addr); break; case 2: *((uae_u16*)pr)=get_word(addr); break; case 4: *((uae_u32*)pr)=get_long(addr); break; default: abort(); } } else { /* write */ switch(size) { case 1: put_byte(addr,*((uae_u8*)pr)); break; case 2: put_word(addr,*((uae_u16*)pr)); break; case 4: put_long(addr,*((uae_u32*)pr)); break; default: abort(); } } write_log("Handled one access!\n"); fflush(stdout); segvcount++; sc.eip+=len; } else { void* tmp=target; int i; uae_u8 vecbuf[5]; addr-=NATMEM_OFFSET; if ((addr>=0x10000000 && addr<0x40000000) || (addr>=0x50000000)) { write_log("Suspicious address in %x SEGV handler.\n",addr); } target=(uae_u8*)sc.eip; for (i=0;i<5;i++) vecbuf[i]=target[i]; emit_byte(0xe9); emit_long((uintptr)veccode-(uintptr)target-4); write_log("Create jump to %p\n",veccode); write_log("Handled one access!\n"); fflush(stdout); segvcount++; target=veccode; if (dir==SIG_READ) { switch(size) { case 1: raw_mov_b_ri(r,get_byte(addr)); break; case 2: raw_mov_w_ri(r,get_byte(addr)); break; case 4: raw_mov_l_ri(r,get_byte(addr)); break; default: abort(); } } else { /* write */ switch(size) { case 1: put_byte(addr,*((uae_u8*)pr)); break; case 2: put_word(addr,*((uae_u16*)pr)); break; case 4: put_long(addr,*((uae_u32*)pr)); break; default: abort(); } } for (i=0;i<5;i++) raw_mov_b_mi(sc.eip+i,vecbuf[i]); raw_mov_l_mi((uintptr)&in_handler,0); emit_byte(0xe9); emit_long(sc.eip+len-(uintptr)target-4); in_handler=1; target=tmp; } bi=active; while (bi) { if (bi->handler && (uae_u8*)bi->direct_handler<=i && (uae_u8*)bi->nexthandler>i) { write_log("deleted trigger (%p<%p<%p) %p\n", bi->handler, i, bi->nexthandler, bi->pc_p); invalidate_block(bi); raise_in_cl_list(bi); set_special(0); return; } bi=bi->next; } /* Not found in the active list. Might be a rom routine that is in the dormant list */ bi=dormant; while (bi) { if (bi->handler && (uae_u8*)bi->direct_handler<=i && (uae_u8*)bi->nexthandler>i) { write_log("deleted trigger (%p<%p<%p) %p\n", bi->handler, i, bi->nexthandler, bi->pc_p); invalidate_block(bi); raise_in_cl_list(bi); set_special(0); return; } bi=bi->next; } write_log("Huh? Could not find trigger!\n"); return; } } write_log("Can't handle access!\n"); for (j=0;j<10;j++) { write_log("instruction byte %2d is %02x\n",j,i[j]); } write_log("Please send the above info (starting at \"fault address\") to\n" "bmeyer@csse.monash.edu.au\n" "This shouldn't happen ;-)\n"); fflush(stdout); signal(SIGSEGV,SIG_DFL); /* returning here will cause a "real" SEGV */ } #endif /************************************************************************* * Checking for CPU features * *************************************************************************/ struct cpuinfo_x86 { uae_u8 x86; // CPU family uae_u8 x86_vendor; // CPU vendor uae_u8 x86_processor; // CPU canonical processor type uae_u8 x86_brand_id; // CPU BrandID if supported, yield 0 otherwise uae_u32 x86_hwcap; uae_u8 x86_model; uae_u8 x86_mask; int cpuid_level; // Maximum supported CPUID level, -1=no CPUID char x86_vendor_id[16]; }; struct cpuinfo_x86 cpuinfo; enum { X86_VENDOR_INTEL = 0, X86_VENDOR_CYRIX = 1, X86_VENDOR_AMD = 2, X86_VENDOR_UMC = 3, X86_VENDOR_NEXGEN = 4, X86_VENDOR_CENTAUR = 5, X86_VENDOR_RISE = 6, X86_VENDOR_TRANSMETA = 7, X86_VENDOR_NSC = 8, X86_VENDOR_UNKNOWN = 0xff }; enum { X86_PROCESSOR_I386, /* 80386 */ X86_PROCESSOR_I486, /* 80486DX, 80486SX, 80486DX[24] */ X86_PROCESSOR_PENTIUM, X86_PROCESSOR_PENTIUMPRO, X86_PROCESSOR_K6, X86_PROCESSOR_ATHLON, X86_PROCESSOR_PENTIUM4, X86_PROCESSOR_X86_64, X86_PROCESSOR_max }; static const char * x86_processor_string_table[X86_PROCESSOR_max] = { "80386", "80486", "Pentium", "PentiumPro", "K6", "Athlon", "Pentium4", "x86-64" }; static struct ptt { const int align_loop; const int align_loop_max_skip; const int align_jump; const int align_jump_max_skip; const int align_func; } x86_alignments[X86_PROCESSOR_max] = { { 4, 3, 4, 3, 4 }, { 16, 15, 16, 15, 16 }, { 16, 7, 16, 7, 16 }, { 16, 15, 16, 7, 16 }, { 32, 7, 32, 7, 32 }, { 16, 7, 16, 7, 16 }, { 0, 0, 0, 0, 0 }, { 16, 7, 16, 7, 16 } }; static void x86_get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; if (!strcmp(v, "GenuineIntel")) c->x86_vendor = X86_VENDOR_INTEL; else if (!strcmp(v, "AuthenticAMD")) c->x86_vendor = X86_VENDOR_AMD; else if (!strcmp(v, "CyrixInstead")) c->x86_vendor = X86_VENDOR_CYRIX; else if (!strcmp(v, "Geode by NSC")) c->x86_vendor = X86_VENDOR_NSC; else if (!strcmp(v, "UMC UMC UMC ")) c->x86_vendor = X86_VENDOR_UMC; else if (!strcmp(v, "CentaurHauls")) c->x86_vendor = X86_VENDOR_CENTAUR; else if (!strcmp(v, "NexGenDriven")) c->x86_vendor = X86_VENDOR_NEXGEN; else if (!strcmp(v, "RiseRiseRise")) c->x86_vendor = X86_VENDOR_RISE; else if (!strcmp(v, "GenuineTMx86") || !strcmp(v, "TransmetaCPU")) c->x86_vendor = X86_VENDOR_TRANSMETA; else c->x86_vendor = X86_VENDOR_UNKNOWN; } static void cpuid(uae_u32 op, uae_u32 *eax, uae_u32 *ebx, uae_u32 *ecx, uae_u32 *edx) { const int CPUID_SPACE = 4096; uae_u8* cpuid_space = (uae_u8 *)vm_acquire(CPUID_SPACE); if (cpuid_space == VM_MAP_FAILED) abort(); vm_protect(cpuid_space, CPUID_SPACE, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE); static uae_u32 s_op, s_eax, s_ebx, s_ecx, s_edx; uae_u8* tmp=get_target(); s_op = op; set_target(cpuid_space); raw_push_l_r(0); /* eax */ raw_push_l_r(1); /* ecx */ raw_push_l_r(2); /* edx */ raw_push_l_r(3); /* ebx */ raw_mov_l_rm(0,(uintptr)&s_op); raw_cpuid(0); raw_mov_l_mr((uintptr)&s_eax,0); raw_mov_l_mr((uintptr)&s_ebx,3); raw_mov_l_mr((uintptr)&s_ecx,1); raw_mov_l_mr((uintptr)&s_edx,2); raw_pop_l_r(3); raw_pop_l_r(2); raw_pop_l_r(1); raw_pop_l_r(0); raw_ret(); set_target(tmp); ((cpuop_func*)cpuid_space)(0); if (eax != NULL) *eax = s_eax; if (ebx != NULL) *ebx = s_ebx; if (ecx != NULL) *ecx = s_ecx; if (edx != NULL) *edx = s_edx; vm_release(cpuid_space, CPUID_SPACE); } static void raw_init_cpu(void) { struct cpuinfo_x86 *c = &cpuinfo; /* Defaults */ c->x86_processor = X86_PROCESSOR_max; c->x86_vendor = X86_VENDOR_UNKNOWN; c->cpuid_level = -1; /* CPUID not detected */ c->x86_model = c->x86_mask = 0; /* So far unknown... */ c->x86_vendor_id[0] = '\0'; /* Unset */ c->x86_hwcap = 0; /* Get vendor name */ c->x86_vendor_id[12] = '\0'; cpuid(0x00000000, (uae_u32 *)&c->cpuid_level, (uae_u32 *)&c->x86_vendor_id[0], (uae_u32 *)&c->x86_vendor_id[8], (uae_u32 *)&c->x86_vendor_id[4]); x86_get_cpu_vendor(c); /* Intel-defined flags: level 0x00000001 */ c->x86_brand_id = 0; if ( c->cpuid_level >= 0x00000001 ) { uae_u32 tfms, brand_id; cpuid(0x00000001, &tfms, &brand_id, NULL, &c->x86_hwcap); c->x86 = (tfms >> 8) & 15; if (c->x86 == 0xf) c->x86 += (tfms >> 20) & 0xff; /* extended family */ c->x86_model = (tfms >> 4) & 15; if (c->x86_model == 0xf) c->x86_model |= (tfms >> 12) & 0xf0; /* extended model */ c->x86_brand_id = brand_id & 0xff; c->x86_mask = tfms & 15; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; } /* AMD-defined flags: level 0x80000001 */ uae_u32 xlvl; cpuid(0x80000000, &xlvl, NULL, NULL, NULL); if ( (xlvl & 0xffff0000) == 0x80000000 ) { if ( xlvl >= 0x80000001 ) { uae_u32 features, extra_features; cpuid(0x80000001, NULL, NULL, &extra_features, &features); if (features & (1 << 29)) { /* Assume x86-64 if long mode is supported */ c->x86_processor = X86_PROCESSOR_X86_64; } if (extra_features & (1 << 0)) have_lahf_lm = true; } } /* Canonicalize processor ID */ switch (c->x86) { case 3: c->x86_processor = X86_PROCESSOR_I386; break; case 4: c->x86_processor = X86_PROCESSOR_I486; break; case 5: if (c->x86_vendor == X86_VENDOR_AMD) c->x86_processor = X86_PROCESSOR_K6; else c->x86_processor = X86_PROCESSOR_PENTIUM; break; case 6: if (c->x86_vendor == X86_VENDOR_AMD) c->x86_processor = X86_PROCESSOR_ATHLON; else c->x86_processor = X86_PROCESSOR_PENTIUMPRO; break; case 15: if (c->x86_processor == X86_PROCESSOR_max) { switch (c->x86_vendor) { case X86_VENDOR_INTEL: c->x86_processor = X86_PROCESSOR_PENTIUM4; break; case X86_VENDOR_AMD: /* Assume a 32-bit Athlon processor if not in long mode */ c->x86_processor = X86_PROCESSOR_ATHLON; break; } } break; } if (c->x86_processor == X86_PROCESSOR_max) { c->x86_processor = X86_PROCESSOR_I386; fprintf(stderr, "Error: unknown processor type, assuming i386\n"); fprintf(stderr, " Family : %d\n", c->x86); fprintf(stderr, " Model : %d\n", c->x86_model); fprintf(stderr, " Mask : %d\n", c->x86_mask); fprintf(stderr, " Vendor : %s [%d]\n", c->x86_vendor_id, c->x86_vendor); if (c->x86_brand_id) fprintf(stderr, " BrandID : %02x\n", c->x86_brand_id); } /* Have CMOV support? */ have_cmov = c->x86_hwcap & (1 << 15); #if defined(__x86_64__) if (!have_cmov) { write_log("x86-64 implementations are bound to have CMOV!\n"); abort(); } #endif /* Can the host CPU suffer from partial register stalls? */ have_rat_stall = (c->x86_vendor == X86_VENDOR_INTEL); #if 1 /* It appears that partial register writes are a bad idea even on AMD K7 cores, even though they are not supposed to have the dreaded rat stall. Why? Anyway, that's why we lie about it ;-) */ if (c->x86_processor == X86_PROCESSOR_ATHLON) have_rat_stall = true; #endif /* Alignments */ if (tune_alignment) { align_loops = x86_alignments[c->x86_processor].align_loop; align_jumps = x86_alignments[c->x86_processor].align_jump; } write_log("Max CPUID level=%d Processor is %s [%s]\n", c->cpuid_level, c->x86_vendor_id, x86_processor_string_table[c->x86_processor]); raw_flags_init(); } static bool target_check_bsf(void) { bool mismatch = false; for (int g_ZF = 0; g_ZF <= 1; g_ZF++) { for (int g_CF = 0; g_CF <= 1; g_CF++) { for (int g_OF = 0; g_OF <= 1; g_OF++) { for (int g_SF = 0; g_SF <= 1; g_SF++) { for (int value = -1; value <= 1; value++) { unsigned long flags = (g_SF << 7) | (g_OF << 11) | (g_ZF << 6) | g_CF; unsigned long tmp = value; __asm__ __volatile__ ("push %0; popf; bsf %1,%1; pushf; pop %0" : "+r" (flags), "+r" (tmp) : : "cc"); int OF = (flags >> 11) & 1; int SF = (flags >> 7) & 1; int ZF = (flags >> 6) & 1; int CF = flags & 1; tmp = (value == 0); if (ZF != tmp || SF != g_SF || OF != g_OF || CF != g_CF) mismatch = true; } }}}} if (mismatch) write_log("Target CPU defines all flags on BSF instruction\n"); return !mismatch; } /************************************************************************* * FPU stuff * *************************************************************************/ static __inline__ void raw_fp_init(void) { int i; for (i=0;i1) { emit_byte(0x9b); emit_byte(0xdb); emit_byte(0xe3); live.tos=-1; } #endif while (live.tos>=1) { emit_byte(0xde); emit_byte(0xd9); live.tos-=2; } while (live.tos>=0) { emit_byte(0xdd); emit_byte(0xd8); live.tos--; } raw_fp_init(); } static __inline__ void make_tos(int r) { int p,q; if (live.spos[r]<0) { /* Register not yet on stack */ emit_byte(0xd9); emit_byte(0xe8); /* Push '1' on the stack, just to grow it */ live.tos++; live.spos[r]=live.tos; live.onstack[live.tos]=r; return; } /* Register is on stack */ if (live.tos==live.spos[r]) return; p=live.spos[r]; q=live.onstack[live.tos]; emit_byte(0xd9); emit_byte(0xc8+live.tos-live.spos[r]); /* exchange it with top of stack */ live.onstack[live.tos]=r; live.spos[r]=live.tos; live.onstack[p]=q; live.spos[q]=p; } static __inline__ void make_tos2(int r, int r2) { int q; make_tos(r2); /* Put the reg that's supposed to end up in position2 on top */ if (live.spos[r]<0) { /* Register not yet on stack */ make_tos(r); /* This will extend the stack */ return; } /* Register is on stack */ emit_byte(0xd9); emit_byte(0xc9); /* Move r2 into position 2 */ q=live.onstack[live.tos-1]; live.onstack[live.tos]=q; live.spos[q]=live.tos; live.onstack[live.tos-1]=r2; live.spos[r2]=live.tos-1; make_tos(r); /* And r into 1 */ } static __inline__ int stackpos(int r) { if (live.spos[r]<0) abort(); if (live.tos=0) { /* source is on top of stack, and we already have the dest */ int dd=stackpos(d); emit_byte(0xdd); emit_byte(0xd0+dd); } else { emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source on tos */ tos_make(d); /* store to destination, pop if necessary */ } } LENDFUNC(NONE,NONE,2,raw_fmov_rr,(FW d, FR s)) LOWFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base)) { emit_byte(0xd9); emit_byte(0xa8+index); emit_long(base); } LENDFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base)) LOWFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xfa); /* take square root */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xfa); /* take square root */ } } LENDFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xe1); /* take fabs */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xe1); /* take fabs */ } } LENDFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xfc); /* take frndint */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xfc); /* take frndint */ } } LENDFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xff); /* take cos */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xff); /* take cos */ } } LENDFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xfe); /* take sin */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xfe); /* take sin */ } } LENDFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s)) static const double one=1; LOWFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s)) { int ds; usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xc0); /* duplicate top of stack. Now up to 8 high */ emit_byte(0xd9); emit_byte(0xfc); /* rndint */ emit_byte(0xd9); emit_byte(0xc9); /* swap top two elements */ emit_byte(0xd8); emit_byte(0xe1); /* subtract rounded from original */ emit_byte(0xd9); emit_byte(0xf0); /* f2xm1 */ x86_fadd_m((uintptr)&one); /* Add '1' without using extra stack space */ emit_byte(0xd9); emit_byte(0xfd); /* and scale it */ emit_byte(0xdd); emit_byte(0xd9); /* take he rounded value off */ tos_make(d); /* store to destination */ } LENDFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s)) { int ds; usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xea); /* fldl2e */ emit_byte(0xde); emit_byte(0xc9); /* fmulp --- multiply source by log2(e) */ emit_byte(0xd9); emit_byte(0xc0); /* duplicate top of stack. Now up to 8 high */ emit_byte(0xd9); emit_byte(0xfc); /* rndint */ emit_byte(0xd9); emit_byte(0xc9); /* swap top two elements */ emit_byte(0xd8); emit_byte(0xe1); /* subtract rounded from original */ emit_byte(0xd9); emit_byte(0xf0); /* f2xm1 */ x86_fadd_m((uintptr)&one); /* Add '1' without using extra stack space */ emit_byte(0xd9); emit_byte(0xfd); /* and scale it */ emit_byte(0xdd); emit_byte(0xd9); /* take he rounded value off */ tos_make(d); /* store to destination */ } LENDFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s)) { int ds; usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xe8); /* push '1' */ emit_byte(0xd9); emit_byte(0xc9); /* swap top two */ emit_byte(0xd9); emit_byte(0xf1); /* take 1*log2(x) */ tos_make(d); /* store to destination */ } LENDFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xe0); /* take fchs */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xe0); /* take fchs */ } } LENDFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xc0+ds); /* add source to dest*/ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xc0+ds); /* add source to dest*/ } } LENDFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xe8+ds); /* sub source from dest*/ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xe0+ds); /* sub src from dest */ } } LENDFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s)) { int ds; usereg(s); usereg(d); make_tos(d); ds=stackpos(s); emit_byte(0xdd); emit_byte(0xe0+ds); /* cmp dest with source*/ } LENDFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s)) LOWFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xc8+ds); /* mul dest by source*/ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xc8+ds); /* mul dest by source*/ } } LENDFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xf8+ds); /* div dest by source */ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xf0+ds); /* div dest by source*/ } } LENDFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); make_tos2(d,s); ds=stackpos(s); if (ds!=1) { printf("Failed horribly in raw_frem_rr! ds is %d\n",ds); abort(); } emit_byte(0xd9); emit_byte(0xf8); /* take rem from dest by source */ } LENDFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); make_tos2(d,s); ds=stackpos(s); if (ds!=1) { printf("Failed horribly in raw_frem1_rr! ds is %d\n",ds); abort(); } emit_byte(0xd9); emit_byte(0xf5); /* take rem1 from dest by source */ } LENDFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,1,raw_ftst_r,(FR r)) { make_tos(r); emit_byte(0xd9); /* ftst */ emit_byte(0xe4); } LENDFUNC(NONE,NONE,1,raw_ftst_r,(FR r)) /* %eax register is clobbered if target processor doesn't support fucomi */ #define FFLAG_NREG_CLOBBER_CONDITION !have_cmov #define FFLAG_NREG EAX_INDEX static __inline__ void raw_fflags_into_flags(int r) { int p; usereg(r); p=stackpos(r); emit_byte(0xd9); emit_byte(0xee); /* Push 0 */ emit_byte(0xd9); emit_byte(0xc9+p); /* swap top two around */ if (have_cmov) { // gb-- fucomi is for P6 cores only, not K6-2 then... emit_byte(0xdb); emit_byte(0xe9+p); /* fucomi them */ } else { emit_byte(0xdd); emit_byte(0xe1+p); /* fucom them */ emit_byte(0x9b); emit_byte(0xdf); emit_byte(0xe0); /* fstsw ax */ raw_sahf(0); /* sahf */ } emit_byte(0xdd); emit_byte(0xd9+p); /* store value back, and get rid of 0 */ } BasiliskII/src/uae_cpu/compiler/codegen_x86.h0000644000175000017500000036733510755660121021271 0ustar centriscentris/******************** -*- mode: C; tab-width: 8 -*- ******************** * * Run-time assembler for IA-32 and AMD64 * ***********************************************************************/ /*********************************************************************** * * This file is derived from CCG. * * Copyright 1999, 2000, 2001, 2002, 2003 Ian Piumarta * * Adaptations and enhancements for AMD64 support, Copyright 2003-2008 * Gwenole Beauchesne * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 * ***********************************************************************/ #ifndef X86_RTASM_H #define X86_RTASM_H /* NOTES * * o Best viewed on a 1024x768 screen with fixed-6x10 font ;-) * * TODO * * o Fix FIXMEs * o SSE instructions * o Optimize for cases where register numbers are not integral constants */ /* --- Configuration ------------------------------------------------------- */ /* Define to settle a "flat" register set, i.e. different regno for each size variant. */ #ifndef X86_FLAT_REGISTERS #define X86_FLAT_REGISTERS 1 #endif /* Define to generate x86-64 code. */ #ifndef X86_TARGET_64BIT #define X86_TARGET_64BIT 0 #endif /* Define to optimize ALU instructions. */ #ifndef X86_OPTIMIZE_ALU #define X86_OPTIMIZE_ALU 1 #endif /* Define to optimize rotate/shift instructions. */ #ifndef X86_OPTIMIZE_ROTSHI #define X86_OPTIMIZE_ROTSHI 1 #endif /* Define to optimize absolute addresses for RIP relative addressing. */ #ifndef X86_RIP_RELATIVE_ADDR #define X86_RIP_RELATIVE_ADDR 1 #endif /* --- Macros -------------------------------------------------------------- */ /* Functions used to emit code. * * x86_emit_byte(B) * x86_emit_word(W) * x86_emit_long(L) */ /* Get pointer to current code * * x86_get_target() */ /* Abort assembler, fatal failure. * * x86_emit_failure(MSG) */ #define x86_emit_failure0(MSG) (x86_emit_failure(MSG),0) /* --- Register set -------------------------------------------------------- */ enum { X86_RIP = -2, #if X86_FLAT_REGISTERS X86_NOREG = 0, X86_Reg8L_Base = 0x10, X86_Reg8H_Base = 0x20, X86_Reg16_Base = 0x30, X86_Reg32_Base = 0x40, X86_Reg64_Base = 0x50, X86_RegMMX_Base = 0x60, X86_RegXMM_Base = 0x70, X86_RegFPU_Base = 0x80 #else X86_NOREG = -1, X86_Reg8L_Base = 0, X86_Reg8H_Base = 16, X86_Reg16_Base = 0, X86_Reg32_Base = 0, X86_Reg64_Base = 0, X86_RegMMX_Base = 0, X86_RegXMM_Base = 0, X86_RegFPU_Base = 0 #endif }; enum { X86_AL = X86_Reg8L_Base, X86_CL, X86_DL, X86_BL, X86_SPL, X86_BPL, X86_SIL, X86_DIL, X86_R8B, X86_R9B, X86_R10B, X86_R11B, X86_R12B, X86_R13B, X86_R14B, X86_R15B, X86_AH = X86_Reg8H_Base + 4, X86_CH, X86_DH, X86_BH }; enum { X86_AX = X86_Reg16_Base, X86_CX, X86_DX, X86_BX, X86_SP, X86_BP, X86_SI, X86_DI, X86_R8W, X86_R9W, X86_R10W, X86_R11W, X86_R12W, X86_R13W, X86_R14W, X86_R15W }; enum { X86_EAX = X86_Reg32_Base, X86_ECX, X86_EDX, X86_EBX, X86_ESP, X86_EBP, X86_ESI, X86_EDI, X86_R8D, X86_R9D, X86_R10D, X86_R11D, X86_R12D, X86_R13D, X86_R14D, X86_R15D }; enum { X86_RAX = X86_Reg64_Base, X86_RCX, X86_RDX, X86_RBX, X86_RSP, X86_RBP, X86_RSI, X86_RDI, X86_R8, X86_R9, X86_R10, X86_R11, X86_R12, X86_R13, X86_R14, X86_R15 }; enum { X86_MM0 = X86_RegMMX_Base, X86_MM1, X86_MM2, X86_MM3, X86_MM4, X86_MM5, X86_MM6, X86_MM7, }; enum { X86_XMM0 = X86_RegXMM_Base, X86_XMM1, X86_XMM2, X86_XMM3, X86_XMM4, X86_XMM5, X86_XMM6, X86_XMM7, X86_XMM8, X86_XMM9, X86_XMM10, X86_XMM11, X86_XMM12, X86_XMM13, X86_XMM14, X86_XMM15 }; enum { X86_ST0 = X86_RegFPU_Base, X86_ST1, X86_ST2, X86_ST3, X86_ST4, X86_ST5, X86_ST6, X86_ST7 }; /* Register control and access * * _r0P(R) Null register? * _rIP(R) RIP register? * _rXP(R) Extended register? * * _rC(R) Class of register (only valid if X86_FLAT_REGISTERS) * _rR(R) Full register number * _rN(R) Short register number for encoding * * _r1(R) 8-bit register ID * _r2(R) 16-bit register ID * _r4(R) 32-bit register ID * _r8(R) 64-bit register ID * _rM(R) MMX register ID * _rX(R) XMM register ID * _rF(R) FPU register ID * _rA(R) Address register ID used for EA calculation */ #define _rST0P(R) ((int)(R) == (int)X86_ST0) #define _r0P(R) ((int)(R) == (int)X86_NOREG) #define _rIP(R) (X86_TARGET_64BIT ? ((int)(R) == (int)X86_RIP) : 0) #if X86_FLAT_REGISTERS #define _rC(R) ((R) & 0xf0) #define _rR(R) ((R) & 0x0f) #define _rN(R) ((R) & 0x07) #define _rXP(R) ((R) > 0 && _rR(R) > 7) #else #define _rN(R) ((R) & 0x07) #define _rR(R) (int(R)) #define _rXP(R) (_rR(R) > 7 && _rR(R) < 16) #endif #if !defined(_ASM_SAFETY) || ! X86_FLAT_REGISTERS #define _r1(R) _rN(R) #define _r2(R) _rN(R) #define _r4(R) _rN(R) #define _r8(R) _rN(R) #define _rA(R) _rN(R) #define _rM(R) _rN(R) #define _rX(R) _rN(R) #define _rF(R) _rN(R) #else #define _r1(R) ( ((_rC(R) & (X86_Reg8L_Base | X86_Reg8H_Base)) != 0) ? _rN(R) : x86_emit_failure0( "8-bit register required")) #define _r2(R) ( (_rC(R) == X86_Reg16_Base) ? _rN(R) : x86_emit_failure0("16-bit register required")) #define _r4(R) ( (_rC(R) == X86_Reg32_Base) ? _rN(R) : x86_emit_failure0("32-bit register required")) #define _r8(R) ( (_rC(R) == X86_Reg64_Base) ? _rN(R) : x86_emit_failure0("64-bit register required")) #define _rA(R) ( X86_TARGET_64BIT ? \ ( (_rC(R) == X86_Reg64_Base) ? _rN(R) : x86_emit_failure0("not a valid 64-bit base/index expression")) : \ ( (_rC(R) == X86_Reg32_Base) ? _rN(R) : x86_emit_failure0("not a valid 32-bit base/index expression")) ) #define _rM(R) ( (_rC(R) == X86_RegMMX_Base) ? _rN(R) : x86_emit_failure0("MMX register required")) #define _rX(R) ( (_rC(R) == X86_RegXMM_Base) ? _rN(R) : x86_emit_failure0("SSE register required")) #define _rF(R) ( (_rC(R) == X86_RegFPU_Base) ? _rN(R) : x86_emit_failure0("FPU register required")) #endif #define _rSP() (X86_TARGET_64BIT ? (int)X86_RSP : (int)X86_ESP) #define _r1e8lP(R) (int(R) >= X86_SPL && int(R) <= X86_DIL) #define _rbpP(R) (_rR(R) == _rR(X86_RBP)) #define _rspP(R) (_rR(R) == _rR(X86_RSP)) #define _rbp13P(R) (_rN(R) == _rN(X86_RBP)) #define _rsp12P(R) (_rN(R) == _rN(X86_RSP)) /* ========================================================================= */ /* --- UTILITY ------------------------------------------------------------- */ /* ========================================================================= */ typedef signed char _sc; typedef unsigned char _uc; typedef signed short _ss; typedef unsigned short _us; typedef signed int _sl; typedef unsigned int _ul; #define _UC(X) ((_uc )(unsigned long)(X)) #define _US(X) ((_us )(unsigned long)(X)) #define _SL(X) ((_sl )(unsigned long)(X)) #define _UL(X) ((_ul )(unsigned long)(X)) #define _PUC(X) ((_uc *)(X)) #define _PUS(X) ((_us *)(X)) #define _PSL(X) ((_sl *)(X)) #define _PUL(X) ((_ul *)(X)) #define _B(B) x86_emit_byte((B)) #define _W(W) x86_emit_word((W)) #define _L(L) x86_emit_long((L)) #define _Q(Q) x86_emit_quad((Q)) #define _MASK(N) ((unsigned)((1<<(N)))-1) #define _siP(N,I) (!((((unsigned)(I))^(((unsigned)(I))<<1))&~_MASK(N))) #define _uiP(N,I) (!(((unsigned)(I))&~_MASK(N))) #define _suiP(N,I) (_siP(N,I) | _uiP(N,I)) #ifndef _ASM_SAFETY #define _ck_s(W,I) (_UL(I) & _MASK(W)) #define _ck_u(W,I) (_UL(I) & _MASK(W)) #define _ck_su(W,I) (_UL(I) & _MASK(W)) #define _ck_d(W,I) (_UL(I) & _MASK(W)) #else #define _ck_s(W,I) (_siP(W,I) ? (_UL(I) & _MASK(W)) : x86_emit_failure0( "signed integer `"#I"' too large for "#W"-bit field")) #define _ck_u(W,I) (_uiP(W,I) ? (_UL(I) & _MASK(W)) : x86_emit_failure0("unsigned integer `"#I"' too large for "#W"-bit field")) #define _ck_su(W,I) (_suiP(W,I) ? (_UL(I) & _MASK(W)) : x86_emit_failure0( "integer `"#I"' too large for "#W"-bit field")) #define _ck_d(W,I) (_siP(W,I) ? (_UL(I) & _MASK(W)) : x86_emit_failure0( "displacement `"#I"' too large for "#W"-bit field")) #endif #define _s0P(I) ((I)==0) #define _s8P(I) _siP(8,I) #define _s16P(I) _siP(16,I) #define _u8P(I) _uiP(8,I) #define _u16P(I) _uiP(16,I) #define _su8(I) _ck_su(8,I) #define _su16(I) _ck_su(16,I) #define _s1(I) _ck_s( 1,I) #define _s2(I) _ck_s( 2,I) #define _s3(I) _ck_s( 3,I) #define _s4(I) _ck_s( 4,I) #define _s5(I) _ck_s( 5,I) #define _s6(I) _ck_s( 6,I) #define _s7(I) _ck_s( 7,I) #define _s8(I) _ck_s( 8,I) #define _s9(I) _ck_s( 9,I) #define _s10(I) _ck_s(10,I) #define _s11(I) _ck_s(11,I) #define _s12(I) _ck_s(12,I) #define _s13(I) _ck_s(13,I) #define _s14(I) _ck_s(14,I) #define _s15(I) _ck_s(15,I) #define _s16(I) _ck_s(16,I) #define _s17(I) _ck_s(17,I) #define _s18(I) _ck_s(18,I) #define _s19(I) _ck_s(19,I) #define _s20(I) _ck_s(20,I) #define _s21(I) _ck_s(21,I) #define _s22(I) _ck_s(22,I) #define _s23(I) _ck_s(23,I) #define _s24(I) _ck_s(24,I) #define _s25(I) _ck_s(25,I) #define _s26(I) _ck_s(26,I) #define _s27(I) _ck_s(27,I) #define _s28(I) _ck_s(28,I) #define _s29(I) _ck_s(29,I) #define _s30(I) _ck_s(30,I) #define _s31(I) _ck_s(31,I) #define _u1(I) _ck_u( 1,I) #define _u2(I) _ck_u( 2,I) #define _u3(I) _ck_u( 3,I) #define _u4(I) _ck_u( 4,I) #define _u5(I) _ck_u( 5,I) #define _u6(I) _ck_u( 6,I) #define _u7(I) _ck_u( 7,I) #define _u8(I) _ck_u( 8,I) #define _u9(I) _ck_u( 9,I) #define _u10(I) _ck_u(10,I) #define _u11(I) _ck_u(11,I) #define _u12(I) _ck_u(12,I) #define _u13(I) _ck_u(13,I) #define _u14(I) _ck_u(14,I) #define _u15(I) _ck_u(15,I) #define _u16(I) _ck_u(16,I) #define _u17(I) _ck_u(17,I) #define _u18(I) _ck_u(18,I) #define _u19(I) _ck_u(19,I) #define _u20(I) _ck_u(20,I) #define _u21(I) _ck_u(21,I) #define _u22(I) _ck_u(22,I) #define _u23(I) _ck_u(23,I) #define _u24(I) _ck_u(24,I) #define _u25(I) _ck_u(25,I) #define _u26(I) _ck_u(26,I) #define _u27(I) _ck_u(27,I) #define _u28(I) _ck_u(28,I) #define _u29(I) _ck_u(29,I) #define _u30(I) _ck_u(30,I) #define _u31(I) _ck_u(31,I) /* ========================================================================= */ /* --- ASSEMBLER ----------------------------------------------------------- */ /* ========================================================================= */ #define _b00 0 #define _b01 1 #define _b10 2 #define _b11 3 #define _b000 0 #define _b001 1 #define _b010 2 #define _b011 3 #define _b100 4 #define _b101 5 #define _b110 6 #define _b111 7 #define _OFF4(D) (_UL(D) - _UL(x86_get_target())) #define _CKD8(D) _ck_d(8, ((_uc) _OFF4(D)) ) #define _D8(D) (_B(0), ((*(_PUC(x86_get_target())-1))= _CKD8(D))) #define _D32(D) (_L(0), ((*(_PUL(x86_get_target())-1))= _OFF4(D))) #ifndef _ASM_SAFETY # define _M(M) (M) # define _r(R) (R) # define _m(M) (M) # define _s(S) (S) # define _i(I) (I) # define _b(B) (B) #else # define _M(M) (((M)>3) ? x86_emit_failure0("internal error: mod = " #M) : (M)) # define _r(R) (((R)>7) ? x86_emit_failure0("internal error: reg = " #R) : (R)) # define _m(M) (((M)>7) ? x86_emit_failure0("internal error: r/m = " #M) : (M)) # define _s(S) (((S)>3) ? x86_emit_failure0("internal error: memory scale = " #S) : (S)) # define _i(I) (((I)>7) ? x86_emit_failure0("internal error: memory index = " #I) : (I)) # define _b(B) (((B)>7) ? x86_emit_failure0("internal error: memory base = " #B) : (B)) #endif #define _Mrm(Md,R,M) _B((_M(Md)<<6)|(_r(R)<<3)|_m(M)) #define _SIB(Sc,I, B) _B((_s(Sc)<<6)|(_i(I)<<3)|_b(B)) #define _SCL(S) ((((S)==1) ? _b00 : \ (((S)==2) ? _b01 : \ (((S)==4) ? _b10 : \ (((S)==8) ? _b11 : x86_emit_failure0("illegal scale: " #S)))))) /* --- Memory subformats - urgh! ------------------------------------------- */ /* _r_D() is RIP addressing mode if X86_TARGET_64BIT, use _r_DSIB() instead */ #define _r_D( R, D ) (_Mrm(_b00,_rN(R),_b101 ) ,_L((_sl)(D))) #define _r_DSIB(R, D ) (_Mrm(_b00,_rN(R),_b100 ),_SIB(_SCL(1),_b100 ,_b101 ),_L((_sl)(D))) #define _r_0B( R, B ) (_Mrm(_b00,_rN(R),_rA(B)) ) #define _r_0BIS(R, B,I,S) (_Mrm(_b00,_rN(R),_b100 ),_SIB(_SCL(S),_rA(I),_rA(B)) ) #define _r_1B( R, D,B ) (_Mrm(_b01,_rN(R),_rA(B)) ,_B((_sc)(D))) #define _r_1BIS(R, D,B,I,S) (_Mrm(_b01,_rN(R),_b100 ),_SIB(_SCL(S),_rA(I),_rA(B)),_B((_sc)(D))) #define _r_4B( R, D,B ) (_Mrm(_b10,_rN(R),_rA(B)) ,_L((_sl)(D))) #define _r_4IS( R, D,I,S) (_Mrm(_b00,_rN(R),_b100 ),_SIB(_SCL(S),_rA(I),_b101 ),_L((_sl)(D))) #define _r_4BIS(R, D,B,I,S) (_Mrm(_b10,_rN(R),_b100 ),_SIB(_SCL(S),_rA(I),_rA(B)),_L((_sl)(D))) #define _r_DB( R, D,B ) ((_s0P(D) && (!_rbp13P(B)) ? _r_0B (R, B ) : (_s8P(D) ? _r_1B( R,D,B ) : _r_4B( R,D,B )))) #define _r_DBIS(R, D,B,I,S) ((_s0P(D) && (!_rbp13P(B)) ? _r_0BIS(R, B,I,S) : (_s8P(D) ? _r_1BIS(R,D,B,I,S) : _r_4BIS(R,D,B,I,S)))) /* Use RIP-addressing in 64-bit mode, if possible */ #define _x86_RIP_addressing_possible(D,O) (X86_RIP_RELATIVE_ADDR && \ ((uintptr)x86_get_target() + 4 + (O) - (D) <= 0xffffffff)) #define _r_X( R, D,B,I,S,O) (_r0P(I) ? (_r0P(B) ? (!X86_TARGET_64BIT ? _r_D(R,D) : \ (_x86_RIP_addressing_possible(D, O) ? \ _r_D(R, (D) - ((uintptr)x86_get_target() + 4 + (O))) : \ _r_DSIB(R,D))) : \ (_rIP(B) ? _r_D (R,D ) : \ (_rsp12P(B) ? _r_DBIS(R,D,_rSP(),_rSP(),1) : \ _r_DB (R,D, B )))) : \ (_r0P(B) ? _r_4IS (R,D, I,S) : \ (!_rspP(I) ? _r_DBIS(R,D, B, I,S) : \ x86_emit_failure("illegal index register: %esp")))) /* --- Instruction formats ------------------------------------------------- */ #define _m32only(X) (! X86_TARGET_64BIT ? X : x86_emit_failure("invalid instruction in 64-bit mode")) #define _m64only(X) ( X86_TARGET_64BIT ? X : x86_emit_failure("invalid instruction in 32-bit mode")) #define _m64(X) ( X86_TARGET_64BIT ? X : ((void)0) ) /* _format Opcd ModR/M dN(rB,rI,Sc) imm... */ #define _d16() ( _B(0x66 ) ) #define _O( OP ) ( _B( OP ) ) #define _Or( OP,R ) ( _B( (OP)|_r(R)) ) #define _OO( OP ) ( _B((OP)>>8), _B(( (OP) )&0xff) ) #define _OOr( OP,R ) ( _B((OP)>>8), _B(( (OP)|_r(R))&0xff) ) #define _Os( OP,B ) ( _s8P(B) ? _B(((OP)|_b10)) : _B(OP) ) #define _sW( W ) ( _s8P(W) ? _B(W):_W(W) ) #define _sL( L ) ( _s8P(L) ? _B(L):_L(L) ) #define _sWO( W ) ( _s8P(W) ? 1 : 2 ) #define _sLO( L ) ( _s8P(L) ? 1 : 4 ) #define _O_B( OP ,B ) ( _O ( OP ) ,_B(B) ) #define _O_W( OP ,W ) ( _O ( OP ) ,_W(W) ) #define _O_L( OP ,L ) ( _O ( OP ) ,_L(L) ) #define _OO_L( OP ,L ) ( _OO ( OP ) ,_L(L) ) #define _O_D8( OP ,D ) ( _O ( OP ) ,_D8(D) ) #define _O_D32( OP ,D ) ( _O ( OP ) ,_D32(D) ) #define _OO_D32( OP ,D ) ( _OO ( OP ) ,_D32(D) ) #define _Os_sW( OP ,W ) ( _Os ( OP,W) ,_sW(W) ) #define _Os_sL( OP ,L ) ( _Os ( OP,L) ,_sL(L) ) #define _O_W_B( OP ,W,B) ( _O ( OP ) ,_W(W),_B(B)) #define _Or_B( OP,R ,B ) ( _Or ( OP,R) ,_B(B) ) #define _Or_W( OP,R ,W ) ( _Or ( OP,R) ,_W(W) ) #define _Or_L( OP,R ,L ) ( _Or ( OP,R) ,_L(L) ) #define _Or_Q( OP,R ,Q ) ( _Or ( OP,R) ,_Q(Q) ) #define _O_Mrm( OP ,MO,R,M ) ( _O ( OP ),_Mrm(MO,R,M ) ) #define _OO_Mrm( OP ,MO,R,M ) ( _OO ( OP ),_Mrm(MO,R,M ) ) #define _O_Mrm_B( OP ,MO,R,M ,B ) ( _O ( OP ),_Mrm(MO,R,M ) ,_B(B) ) #define _O_Mrm_W( OP ,MO,R,M ,W ) ( _O ( OP ),_Mrm(MO,R,M ) ,_W(W) ) #define _O_Mrm_L( OP ,MO,R,M ,L ) ( _O ( OP ),_Mrm(MO,R,M ) ,_L(L) ) #define _OO_Mrm_B( OP ,MO,R,M ,B ) ( _OO ( OP ),_Mrm(MO,R,M ) ,_B(B) ) #define _Os_Mrm_sW(OP ,MO,R,M ,W ) ( _Os ( OP,W),_Mrm(MO,R,M ),_sW(W) ) #define _Os_Mrm_sL(OP ,MO,R,M ,L ) ( _Os ( OP,L),_Mrm(MO,R,M ),_sL(L) ) #define _O_r_X( OP ,R ,MD,MB,MI,MS ) ( _O ( OP ),_r_X( R ,MD,MB,MI,MS,0) ) #define _OO_r_X( OP ,R ,MD,MB,MI,MS ) ( _OO ( OP ),_r_X( R ,MD,MB,MI,MS,0) ) #define _O_r_X_B( OP ,R ,MD,MB,MI,MS,B ) ( _O ( OP ),_r_X( R ,MD,MB,MI,MS,1) ,_B(B) ) #define _O_r_X_W( OP ,R ,MD,MB,MI,MS,W ) ( _O ( OP ),_r_X( R ,MD,MB,MI,MS,2) ,_W(W) ) #define _O_r_X_L( OP ,R ,MD,MB,MI,MS,L ) ( _O ( OP ),_r_X( R ,MD,MB,MI,MS,4) ,_L(L) ) #define _OO_r_X_B( OP ,R ,MD,MB,MI,MS,B ) ( _OO ( OP ),_r_X( R ,MD,MB,MI,MS,1) ,_B(B) ) #define _Os_r_X_sW(OP ,R ,MD,MB,MI,MS,W ) ( _Os ( OP,W),_r_X( R ,MD,MB,MI,MS,_sWO(W)),_sW(W)) #define _Os_r_X_sL(OP ,R ,MD,MB,MI,MS,L ) ( _Os ( OP,L),_r_X( R ,MD,MB,MI,MS,_sLO(L)),_sL(L)) #define _O_X_B( OP ,MD,MB,MI,MS,B ) ( _O_r_X_B( OP ,0 ,MD,MB,MI,MS ,B) ) #define _O_X_W( OP ,MD,MB,MI,MS,W ) ( _O_r_X_W( OP ,0 ,MD,MB,MI,MS ,W) ) #define _O_X_L( OP ,MD,MB,MI,MS,L ) ( _O_r_X_L( OP ,0 ,MD,MB,MI,MS ,L) ) /* --- REX prefixes -------------------------------------------------------- */ #define _VOID() ((void)0) #define _BIT(X) (!!(X)) #define _d64(W,R,X,B) (_B(0x40|(W)<<3|(R)<<2|(X)<<1|(B))) #define __REXwrxb(L,W,R,X,B) ((W|R|X|B) || (L) ? _d64(W,R,X,B) : _VOID()) #define __REXwrx_(L,W,R,X,MR) (__REXwrxb(L,W,R,X,_BIT(_rIP(MR)?0:_rXP(MR)))) #define __REXw_x_(L,W,R,X,MR) (__REXwrx_(L,W,_BIT(_rXP(R)),X,MR)) #define __REX_reg(RR) (__REXwrxb(0,0,0,00,_BIT(_rXP(RR)))) #define __REX_mem(MB,MI) (__REXwrxb(0,0,0,_BIT(_rXP(MI)),_BIT(_rXP(MB)))) // FIXME: can't mix new (SPL,BPL,SIL,DIL) with (AH,BH,CH,DH) #define _REXBrr(RR,MR) _m64(__REXw_x_(_r1e8lP(RR)||_r1e8lP(MR),0,RR,0,MR)) #define _REXBmr(MB,MI,RD) _m64(__REXw_x_(_r1e8lP(RD)||_r1e8lP(MB),0,RD,_BIT(_rXP(MI)),MB)) #define _REXBrm(RS,MB,MI) _REXBmr(MB,MI,RS) #define _REXBLrr(RR,MR) _m64(__REXw_x_(_r1e8lP(MR),0,RR,0,MR)) #define _REXLrr(RR,MR) _m64(__REXw_x_(0,0,RR,0,MR)) #define _REXLmr(MB,MI,RD) _m64(__REXw_x_(0,0,RD,_BIT(_rXP(MI)),MB)) #define _REXLrm(RS,MB,MI) _REXLmr(MB,MI,RS) #define _REXLr(RR) _m64(__REX_reg(RR)) #define _REXLm(MB,MI) _m64(__REX_mem(MB,MI)) #define _REXQrr(RR,MR) _m64only(__REXw_x_(0,1,RR,0,MR)) #define _REXQmr(MB,MI,RD) _m64only(__REXw_x_(0,1,RD,_BIT(_rXP(MI)),MB)) #define _REXQrm(RS,MB,MI) _REXQmr(MB,MI,RS) #define _REXQr(RR) _m64only(__REX_reg(RR)) #define _REXQm(MB,MI) _m64only(__REX_mem(MB,MI)) /* ========================================================================= */ /* --- Fully-qualified intrinsic instructions ------------------------------ */ /* ========================================================================= */ /* OPCODE + i = immediate operand * + r = register operand * + m = memory operand (disp,base,index,scale) * + sr/sm = a star preceding a register or memory * + 0 = top of stack register (for FPU instructions) * * NOTE in x86-64 mode: a memory operand with only a valid * displacement value will lead to the expect absolute mode. If * RIP addressing is necessary, X86_RIP shall be used as the base * register argument. */ /* --- ALU instructions ---------------------------------------------------- */ enum { X86_ADD = 0, X86_OR = 1, X86_ADC = 2, X86_SBB = 3, X86_AND = 4, X86_SUB = 5, X86_XOR = 6, X86_CMP = 7, }; /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define _ALUBrr(OP,RS, RD) (_REXBrr(RS, RD), _O_Mrm (((OP) << 3) ,_b11,_r1(RS),_r1(RD) )) #define _ALUBmr(OP, MD, MB, MI, MS, RD) (_REXBmr(MB, MI, RD), _O_r_X (((OP) << 3) + 2 ,_r1(RD) ,MD,MB,MI,MS )) #define _ALUBrm(OP, RS, MD, MB, MI, MS) (_REXBrm(RS, MB, MI), _O_r_X (((OP) << 3) ,_r1(RS) ,MD,MB,MI,MS )) #define _ALUBir(OP, IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_AL) ? \ (_REXBrr(0, RD), _O_B (((OP) << 3) + 4 ,_su8(IM))) : \ (_REXBrr(0, RD), _O_Mrm_B (0x80 ,_b11,OP ,_r1(RD) ,_su8(IM))) ) #define _ALUBim(OP, IM, MD, MB, MI, MS) (_REXBrm(0, MB, MI), _O_r_X_B (0x80 ,OP ,MD,MB,MI,MS ,_su8(IM))) #define _ALUWrr(OP, RS, RD) (_d16(), _REXLrr(RS, RD), _O_Mrm (((OP) << 3) + 1,_b11,_r2(RS),_r2(RD) )) #define _ALUWmr(OP, MD, MB, MI, MS, RD) (_d16(), _REXLmr(MB, MI, RD), _O_r_X (((OP) << 3) + 3 ,_r2(RD) ,MD,MB,MI,MS )) #define _ALUWrm(OP, RS, MD, MB, MI, MS) (_d16(), _REXLrm(RS, MB, MI), _O_r_X (((OP) << 3) + 1 ,_r2(RS) ,MD,MB,MI,MS )) #define _ALUWir(OP, IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_AX) ? \ (_d16(), _REXLrr(0, RD), _O_W (((OP) << 3) + 5 ,_su16(IM))) : \ (_d16(), _REXLrr(0, RD), _Os_Mrm_sW (0x81 ,_b11,OP ,_r2(RD) ,_su16(IM))) ) #define _ALUWim(OP, IM, MD, MB, MI, MS) (_d16(), _REXLrm(0, MB, MI), _Os_r_X_sW (0x81 ,OP ,MD,MB,MI,MS ,_su16(IM))) #define _ALULrr(OP, RS, RD) (_REXLrr(RS, RD), _O_Mrm (((OP) << 3) + 1,_b11,_r4(RS),_r4(RD) )) #define _ALULmr(OP, MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _O_r_X (((OP) << 3) + 3 ,_r4(RD) ,MD,MB,MI,MS )) #define _ALULrm(OP, RS, MD, MB, MI, MS) (_REXLrm(RS, MB, MI), _O_r_X (((OP) << 3) + 1 ,_r4(RS) ,MD,MB,MI,MS )) #define _ALULir(OP, IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_EAX) ? \ (_REXLrr(0, RD), _O_L (((OP) << 3) + 5 ,IM )) : \ (_REXLrr(0, RD), _Os_Mrm_sL (0x81 ,_b11,OP ,_r4(RD) ,IM )) ) #define _ALULim(OP, IM, MD, MB, MI, MS) (_REXLrm(0, MB, MI), _Os_r_X_sL (0x81 ,OP ,MD,MB,MI,MS ,IM )) #define _ALUQrr(OP, RS, RD) (_REXQrr(RS, RD), _O_Mrm (((OP) << 3) + 1,_b11,_r8(RS),_r8(RD) )) #define _ALUQmr(OP, MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _O_r_X (((OP) << 3) + 3 ,_r8(RD) ,MD,MB,MI,MS )) #define _ALUQrm(OP, RS, MD, MB, MI, MS) (_REXQrm(RS, MB, MI), _O_r_X (((OP) << 3) + 1 ,_r8(RS) ,MD,MB,MI,MS )) #define _ALUQir(OP, IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_RAX) ? \ (_REXQrr(0, RD), _O_L (((OP) << 3) + 5 ,IM )) : \ (_REXQrr(0, RD), _Os_Mrm_sL (0x81 ,_b11,OP ,_r8(RD) ,IM )) ) #define _ALUQim(OP, IM, MD, MB, MI, MS) (_REXQrm(0, MB, MI), _Os_r_X_sL (0x81 ,OP ,MD,MB,MI,MS ,IM )) #define ADCBrr(RS, RD) _ALUBrr(X86_ADC, RS, RD) #define ADCBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_ADC, MD, MB, MI, MS, RD) #define ADCBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_ADC, RS, MD, MB, MI, MS) #define ADCBir(IM, RD) _ALUBir(X86_ADC, IM, RD) #define ADCBim(IM, MD, MB, MI, MS) _ALUBim(X86_ADC, IM, MD, MB, MI, MS) #define ADCWrr(RS, RD) _ALUWrr(X86_ADC, RS, RD) #define ADCWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_ADC, MD, MB, MI, MS, RD) #define ADCWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_ADC, RS, MD, MB, MI, MS) #define ADCWir(IM, RD) _ALUWir(X86_ADC, IM, RD) #define ADCWim(IM, MD, MB, MI, MS) _ALUWim(X86_ADC, IM, MD, MB, MI, MS) #define ADCLrr(RS, RD) _ALULrr(X86_ADC, RS, RD) #define ADCLmr(MD, MB, MI, MS, RD) _ALULmr(X86_ADC, MD, MB, MI, MS, RD) #define ADCLrm(RS, MD, MB, MI, MS) _ALULrm(X86_ADC, RS, MD, MB, MI, MS) #define ADCLir(IM, RD) _ALULir(X86_ADC, IM, RD) #define ADCLim(IM, MD, MB, MI, MS) _ALULim(X86_ADC, IM, MD, MB, MI, MS) #define ADCQrr(RS, RD) _ALUQrr(X86_ADC, RS, RD) #define ADCQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_ADC, MD, MB, MI, MS, RD) #define ADCQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_ADC, RS, MD, MB, MI, MS) #define ADCQir(IM, RD) _ALUQir(X86_ADC, IM, RD) #define ADCQim(IM, MD, MB, MI, MS) _ALUQim(X86_ADC, IM, MD, MB, MI, MS) #define ADDBrr(RS, RD) _ALUBrr(X86_ADD, RS, RD) #define ADDBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_ADD, MD, MB, MI, MS, RD) #define ADDBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_ADD, RS, MD, MB, MI, MS) #define ADDBir(IM, RD) _ALUBir(X86_ADD, IM, RD) #define ADDBim(IM, MD, MB, MI, MS) _ALUBim(X86_ADD, IM, MD, MB, MI, MS) #define ADDWrr(RS, RD) _ALUWrr(X86_ADD, RS, RD) #define ADDWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_ADD, MD, MB, MI, MS, RD) #define ADDWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_ADD, RS, MD, MB, MI, MS) #define ADDWir(IM, RD) _ALUWir(X86_ADD, IM, RD) #define ADDWim(IM, MD, MB, MI, MS) _ALUWim(X86_ADD, IM, MD, MB, MI, MS) #define ADDLrr(RS, RD) _ALULrr(X86_ADD, RS, RD) #define ADDLmr(MD, MB, MI, MS, RD) _ALULmr(X86_ADD, MD, MB, MI, MS, RD) #define ADDLrm(RS, MD, MB, MI, MS) _ALULrm(X86_ADD, RS, MD, MB, MI, MS) #define ADDLir(IM, RD) _ALULir(X86_ADD, IM, RD) #define ADDLim(IM, MD, MB, MI, MS) _ALULim(X86_ADD, IM, MD, MB, MI, MS) #define ADDQrr(RS, RD) _ALUQrr(X86_ADD, RS, RD) #define ADDQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_ADD, MD, MB, MI, MS, RD) #define ADDQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_ADD, RS, MD, MB, MI, MS) #define ADDQir(IM, RD) _ALUQir(X86_ADD, IM, RD) #define ADDQim(IM, MD, MB, MI, MS) _ALUQim(X86_ADD, IM, MD, MB, MI, MS) #define ANDBrr(RS, RD) _ALUBrr(X86_AND, RS, RD) #define ANDBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_AND, MD, MB, MI, MS, RD) #define ANDBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_AND, RS, MD, MB, MI, MS) #define ANDBir(IM, RD) _ALUBir(X86_AND, IM, RD) #define ANDBim(IM, MD, MB, MI, MS) _ALUBim(X86_AND, IM, MD, MB, MI, MS) #define ANDWrr(RS, RD) _ALUWrr(X86_AND, RS, RD) #define ANDWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_AND, MD, MB, MI, MS, RD) #define ANDWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_AND, RS, MD, MB, MI, MS) #define ANDWir(IM, RD) _ALUWir(X86_AND, IM, RD) #define ANDWim(IM, MD, MB, MI, MS) _ALUWim(X86_AND, IM, MD, MB, MI, MS) #define ANDLrr(RS, RD) _ALULrr(X86_AND, RS, RD) #define ANDLmr(MD, MB, MI, MS, RD) _ALULmr(X86_AND, MD, MB, MI, MS, RD) #define ANDLrm(RS, MD, MB, MI, MS) _ALULrm(X86_AND, RS, MD, MB, MI, MS) #define ANDLir(IM, RD) _ALULir(X86_AND, IM, RD) #define ANDLim(IM, MD, MB, MI, MS) _ALULim(X86_AND, IM, MD, MB, MI, MS) #define ANDQrr(RS, RD) _ALUQrr(X86_AND, RS, RD) #define ANDQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_AND, MD, MB, MI, MS, RD) #define ANDQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_AND, RS, MD, MB, MI, MS) #define ANDQir(IM, RD) _ALUQir(X86_AND, IM, RD) #define ANDQim(IM, MD, MB, MI, MS) _ALUQim(X86_AND, IM, MD, MB, MI, MS) #define CMPBrr(RS, RD) _ALUBrr(X86_CMP, RS, RD) #define CMPBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_CMP, MD, MB, MI, MS, RD) #define CMPBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_CMP, RS, MD, MB, MI, MS) #define CMPBir(IM, RD) _ALUBir(X86_CMP, IM, RD) #define CMPBim(IM, MD, MB, MI, MS) _ALUBim(X86_CMP, IM, MD, MB, MI, MS) #define CMPWrr(RS, RD) _ALUWrr(X86_CMP, RS, RD) #define CMPWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_CMP, MD, MB, MI, MS, RD) #define CMPWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_CMP, RS, MD, MB, MI, MS) #define CMPWir(IM, RD) _ALUWir(X86_CMP, IM, RD) #define CMPWim(IM, MD, MB, MI, MS) _ALUWim(X86_CMP, IM, MD, MB, MI, MS) #define CMPLrr(RS, RD) _ALULrr(X86_CMP, RS, RD) #define CMPLmr(MD, MB, MI, MS, RD) _ALULmr(X86_CMP, MD, MB, MI, MS, RD) #define CMPLrm(RS, MD, MB, MI, MS) _ALULrm(X86_CMP, RS, MD, MB, MI, MS) #define CMPLir(IM, RD) _ALULir(X86_CMP, IM, RD) #define CMPLim(IM, MD, MB, MI, MS) _ALULim(X86_CMP, IM, MD, MB, MI, MS) #define CMPQrr(RS, RD) _ALUQrr(X86_CMP, RS, RD) #define CMPQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_CMP, MD, MB, MI, MS, RD) #define CMPQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_CMP, RS, MD, MB, MI, MS) #define CMPQir(IM, RD) _ALUQir(X86_CMP, IM, RD) #define CMPQim(IM, MD, MB, MI, MS) _ALUQim(X86_CMP, IM, MD, MB, MI, MS) #define ORBrr(RS, RD) _ALUBrr(X86_OR, RS, RD) #define ORBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_OR, MD, MB, MI, MS, RD) #define ORBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_OR, RS, MD, MB, MI, MS) #define ORBir(IM, RD) _ALUBir(X86_OR, IM, RD) #define ORBim(IM, MD, MB, MI, MS) _ALUBim(X86_OR, IM, MD, MB, MI, MS) #define ORWrr(RS, RD) _ALUWrr(X86_OR, RS, RD) #define ORWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_OR, MD, MB, MI, MS, RD) #define ORWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_OR, RS, MD, MB, MI, MS) #define ORWir(IM, RD) _ALUWir(X86_OR, IM, RD) #define ORWim(IM, MD, MB, MI, MS) _ALUWim(X86_OR, IM, MD, MB, MI, MS) #define ORLrr(RS, RD) _ALULrr(X86_OR, RS, RD) #define ORLmr(MD, MB, MI, MS, RD) _ALULmr(X86_OR, MD, MB, MI, MS, RD) #define ORLrm(RS, MD, MB, MI, MS) _ALULrm(X86_OR, RS, MD, MB, MI, MS) #define ORLir(IM, RD) _ALULir(X86_OR, IM, RD) #define ORLim(IM, MD, MB, MI, MS) _ALULim(X86_OR, IM, MD, MB, MI, MS) #define ORQrr(RS, RD) _ALUQrr(X86_OR, RS, RD) #define ORQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_OR, MD, MB, MI, MS, RD) #define ORQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_OR, RS, MD, MB, MI, MS) #define ORQir(IM, RD) _ALUQir(X86_OR, IM, RD) #define ORQim(IM, MD, MB, MI, MS) _ALUQim(X86_OR, IM, MD, MB, MI, MS) #define SBBBrr(RS, RD) _ALUBrr(X86_SBB, RS, RD) #define SBBBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_SBB, MD, MB, MI, MS, RD) #define SBBBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_SBB, RS, MD, MB, MI, MS) #define SBBBir(IM, RD) _ALUBir(X86_SBB, IM, RD) #define SBBBim(IM, MD, MB, MI, MS) _ALUBim(X86_SBB, IM, MD, MB, MI, MS) #define SBBWrr(RS, RD) _ALUWrr(X86_SBB, RS, RD) #define SBBWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_SBB, MD, MB, MI, MS, RD) #define SBBWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_SBB, RS, MD, MB, MI, MS) #define SBBWir(IM, RD) _ALUWir(X86_SBB, IM, RD) #define SBBWim(IM, MD, MB, MI, MS) _ALUWim(X86_SBB, IM, MD, MB, MI, MS) #define SBBLrr(RS, RD) _ALULrr(X86_SBB, RS, RD) #define SBBLmr(MD, MB, MI, MS, RD) _ALULmr(X86_SBB, MD, MB, MI, MS, RD) #define SBBLrm(RS, MD, MB, MI, MS) _ALULrm(X86_SBB, RS, MD, MB, MI, MS) #define SBBLir(IM, RD) _ALULir(X86_SBB, IM, RD) #define SBBLim(IM, MD, MB, MI, MS) _ALULim(X86_SBB, IM, MD, MB, MI, MS) #define SBBQrr(RS, RD) _ALUQrr(X86_SBB, RS, RD) #define SBBQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_SBB, MD, MB, MI, MS, RD) #define SBBQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_SBB, RS, MD, MB, MI, MS) #define SBBQir(IM, RD) _ALUQir(X86_SBB, IM, RD) #define SBBQim(IM, MD, MB, MI, MS) _ALUQim(X86_SBB, IM, MD, MB, MI, MS) #define SUBBrr(RS, RD) _ALUBrr(X86_SUB, RS, RD) #define SUBBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_SUB, MD, MB, MI, MS, RD) #define SUBBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_SUB, RS, MD, MB, MI, MS) #define SUBBir(IM, RD) _ALUBir(X86_SUB, IM, RD) #define SUBBim(IM, MD, MB, MI, MS) _ALUBim(X86_SUB, IM, MD, MB, MI, MS) #define SUBWrr(RS, RD) _ALUWrr(X86_SUB, RS, RD) #define SUBWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_SUB, MD, MB, MI, MS, RD) #define SUBWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_SUB, RS, MD, MB, MI, MS) #define SUBWir(IM, RD) _ALUWir(X86_SUB, IM, RD) #define SUBWim(IM, MD, MB, MI, MS) _ALUWim(X86_SUB, IM, MD, MB, MI, MS) #define SUBLrr(RS, RD) _ALULrr(X86_SUB, RS, RD) #define SUBLmr(MD, MB, MI, MS, RD) _ALULmr(X86_SUB, MD, MB, MI, MS, RD) #define SUBLrm(RS, MD, MB, MI, MS) _ALULrm(X86_SUB, RS, MD, MB, MI, MS) #define SUBLir(IM, RD) _ALULir(X86_SUB, IM, RD) #define SUBLim(IM, MD, MB, MI, MS) _ALULim(X86_SUB, IM, MD, MB, MI, MS) #define SUBQrr(RS, RD) _ALUQrr(X86_SUB, RS, RD) #define SUBQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_SUB, MD, MB, MI, MS, RD) #define SUBQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_SUB, RS, MD, MB, MI, MS) #define SUBQir(IM, RD) _ALUQir(X86_SUB, IM, RD) #define SUBQim(IM, MD, MB, MI, MS) _ALUQim(X86_SUB, IM, MD, MB, MI, MS) #define XORBrr(RS, RD) _ALUBrr(X86_XOR, RS, RD) #define XORBmr(MD, MB, MI, MS, RD) _ALUBmr(X86_XOR, MD, MB, MI, MS, RD) #define XORBrm(RS, MD, MB, MI, MS) _ALUBrm(X86_XOR, RS, MD, MB, MI, MS) #define XORBir(IM, RD) _ALUBir(X86_XOR, IM, RD) #define XORBim(IM, MD, MB, MI, MS) _ALUBim(X86_XOR, IM, MD, MB, MI, MS) #define XORWrr(RS, RD) _ALUWrr(X86_XOR, RS, RD) #define XORWmr(MD, MB, MI, MS, RD) _ALUWmr(X86_XOR, MD, MB, MI, MS, RD) #define XORWrm(RS, MD, MB, MI, MS) _ALUWrm(X86_XOR, RS, MD, MB, MI, MS) #define XORWir(IM, RD) _ALUWir(X86_XOR, IM, RD) #define XORWim(IM, MD, MB, MI, MS) _ALUWim(X86_XOR, IM, MD, MB, MI, MS) #define XORLrr(RS, RD) _ALULrr(X86_XOR, RS, RD) #define XORLmr(MD, MB, MI, MS, RD) _ALULmr(X86_XOR, MD, MB, MI, MS, RD) #define XORLrm(RS, MD, MB, MI, MS) _ALULrm(X86_XOR, RS, MD, MB, MI, MS) #define XORLir(IM, RD) _ALULir(X86_XOR, IM, RD) #define XORLim(IM, MD, MB, MI, MS) _ALULim(X86_XOR, IM, MD, MB, MI, MS) #define XORQrr(RS, RD) _ALUQrr(X86_XOR, RS, RD) #define XORQmr(MD, MB, MI, MS, RD) _ALUQmr(X86_XOR, MD, MB, MI, MS, RD) #define XORQrm(RS, MD, MB, MI, MS) _ALUQrm(X86_XOR, RS, MD, MB, MI, MS) #define XORQir(IM, RD) _ALUQir(X86_XOR, IM, RD) #define XORQim(IM, MD, MB, MI, MS) _ALUQim(X86_XOR, IM, MD, MB, MI, MS) /* --- Shift/Rotate instructions ------------------------------------------- */ enum { X86_ROL = 0, X86_ROR = 1, X86_RCL = 2, X86_RCR = 3, X86_SHL = 4, X86_SHR = 5, X86_SAR = 7, }; /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define _ROTSHIBir(OP,IM,RD) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_REXBrr(0, RD), _O_Mrm (0xd0 ,_b11,OP,_r1(RD) )) : \ (_REXBrr(0, RD), _O_Mrm_B (0xc0 ,_b11,OP,_r1(RD) ,_u8(IM))) ) #define _ROTSHIBim(OP,IM,MD,MB,MI,MS) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_REXBrm(0, MB, MI), _O_r_X (0xd0 ,OP ,MD,MB,MI,MS )) : \ (_REXBrm(0, MB, MI), _O_r_X_B (0xc0 ,OP ,MD,MB,MI,MS ,_u8(IM))) ) #define _ROTSHIBrr(OP,RS,RD) (((RS) == X86_CL) ? \ (_REXBrr(RS, RD), _O_Mrm (0xd2 ,_b11,OP,_r1(RD) )) : \ x86_emit_failure("source register must be CL" ) ) #define _ROTSHIBrm(OP,RS,MD,MB,MI,MS) (((RS) == X86_CL) ? \ (_REXBrm(RS, MB, MI), _O_r_X (0xd2 ,OP ,MD,MB,MI,MS )) : \ x86_emit_failure("source register must be CL" ) ) #define _ROTSHIWir(OP,IM,RD) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_d16(), _REXLrr(0, RD), _O_Mrm (0xd1 ,_b11,OP,_r2(RD) )) : \ (_d16(), _REXLrr(0, RD), _O_Mrm_B (0xc1 ,_b11,OP,_r2(RD) ,_u8(IM))) ) #define _ROTSHIWim(OP,IM,MD,MB,MI,MS) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_d16(), _REXLrm(0, MB, MI), _O_r_X (0xd1 ,OP ,MD,MB,MI,MS )) : \ (_d16(), _REXLrm(0, MB, MI), _O_r_X_B (0xc1 ,OP ,MD,MB,MI,MS ,_u8(IM))) ) #define _ROTSHIWrr(OP,RS,RD) (((RS) == X86_CL) ? \ (_d16(), _REXLrr(RS, RD), _O_Mrm (0xd3 ,_b11,OP,_r2(RD) )) : \ x86_emit_failure("source register must be CL" ) ) #define _ROTSHIWrm(OP,RS,MD,MB,MI,MS) (((RS) == X86_CL) ? \ (_d16(), _REXLrm(RS, MB, MI), _O_r_X (0xd3 ,OP ,MD,MB,MI,MS )) : \ x86_emit_failure("source register must be CL" ) ) #define _ROTSHILir(OP,IM,RD) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_REXLrr(0, RD), _O_Mrm (0xd1 ,_b11,OP,_r4(RD) )) : \ (_REXLrr(0, RD), _O_Mrm_B (0xc1 ,_b11,OP,_r4(RD) ,_u8(IM))) ) #define _ROTSHILim(OP,IM,MD,MB,MI,MS) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_REXLrm(0, MB, MI), _O_r_X (0xd1 ,OP ,MD,MB,MI,MS )) : \ (_REXLrm(0, MB, MI), _O_r_X_B (0xc1 ,OP ,MD,MB,MI,MS ,_u8(IM))) ) #define _ROTSHILrr(OP,RS,RD) (((RS) == X86_CL) ? \ (_REXLrr(RS, RD), _O_Mrm (0xd3 ,_b11,OP,_r4(RD) )) : \ x86_emit_failure("source register must be CL" ) ) #define _ROTSHILrm(OP,RS,MD,MB,MI,MS) (((RS) == X86_CL) ? \ (_REXLrm(RS, MB, MI), _O_r_X (0xd3 ,OP ,MD,MB,MI,MS )) : \ x86_emit_failure("source register must be CL" ) ) #define _ROTSHIQir(OP,IM,RD) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_REXQrr(0, RD), _O_Mrm (0xd1 ,_b11,OP,_r8(RD) )) : \ (_REXQrr(0, RD), _O_Mrm_B (0xc1 ,_b11,OP,_r8(RD) ,_u8(IM))) ) #define _ROTSHIQim(OP,IM,MD,MB,MI,MS) (X86_OPTIMIZE_ROTSHI && ((IM) == 1) ? \ (_REXQrm(0, MB, MI), _O_r_X (0xd1 ,OP ,MD,MB,MI,MS )) : \ (_REXQrm(0, MB, MI), _O_r_X_B (0xc1 ,OP ,MD,MB,MI,MS ,_u8(IM))) ) #define _ROTSHIQrr(OP,RS,RD) (((RS) == X86_CL) ? \ (_REXQrr(RS, RD), _O_Mrm (0xd3 ,_b11,OP,_r8(RD) )) : \ x86_emit_failure("source register must be CL" ) ) #define _ROTSHIQrm(OP,RS,MD,MB,MI,MS) (((RS) == X86_CL) ? \ (_REXQrm(RS, MB, MI), _O_r_X (0xd3 ,OP ,MD,MB,MI,MS )) : \ x86_emit_failure("source register must be CL" ) ) #define ROLBir(IM, RD) _ROTSHIBir(X86_ROL, IM, RD) #define ROLBim(IM, MD, MB, MI, MS) _ROTSHIBim(X86_ROL, IM, MD, MB, MI, MS) #define ROLBrr(RS, RD) _ROTSHIBrr(X86_ROL, RS, RD) #define ROLBrm(RS, MD, MB, MI, MS) _ROTSHIBrm(X86_ROL, RS, MD, MB, MI, MS) #define ROLWir(IM, RD) _ROTSHIWir(X86_ROL, IM, RD) #define ROLWim(IM, MD, MB, MI, MS) _ROTSHIWim(X86_ROL, IM, MD, MB, MI, MS) #define ROLWrr(RS, RD) _ROTSHIWrr(X86_ROL, RS, RD) #define ROLWrm(RS, MD, MB, MI, MS) _ROTSHIWrm(X86_ROL, RS, MD, MB, MI, MS) #define ROLLir(IM, RD) _ROTSHILir(X86_ROL, IM, RD) #define ROLLim(IM, MD, MB, MI, MS) _ROTSHILim(X86_ROL, IM, MD, MB, MI, MS) #define ROLLrr(RS, RD) _ROTSHILrr(X86_ROL, RS, RD) #define ROLLrm(RS, MD, MB, MI, MS) _ROTSHILrm(X86_ROL, RS, MD, MB, MI, MS) #define ROLQir(IM, RD) _ROTSHIQir(X86_ROL, IM, RD) #define ROLQim(IM, MD, MB, MI, MS) _ROTSHIQim(X86_ROL, IM, MD, MB, MI, MS) #define ROLQrr(RS, RD) _ROTSHIQrr(X86_ROL, RS, RD) #define ROLQrm(RS, MD, MB, MI, MS) _ROTSHIQrm(X86_ROL, RS, MD, MB, MI, MS) #define RORBir(IM, RD) _ROTSHIBir(X86_ROR, IM, RD) #define RORBim(IM, MD, MB, MI, MS) _ROTSHIBim(X86_ROR, IM, MD, MB, MI, MS) #define RORBrr(RS, RD) _ROTSHIBrr(X86_ROR, RS, RD) #define RORBrm(RS, MD, MB, MI, MS) _ROTSHIBrm(X86_ROR, RS, MD, MB, MI, MS) #define RORWir(IM, RD) _ROTSHIWir(X86_ROR, IM, RD) #define RORWim(IM, MD, MB, MI, MS) _ROTSHIWim(X86_ROR, IM, MD, MB, MI, MS) #define RORWrr(RS, RD) _ROTSHIWrr(X86_ROR, RS, RD) #define RORWrm(RS, MD, MB, MI, MS) _ROTSHIWrm(X86_ROR, RS, MD, MB, MI, MS) #define RORLir(IM, RD) _ROTSHILir(X86_ROR, IM, RD) #define RORLim(IM, MD, MB, MI, MS) _ROTSHILim(X86_ROR, IM, MD, MB, MI, MS) #define RORLrr(RS, RD) _ROTSHILrr(X86_ROR, RS, RD) #define RORLrm(RS, MD, MB, MI, MS) _ROTSHILrm(X86_ROR, RS, MD, MB, MI, MS) #define RORQir(IM, RD) _ROTSHIQir(X86_ROR, IM, RD) #define RORQim(IM, MD, MB, MI, MS) _ROTSHIQim(X86_ROR, IM, MD, MB, MI, MS) #define RORQrr(RS, RD) _ROTSHIQrr(X86_ROR, RS, RD) #define RORQrm(RS, MD, MB, MI, MS) _ROTSHIQrm(X86_ROR, RS, MD, MB, MI, MS) #define RCLBir(IM, RD) _ROTSHIBir(X86_RCL, IM, RD) #define RCLBim(IM, MD, MB, MI, MS) _ROTSHIBim(X86_RCL, IM, MD, MB, MI, MS) #define RCLBrr(RS, RD) _ROTSHIBrr(X86_RCL, RS, RD) #define RCLBrm(RS, MD, MB, MI, MS) _ROTSHIBrm(X86_RCL, RS, MD, MB, MI, MS) #define RCLWir(IM, RD) _ROTSHIWir(X86_RCL, IM, RD) #define RCLWim(IM, MD, MB, MI, MS) _ROTSHIWim(X86_RCL, IM, MD, MB, MI, MS) #define RCLWrr(RS, RD) _ROTSHIWrr(X86_RCL, RS, RD) #define RCLWrm(RS, MD, MB, MI, MS) _ROTSHIWrm(X86_RCL, RS, MD, MB, MI, MS) #define RCLLir(IM, RD) _ROTSHILir(X86_RCL, IM, RD) #define RCLLim(IM, MD, MB, MI, MS) _ROTSHILim(X86_RCL, IM, MD, MB, MI, MS) #define RCLLrr(RS, RD) _ROTSHILrr(X86_RCL, RS, RD) #define RCLLrm(RS, MD, MB, MI, MS) _ROTSHILrm(X86_RCL, RS, MD, MB, MI, MS) #define RCLQir(IM, RD) _ROTSHIQir(X86_RCL, IM, RD) #define RCLQim(IM, MD, MB, MI, MS) _ROTSHIQim(X86_RCL, IM, MD, MB, MI, MS) #define RCLQrr(RS, RD) _ROTSHIQrr(X86_RCL, RS, RD) #define RCLQrm(RS, MD, MB, MI, MS) _ROTSHIQrm(X86_RCL, RS, MD, MB, MI, MS) #define RCRBir(IM, RD) _ROTSHIBir(X86_RCR, IM, RD) #define RCRBim(IM, MD, MB, MI, MS) _ROTSHIBim(X86_RCR, IM, MD, MB, MI, MS) #define RCRBrr(RS, RD) _ROTSHIBrr(X86_RCR, RS, RD) #define RCRBrm(RS, MD, MB, MI, MS) _ROTSHIBrm(X86_RCR, RS, MD, MB, MI, MS) #define RCRWir(IM, RD) _ROTSHIWir(X86_RCR, IM, RD) #define RCRWim(IM, MD, MB, MI, MS) _ROTSHIWim(X86_RCR, IM, MD, MB, MI, MS) #define RCRWrr(RS, RD) _ROTSHIWrr(X86_RCR, RS, RD) #define RCRWrm(RS, MD, MB, MI, MS) _ROTSHIWrm(X86_RCR, RS, MD, MB, MI, MS) #define RCRLir(IM, RD) _ROTSHILir(X86_RCR, IM, RD) #define RCRLim(IM, MD, MB, MI, MS) _ROTSHILim(X86_RCR, IM, MD, MB, MI, MS) #define RCRLrr(RS, RD) _ROTSHILrr(X86_RCR, RS, RD) #define RCRLrm(RS, MD, MB, MI, MS) _ROTSHILrm(X86_RCR, RS, MD, MB, MI, MS) #define RCRQir(IM, RD) _ROTSHIQir(X86_RCR, IM, RD) #define RCRQim(IM, MD, MB, MI, MS) _ROTSHIQim(X86_RCR, IM, MD, MB, MI, MS) #define RCRQrr(RS, RD) _ROTSHIQrr(X86_RCR, RS, RD) #define RCRQrm(RS, MD, MB, MI, MS) _ROTSHIQrm(X86_RCR, RS, MD, MB, MI, MS) #define SHLBir(IM, RD) _ROTSHIBir(X86_SHL, IM, RD) #define SHLBim(IM, MD, MB, MI, MS) _ROTSHIBim(X86_SHL, IM, MD, MB, MI, MS) #define SHLBrr(RS, RD) _ROTSHIBrr(X86_SHL, RS, RD) #define SHLBrm(RS, MD, MB, MI, MS) _ROTSHIBrm(X86_SHL, RS, MD, MB, MI, MS) #define SHLWir(IM, RD) _ROTSHIWir(X86_SHL, IM, RD) #define SHLWim(IM, MD, MB, MI, MS) _ROTSHIWim(X86_SHL, IM, MD, MB, MI, MS) #define SHLWrr(RS, RD) _ROTSHIWrr(X86_SHL, RS, RD) #define SHLWrm(RS, MD, MB, MI, MS) _ROTSHIWrm(X86_SHL, RS, MD, MB, MI, MS) #define SHLLir(IM, RD) _ROTSHILir(X86_SHL, IM, RD) #define SHLLim(IM, MD, MB, MI, MS) _ROTSHILim(X86_SHL, IM, MD, MB, MI, MS) #define SHLLrr(RS, RD) _ROTSHILrr(X86_SHL, RS, RD) #define SHLLrm(RS, MD, MB, MI, MS) _ROTSHILrm(X86_SHL, RS, MD, MB, MI, MS) #define SHLQir(IM, RD) _ROTSHIQir(X86_SHL, IM, RD) #define SHLQim(IM, MD, MB, MI, MS) _ROTSHIQim(X86_SHL, IM, MD, MB, MI, MS) #define SHLQrr(RS, RD) _ROTSHIQrr(X86_SHL, RS, RD) #define SHLQrm(RS, MD, MB, MI, MS) _ROTSHIQrm(X86_SHL, RS, MD, MB, MI, MS) #define SHRBir(IM, RD) _ROTSHIBir(X86_SHR, IM, RD) #define SHRBim(IM, MD, MB, MI, MS) _ROTSHIBim(X86_SHR, IM, MD, MB, MI, MS) #define SHRBrr(RS, RD) _ROTSHIBrr(X86_SHR, RS, RD) #define SHRBrm(RS, MD, MB, MI, MS) _ROTSHIBrm(X86_SHR, RS, MD, MB, MI, MS) #define SHRWir(IM, RD) _ROTSHIWir(X86_SHR, IM, RD) #define SHRWim(IM, MD, MB, MI, MS) _ROTSHIWim(X86_SHR, IM, MD, MB, MI, MS) #define SHRWrr(RS, RD) _ROTSHIWrr(X86_SHR, RS, RD) #define SHRWrm(RS, MD, MB, MI, MS) _ROTSHIWrm(X86_SHR, RS, MD, MB, MI, MS) #define SHRLir(IM, RD) _ROTSHILir(X86_SHR, IM, RD) #define SHRLim(IM, MD, MB, MI, MS) _ROTSHILim(X86_SHR, IM, MD, MB, MI, MS) #define SHRLrr(RS, RD) _ROTSHILrr(X86_SHR, RS, RD) #define SHRLrm(RS, MD, MB, MI, MS) _ROTSHILrm(X86_SHR, RS, MD, MB, MI, MS) #define SHRQir(IM, RD) _ROTSHIQir(X86_SHR, IM, RD) #define SHRQim(IM, MD, MB, MI, MS) _ROTSHIQim(X86_SHR, IM, MD, MB, MI, MS) #define SHRQrr(RS, RD) _ROTSHIQrr(X86_SHR, RS, RD) #define SHRQrm(RS, MD, MB, MI, MS) _ROTSHIQrm(X86_SHR, RS, MD, MB, MI, MS) #define SALBir SHLBir #define SALBim SHLBim #define SALBrr SHLBrr #define SALBrm SHLBrm #define SALWir SHLWir #define SALWim SHLWim #define SALWrr SHLWrr #define SALWrm SHLWrm #define SALLir SHLLir #define SALLim SHLLim #define SALLrr SHLLrr #define SALLrm SHLLrm #define SALQir SHLQir #define SALQim SHLQim #define SALQrr SHLQrr #define SALQrm SHLQrm #define SARBir(IM, RD) _ROTSHIBir(X86_SAR, IM, RD) #define SARBim(IM, MD, MB, MI, MS) _ROTSHIBim(X86_SAR, IM, MD, MB, MI, MS) #define SARBrr(RS, RD) _ROTSHIBrr(X86_SAR, RS, RD) #define SARBrm(RS, MD, MB, MI, MS) _ROTSHIBrm(X86_SAR, RS, MD, MB, MI, MS) #define SARWir(IM, RD) _ROTSHIWir(X86_SAR, IM, RD) #define SARWim(IM, MD, MB, MI, MS) _ROTSHIWim(X86_SAR, IM, MD, MB, MI, MS) #define SARWrr(RS, RD) _ROTSHIWrr(X86_SAR, RS, RD) #define SARWrm(RS, MD, MB, MI, MS) _ROTSHIWrm(X86_SAR, RS, MD, MB, MI, MS) #define SARLir(IM, RD) _ROTSHILir(X86_SAR, IM, RD) #define SARLim(IM, MD, MB, MI, MS) _ROTSHILim(X86_SAR, IM, MD, MB, MI, MS) #define SARLrr(RS, RD) _ROTSHILrr(X86_SAR, RS, RD) #define SARLrm(RS, MD, MB, MI, MS) _ROTSHILrm(X86_SAR, RS, MD, MB, MI, MS) #define SARQir(IM, RD) _ROTSHIQir(X86_SAR, IM, RD) #define SARQim(IM, MD, MB, MI, MS) _ROTSHIQim(X86_SAR, IM, MD, MB, MI, MS) #define SARQrr(RS, RD) _ROTSHIQrr(X86_SAR, RS, RD) #define SARQrm(RS, MD, MB, MI, MS) _ROTSHIQrm(X86_SAR, RS, MD, MB, MI, MS) /* --- Bit test instructions ----------------------------------------------- */ enum { X86_BT = 4, X86_BTS = 5, X86_BTR = 6, X86_BTC = 7, }; /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define _BTWir(OP, IM, RD) (_d16(), _REXLrr(0, RD), _OO_Mrm_B (0x0fba ,_b11,OP ,_r2(RD) ,_u8(IM))) #define _BTWim(OP, IM, MD, MB, MI, MS) (_d16(), _REXLrm(0, MB, MI), _OO_r_X_B (0x0fba ,OP ,MD,MB,MI,MS ,_u8(IM))) #define _BTWrr(OP, RS, RD) (_d16(), _REXLrr(RS, RD), _OO_Mrm (0x0f83|((OP)<<3),_b11,_r2(RS),_r2(RD) )) #define _BTWrm(OP, RS, MD, MB, MI, MS) (_d16(), _REXLrm(RS, MB, MI), _OO_r_X (0x0f83|((OP)<<3) ,_r2(RS) ,MD,MB,MI,MS )) #define _BTLir(OP, IM, RD) (_REXLrr(0, RD), _OO_Mrm_B (0x0fba ,_b11,OP ,_r4(RD) ,_u8(IM))) #define _BTLim(OP, IM, MD, MB, MI, MS) (_REXLrm(0, MB, MI), _OO_r_X_B (0x0fba ,OP ,MD,MB,MI,MS ,_u8(IM))) #define _BTLrr(OP, RS, RD) (_REXLrr(RS, RD), _OO_Mrm (0x0f83|((OP)<<3),_b11,_r4(RS),_r4(RD) )) #define _BTLrm(OP, RS, MD, MB, MI, MS) (_REXLrm(RS, MB, MI), _OO_r_X (0x0f83|((OP)<<3) ,_r4(RS) ,MD,MB,MI,MS )) #define _BTQir(OP, IM, RD) (_REXQrr(0, RD), _OO_Mrm_B (0x0fba ,_b11,OP ,_r8(RD) ,_u8(IM))) #define _BTQim(OP, IM, MD, MB, MI, MS) (_REXQrm(0, MB, MI), _OO_r_X_B (0x0fba ,OP ,MD,MB,MI,MS ,_u8(IM))) #define _BTQrr(OP, RS, RD) (_REXQrr(RS, RD), _OO_Mrm (0x0f83|((OP)<<3),_b11,_r8(RS),_r8(RD) )) #define _BTQrm(OP, RS, MD, MB, MI, MS) (_REXQrm(RS, MB, MI), _OO_r_X (0x0f83|((OP)<<3) ,_r8(RS) ,MD,MB,MI,MS )) #define BTWir(IM, RD) _BTWir(X86_BT, IM, RD) #define BTWim(IM, MD, MB, MI, MS) _BTWim(X86_BT, IM, MD, MB, MI, MS) #define BTWrr(RS, RD) _BTWrr(X86_BT, RS, RD) #define BTWrm(RS, MD, MB, MI, MS) _BTWrm(X86_BT, RS, MD, MB, MI, MS) #define BTLir(IM, RD) _BTLir(X86_BT, IM, RD) #define BTLim(IM, MD, MB, MI, MS) _BTLim(X86_BT, IM, MD, MB, MI, MS) #define BTLrr(RS, RD) _BTLrr(X86_BT, RS, RD) #define BTLrm(RS, MD, MB, MI, MS) _BTLrm(X86_BT, RS, MD, MB, MI, MS) #define BTQir(IM, RD) _BTQir(X86_BT, IM, RD) #define BTQim(IM, MD, MB, MI, MS) _BTQim(X86_BT, IM, MD, MB, MI, MS) #define BTQrr(RS, RD) _BTQrr(X86_BT, RS, RD) #define BTQrm(RS, MD, MB, MI, MS) _BTQrm(X86_BT, RS, MD, MB, MI, MS) #define BTCWir(IM, RD) _BTWir(X86_BTC, IM, RD) #define BTCWim(IM, MD, MB, MI, MS) _BTWim(X86_BTC, IM, MD, MB, MI, MS) #define BTCWrr(RS, RD) _BTWrr(X86_BTC, RS, RD) #define BTCWrm(RS, MD, MB, MI, MS) _BTWrm(X86_BTC, RS, MD, MB, MI, MS) #define BTCLir(IM, RD) _BTLir(X86_BTC, IM, RD) #define BTCLim(IM, MD, MB, MI, MS) _BTLim(X86_BTC, IM, MD, MB, MI, MS) #define BTCLrr(RS, RD) _BTLrr(X86_BTC, RS, RD) #define BTCLrm(RS, MD, MB, MI, MS) _BTLrm(X86_BTC, RS, MD, MB, MI, MS) #define BTCQir(IM, RD) _BTQir(X86_BTC, IM, RD) #define BTCQim(IM, MD, MB, MI, MS) _BTQim(X86_BTC, IM, MD, MB, MI, MS) #define BTCQrr(RS, RD) _BTQrr(X86_BTC, RS, RD) #define BTCQrm(RS, MD, MB, MI, MS) _BTQrm(X86_BTC, RS, MD, MB, MI, MS) #define BTRWir(IM, RD) _BTWir(X86_BTR, IM, RD) #define BTRWim(IM, MD, MB, MI, MS) _BTWim(X86_BTR, IM, MD, MB, MI, MS) #define BTRWrr(RS, RD) _BTWrr(X86_BTR, RS, RD) #define BTRWrm(RS, MD, MB, MI, MS) _BTWrm(X86_BTR, RS, MD, MB, MI, MS) #define BTRLir(IM, RD) _BTLir(X86_BTR, IM, RD) #define BTRLim(IM, MD, MB, MI, MS) _BTLim(X86_BTR, IM, MD, MB, MI, MS) #define BTRLrr(RS, RD) _BTLrr(X86_BTR, RS, RD) #define BTRLrm(RS, MD, MB, MI, MS) _BTLrm(X86_BTR, RS, MD, MB, MI, MS) #define BTRQir(IM, RD) _BTQir(X86_BTR, IM, RD) #define BTRQim(IM, MD, MB, MI, MS) _BTQim(X86_BTR, IM, MD, MB, MI, MS) #define BTRQrr(RS, RD) _BTQrr(X86_BTR, RS, RD) #define BTRQrm(RS, MD, MB, MI, MS) _BTQrm(X86_BTR, RS, MD, MB, MI, MS) #define BTSWir(IM, RD) _BTWir(X86_BTS, IM, RD) #define BTSWim(IM, MD, MB, MI, MS) _BTWim(X86_BTS, IM, MD, MB, MI, MS) #define BTSWrr(RS, RD) _BTWrr(X86_BTS, RS, RD) #define BTSWrm(RS, MD, MB, MI, MS) _BTWrm(X86_BTS, RS, MD, MB, MI, MS) #define BTSLir(IM, RD) _BTLir(X86_BTS, IM, RD) #define BTSLim(IM, MD, MB, MI, MS) _BTLim(X86_BTS, IM, MD, MB, MI, MS) #define BTSLrr(RS, RD) _BTLrr(X86_BTS, RS, RD) #define BTSLrm(RS, MD, MB, MI, MS) _BTLrm(X86_BTS, RS, MD, MB, MI, MS) #define BTSQir(IM, RD) _BTQir(X86_BTS, IM, RD) #define BTSQim(IM, MD, MB, MI, MS) _BTQim(X86_BTS, IM, MD, MB, MI, MS) #define BTSQrr(RS, RD) _BTQrr(X86_BTS, RS, RD) #define BTSQrm(RS, MD, MB, MI, MS) _BTQrm(X86_BTS, RS, MD, MB, MI, MS) /* --- Move instructions --------------------------------------------------- */ /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define MOVBrr(RS, RD) (_REXBrr(RS, RD), _O_Mrm (0x88 ,_b11,_r1(RS),_r1(RD) )) #define MOVBmr(MD, MB, MI, MS, RD) (_REXBmr(MB, MI, RD), _O_r_X (0x8a ,_r1(RD) ,MD,MB,MI,MS )) #define MOVBrm(RS, MD, MB, MI, MS) (_REXBrm(RS, MB, MI), _O_r_X (0x88 ,_r1(RS) ,MD,MB,MI,MS )) #define MOVBir(IM, R) (_REXBrr(0, R), _Or_B (0xb0,_r1(R) ,_su8(IM))) #define MOVBim(IM, MD, MB, MI, MS) (_REXBrm(0, MB, MI), _O_X_B (0xc6 ,MD,MB,MI,MS ,_su8(IM))) #define MOVWrr(RS, RD) (_d16(), _REXLrr(RS, RD), _O_Mrm (0x89 ,_b11,_r2(RS),_r2(RD) )) #define MOVWmr(MD, MB, MI, MS, RD) (_d16(), _REXLmr(MB, MI, RD), _O_r_X (0x8b ,_r2(RD) ,MD,MB,MI,MS )) #define MOVWrm(RS, MD, MB, MI, MS) (_d16(), _REXLrm(RS, MB, MI), _O_r_X (0x89 ,_r2(RS) ,MD,MB,MI,MS )) #define MOVWir(IM, R) (_d16(), _REXLrr(0, R), _Or_W (0xb8,_r2(R) ,_su16(IM))) #define MOVWim(IM, MD, MB, MI, MS) (_d16(), _REXLrm(0, MB, MI), _O_X_W (0xc7 ,MD,MB,MI,MS ,_su16(IM))) #define MOVLrr(RS, RD) (_REXLrr(RS, RD), _O_Mrm (0x89 ,_b11,_r4(RS),_r4(RD) )) #define MOVLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _O_r_X (0x8b ,_r4(RD) ,MD,MB,MI,MS )) #define MOVLrm(RS, MD, MB, MI, MS) (_REXLrm(RS, MB, MI), _O_r_X (0x89 ,_r4(RS) ,MD,MB,MI,MS )) #define MOVLir(IM, R) (_REXLrr(0, R), _Or_L (0xb8,_r4(R) ,IM )) #define MOVLim(IM, MD, MB, MI, MS) (_REXLrm(0, MB, MI), _O_X_L (0xc7 ,MD,MB,MI,MS ,IM )) #define MOVQrr(RS, RD) (_REXQrr(RS, RD), _O_Mrm (0x89 ,_b11,_r8(RS),_r8(RD) )) #define MOVQmr(MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _O_r_X (0x8b ,_r8(RD) ,MD,MB,MI,MS )) #define MOVQrm(RS, MD, MB, MI, MS) (_REXQrm(RS, MB, MI), _O_r_X (0x89 ,_r8(RS) ,MD,MB,MI,MS )) #define MOVQir(IM, R) (_REXQrr(0, R), _Or_Q (0xb8,_r8(R) ,IM )) #define MOVQim(IM, MD, MB, MI, MS) (_REXQrm(0, MB, MI), _O_X_L (0xc7 ,MD,MB,MI,MS ,IM )) /* --- Unary and Multiply/Divide instructions ------------------------------ */ enum { X86_NOT = 2, X86_NEG = 3, X86_MUL = 4, X86_IMUL = 5, X86_DIV = 6, X86_IDIV = 7, }; /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define _UNARYBr(OP, RS) (_REXBrr(0, RS), _O_Mrm (0xf6 ,_b11,OP ,_r1(RS) )) #define _UNARYBm(OP, MD, MB, MI, MS) (_REXBrm(0, MB, MI), _O_r_X (0xf6 ,OP ,MD,MB,MI,MS )) #define _UNARYWr(OP, RS) (_d16(), _REXLrr(0, RS), _O_Mrm (0xf7 ,_b11,OP ,_r2(RS) )) #define _UNARYWm(OP, MD, MB, MI, MS) (_d16(), _REXLmr(MB, MI, 0), _O_r_X (0xf7 ,OP ,MD,MB,MI,MS )) #define _UNARYLr(OP, RS) (_REXLrr(0, RS), _O_Mrm (0xf7 ,_b11,OP ,_r4(RS) )) #define _UNARYLm(OP, MD, MB, MI, MS) (_REXLmr(MB, MI, 0), _O_r_X (0xf7 ,OP ,MD,MB,MI,MS )) #define _UNARYQr(OP, RS) (_REXQrr(0, RS), _O_Mrm (0xf7 ,_b11,OP ,_r8(RS) )) #define _UNARYQm(OP, MD, MB, MI, MS) (_REXQmr(MB, MI, 0), _O_r_X (0xf7 ,OP ,MD,MB,MI,MS )) #define NOTBr(RS) _UNARYBr(X86_NOT, RS) #define NOTBm(MD, MB, MI, MS) _UNARYBm(X86_NOT, MD, MB, MI, MS) #define NOTWr(RS) _UNARYWr(X86_NOT, RS) #define NOTWm(MD, MB, MI, MS) _UNARYWm(X86_NOT, MD, MB, MI, MS) #define NOTLr(RS) _UNARYLr(X86_NOT, RS) #define NOTLm(MD, MB, MI, MS) _UNARYLm(X86_NOT, MD, MB, MI, MS) #define NOTQr(RS) _UNARYQr(X86_NOT, RS) #define NOTQm(MD, MB, MI, MS) _UNARYQm(X86_NOT, MD, MB, MI, MS) #define NEGBr(RS) _UNARYBr(X86_NEG, RS) #define NEGBm(MD, MB, MI, MS) _UNARYBm(X86_NEG, MD, MB, MI, MS) #define NEGWr(RS) _UNARYWr(X86_NEG, RS) #define NEGWm(MD, MB, MI, MS) _UNARYWm(X86_NEG, MD, MB, MI, MS) #define NEGLr(RS) _UNARYLr(X86_NEG, RS) #define NEGLm(MD, MB, MI, MS) _UNARYLm(X86_NEG, MD, MB, MI, MS) #define NEGQr(RS) _UNARYQr(X86_NEG, RS) #define NEGQm(MD, MB, MI, MS) _UNARYQm(X86_NEG, MD, MB, MI, MS) #define MULBr(RS) _UNARYBr(X86_MUL, RS) #define MULBm(MD, MB, MI, MS) _UNARYBm(X86_MUL, MD, MB, MI, MS) #define MULWr(RS) _UNARYWr(X86_MUL, RS) #define MULWm(MD, MB, MI, MS) _UNARYWm(X86_MUL, MD, MB, MI, MS) #define MULLr(RS) _UNARYLr(X86_MUL, RS) #define MULLm(MD, MB, MI, MS) _UNARYLm(X86_MUL, MD, MB, MI, MS) #define MULQr(RS) _UNARYQr(X86_MUL, RS) #define MULQm(MD, MB, MI, MS) _UNARYQm(X86_MUL, MD, MB, MI, MS) #define IMULBr(RS) _UNARYBr(X86_IMUL, RS) #define IMULBm(MD, MB, MI, MS) _UNARYBm(X86_IMUL, MD, MB, MI, MS) #define IMULWr(RS) _UNARYWr(X86_IMUL, RS) #define IMULWm(MD, MB, MI, MS) _UNARYWm(X86_IMUL, MD, MB, MI, MS) #define IMULLr(RS) _UNARYLr(X86_IMUL, RS) #define IMULLm(MD, MB, MI, MS) _UNARYLm(X86_IMUL, MD, MB, MI, MS) #define IMULQr(RS) _UNARYQr(X86_IMUL, RS) #define IMULQm(MD, MB, MI, MS) _UNARYQm(X86_IMUL, MD, MB, MI, MS) #define DIVBr(RS) _UNARYBr(X86_DIV, RS) #define DIVBm(MD, MB, MI, MS) _UNARYBm(X86_DIV, MD, MB, MI, MS) #define DIVWr(RS) _UNARYWr(X86_DIV, RS) #define DIVWm(MD, MB, MI, MS) _UNARYWm(X86_DIV, MD, MB, MI, MS) #define DIVLr(RS) _UNARYLr(X86_DIV, RS) #define DIVLm(MD, MB, MI, MS) _UNARYLm(X86_DIV, MD, MB, MI, MS) #define DIVQr(RS) _UNARYQr(X86_DIV, RS) #define DIVQm(MD, MB, MI, MS) _UNARYQm(X86_DIV, MD, MB, MI, MS) #define IDIVBr(RS) _UNARYBr(X86_IDIV, RS) #define IDIVBm(MD, MB, MI, MS) _UNARYBm(X86_IDIV, MD, MB, MI, MS) #define IDIVWr(RS) _UNARYWr(X86_IDIV, RS) #define IDIVWm(MD, MB, MI, MS) _UNARYWm(X86_IDIV, MD, MB, MI, MS) #define IDIVLr(RS) _UNARYLr(X86_IDIV, RS) #define IDIVLm(MD, MB, MI, MS) _UNARYLm(X86_IDIV, MD, MB, MI, MS) #define IDIVQr(RS) _UNARYQr(X86_IDIV, RS) #define IDIVQm(MD, MB, MI, MS) _UNARYQm(X86_IDIV, MD, MB, MI, MS) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define IMULWrr(RS, RD) (_d16(), _REXLrr(RD, RS), _OO_Mrm (0x0faf ,_b11,_r2(RD),_r2(RS) )) #define IMULWmr(MD, MB, MI, MS, RD) (_d16(), _REXLmr(MB, MI, RD), _OO_r_X (0x0faf ,_r2(RD) ,MD,MB,MI,MS )) #define IMULWirr(IM,RS,RD) (_d16(), _REXLrr(RS, RD), _Os_Mrm_sW (0x69 ,_b11,_r2(RS),_r2(RD) ,_su16(IM) )) #define IMULWimr(IM,MD,MB,MI,MS,RD) (_d16(), _REXLmr(MB, MI, RD), _Os_r_X_sW (0x69 ,_r2(RD) ,MD,MB,MI,MS ,_su16(IM) )) #define IMULLir(IM, RD) (_REXLrr(0, RD), _Os_Mrm_sL (0x69 ,_b11,_r4(RD),_r4(RD) ,IM )) #define IMULLrr(RS, RD) (_REXLrr(RD, RS), _OO_Mrm (0x0faf ,_b11,_r4(RD),_r4(RS) )) #define IMULLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0faf ,_r4(RD) ,MD,MB,MI,MS )) #define IMULQir(IM, RD) (_REXQrr(0, RD), _Os_Mrm_sL (0x69 ,_b11,_r8(RD),_r8(RD) ,IM )) #define IMULQrr(RS, RD) (_REXQrr(RD, RS), _OO_Mrm (0x0faf ,_b11,_r8(RD),_r8(RS) )) #define IMULQmr(MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _OO_r_X (0x0faf ,_r8(RD) ,MD,MB,MI,MS )) #define IMULLirr(IM,RS,RD) (_REXLrr(RS, RD), _Os_Mrm_sL (0x69 ,_b11,_r4(RS),_r4(RD) ,IM )) #define IMULLimr(IM,MD,MB,MI,MS,RD) (_REXLmr(MB, MI, RD), _Os_r_X_sL (0x69 ,_r4(RD) ,MD,MB,MI,MS ,IM )) #define IMULQirr(IM,RS,RD) (_REXQrr(RS, RD), _Os_Mrm_sL (0x69 ,_b11,_r8(RS),_r8(RD) ,IM )) #define IMULQimr(IM,MD,MB,MI,MS,RD) (_REXQmr(MB, MI, RD), _Os_r_X_sL (0x69 ,_r8(RD) ,MD,MB,MI,MS ,IM )) /* --- Control Flow related instructions ----------------------------------- */ enum { X86_CC_O = 0x0, X86_CC_NO = 0x1, X86_CC_NAE = 0x2, X86_CC_B = 0x2, X86_CC_C = 0x2, X86_CC_AE = 0x3, X86_CC_NB = 0x3, X86_CC_NC = 0x3, X86_CC_E = 0x4, X86_CC_Z = 0x4, X86_CC_NE = 0x5, X86_CC_NZ = 0x5, X86_CC_BE = 0x6, X86_CC_NA = 0x6, X86_CC_A = 0x7, X86_CC_NBE = 0x7, X86_CC_S = 0x8, X86_CC_NS = 0x9, X86_CC_P = 0xa, X86_CC_PE = 0xa, X86_CC_NP = 0xb, X86_CC_PO = 0xb, X86_CC_L = 0xc, X86_CC_NGE = 0xc, X86_CC_GE = 0xd, X86_CC_NL = 0xd, X86_CC_LE = 0xe, X86_CC_NG = 0xe, X86_CC_G = 0xf, X86_CC_NLE = 0xf, }; /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ // FIXME: no prefix is availble to encode a 32-bit operand size in 64-bit mode #define CALLm(M) _O_D32 (0xe8 ,(int)(M) ) #define _CALLLsr(R) (_REXLrr(0, R), _O_Mrm (0xff ,_b11,_b010,_r4(R) )) #define _CALLQsr(R) (_REXLrr(0, R), _O_Mrm (0xff ,_b11,_b010,_r8(R) )) #define CALLsr(R) ( X86_TARGET_64BIT ? _CALLQsr(R) : _CALLLsr(R)) #define CALLsm(D,B,I,S) (_REXLrm(0, B, I), _O_r_X (0xff ,_b010 ,(int)(D),B,I,S )) // FIXME: no prefix is availble to encode a 32-bit operand size in 64-bit mode #define JMPSm(M) _O_D8 (0xeb ,(int)(M) ) #define JMPm(M) _O_D32 (0xe9 ,(int)(M) ) #define _JMPLsr(R) (_REXLrr(0, R), _O_Mrm (0xff ,_b11,_b100,_r4(R) )) #define _JMPQsr(R) (_REXLrr(0, R), _O_Mrm (0xff ,_b11,_b100,_r8(R) )) #define JMPsr(R) ( X86_TARGET_64BIT ? _JMPQsr(R) : _JMPLsr(R)) #define JMPsm(D,B,I,S) (_REXLrm(0, B, I), _O_r_X (0xff ,_b100 ,(int)(D),B,I,S )) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define JCCSii(CC, D) _O_B (0x70|(CC) ,(_sc)(int)(D) ) #define JCCSim(CC, D) _O_D8 (0x70|(CC) ,(int)(D) ) #define JOSm(D) JCCSim(X86_CC_O, D) #define JNOSm(D) JCCSim(X86_CC_NO, D) #define JBSm(D) JCCSim(X86_CC_B, D) #define JNAESm(D) JCCSim(X86_CC_NAE, D) #define JNBSm(D) JCCSim(X86_CC_NB, D) #define JAESm(D) JCCSim(X86_CC_AE, D) #define JESm(D) JCCSim(X86_CC_E, D) #define JZSm(D) JCCSim(X86_CC_Z, D) #define JNESm(D) JCCSim(X86_CC_NE, D) #define JNZSm(D) JCCSim(X86_CC_NZ, D) #define JBESm(D) JCCSim(X86_CC_BE, D) #define JNASm(D) JCCSim(X86_CC_NA, D) #define JNBESm(D) JCCSim(X86_CC_NBE, D) #define JASm(D) JCCSim(X86_CC_A, D) #define JSSm(D) JCCSim(X86_CC_S, D) #define JNSSm(D) JCCSim(X86_CC_NS, D) #define JPSm(D) JCCSim(X86_CC_P, D) #define JPESm(D) JCCSim(X86_CC_PE, D) #define JNPSm(D) JCCSim(X86_CC_NP, D) #define JPOSm(D) JCCSim(X86_CC_PO, D) #define JLSm(D) JCCSim(X86_CC_L, D) #define JNGESm(D) JCCSim(X86_CC_NGE, D) #define JNLSm(D) JCCSim(X86_CC_NL, D) #define JGESm(D) JCCSim(X86_CC_GE, D) #define JLESm(D) JCCSim(X86_CC_LE, D) #define JNGSm(D) JCCSim(X86_CC_NG, D) #define JNLESm(D) JCCSim(X86_CC_NLE, D) #define JGSm(D) JCCSim(X86_CC_G, D) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define JCCii(CC, D) _OO_L (0x0f80|(CC) ,(int)(D) ) #define JCCim(CC, D) _OO_D32 (0x0f80|(CC) ,(int)(D) ) #define JOm(D) JCCim(X86_CC_O, D) #define JNOm(D) JCCim(X86_CC_NO, D) #define JBm(D) JCCim(X86_CC_B, D) #define JNAEm(D) JCCim(X86_CC_NAE, D) #define JNBm(D) JCCim(X86_CC_NB, D) #define JAEm(D) JCCim(X86_CC_AE, D) #define JEm(D) JCCim(X86_CC_E, D) #define JZm(D) JCCim(X86_CC_Z, D) #define JNEm(D) JCCim(X86_CC_NE, D) #define JNZm(D) JCCim(X86_CC_NZ, D) #define JBEm(D) JCCim(X86_CC_BE, D) #define JNAm(D) JCCim(X86_CC_NA, D) #define JNBEm(D) JCCim(X86_CC_NBE, D) #define JAm(D) JCCim(X86_CC_A, D) #define JSm(D) JCCim(X86_CC_S, D) #define JNSm(D) JCCim(X86_CC_NS, D) #define JPm(D) JCCim(X86_CC_P, D) #define JPEm(D) JCCim(X86_CC_PE, D) #define JNPm(D) JCCim(X86_CC_NP, D) #define JPOm(D) JCCim(X86_CC_PO, D) #define JLm(D) JCCim(X86_CC_L, D) #define JNGEm(D) JCCim(X86_CC_NGE, D) #define JNLm(D) JCCim(X86_CC_NL, D) #define JGEm(D) JCCim(X86_CC_GE, D) #define JLEm(D) JCCim(X86_CC_LE, D) #define JNGm(D) JCCim(X86_CC_NG, D) #define JNLEm(D) JCCim(X86_CC_NLE, D) #define JGm(D) JCCim(X86_CC_G, D) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define SETCCir(CC, RD) (_REXBrr(0, RD), _OO_Mrm (0x0f90|(CC) ,_b11,_b000,_r1(RD) )) #define SETOr(RD) SETCCir(X86_CC_O, RD) #define SETNOr(RD) SETCCir(X86_CC_NO, RD) #define SETBr(RD) SETCCir(X86_CC_B, RD) #define SETNAEr(RD) SETCCir(X86_CC_NAE, RD) #define SETNBr(RD) SETCCir(X86_CC_NB, RD) #define SETAEr(RD) SETCCir(X86_CC_AE, RD) #define SETEr(RD) SETCCir(X86_CC_E, RD) #define SETZr(RD) SETCCir(X86_CC_Z, RD) #define SETNEr(RD) SETCCir(X86_CC_NE, RD) #define SETNZr(RD) SETCCir(X86_CC_NZ, RD) #define SETBEr(RD) SETCCir(X86_CC_BE, RD) #define SETNAr(RD) SETCCir(X86_CC_NA, RD) #define SETNBEr(RD) SETCCir(X86_CC_NBE, RD) #define SETAr(RD) SETCCir(X86_CC_A, RD) #define SETSr(RD) SETCCir(X86_CC_S, RD) #define SETNSr(RD) SETCCir(X86_CC_NS, RD) #define SETPr(RD) SETCCir(X86_CC_P, RD) #define SETPEr(RD) SETCCir(X86_CC_PE, RD) #define SETNPr(RD) SETCCir(X86_CC_NP, RD) #define SETPOr(RD) SETCCir(X86_CC_PO, RD) #define SETLr(RD) SETCCir(X86_CC_L, RD) #define SETNGEr(RD) SETCCir(X86_CC_NGE, RD) #define SETNLr(RD) SETCCir(X86_CC_NL, RD) #define SETGEr(RD) SETCCir(X86_CC_GE, RD) #define SETLEr(RD) SETCCir(X86_CC_LE, RD) #define SETNGr(RD) SETCCir(X86_CC_NG, RD) #define SETNLEr(RD) SETCCir(X86_CC_NLE, RD) #define SETGr(RD) SETCCir(X86_CC_G, RD) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define SETCCim(CC,MD,MB,MI,MS) (_REXBrm(0, MB, MI), _OO_r_X (0x0f90|(CC) ,_b000 ,MD,MB,MI,MS )) #define SETOm(D, B, I, S) SETCCim(X86_CC_O, D, B, I, S) #define SETNOm(D, B, I, S) SETCCim(X86_CC_NO, D, B, I, S) #define SETBm(D, B, I, S) SETCCim(X86_CC_B, D, B, I, S) #define SETNAEm(D, B, I, S) SETCCim(X86_CC_NAE, D, B, I, S) #define SETNBm(D, B, I, S) SETCCim(X86_CC_NB, D, B, I, S) #define SETAEm(D, B, I, S) SETCCim(X86_CC_AE, D, B, I, S) #define SETEm(D, B, I, S) SETCCim(X86_CC_E, D, B, I, S) #define SETZm(D, B, I, S) SETCCim(X86_CC_Z, D, B, I, S) #define SETNEm(D, B, I, S) SETCCim(X86_CC_NE, D, B, I, S) #define SETNZm(D, B, I, S) SETCCim(X86_CC_NZ, D, B, I, S) #define SETBEm(D, B, I, S) SETCCim(X86_CC_BE, D, B, I, S) #define SETNAm(D, B, I, S) SETCCim(X86_CC_NA, D, B, I, S) #define SETNBEm(D, B, I, S) SETCCim(X86_CC_NBE, D, B, I, S) #define SETAm(D, B, I, S) SETCCim(X86_CC_A, D, B, I, S) #define SETSm(D, B, I, S) SETCCim(X86_CC_S, D, B, I, S) #define SETNSm(D, B, I, S) SETCCim(X86_CC_NS, D, B, I, S) #define SETPm(D, B, I, S) SETCCim(X86_CC_P, D, B, I, S) #define SETPEm(D, B, I, S) SETCCim(X86_CC_PE, D, B, I, S) #define SETNPm(D, B, I, S) SETCCim(X86_CC_NP, D, B, I, S) #define SETPOm(D, B, I, S) SETCCim(X86_CC_PO, D, B, I, S) #define SETLm(D, B, I, S) SETCCim(X86_CC_L, D, B, I, S) #define SETNGEm(D, B, I, S) SETCCim(X86_CC_NGE, D, B, I, S) #define SETNLm(D, B, I, S) SETCCim(X86_CC_NL, D, B, I, S) #define SETGEm(D, B, I, S) SETCCim(X86_CC_GE, D, B, I, S) #define SETLEm(D, B, I, S) SETCCim(X86_CC_LE, D, B, I, S) #define SETNGm(D, B, I, S) SETCCim(X86_CC_NG, D, B, I, S) #define SETNLEm(D, B, I, S) SETCCim(X86_CC_NLE, D, B, I, S) #define SETGm(D, B, I, S) SETCCim(X86_CC_G, D, B, I, S) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define CMOVWrr(CC,RS,RD) (_d16(), _REXLrr(RD, RS), _OO_Mrm (0x0f40|(CC) ,_b11,_r2(RD),_r2(RS) )) #define CMOVWmr(CC,MD,MB,MI,MS,RD) (_d16(), _REXLmr(MB, MI, RD), _OO_r_X (0x0f40|(CC) ,_r2(RD) ,MD,MB,MI,MS )) #define CMOVLrr(CC,RS,RD) (_REXLrr(RD, RS), _OO_Mrm (0x0f40|(CC) ,_b11,_r4(RD),_r4(RS) )) #define CMOVLmr(CC,MD,MB,MI,MS,RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0f40|(CC) ,_r4(RD) ,MD,MB,MI,MS )) #define CMOVQrr(CC,RS,RD) (_REXQrr(RD, RS), _OO_Mrm (0x0f40|(CC) ,_b11,_r8(RD),_r8(RS) )) #define CMOVQmr(CC,MD,MB,MI,MS,RD) (_REXQmr(MB, MI, RD), _OO_r_X (0x0f40|(CC) ,_r8(RD) ,MD,MB,MI,MS )) /* --- Push/Pop instructions ----------------------------------------------- */ /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define POPWr(RD) _m32only((_d16(), _Or (0x58,_r2(RD) ))) #define POPWm(MD, MB, MI, MS) _m32only((_d16(), _O_r_X (0x8f ,_b000 ,MD,MB,MI,MS ))) #define POPLr(RD) _m32only( _Or (0x58,_r4(RD) )) #define POPLm(MD, MB, MI, MS) _m32only( _O_r_X (0x8f ,_b000 ,MD,MB,MI,MS )) #define POPQr(RD) _m64only((_REXQr(RD), _Or (0x58,_r8(RD) ))) #define POPQm(MD, MB, MI, MS) _m64only((_REXQm(MB, MI), _O_r_X (0x8f ,_b000 ,MD,MB,MI,MS ))) #define PUSHWr(RS) _m32only((_d16(), _Or (0x50,_r2(RS) ))) #define PUSHWm(MD, MB, MI, MS) _m32only((_d16(), _O_r_X (0xff, ,_b110 ,MD,MB,MI,MS ))) #define PUSHWi(IM) _m32only((_d16(), _Os_sW (0x68 ,IM ))) #define PUSHLr(RS) _m32only( _Or (0x50,_r4(RS) )) #define PUSHLm(MD, MB, MI, MS) _m32only( _O_r_X (0xff ,_b110 ,MD,MB,MI,MS )) #define PUSHLi(IM) _m32only( _Os_sL (0x68 ,IM )) #define PUSHQr(RS) _m64only((_REXQr(RS), _Or (0x50,_r8(RS) ))) #define PUSHQm(MD, MB, MI, MS) _m64only((_REXQm(MB, MI), _O_r_X (0xff ,_b110 ,MD,MB,MI,MS ))) #define PUSHQi(IM) _m64only( _Os_sL (0x68 ,IM )) #define POPA() (_d16(), _O (0x61 )) #define POPAD() _O (0x61 ) #define PUSHA() (_d16(), _O (0x60 )) #define PUSHAD() _O (0x60 ) #define POPF() _O (0x9d ) #define PUSHF() _O (0x9c ) /* --- Test instructions --------------------------------------------------- */ /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define TESTBrr(RS, RD) (_REXBrr(RS, RD), _O_Mrm (0x84 ,_b11,_r1(RS),_r1(RD) )) #define TESTBrm(RS, MD, MB, MI, MS) (_REXBrm(RS, MB, MI), _O_r_X (0x84 ,_r1(RS) ,MD,MB,MI,MS )) #define TESTBir(IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_AL) ? \ (_REXBrr(0, RD), _O_B (0xa8 ,_u8(IM))) : \ (_REXBrr(0, RD), _O_Mrm_B (0xf6 ,_b11,_b000 ,_r1(RD) ,_u8(IM))) ) #define TESTBim(IM, MD, MB, MI, MS) (_REXBrm(0, MB, MI), _O_r_X_B (0xf6 ,_b000 ,MD,MB,MI,MS ,_u8(IM))) #define TESTWrr(RS, RD) (_d16(), _REXLrr(RS, RD), _O_Mrm (0x85 ,_b11,_r2(RS),_r2(RD) )) #define TESTWrm(RS, MD, MB, MI, MS) (_d16(), _REXLrm(RS, MB, MI), _O_r_X (0x85 ,_r2(RS) ,MD,MB,MI,MS )) #define TESTWir(IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_AX) ? \ (_d16(), _REXLrr(0, RD), _O_W (0xa9 ,_u16(IM))) : \ (_d16(), _REXLrr(0, RD), _O_Mrm_W (0xf7 ,_b11,_b000 ,_r2(RD) ,_u16(IM))) ) #define TESTWim(IM, MD, MB, MI, MS) (_d16(), _REXLrm(0, MB, MI), _O_r_X_W (0xf7 ,_b000 ,MD,MB,MI,MS ,_u16(IM))) #define TESTLrr(RS, RD) (_REXLrr(RS, RD), _O_Mrm (0x85 ,_b11,_r4(RS),_r4(RD) )) #define TESTLrm(RS, MD, MB, MI, MS) (_REXLrm(RS, MB, MI), _O_r_X (0x85 ,_r4(RS) ,MD,MB,MI,MS )) #define TESTLir(IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_EAX) ? \ (_REXLrr(0, RD), _O_L (0xa9 ,IM )) : \ (_REXLrr(0, RD), _O_Mrm_L (0xf7 ,_b11,_b000 ,_r4(RD) ,IM )) ) #define TESTLim(IM, MD, MB, MI, MS) (_REXLrm(0, MB, MI), _O_r_X_L (0xf7 ,_b000 ,MD,MB,MI,MS ,IM )) #define TESTQrr(RS, RD) (_REXQrr(RS, RD), _O_Mrm (0x85 ,_b11,_r8(RS),_r8(RD) )) #define TESTQrm(RS, MD, MB, MI, MS) (_REXQrm(RS, MB, MI), _O_r_X (0x85 ,_r8(RS) ,MD,MB,MI,MS )) #define TESTQir(IM, RD) (X86_OPTIMIZE_ALU && ((RD) == X86_RAX) ? \ (_REXQrr(0, RD), _O_L (0xa9 ,IM )) : \ (_REXQrr(0, RD), _O_Mrm_L (0xf7 ,_b11,_b000 ,_r8(RD) ,IM )) ) #define TESTQim(IM, MD, MB, MI, MS) (_REXQrm(0, MB, MI), _O_r_X_L (0xf7 ,_b000 ,MD,MB,MI,MS ,IM )) /* --- Exchange instructions ----------------------------------------------- */ /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define CMPXCHGBrr(RS, RD) (_REXBrr(RS, RD), _OO_Mrm (0x0fb0 ,_b11,_r1(RS),_r1(RD) )) #define CMPXCHGBrm(RS, MD, MB, MI, MS) (_REXBrm(RS, MB, MI), _OO_r_X (0x0fb0 ,_r1(RS) ,MD,MB,MI,MS )) #define CMPXCHGWrr(RS, RD) (_d16(), _REXLrr(RS, RD), _OO_Mrm (0x0fb1 ,_b11,_r2(RS),_r2(RD) )) #define CMPXCHGWrm(RS, MD, MB, MI, MS) (_d16(), _REXLrm(RS, MB, MI), _OO_r_X (0x0fb1 ,_r2(RS) ,MD,MB,MI,MS )) #define CMPXCHGLrr(RS, RD) (_REXLrr(RS, RD), _OO_Mrm (0x0fb1 ,_b11,_r4(RS),_r4(RD) )) #define CMPXCHGLrm(RS, MD, MB, MI, MS) (_REXLrm(RS, MB, MI), _OO_r_X (0x0fb1 ,_r4(RS) ,MD,MB,MI,MS )) #define CMPXCHGQrr(RS, RD) (_REXQrr(RS, RD), _OO_Mrm (0x0fb1 ,_b11,_r8(RS),_r8(RD) )) #define CMPXCHGQrm(RS, MD, MB, MI, MS) (_REXQrm(RS, MB, MI), _OO_r_X (0x0fb1 ,_r8(RS) ,MD,MB,MI,MS )) #define XADDBrr(RS, RD) (_REXBrr(RS, RD), _OO_Mrm (0x0fc0 ,_b11,_r1(RS),_r1(RD) )) #define XADDBrm(RS, MD, MB, MI, MS) (_REXBrm(RS, MB, MI), _OO_r_X (0x0fc0 ,_r1(RS) ,MD,MB,MI,MS )) #define XADDWrr(RS, RD) (_d16(), _REXLrr(RS, RD), _OO_Mrm (0x0fc1 ,_b11,_r2(RS),_r2(RD) )) #define XADDWrm(RS, MD, MB, MI, MS) (_d16(), _REXLrm(RS, MB, MI), _OO_r_X (0x0fc1 ,_r2(RS) ,MD,MB,MI,MS )) #define XADDLrr(RS, RD) (_REXLrr(RS, RD), _OO_Mrm (0x0fc1 ,_b11,_r4(RS),_r4(RD) )) #define XADDLrm(RS, MD, MB, MI, MS) (_REXLrm(RS, MB, MI), _OO_r_X (0x0fc1 ,_r4(RS) ,MD,MB,MI,MS )) #define XADDQrr(RS, RD) (_REXQrr(RS, RD), _OO_Mrm (0x0fc1 ,_b11,_r8(RS),_r8(RD) )) #define XADDQrm(RS, MD, MB, MI, MS) (_REXQrm(RS, MB, MI), _OO_r_X (0x0fc1 ,_r8(RS) ,MD,MB,MI,MS )) #define XCHGBrr(RS, RD) (_REXBrr(RS, RD), _O_Mrm (0x86 ,_b11,_r1(RS),_r1(RD) )) #define XCHGBrm(RS, MD, MB, MI, MS) (_REXBrm(RS, MB, MI), _O_r_X (0x86 ,_r1(RS) ,MD,MB,MI,MS )) #define XCHGWrr(RS, RD) (_d16(), _REXLrr(RS, RD), _O_Mrm (0x87 ,_b11,_r2(RS),_r2(RD) )) #define XCHGWrm(RS, MD, MB, MI, MS) (_d16(), _REXLrm(RS, MB, MI), _O_r_X (0x87 ,_r2(RS) ,MD,MB,MI,MS )) #define XCHGLrr(RS, RD) (_REXLrr(RS, RD), _O_Mrm (0x87 ,_b11,_r4(RS),_r4(RD) )) #define XCHGLrm(RS, MD, MB, MI, MS) (_REXLrm(RS, MB, MI), _O_r_X (0x87 ,_r4(RS) ,MD,MB,MI,MS )) #define XCHGQrr(RS, RD) (_REXQrr(RS, RD), _O_Mrm (0x87 ,_b11,_r8(RS),_r8(RD) )) #define XCHGQrm(RS, MD, MB, MI, MS) (_REXQrm(RS, MB, MI), _O_r_X (0x87 ,_r8(RS) ,MD,MB,MI,MS )) /* --- Increment/Decrement instructions ------------------------------------ */ /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define DECBm(MD, MB, MI, MS) (_REXBrm(0, MB, MI), _O_r_X (0xfe ,_b001 ,MD,MB,MI,MS )) #define DECBr(RD) (_REXBrr(0, RD), _O_Mrm (0xfe ,_b11,_b001 ,_r1(RD) )) #define DECWm(MD, MB, MI, MS) (_d16(), _REXLrm(0, MB, MI), _O_r_X (0xff ,_b001 ,MD,MB,MI,MS )) #define DECWr(RD) (! X86_TARGET_64BIT ? (_d16(), _Or (0x48,_r2(RD) )) : \ (_d16(), _REXLrr(0, RD), _O_Mrm (0xff ,_b11,_b001 ,_r2(RD) ))) #define DECLm(MD, MB, MI, MS) (_REXLrm(0, MB, MI), _O_r_X (0xff ,_b001 ,MD,MB,MI,MS )) #define DECLr(RD) (! X86_TARGET_64BIT ? _Or (0x48,_r4(RD) ) : \ (_REXLrr(0, RD), _O_Mrm (0xff ,_b11,_b001 ,_r4(RD) ))) #define DECQm(MD, MB, MI, MS) (_REXQrm(0, MB, MI), _O_r_X (0xff ,_b001 ,MD,MB,MI,MS )) #define DECQr(RD) (_REXQrr(0, RD), _O_Mrm (0xff ,_b11,_b001 ,_r8(RD) )) #define INCBm(MD, MB, MI, MS) (_REXBrm(0, MB, MI), _O_r_X (0xfe ,_b000 ,MD,MB,MI,MS )) #define INCBr(RD) (_REXBrr(0, RD), _O_Mrm (0xfe ,_b11,_b000 ,_r1(RD) )) #define INCWm(MD, MB, MI, MS) (_d16(), _REXLrm(0, MB, MI), _O_r_X (0xff ,_b000 ,MD,MB,MI,MS )) #define INCWr(RD) (! X86_TARGET_64BIT ? (_d16(), _Or (0x40,_r2(RD) )) : \ (_d16(), _REXLrr(0, RD), _O_Mrm (0xff ,_b11,_b000 ,_r2(RD) )) ) #define INCLm(MD, MB, MI, MS) (_REXLrm(0, MB, MI), _O_r_X (0xff ,_b000 ,MD,MB,MI,MS )) #define INCLr(RD) (! X86_TARGET_64BIT ? _Or (0x40,_r4(RD) ) : \ (_REXLrr(0, RD), _O_Mrm (0xff ,_b11,_b000 ,_r4(RD) ))) #define INCQm(MD, MB, MI, MS) (_REXQrm(0, MB, MI), _O_r_X (0xff ,_b000 ,MD,MB,MI,MS )) #define INCQr(RD) (_REXQrr(0, RD), _O_Mrm (0xff ,_b11,_b000 ,_r8(RD) )) /* --- Misc instructions --------------------------------------------------- */ /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define BSFWrr(RS, RD) (_d16(), _REXLrr(RD, RS), _OO_Mrm (0x0fbc ,_b11,_r2(RD),_r2(RS) )) #define BSFWmr(MD, MB, MI, MS, RD) (_d16(), _REXLmr(MB, MI, RD), _OO_r_X (0x0fbc ,_r2(RD) ,MD,MB,MI,MS )) #define BSRWrr(RS, RD) (_d16(), _REXLrr(RD, RS), _OO_Mrm (0x0fbd ,_b11,_r2(RD),_r2(RS) )) #define BSRWmr(MD, MB, MI, MS, RD) (_d16(), _REXLmr(MB, MI, RD), _OO_r_X (0x0fbd ,_r2(RD) ,MD,MB,MI,MS )) #define BSFLrr(RS, RD) (_REXLrr(RD, RS), _OO_Mrm (0x0fbc ,_b11,_r4(RD),_r4(RS) )) #define BSFLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0fbc ,_r4(RD) ,MD,MB,MI,MS )) #define BSRLrr(RS, RD) (_REXLrr(RD, RS), _OO_Mrm (0x0fbd ,_b11,_r4(RD),_r4(RS) )) #define BSRLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0fbd ,_r4(RD) ,MD,MB,MI,MS )) #define BSFQrr(RS, RD) (_REXQrr(RD, RS), _OO_Mrm (0x0fbc ,_b11,_r8(RD),_r8(RS) )) #define BSFQmr(MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _OO_r_X (0x0fbc ,_r8(RD) ,MD,MB,MI,MS )) #define BSRQrr(RS, RD) (_REXQrr(RD, RS), _OO_Mrm (0x0fbd ,_b11,_r8(RD),_r8(RS) )) #define BSRQmr(MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _OO_r_X (0x0fbd ,_r8(RD) ,MD,MB,MI,MS )) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define MOVSBWrr(RS, RD) (_d16(), _REXBLrr(RD, RS), _OO_Mrm (0x0fbe ,_b11,_r2(RD),_r1(RS) )) #define MOVSBWmr(MD, MB, MI, MS, RD) (_d16(), _REXLmr(MB, MI, RD), _OO_r_X (0x0fbe ,_r2(RD) ,MD,MB,MI,MS )) #define MOVZBWrr(RS, RD) (_d16(), _REXBLrr(RD, RS), _OO_Mrm (0x0fb6 ,_b11,_r2(RD),_r1(RS) )) #define MOVZBWmr(MD, MB, MI, MS, RD) (_d16(), _REXLmr(MB, MI, RD), _OO_r_X (0x0fb6 ,_r2(RD) ,MD,MB,MI,MS )) #define MOVSBLrr(RS, RD) (_REXBLrr(RD, RS), _OO_Mrm (0x0fbe ,_b11,_r4(RD),_r1(RS) )) #define MOVSBLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0fbe ,_r4(RD) ,MD,MB,MI,MS )) #define MOVZBLrr(RS, RD) (_REXBLrr(RD, RS), _OO_Mrm (0x0fb6 ,_b11,_r4(RD),_r1(RS) )) #define MOVZBLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0fb6 ,_r4(RD) ,MD,MB,MI,MS )) #define MOVSBQrr(RS, RD) (_REXQrr(RD, RS), _OO_Mrm (0x0fbe ,_b11,_r8(RD),_r1(RS) )) #define MOVSBQmr(MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _OO_r_X (0x0fbe ,_r8(RD) ,MD,MB,MI,MS )) #define MOVZBQrr(RS, RD) (_REXQrr(RD, RS), _OO_Mrm (0x0fb6 ,_b11,_r8(RD),_r1(RS) )) #define MOVZBQmr(MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _OO_r_X (0x0fb6 ,_r8(RD) ,MD,MB,MI,MS )) #define MOVSWLrr(RS, RD) (_REXLrr(RD, RS), _OO_Mrm (0x0fbf ,_b11,_r4(RD),_r2(RS) )) #define MOVSWLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0fbf ,_r4(RD) ,MD,MB,MI,MS )) #define MOVZWLrr(RS, RD) (_REXLrr(RD, RS), _OO_Mrm (0x0fb7 ,_b11,_r4(RD),_r2(RS) )) #define MOVZWLmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _OO_r_X (0x0fb7 ,_r4(RD) ,MD,MB,MI,MS )) #define MOVSWQrr(RS, RD) _m64only((_REXQrr(RD, RS), _OO_Mrm (0x0fbf ,_b11,_r8(RD),_r2(RS) ))) #define MOVSWQmr(MD, MB, MI, MS, RD) _m64only((_REXQmr(MB, MI, RD), _OO_r_X (0x0fbf ,_r8(RD) ,MD,MB,MI,MS ))) #define MOVZWQrr(RS, RD) _m64only((_REXQrr(RD, RS), _OO_Mrm (0x0fb7 ,_b11,_r8(RD),_r2(RS) ))) #define MOVZWQmr(MD, MB, MI, MS, RD) _m64only((_REXQmr(MB, MI, RD), _OO_r_X (0x0fb7 ,_r8(RD) ,MD,MB,MI,MS ))) #define MOVSLQrr(RS, RD) _m64only((_REXQrr(RD, RS), _O_Mrm (0x63 ,_b11,_r8(RD),_r4(RS) ))) #define MOVSLQmr(MD, MB, MI, MS, RD) _m64only((_REXQmr(MB, MI, RD), _O_r_X (0x63 ,_r8(RD) ,MD,MB,MI,MS ))) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define LEALmr(MD, MB, MI, MS, RD) (_REXLmr(MB, MI, RD), _O_r_X (0x8d ,_r4(RD) ,MD,MB,MI,MS )) #define LEAQmr(MD, MB, MI, MS, RD) (_REXQmr(MB, MI, RD), _O_r_X (0x8d ,_r4(RD) ,MD,MB,MI,MS )) #define BSWAPLr(R) (_REXLrr(0, R), _OOr (0x0fc8,_r4(R) )) #define BSWAPQr(R) (_REXQrr(0, R), _OOr (0x0fc8,_r8(R) )) #define CLC() _O (0xf8 ) #define STC() _O (0xf9 ) #define CMC() _O (0xf5 ) #define CLD() _O (0xfc ) #define STD() _O (0xfd ) #define CBTW() (_d16(), _O (0x98 )) #define CWTL() _O (0x98 ) #define CLTQ() _m64only(_REXQrr(0, 0), _O (0x98 )) #define CBW CBTW #define CWDE CWTL #define CDQE CLTQ #define CWTD() (_d16(), _O (0x99 )) #define CLTD() _O (0x99 ) #define CQTO() _m64only(_REXQrr(0, 0), _O (0x99 )) #define CWD CWTD #define CDQ CLTD #define CQO CQTO #define LAHF() _O (0x9f ) #define SAHF() _O (0x9e ) /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define CPUID() _OO (0x0fa2 ) #define RDTSC() _OO (0xff31 ) #define ENTERii(W, B) _O_W_B (0xc8 ,_su16(W),_su8(B)) #define LEAVE() _O (0xc9 ) #define RET() _O (0xc3 ) #define RETi(IM) _O_W (0xc2 ,_su16(IM)) #define NOP() _O (0x90 ) /* --- Media 64-bit instructions ------------------------------------------- */ enum { X86_MMX_PABSB = 0x1c, // 2P X86_MMX_PABSW = 0x1d, // 2P X86_MMX_PABSD = 0x1e, // 2P X86_MMX_PACKSSWB = 0x63, X86_MMX_PACKSSDW = 0x6b, X86_MMX_PACKUSWB = 0x67, X86_MMX_PADDB = 0xfc, X86_MMX_PADDW = 0xfd, X86_MMX_PADDD = 0xfe, X86_MMX_PADDQ = 0xd4, X86_MMX_PADDSB = 0xec, X86_MMX_PADDSW = 0xed, X86_MMX_PADDUSB = 0xdc, X86_MMX_PADDUSW = 0xdd, X86_MMX_PAND = 0xdb, X86_MMX_PANDN = 0xdf, X86_MMX_PAVGB = 0xe0, X86_MMX_PAVGW = 0xe3, X86_MMX_PCMPEQB = 0x74, X86_MMX_PCMPEQW = 0x75, X86_MMX_PCMPEQD = 0x76, X86_MMX_PCMPGTB = 0x64, X86_MMX_PCMPGTW = 0x65, X86_MMX_PCMPGTD = 0x66, X86_MMX_PEXTRW = 0xc5, // 64, /r ib X86_MMX_PHADDW = 0x01, // 2P X86_MMX_PHADDD = 0x02, // 2P X86_MMX_PHADDSW = 0x03, // 2P X86_MMX_PHSUBW = 0x05, // 2P X86_MMX_PHSUBD = 0x06, // 2P X86_MMX_PHSUBSW = 0x07, // 2P X86_MMX_PINSRW = 0xc4, // 64, /r ib X86_MMX_PMADDUBSW = 0x04, // 2P X86_MMX_PMADDWD = 0xf5, X86_MMX_PMAXSW = 0xee, X86_MMX_PMAXUB = 0xde, X86_MMX_PMINSW = 0xea, X86_MMX_PMINUB = 0xda, X86_MMX_PMOVMSKB = 0xd7, // 64 X86_MMX_PMULHRSW = 0x0b, // 2P X86_MMX_PMULHUW = 0xe4, X86_MMX_PMULHW = 0xe5, X86_MMX_PMULLW = 0xd5, X86_MMX_PMULUDQ = 0xf4, X86_MMX_POR = 0xeb, X86_MMX_PSADBW = 0xf6, X86_MMX_PSHUFB = 0x00, // 2P X86_MMX_PSHUFW = 0x70, // /r ib X86_MMX_PSIGNB = 0x08, // 2P X86_MMX_PSIGNW = 0x09, // 2P X86_MMX_PSIGND = 0x0a, // 2P X86_MMX_PSLLW = 0xf1, X86_MMX_PSLLWi = 0x71, // /6 ib X86_MMX_PSLLD = 0xf2, X86_MMX_PSLLDi = 0x72, // /6 ib X86_MMX_PSLLQ = 0xf3, X86_MMX_PSLLQi = 0x73, // /6 ib X86_MMX_PSRAW = 0xe1, X86_MMX_PSRAWi = 0x71, // /4 ib X86_MMX_PSRAD = 0xe2, X86_MMX_PSRADi = 0x72, // /4 ib X86_MMX_PSRLW = 0xd1, X86_MMX_PSRLWi = 0x71, // /2 ib X86_MMX_PSRLD = 0xd2, X86_MMX_PSRLDi = 0x72, // /2 ib X86_MMX_PSRLQ = 0xd3, X86_MMX_PSRLQi = 0x73, // /2 ib X86_MMX_PSUBB = 0xf8, X86_MMX_PSUBW = 0xf9, X86_MMX_PSUBD = 0xfa, X86_MMX_PSUBQ = 0xfb, X86_MMX_PSUBSB = 0xe8, X86_MMX_PSUBSW = 0xe9, X86_MMX_PSUBUSB = 0xd8, X86_MMX_PSUBUSW = 0xd9, X86_MMX_PUNPCKHBW = 0x68, X86_MMX_PUNPCKHWD = 0x69, X86_MMX_PUNPCKHDQ = 0x6a, X86_MMX_PUNPCKLBW = 0x60, X86_MMX_PUNPCKLWD = 0x61, X86_MMX_PUNPCKLDQ = 0x62, X86_MMX_PXOR = 0xef, }; #define __MMXLrr(OP,RS,RSA,RD,RDA) (_REXLrr(RD, RS), _OO_Mrm (0x0f00|(OP) ,_b11,RDA(RD),RSA(RS) )) #define __MMXLmr(OP,MD,MB,MI,MS,RD,RDA) (_REXLmr(MB, MI, RD), _OO_r_X (0x0f00|(OP) ,RDA(RD) ,MD,MB,MI,MS )) #define __MMXLrm(OP,RS,RSA,MD,MB,MI,MS) (_REXLrm(RS, MB, MI), _OO_r_X (0x0f00|(OP) ,RSA(RS) ,MD,MB,MI,MS )) #define __MMXLirr(OP,IM,RS,RSA,RD,RDA) (_REXLrr(RD, RS), _OO_Mrm_B (0x0f00|(OP) ,_b11,RDA(RD),RSA(RS) ,_u8(IM))) #define __MMXLimr(OP,IM,MD,MB,MI,MS,RD,RDA) (_REXLmr(MB, MI, RS), _OO_r_X_B (0x0f00|(OP) ,RDA(RD) ,MD,MB,MI,MS ,_u8(IM))) #define __MMXQrr(OP,RS,RSA,RD,RDA) (_REXQrr(RD, RS), _OO_Mrm (0x0f00|(OP) ,_b11,RDA(RD),RSA(RS) )) #define __MMXQmr(OP,MD,MB,MI,MS,RD,RDA) (_REXQmr(MB, MI, RD), _OO_r_X (0x0f00|(OP) ,RDA(RD) ,MD,MB,MI,MS )) #define __MMXQrm(OP,RS,RSA,MD,MB,MI,MS) (_REXQrm(RS, MB, MI), _OO_r_X (0x0f00|(OP) ,RSA(RS) ,MD,MB,MI,MS )) #define __MMXQirr(OP,IM,RS,RSA,RD,RDA) (_REXQrr(RD, RS), _OO_Mrm_B (0x0f00|(OP) ,_b11,RDA(RD),RSA(RS) ,_u8(IM))) #define __MMXQimr(OP,IM,MD,MB,MI,MS,RD,RDA) (_REXQmr(MB, MI, RS), _OO_r_X_B (0x0f00|(OP) ,RDA(RD) ,MD,MB,MI,MS ,_u8(IM))) #define __MMX1Lrr(PX,OP,RS,RSA,RD,RDA) (_REXLrr(RD, RS), _B(0x0f),_OO_Mrm(((PX)<<8)|(OP) ,_b11,RDA(RD),RSA(RS) )) #define __MMX1Lmr(PX,OP,MD,MB,MI,MS,RD,RDA) (_REXLmr(MB, MI, RD), _B(0x0f),_OO_r_X(((PX)<<8)|(OP) ,RDA(RD) ,MD,MB,MI,MS )) #define __MMX1Lrm(PX,OP,RS,RSA,MD,MB,MI,MS) (_REXLrm(RS, MB, MI), _B(0x0f),_OO_r_X(((PX)<<8)|(OP) ,RSA(RS) ,MD,MB,MI,MS )) #define _MMXLrr(OP,RS,RD) __MMXLrr(OP,RS,_rM,RD,_rM) #define _MMXLmr(OP,MD,MB,MI,MS,RD) __MMXLmr(OP,MD,MB,MI,MS,RD,_rM) #define _MMXLrm(OP,RS,MD,MB,MI,MS) __MMXLrm(OP,RS,_rM,MD,MB,MI,MS) #define _MMXQrr(OP,RS,RD) __MMXQrr(OP,RS,_rM,RD,_rM) #define _MMXQmr(OP,MD,MB,MI,MS,RD) __MMXQmr(OP,MD,MB,MI,MS,RD,_rM) #define _MMXQrm(OP,RS,MD,MB,MI,MS) __MMXQrm(OP,RS,_rM,MD,MB,MI,MS) #define _2P_MMXLrr(OP,RS,RD) __MMX1Lrr(0x38, OP,RS,_rM,RD,_rM) #define _2P_MMXLmr(OP,MD,MB,MI,MS,RD) __MMX1Lmr(0x38, OP,MD,MB,MI,MS,RD,_rM) #define _2P_MMXLrm(OP,RS,MD,MB,MI,MS) __MMX1Lrm(0x38, OP,RS,_rM,MD,MB,MI,MS) #define MMX_MOVDMDrr(RS, RD) __MMXLrr(0x6e, RS,_r4, RD,_rM) #define MMX_MOVQMDrr(RS, RD) __MMXQrr(0x6e, RS,_r8, RD,_rM) #define MMX_MOVDMSrr(RS, RD) __MMXLrr(0x7e, RD,_r4, RS,_rM) #define MMX_MOVQMSrr(RS, RD) __MMXQrr(0x7e, RD,_r8, RS,_rM) #define MMX_MOVDmr(MD, MB, MI, MS, RD) _MMXLmr(0x6e, MD, MB, MI, MS, RD) #define MMX_MOVDrm(RS, MD, MB, MI, MS) _MMXLrm(0x7e, RS, MD, MB, MI, MS) #define MMX_MOVQrr(RS, RD) _MMXLrr(0x6f, RS, RD) #define MMX_MOVQmr(MD, MB, MI, MS, RD) _MMXLmr(0x6f, MD, MB, MI, MS, RD) #define MMX_MOVQrm(RS, MD, MB, MI, MS) _MMXLrm(0x7f, RS, MD, MB, MI, MS) // Original MMX instructions #define MMX_PACKSSWBrr(RS, RD) _MMXLrr(X86_MMX_PACKSSWB,RS,RD) #define MMX_PACKSSWBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PACKSSWB, MD, MB, MI, MS, RD) #define MMX_PACKSSDWrr(RS, RD) _MMXLrr(X86_MMX_PACKSSDW,RS,RD) #define MMX_PACKSSDWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PACKSSDW, MD, MB, MI, MS, RD) #define MMX_PACKUSWBrr(RS, RD) _MMXLrr(X86_MMX_PACKUSWB,RS,RD) #define MMX_PACKUSWBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PACKUSWB, MD, MB, MI, MS, RD) #define MMX_PADDBrr(RS, RD) _MMXLrr(X86_MMX_PADDB,RS,RD) #define MMX_PADDBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDB, MD, MB, MI, MS, RD) #define MMX_PADDWrr(RS, RD) _MMXLrr(X86_MMX_PADDW,RS,RD) #define MMX_PADDWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDW, MD, MB, MI, MS, RD) #define MMX_PADDDrr(RS, RD) _MMXLrr(X86_MMX_PADDD,RS,RD) #define MMX_PADDDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDD, MD, MB, MI, MS, RD) #define MMX_PADDQrr(RS, RD) _MMXLrr(X86_MMX_PADDQ,RS,RD) #define MMX_PADDQmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDQ, MD, MB, MI, MS, RD) #define MMX_PADDSBrr(RS, RD) _MMXLrr(X86_MMX_PADDSB,RS,RD) #define MMX_PADDSBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDSB, MD, MB, MI, MS, RD) #define MMX_PADDSWrr(RS, RD) _MMXLrr(X86_MMX_PADDSW,RS,RD) #define MMX_PADDSWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDSW, MD, MB, MI, MS, RD) #define MMX_PADDUSBrr(RS, RD) _MMXLrr(X86_MMX_PADDUSB,RS,RD) #define MMX_PADDUSBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDUSB, MD, MB, MI, MS, RD) #define MMX_PADDUSWrr(RS, RD) _MMXLrr(X86_MMX_PADDUSW,RS,RD) #define MMX_PADDUSWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PADDUSW, MD, MB, MI, MS, RD) #define MMX_PANDrr(RS, RD) _MMXLrr(X86_MMX_PAND,RS,RD) #define MMX_PANDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PAND, MD, MB, MI, MS, RD) #define MMX_PANDNrr(RS, RD) _MMXLrr(X86_MMX_PANDN,RS,RD) #define MMX_PANDNmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PANDN, MD, MB, MI, MS, RD) #define MMX_PAVGBrr(RS, RD) _MMXLrr(X86_MMX_PAVGB,RS,RD) #define MMX_PAVGBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PAVGB, MD, MB, MI, MS, RD) #define MMX_PAVGWrr(RS, RD) _MMXLrr(X86_MMX_PAVGW,RS,RD) #define MMX_PAVGWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PAVGW, MD, MB, MI, MS, RD) #define MMX_PCMPEQBrr(RS, RD) _MMXLrr(X86_MMX_PCMPEQB,RS,RD) #define MMX_PCMPEQBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PCMPEQB, MD, MB, MI, MS, RD) #define MMX_PCMPEQWrr(RS, RD) _MMXLrr(X86_MMX_PCMPEQW,RS,RD) #define MMX_PCMPEQWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PCMPEQW, MD, MB, MI, MS, RD) #define MMX_PCMPEQDrr(RS, RD) _MMXLrr(X86_MMX_PCMPEQD,RS,RD) #define MMX_PCMPEQDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PCMPEQD, MD, MB, MI, MS, RD) #define MMX_PCMPGTBrr(RS, RD) _MMXLrr(X86_MMX_PCMPGTB,RS,RD) #define MMX_PCMPGTBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PCMPGTB, MD, MB, MI, MS, RD) #define MMX_PCMPGTWrr(RS, RD) _MMXLrr(X86_MMX_PCMPGTW,RS,RD) #define MMX_PCMPGTWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PCMPGTW, MD, MB, MI, MS, RD) #define MMX_PCMPGTDrr(RS, RD) _MMXLrr(X86_MMX_PCMPGTD,RS,RD) #define MMX_PCMPGTDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PCMPGTD, MD, MB, MI, MS, RD) #define MMX_PMADDWDrr(RS, RD) _MMXLrr(X86_MMX_PMADDWD,RS,RD) #define MMX_PMADDWDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMADDWD, MD, MB, MI, MS, RD) #define MMX_PMAXSWrr(RS, RD) _MMXLrr(X86_MMX_PMAXSW,RS,RD) #define MMX_PMAXSWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMAXSW, MD, MB, MI, MS, RD) #define MMX_PMAXUBrr(RS, RD) _MMXLrr(X86_MMX_PMAXUB,RS,RD) #define MMX_PMAXUBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMAXUB, MD, MB, MI, MS, RD) #define MMX_PMINSWrr(RS, RD) _MMXLrr(X86_MMX_PMINSW,RS,RD) #define MMX_PMINSWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMINSW, MD, MB, MI, MS, RD) #define MMX_PMINUBrr(RS, RD) _MMXLrr(X86_MMX_PMINUB,RS,RD) #define MMX_PMINUBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMINUB, MD, MB, MI, MS, RD) #define MMX_PMULHUWrr(RS, RD) _MMXLrr(X86_MMX_PMULHUW,RS,RD) #define MMX_PMULHUWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMULHUW, MD, MB, MI, MS, RD) #define MMX_PMULHWrr(RS, RD) _MMXLrr(X86_MMX_PMULHW,RS,RD) #define MMX_PMULHWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMULHW, MD, MB, MI, MS, RD) #define MMX_PMULLWrr(RS, RD) _MMXLrr(X86_MMX_PMULLW,RS,RD) #define MMX_PMULLWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMULLW, MD, MB, MI, MS, RD) #define MMX_PMULUDQrr(RS, RD) _MMXLrr(X86_MMX_PMULUDQ,RS,RD) #define MMX_PMULUDQmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PMULUDQ, MD, MB, MI, MS, RD) #define MMX_PORrr(RS, RD) _MMXLrr(X86_MMX_POR,RS,RD) #define MMX_PORmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_POR, MD, MB, MI, MS, RD) #define MMX_PSADBWrr(RS, RD) _MMXLrr(X86_MMX_PSADBW,RS,RD) #define MMX_PSADBWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSADBW, MD, MB, MI, MS, RD) #define MMX_PSLLWir(IM, RD) __MMXLirr(X86_MMX_PSLLWi, IM, RD,_rM, _b110,_rN) #define MMX_PSLLWrr(RS, RD) _MMXLrr(X86_MMX_PSLLW,RS,RD) #define MMX_PSLLWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSLLW, MD, MB, MI, MS, RD) #define MMX_PSLLDir(IM, RD) __MMXLirr(X86_MMX_PSLLDi, IM, RD,_rM, _b110,_rN) #define MMX_PSLLDrr(RS, RD) _MMXLrr(X86_MMX_PSLLD,RS,RD) #define MMX_PSLLDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSLLD, MD, MB, MI, MS, RD) #define MMX_PSLLQir(IM, RD) __MMXLirr(X86_MMX_PSLLQi, IM, RD,_rM, _b110,_rN) #define MMX_PSLLQrr(RS, RD) _MMXLrr(X86_MMX_PSLLQ,RS,RD) #define MMX_PSLLQmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSLLQ, MD, MB, MI, MS, RD) #define MMX_PSRAWir(IM, RD) __MMXLirr(X86_MMX_PSRAWi, IM, RD,_rM, _b100,_rN) #define MMX_PSRAWrr(RS, RD) _MMXLrr(X86_MMX_PSRAW,RS,RD) #define MMX_PSRAWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSRAW, MD, MB, MI, MS, RD) #define MMX_PSRADir(IM, RD) __MMXLirr(X86_MMX_PSRADi, IM, RD,_rM, _b100,_rN) #define MMX_PSRADrr(RS, RD) _MMXLrr(X86_MMX_PSRAD,RS,RD) #define MMX_PSRADmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSRAD, MD, MB, MI, MS, RD) #define MMX_PSRLWir(IM, RD) __MMXLirr(X86_MMX_PSRLWi, IM, RD,_rM, _b010,_rN) #define MMX_PSRLWrr(RS, RD) _MMXLrr(X86_MMX_PSRLW,RS,RD) #define MMX_PSRLWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSRLW, MD, MB, MI, MS, RD) #define MMX_PSRLDir(IM, RD) __MMXLirr(X86_MMX_PSRLDi, IM, RD,_rM, _b010,_rN) #define MMX_PSRLDrr(RS, RD) _MMXLrr(X86_MMX_PSRLD,RS,RD) #define MMX_PSRLDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSRLD, MD, MB, MI, MS, RD) #define MMX_PSRLQir(IM, RD) __MMXLirr(X86_MMX_PSRLQi, IM, RD,_rM, _b010,_rN) #define MMX_PSRLQrr(RS, RD) _MMXLrr(X86_MMX_PSRLQ,RS,RD) #define MMX_PSRLQmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSRLQ, MD, MB, MI, MS, RD) #define MMX_PSUBBrr(RS, RD) _MMXLrr(X86_MMX_PSUBB,RS,RD) #define MMX_PSUBBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBB, MD, MB, MI, MS, RD) #define MMX_PSUBWrr(RS, RD) _MMXLrr(X86_MMX_PSUBW,RS,RD) #define MMX_PSUBWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBW, MD, MB, MI, MS, RD) #define MMX_PSUBDrr(RS, RD) _MMXLrr(X86_MMX_PSUBD,RS,RD) #define MMX_PSUBDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBD, MD, MB, MI, MS, RD) #define MMX_PSUBQrr(RS, RD) _MMXLrr(X86_MMX_PSUBQ,RS,RD) #define MMX_PSUBQmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBQ, MD, MB, MI, MS, RD) #define MMX_PSUBSBrr(RS, RD) _MMXLrr(X86_MMX_PSUBSB,RS,RD) #define MMX_PSUBSBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBSB, MD, MB, MI, MS, RD) #define MMX_PSUBSWrr(RS, RD) _MMXLrr(X86_MMX_PSUBSW,RS,RD) #define MMX_PSUBSWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBSW, MD, MB, MI, MS, RD) #define MMX_PSUBUSBrr(RS, RD) _MMXLrr(X86_MMX_PSUBUSB,RS,RD) #define MMX_PSUBUSBmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBUSB, MD, MB, MI, MS, RD) #define MMX_PSUBUSWrr(RS, RD) _MMXLrr(X86_MMX_PSUBUSW,RS,RD) #define MMX_PSUBUSWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PSUBUSW, MD, MB, MI, MS, RD) #define MMX_PUNPCKHBWrr(RS, RD) _MMXLrr(X86_MMX_PUNPCKHBW,RS,RD) #define MMX_PUNPCKHBWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PUNPCKHBW, MD, MB, MI, MS, RD) #define MMX_PUNPCKHWDrr(RS, RD) _MMXLrr(X86_MMX_PUNPCKHWD,RS,RD) #define MMX_PUNPCKHWDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PUNPCKHWD, MD, MB, MI, MS, RD) #define MMX_PUNPCKHDQrr(RS, RD) _MMXLrr(X86_MMX_PUNPCKHDQ,RS,RD) #define MMX_PUNPCKHDQmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PUNPCKHDQ, MD, MB, MI, MS, RD) #define MMX_PUNPCKLBWrr(RS, RD) _MMXLrr(X86_MMX_PUNPCKLBW,RS,RD) #define MMX_PUNPCKLBWmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PUNPCKLBW, MD, MB, MI, MS, RD) #define MMX_PUNPCKLWDrr(RS, RD) _MMXLrr(X86_MMX_PUNPCKLWD,RS,RD) #define MMX_PUNPCKLWDmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PUNPCKLWD, MD, MB, MI, MS, RD) #define MMX_PUNPCKLDQrr(RS, RD) _MMXLrr(X86_MMX_PUNPCKLDQ,RS,RD) #define MMX_PUNPCKLDQmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PUNPCKLDQ, MD, MB, MI, MS, RD) #define MMX_PXORrr(RS, RD) _MMXLrr(X86_MMX_PXOR,RS,RD) #define MMX_PXORmr(MD,MB,MI,MS,RD) _MMXLmr(X86_MMX_PXOR, MD, MB, MI, MS, RD) #define MMX_PSHUFWirr(IM, RS, RD) __MMXLirr(X86_MMX_PSHUFW, IM, RS,_rM, RD,_rM) #define MMX_PSHUFWimr(IM, MD, MB, MI, MS, RD) __MMXLimr(X86_MMX_PSHUFW, IM, MD, MB, MI, MS, RD,_rM) #define MMX_PEXTRWLirr(IM, RS, RD) __MMXLirr(X86_MMX_PEXTRW, IM, RS,_rM, RD,_r4) #define MMX_PEXTRWQirr(IM, RS, RD) __MMXQirr(X86_MMX_PEXTRW, IM, RS,_rM, RD,_r8) #define MMX_PINSRWLirr(IM, RS, RD) __MMXLirr(X86_MMX_PINSRW, IM, RS,_r4, RD,_rM) #define MMX_PINSRWLimr(IM, MD, MB, MI, MS, RD) __MMXLimr(X86_MMX_PINSRW, IM, MD, MB, MI, MS, RD,_r4) #define MMX_PINSRWQirr(IM, RS, RD) __MMXQirr(X86_MMX_PINSRW, IM, RS,_r4, RD,_rM) #define MMX_PINSRWQimr(IM, MD, MB, MI, MS, RD) __MMXQimr(X86_MMX_PINSRW, IM, MD, MB, MI, MS, RD,_r8) // Additionnal MMX instructions, brought by SSSE3 ISA #define MMX_PABSBrr(RS, RD) _2P_MMXLrr(X86_MMX_PABSB,RS,RD) #define MMX_PABSBmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PABSB, MD, MB, MI, MS, RD) #define MMX_PABSWrr(RS, RD) _2P_MMXLrr(X86_MMX_PABSW,RS,RD) #define MMX_PABSWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PABSW, MD, MB, MI, MS, RD) #define MMX_PABSDrr(RS, RD) _2P_MMXLrr(X86_MMX_PABSD,RS,RD) #define MMX_PABSDmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PABSD, MD, MB, MI, MS, RD) #define MMX_PHADDWrr(RS, RD) _2P_MMXLrr(X86_MMX_PHADDW,RS,RD) #define MMX_PHADDWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PHADDW, MD, MB, MI, MS, RD) #define MMX_PHADDDrr(RS, RD) _2P_MMXLrr(X86_MMX_PHADDD,RS,RD) #define MMX_PHADDDmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PHADDD, MD, MB, MI, MS, RD) #define MMX_PHADDSWrr(RS, RD) _2P_MMXLrr(X86_MMX_PHADDSW,RS,RD) #define MMX_PHADDSWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PHADDSW, MD, MB, MI, MS, RD) #define MMX_PHSUBWrr(RS, RD) _2P_MMXLrr(X86_MMX_PHSUBW,RS,RD) #define MMX_PHSUBWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PHSUBW, MD, MB, MI, MS, RD) #define MMX_PHSUBDrr(RS, RD) _2P_MMXLrr(X86_MMX_PHSUBD,RS,RD) #define MMX_PHSUBDmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PHSUBD, MD, MB, MI, MS, RD) #define MMX_PHSUBSWrr(RS, RD) _2P_MMXLrr(X86_MMX_PHSUBSW,RS,RD) #define MMX_PHSUBSWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PHSUBSW, MD, MB, MI, MS, RD) #define MMX_PMADDUBSWrr(RS, RD) _2P_MMXLrr(X86_MMX_PMADDUBSW,RS,RD) #define MMX_PMADDUBSWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PMADDUBSW, MD, MB, MI, MS, RD) #define MMX_PMULHRSWrr(RS, RD) _2P_MMXLrr(X86_MMX_PMULHRSW,RS,RD) #define MMX_PMULHRSWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PMULHRSW, MD, MB, MI, MS, RD) #define MMX_PSHUFBrr(RS, RD) _2P_MMXLrr(X86_MMX_PSHUFB,RS,RD) #define MMX_PSHUFBmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PSHUFB, MD, MB, MI, MS, RD) #define MMX_PSIGNBrr(RS, RD) _2P_MMXLrr(X86_MMX_PSIGNB,RS,RD) #define MMX_PSIGNBmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PSIGNB, MD, MB, MI, MS, RD) #define MMX_PSIGNWrr(RS, RD) _2P_MMXLrr(X86_MMX_PSIGNW,RS,RD) #define MMX_PSIGNWmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PSIGNW, MD, MB, MI, MS, RD) #define MMX_PSIGNDrr(RS, RD) _2P_MMXLrr(X86_MMX_PSIGND,RS,RD) #define MMX_PSIGNDmr(MD,MB,MI,MS,RD) _2P_MMXLmr(X86_MMX_PSIGND, MD, MB, MI, MS, RD) #define EMMS() _OO (0x0f77 ) /* --- Media 128-bit instructions ------------------------------------------ */ enum { X86_SSE_CC_EQ = 0, X86_SSE_CC_LT = 1, X86_SSE_CC_GT = 1, X86_SSE_CC_LE = 2, X86_SSE_CC_GE = 2, X86_SSE_CC_U = 3, X86_SSE_CC_NEQ = 4, X86_SSE_CC_NLT = 5, X86_SSE_CC_NGT = 5, X86_SSE_CC_NLE = 6, X86_SSE_CC_NGE = 6, X86_SSE_CC_O = 7 }; enum { X86_SSE_UCOMI = 0x2e, X86_SSE_COMI = 0x2f, X86_SSE_CMP = 0xc2, X86_SSE_SQRT = 0x51, X86_SSE_RSQRT = 0x52, X86_SSE_RCP = 0x53, X86_SSE_AND = 0x54, X86_SSE_ANDN = 0x55, X86_SSE_OR = 0x56, X86_SSE_XOR = 0x57, X86_SSE_ADD = 0x58, X86_SSE_MUL = 0x59, X86_SSE_SUB = 0x5c, X86_SSE_MIN = 0x5d, X86_SSE_DIV = 0x5e, X86_SSE_MAX = 0x5f, X86_SSE_CVTDQ2PD = 0xe6, X86_SSE_CVTDQ2PS = 0x5b, X86_SSE_CVTPD2DQ = 0xe6, X86_SSE_CVTPD2PI = 0x2d, X86_SSE_CVTPD2PS = 0x5a, X86_SSE_CVTPI2PD = 0x2a, X86_SSE_CVTPI2PS = 0x2a, X86_SSE_CVTPS2DQ = 0x5b, X86_SSE_CVTPS2PD = 0x5a, X86_SSE_CVTPS2PI = 0x2d, X86_SSE_CVTSD2SI = 0x2d, X86_SSE_CVTSD2SS = 0x5a, X86_SSE_CVTSI2SD = 0x2a, X86_SSE_CVTSI2SS = 0x2a, X86_SSE_CVTSS2SD = 0x5a, X86_SSE_CVTSS2SI = 0x2d, X86_SSE_CVTTPD2PI = 0x2c, X86_SSE_CVTTPD2DQ = 0xe6, X86_SSE_CVTTPS2DQ = 0x5b, X86_SSE_CVTTPS2PI = 0x2c, X86_SSE_CVTTSD2SI = 0x2c, X86_SSE_CVTTSS2SI = 0x2c, X86_SSE_MOVMSK = 0x50, X86_SSE_PACKSSDW = 0x6b, X86_SSE_PACKSSWB = 0x63, X86_SSE_PACKUSWB = 0x67, X86_SSE_PADDB = 0xfc, X86_SSE_PADDD = 0xfe, X86_SSE_PADDQ = 0xd4, X86_SSE_PADDSB = 0xec, X86_SSE_PADDSW = 0xed, X86_SSE_PADDUSB = 0xdc, X86_SSE_PADDUSW = 0xdd, X86_SSE_PADDW = 0xfd, X86_SSE_PAND = 0xdb, X86_SSE_PANDN = 0xdf, X86_SSE_PAVGB = 0xe0, X86_SSE_PAVGW = 0xe3, X86_SSE_PCMPEQB = 0x74, X86_SSE_PCMPEQD = 0x76, X86_SSE_PCMPEQW = 0x75, X86_SSE_PCMPGTB = 0x64, X86_SSE_PCMPGTD = 0x66, X86_SSE_PCMPGTW = 0x65, X86_SSE_PMADDWD = 0xf5, X86_SSE_PMAXSW = 0xee, X86_SSE_PMAXUB = 0xde, X86_SSE_PMINSW = 0xea, X86_SSE_PMINUB = 0xda, X86_SSE_PMOVMSKB = 0xd7, X86_SSE_PMULHUW = 0xe4, X86_SSE_PMULHW = 0xe5, X86_SSE_PMULLW = 0xd5, X86_SSE_PMULUDQ = 0xf4, X86_SSE_POR = 0xeb, X86_SSE_PSADBW = 0xf6, X86_SSE_PSLLD = 0xf2, X86_SSE_PSLLQ = 0xf3, X86_SSE_PSLLW = 0xf1, X86_SSE_PSRAD = 0xe2, X86_SSE_PSRAW = 0xe1, X86_SSE_PSRLD = 0xd2, X86_SSE_PSRLQ = 0xd3, X86_SSE_PSRLW = 0xd1, X86_SSE_PSUBB = 0xf8, X86_SSE_PSUBD = 0xfa, X86_SSE_PSUBQ = 0xfb, X86_SSE_PSUBSB = 0xe8, X86_SSE_PSUBSW = 0xe9, X86_SSE_PSUBUSB = 0xd8, X86_SSE_PSUBUSW = 0xd9, X86_SSE_PSUBW = 0xf9, X86_SSE_PUNPCKHBW = 0x68, X86_SSE_PUNPCKHDQ = 0x6a, X86_SSE_PUNPCKHQDQ = 0x6d, X86_SSE_PUNPCKHWD = 0x69, X86_SSE_PUNPCKLBW = 0x60, X86_SSE_PUNPCKLDQ = 0x62, X86_SSE_PUNPCKLQDQ = 0x6c, X86_SSE_PUNPCKLWD = 0x61, X86_SSE_PXOR = 0xef, X86_SSSE3_PSHUFB = 0x00, }; /* _format Opcd ,Mod ,r ,m ,mem=dsp+sib ,imm... */ #define _SSSE3Lrr(OP1,OP2,RS,RSA,RD,RDA) (_B(0x66), _REXLrr(RD,RD), _B(0x0f), _OO_Mrm (((OP1)<<8)|(OP2) ,_b11,RDA(RD),RSA(RS) )) #define _SSSE3Lmr(OP1,OP2,MD,MB,MI,MS,RD,RDA) (_B(0x66), _REXLmr(MB, MI, RD), _B(0x0f), _OO_r_X (((OP1)<<8)|(OP2) ,RDA(RD) ,MD,MB,MI,MS )) #define _SSSE3Lirr(OP1,OP2,IM,RS,RD) (_B(0x66), _REXLrr(RD, RS), _B(0x0f), _OO_Mrm_B (((OP1)<<8)|(OP2) ,_b11,_rX(RD),_rX(RS) ,_u8(IM))) #define _SSSE3Limr(OP1,OP2,IM,MD,MB,MI,MS,RD) (_B(0x66), _REXLmr(MB, MI, RD), _B(0x0f), _OO_r_X_B (((OP1)<<8)|(OP2) ,_rX(RD) ,MD,MB,MI,MS ,_u8(IM))) #define __SSELir(OP,MO,IM,RD) (_REXLrr(0, RD), _OO_Mrm_B (0x0f00|(OP) ,_b11,MO ,_rX(RD) ,_u8(IM))) #define __SSELim(OP,MO,IM,MD,MB,MI,MS) (_REXLrm(0, MB, MI), _OO_r_X_B (0x0f00|(OP) ,MO ,MD,MB,MI,MS ,_u8(IM))) #define __SSELrr(OP,RS,RSA,RD,RDA) (_REXLrr(RD, RS), _OO_Mrm (0x0f00|(OP) ,_b11,RDA(RD),RSA(RS) )) #define __SSELmr(OP,MD,MB,MI,MS,RD,RDA) (_REXLmr(MB, MI, RD), _OO_r_X (0x0f00|(OP) ,RDA(RD) ,MD,MB,MI,MS )) #define __SSELrm(OP,RS,RSA,MD,MB,MI,MS) (_REXLrm(RS, MB, MI), _OO_r_X (0x0f00|(OP) ,RSA(RS) ,MD,MB,MI,MS )) #define __SSELirr(OP,IM,RS,RD) (_REXLrr(RD, RS), _OO_Mrm_B (0x0f00|(OP) ,_b11,_rX(RD),_rX(RS) ,_u8(IM))) #define __SSELimr(OP,IM,MD,MB,MI,MS,RD) (_REXLmr(MB, MI, RD), _OO_r_X_B (0x0f00|(OP) ,_rX(RD) ,MD,MB,MI,MS ,_u8(IM))) #define __SSEQrr(OP,RS,RSA,RD,RDA) (_REXQrr(RD, RS), _OO_Mrm (0x0f00|(OP) ,_b11,RDA(RD),RSA(RS) )) #define __SSEQmr(OP,MD,MB,MI,MS,RD,RDA) (_REXQmr(MB, MI, RD), _OO_r_X (0x0f00|(OP) ,RDA(RD) ,MD,MB,MI,MS )) #define __SSEQrm(OP,RS,RSA,MD,MB,MI,MS) (_REXQrm(RS, MB, MI), _OO_r_X (0x0f00|(OP) ,RSA(RS) ,MD,MB,MI,MS )) #define _SSELrr(PX,OP,RS,RSA,RD,RDA) (_B(PX), __SSELrr(OP, RS, RSA, RD, RDA)) #define _SSELmr(PX,OP,MD,MB,MI,MS,RD,RDA) (_B(PX), __SSELmr(OP, MD, MB, MI, MS, RD, RDA)) #define _SSELrm(PX,OP,RS,RSA,MD,MB,MI,MS) (_B(PX), __SSELrm(OP, RS, RSA, MD, MB, MI, MS)) #define _SSELir(PX,OP,MO,IM,RD) (_B(PX), __SSELir(OP, MO, IM, RD)) #define _SSELim(PX,OP,MO,IM,MD,MB,MI,MS) (_B(PX), __SSELim(OP, MO, IM, MD, MB, MI, MS)) #define _SSELirr(PX,OP,IM,RS,RD) (_B(PX), __SSELirr(OP, IM, RS, RD)) #define _SSELimr(PX,OP,IM,MD,MB,MI,MS,RD) (_B(PX), __SSELimr(OP, IM, MD, MB, MI, MS, RD)) #define _SSEQrr(PX,OP,RS,RSA,RD,RDA) (_B(PX), __SSEQrr(OP, RS, RSA, RD, RDA)) #define _SSEQmr(PX,OP,MD,MB,MI,MS,RD,RDA) (_B(PX), __SSEQmr(OP, MD, MB, MI, MS, RD, RDA)) #define _SSEQrm(PX,OP,RS,RSA,MD,MB,MI,MS) (_B(PX), __SSEQrm(OP, RS, RSA, MD, MB, MI, MS)) #define _SSEPSrr(OP,RS,RD) __SSELrr( OP, RS,_rX, RD,_rX) #define _SSEPSmr(OP,MD,MB,MI,MS,RD) __SSELmr( OP, MD, MB, MI, MS, RD,_rX) #define _SSEPSrm(OP,RS,MD,MB,MI,MS) __SSELrm( OP, RS,_rX, MD, MB, MI, MS) #define _SSEPSirr(OP,IM,RS,RD) __SSELirr( OP, IM, RS, RD) #define _SSEPSimr(OP,IM,MD,MB,MI,MS,RD) __SSELimr( OP, IM, MD, MB, MI, MS, RD) #define _SSEPDrr(OP,RS,RD) _SSELrr(0x66, OP, RS,_rX, RD,_rX) #define _SSEPDmr(OP,MD,MB,MI,MS,RD) _SSELmr(0x66, OP, MD, MB, MI, MS, RD,_rX) #define _SSEPDrm(OP,RS,MD,MB,MI,MS) _SSELrm(0x66, OP, RS,_rX, MD, MB, MI, MS) #define _SSEPDirr(OP,IM,RS,RD) _SSELirr(0x66, OP, IM, RS, RD) #define _SSEPDimr(OP,IM,MD,MB,MI,MS,RD) _SSELimr(0x66, OP, IM, MD, MB, MI, MS, RD) #define _SSESSrr(OP,RS,RD) _SSELrr(0xf3, OP, RS,_rX, RD,_rX) #define _SSESSmr(OP,MD,MB,MI,MS,RD) _SSELmr(0xf3, OP, MD, MB, MI, MS, RD,_rX) #define _SSESSrm(OP,RS,MD,MB,MI,MS) _SSELrm(0xf3, OP, RS,_rX, MD, MB, MI, MS) #define _SSESSirr(OP,IM,RS,RD) _SSELirr(0xf3, OP, IM, RS, RD) #define _SSESSimr(OP,IM,MD,MB,MI,MS,RD) _SSELimr(0xf3, OP, IM, MD, MB, MI, MS, RD) #define _SSESDrr(OP,RS,RD) _SSELrr(0xf2, OP, RS,_rX, RD,_rX) #define _SSESDmr(OP,MD,MB,MI,MS,RD) _SSELmr(0xf2, OP, MD, MB, MI, MS, RD,_rX) #define _SSESDrm(OP,RS,MD,MB,MI,MS) _SSELrm(0xf2, OP, RS,_rX, MD, MB, MI, MS) #define _SSESDirr(OP,IM,RS,RD) _SSELirr(0xf2, OP, IM, RS, RD) #define _SSESDimr(OP,IM,MD,MB,MI,MS,RD) _SSELimr(0xf2, OP, IM, MD, MB, MI, MS, RD) #define ADDPSrr(RS, RD) _SSEPSrr(X86_SSE_ADD, RS, RD) #define ADDPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_ADD, MD, MB, MI, MS, RD) #define ADDPDrr(RS, RD) _SSEPDrr(X86_SSE_ADD, RS, RD) #define ADDPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_ADD, MD, MB, MI, MS, RD) #define ADDSSrr(RS, RD) _SSESSrr(X86_SSE_ADD, RS, RD) #define ADDSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_ADD, MD, MB, MI, MS, RD) #define ADDSDrr(RS, RD) _SSESDrr(X86_SSE_ADD, RS, RD) #define ADDSDmr(MD, MB, MI, MS, RD) _SSESDmr(X86_SSE_ADD, MD, MB, MI, MS, RD) #define ANDNPSrr(RS, RD) _SSEPSrr(X86_SSE_ANDN, RS, RD) #define ANDNPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_ANDN, MD, MB, MI, MS, RD) #define ANDNPDrr(RS, RD) _SSEPDrr(X86_SSE_ANDN, RS, RD) #define ANDNPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_ANDN, MD, MB, MI, MS, RD) #define ANDPSrr(RS, RD) _SSEPSrr(X86_SSE_AND, RS, RD) #define ANDPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_AND, MD, MB, MI, MS, RD) #define ANDPDrr(RS, RD) _SSEPDrr(X86_SSE_AND, RS, RD) #define ANDPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_AND, MD, MB, MI, MS, RD) #define CMPPSrr(IM, RS, RD) _SSEPSirr(X86_SSE_CMP, IM, RS, RD) #define CMPPSmr(IM, MD, MB, MI, MS, RD) _SSEPSimr(X86_SSE_CMP, IM, MD, MB, MI, MS, RD) #define CMPPDrr(IM, RS, RD) _SSEPDirr(X86_SSE_CMP, IM, RS, RD) #define CMPPDmr(IM, MD, MB, MI, MS, RD) _SSEPDimr(X86_SSE_CMP, IM, MD, MB, MI, MS, RD) #define CMPSSrr(IM, RS, RD) _SSESSirr(X86_SSE_CMP, IM, RS, RD) #define CMPSSmr(IM, MD, MB, MI, MS, RD) _SSESSimr(X86_SSE_CMP, IM, MD, MB, MI, MS, RD) #define CMPSDrr(IM, RS, RD) _SSESDirr(X86_SSE_CMP, IM, RS, RD) #define CMPSDmr(IM, MD, MB, MI, MS, RD) _SSESDimr(X86_SSE_CMP, IM, MD, MB, MI, MS, RD) #define DIVPSrr(RS, RD) _SSEPSrr(X86_SSE_DIV, RS, RD) #define DIVPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_DIV, MD, MB, MI, MS, RD) #define DIVPDrr(RS, RD) _SSEPDrr(X86_SSE_DIV, RS, RD) #define DIVPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_DIV, MD, MB, MI, MS, RD) #define DIVSSrr(RS, RD) _SSESSrr(X86_SSE_DIV, RS, RD) #define DIVSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_DIV, MD, MB, MI, MS, RD) #define DIVSDrr(RS, RD) _SSESDrr(X86_SSE_DIV, RS, RD) #define DIVSDmr(MD, MB, MI, MS, RD) _SSESDmr(X86_SSE_DIV, MD, MB, MI, MS, RD) #define MAXPSrr(RS, RD) _SSEPSrr(X86_SSE_MAX, RS, RD) #define MAXPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_MAX, MD, MB, MI, MS, RD) #define MAXPDrr(RS, RD) _SSEPDrr(X86_SSE_MAX, RS, RD) #define MAXPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_MAX, MD, MB, MI, MS, RD) #define MAXSSrr(RS, RD) _SSESSrr(X86_SSE_MAX, RS, RD) #define MAXSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_MAX, MD, MB, MI, MS, RD) #define MAXSDrr(RS, RD) _SSESDrr(X86_SSE_MAX, RS, RD) #define MAXSDmr(MD, MB, MI, MS, RD) _SSESDmr(X86_SSE_MAX, MD, MB, MI, MS, RD) #define MINPSrr(RS, RD) _SSEPSrr(X86_SSE_MIN, RS, RD) #define MINPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_MIN, MD, MB, MI, MS, RD) #define MINPDrr(RS, RD) _SSEPDrr(X86_SSE_MIN, RS, RD) #define MINPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_MIN, MD, MB, MI, MS, RD) #define MINSSrr(RS, RD) _SSESSrr(X86_SSE_MIN, RS, RD) #define MINSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_MIN, MD, MB, MI, MS, RD) #define MINSDrr(RS, RD) _SSESDrr(X86_SSE_MIN, RS, RD) #define MINSDmr(MD, MB, MI, MS, RD) _SSESDmr(X86_SSE_MIN, MD, MB, MI, MS, RD) #define MULPSrr(RS, RD) _SSEPSrr(X86_SSE_MUL, RS, RD) #define MULPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_MUL, MD, MB, MI, MS, RD) #define MULPDrr(RS, RD) _SSEPDrr(X86_SSE_MUL, RS, RD) #define MULPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_MUL, MD, MB, MI, MS, RD) #define MULSSrr(RS, RD) _SSESSrr(X86_SSE_MUL, RS, RD) #define MULSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_MUL, MD, MB, MI, MS, RD) #define MULSDrr(RS, RD) _SSESDrr(X86_SSE_MUL, RS, RD) #define MULSDmr(MD, MB, MI, MS, RD) _SSESDmr(X86_SSE_MUL, MD, MB, MI, MS, RD) #define ORPSrr(RS, RD) _SSEPSrr(X86_SSE_OR, RS, RD) #define ORPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_OR, MD, MB, MI, MS, RD) #define ORPDrr(RS, RD) _SSEPDrr(X86_SSE_OR, RS, RD) #define ORPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_OR, MD, MB, MI, MS, RD) #define RCPPSrr(RS, RD) _SSEPSrr(X86_SSE_RCP, RS, RD) #define RCPPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_RCP, MD, MB, MI, MS, RD) #define RCPSSrr(RS, RD) _SSESSrr(X86_SSE_RCP, RS, RD) #define RCPSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_RCP, MD, MB, MI, MS, RD) #define RSQRTPSrr(RS, RD) _SSEPSrr(X86_SSE_RSQRT, RS, RD) #define RSQRTPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_RSQRT, MD, MB, MI, MS, RD) #define RSQRTSSrr(RS, RD) _SSESSrr(X86_SSE_RSQRT, RS, RD) #define RSQRTSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_RSQRT, MD, MB, MI, MS, RD) #define SQRTPSrr(RS, RD) _SSEPSrr(X86_SSE_SQRT, RS, RD) #define SQRTPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_SQRT, MD, MB, MI, MS, RD) #define SQRTPDrr(RS, RD) _SSEPDrr(X86_SSE_SQRT, RS, RD) #define SQRTPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_SQRT, MD, MB, MI, MS, RD) #define SQRTSSrr(RS, RD) _SSESSrr(X86_SSE_SQRT, RS, RD) #define SQRTSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_SQRT, MD, MB, MI, MS, RD) #define SQRTSDrr(RS, RD) _SSESDrr(X86_SSE_SQRT, RS, RD) #define SQRTSDmr(MD, MB, MI, MS, RD) _SSESDmr(X86_SSE_SQRT, MD, MB, MI, MS, RD) #define SUBPSrr(RS, RD) _SSEPSrr(X86_SSE_SUB, RS, RD) #define SUBPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_SUB, MD, MB, MI, MS, RD) #define SUBPDrr(RS, RD) _SSEPDrr(X86_SSE_SUB, RS, RD) #define SUBPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_SUB, MD, MB, MI, MS, RD) #define SUBSSrr(RS, RD) _SSESSrr(X86_SSE_SUB, RS, RD) #define SUBSSmr(MD, MB, MI, MS, RD) _SSESSmr(X86_SSE_SUB, MD, MB, MI, MS, RD) #define SUBSDrr(RS, RD) _SSESDrr(X86_SSE_SUB, RS, RD) #define SUBSDmr(MD, MB, MI, MS, RD) _SSESDmr(X86_SSE_SUB, MD, MB, MI, MS, RD) #define XORPSrr(RS, RD) _SSEPSrr(X86_SSE_XOR, RS, RD) #define XORPSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_XOR, MD, MB, MI, MS, RD) #define XORPDrr(RS, RD) _SSEPDrr(X86_SSE_XOR, RS, RD) #define XORPDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_XOR, MD, MB, MI, MS, RD) #define COMISSrr(RS, RD) _SSEPSrr(X86_SSE_COMI, RS, RD) #define COMISSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_COMI, MD, MB, MI, MS, RD) #define COMISDrr(RS, RD) _SSEPDrr(X86_SSE_COMI, RS, RD) #define COMISDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_COMI, MD, MB, MI, MS, RD) #define UCOMISSrr(RS, RD) _SSEPSrr(X86_SSE_UCOMI, RS, RD) #define UCOMISSmr(MD, MB, MI, MS, RD) _SSEPSmr(X86_SSE_UCOMI, MD, MB, MI, MS, RD) #define UCOMISDrr(RS, RD) _SSEPDrr(X86_SSE_UCOMI, RS, RD) #define UCOMISDmr(MD, MB, MI, MS, RD) _SSEPDmr(X86_SSE_UCOMI, MD, MB, MI, MS, RD) #define MOVAPSrr(RS, RD) _SSEPSrr(0x28, RS, RD) #define MOVAPSmr(MD, MB, MI, MS, RD) _SSEPSmr(0x28, MD, MB, MI, MS, RD) #define MOVAPSrm(RS, MD, MB, MI, MS) _SSEPSrm(0x29, RS, MD, MB, MI, MS) #define MOVAPDrr(RS, RD) _SSEPDrr(0x28, RS, RD) #define MOVAPDmr(MD, MB, MI, MS, RD) _SSEPDmr(0x28, MD, MB, MI, MS, RD) #define MOVAPDrm(RS, MD, MB, MI, MS) _SSEPDrm(0x29, RS, MD, MB, MI, MS) #define CVTDQ2PDrr(RS, RD) _SSELrr(0xf3, X86_SSE_CVTDQ2PD, RS,_rX, RD,_rX) #define CVTDQ2PDmr(MD, MB, MI, MS, RD) _SSELmr(0xf3, X86_SSE_CVTDQ2PD, MD, MB, MI, MS, RD,_rX) #define CVTDQ2PSrr(RS, RD) __SSELrr( X86_SSE_CVTDQ2PS, RS,_rX, RD,_rX) #define CVTDQ2PSmr(MD, MB, MI, MS, RD) __SSELmr( X86_SSE_CVTDQ2PS, MD, MB, MI, MS, RD,_rX) #define CVTPD2DQrr(RS, RD) _SSELrr(0xf2, X86_SSE_CVTPD2DQ, RS,_rX, RD,_rX) #define CVTPD2DQmr(MD, MB, MI, MS, RD) _SSELmr(0xf2, X86_SSE_CVTPD2DQ, MD, MB, MI, MS, RD,_rX) #define CVTPD2PIrr(RS, RD) _SSELrr(0x66, X86_SSE_CVTPD2PI, RS,_rX, RD,_rM) #define CVTPD2PImr(MD, MB, MI, MS, RD) _SSELmr(0x66, X86_SSE_CVTPD2PI, MD, MB, MI, MS, RD,_rM) #define CVTPD2PSrr(RS, RD) _SSELrr(0x66, X86_SSE_CVTPD2PS, RS,_rX, RD,_rX) #define CVTPD2PSmr(MD, MB, MI, MS, RD) _SSELmr(0x66, X86_SSE_CVTPD2PS, MD, MB, MI, MS, RD,_rX) #define CVTPI2PDrr(RS, RD) _SSELrr(0x66, X86_SSE_CVTPI2PD, RS,_rM, RD,_rX) #define CVTPI2PDmr(MD, MB, MI, MS, RD) _SSELmr(0x66, X86_SSE_CVTPI2PD, MD, MB, MI, MS, RD,_rX) #define CVTPI2PSrr(RS, RD) __SSELrr( X86_SSE_CVTPI2PS, RS,_rM, RD,_rX) #define CVTPI2PSmr(MD, MB, MI, MS, RD) __SSELmr( X86_SSE_CVTPI2PS, MD, MB, MI, MS, RD,_rX) #define CVTPS2DQrr(RS, RD) _SSELrr(0x66, X86_SSE_CVTPS2DQ, RS,_rX, RD,_rX) #define CVTPS2DQmr(MD, MB, MI, MS, RD) _SSELmr(0x66, X86_SSE_CVTPS2DQ, MD, MB, MI, MS, RD,_rX) #define CVTPS2PDrr(RS, RD) __SSELrr( X86_SSE_CVTPS2PD, RS,_rX, RD,_rX) #define CVTPS2PDmr(MD, MB, MI, MS, RD) __SSELmr( X86_SSE_CVTPS2PD, MD, MB, MI, MS, RD,_rX) #define CVTPS2PIrr(RS, RD) __SSELrr( X86_SSE_CVTPS2PI, RS,_rX, RD,_rM) #define CVTPS2PImr(MD, MB, MI, MS, RD) __SSELmr( X86_SSE_CVTPS2PI, MD, MB, MI, MS, RD,_rM) #define CVTSD2SILrr(RS, RD) _SSELrr(0xf2, X86_SSE_CVTSD2SI, RS,_rX, RD,_r4) #define CVTSD2SILmr(MD, MB, MI, MS, RD) _SSELmr(0xf2, X86_SSE_CVTSD2SI, MD, MB, MI, MS, RD,_r4) #define CVTSD2SIQrr(RS, RD) _SSEQrr(0xf2, X86_SSE_CVTSD2SI, RS,_rX, RD,_r8) #define CVTSD2SIQmr(MD, MB, MI, MS, RD) _SSEQmr(0xf2, X86_SSE_CVTSD2SI, MD, MB, MI, MS, RD,_r8) #define CVTSD2SSrr(RS, RD) _SSELrr(0xf2, X86_SSE_CVTSD2SS, RS,_rX, RD,_rX) #define CVTSD2SSmr(MD, MB, MI, MS, RD) _SSELmr(0xf2, X86_SSE_CVTSD2SS, MD, MB, MI, MS, RD,_rX) #define CVTSI2SDLrr(RS, RD) _SSELrr(0xf2, X86_SSE_CVTSI2SD, RS,_r4, RD,_rX) #define CVTSI2SDLmr(MD, MB, MI, MS, RD) _SSELmr(0xf2, X86_SSE_CVTSI2SD, MD, MB, MI, MS, RD,_rX) #define CVTSI2SDQrr(RS, RD) _SSEQrr(0xf2, X86_SSE_CVTSI2SD, RS,_r8, RD,_rX) #define CVTSI2SDQmr(MD, MB, MI, MS, RD) _SSEQmr(0xf2, X86_SSE_CVTSI2SD, MD, MB, MI, MS, RD,_rX) #define CVTSI2SSLrr(RS, RD) _SSELrr(0xf3, X86_SSE_CVTSI2SS, RS,_r4, RD,_rX) #define CVTSI2SSLmr(MD, MB, MI, MS, RD) _SSELmr(0xf3, X86_SSE_CVTSI2SS, MD, MB, MI, MS, RD,_rX) #define CVTSI2SSQrr(RS, RD) _SSEQrr(0xf3, X86_SSE_CVTSI2SS, RS,_r8, RD,_rX) #define CVTSI2SSQmr(MD, MB, MI, MS, RD) _SSEQmr(0xf3, X86_SSE_CVTSI2SS, MD, MB, MI, MS, RD,_rX) #define CVTSS2SDrr(RS, RD) _SSELrr(0xf3, X86_SSE_CVTSS2SD, RS,_rX, RD,_rX) #define CVTSS2SDmr(MD, MB, MI, MS, RD) _SSELmr(0xf3, X86_SSE_CVTSS2SD, MD, MB, MI, MS, RD,_rX) #define CVTSS2SILrr(RS, RD) _SSELrr(0xf3, X86_SSE_CVTSS2SI, RS,_rX, RD,_r4) #define CVTSS2SILmr(MD, MB, MI, MS, RD) _SSELmr(0xf3, X86_SSE_CVTSS2SI, MD, MB, MI, MS, RD,_r4) #define CVTSS2SIQrr(RS, RD) _SSEQrr(0xf3, X86_SSE_CVTSS2SI, RS,_rX, RD,_r8) #define CVTSS2SIQmr(MD, MB, MI, MS, RD) _SSEQmr(0xf3, X86_SSE_CVTSS2SI, MD, MB, MI, MS, RD,_r8) #define CVTTPD2PIrr(RS, RD) _SSELrr(0x66, X86_SSE_CVTTPD2PI, RS,_rX, RD,_rM) #define CVTTPD2PImr(MD, MB, MI, MS, RD) _SSELmr(0x66, X86_SSE_CVTTPD2PI, MD, MB, MI, MS, RD,_rM) #define CVTTPD2DQrr(RS, RD) _SSELrr(0x66, X86_SSE_CVTTPD2DQ, RS,_rX, RD,_rX) #define CVTTPD2DQmr(MD, MB, MI, MS, RD) _SSELmr(0x66, X86_SSE_CVTTPD2DQ, MD, MB, MI, MS, RD,_rX) #define CVTTPS2DQrr(RS, RD) _SSELrr(0xf3, X86_SSE_CVTTPS2DQ, RS,_rX, RD,_rX) #define CVTTPS2DQmr(MD, MB, MI, MS, RD) _SSELmr(0xf3, X86_SSE_CVTTPS2DQ, MD, MB, MI, MS, RD,_rX) #define CVTTPS2PIrr(RS, RD) __SSELrr( X86_SSE_CVTTPS2PI, RS,_rX, RD,_rM) #define CVTTPS2PImr(MD, MB, MI, MS, RD) __SSELmr( X86_SSE_CVTTPS2PI, MD, MB, MI, MS, RD,_rM) #define CVTTSD2SILrr(RS, RD) _SSELrr(0xf2, X86_SSE_CVTTSD2SI, RS,_rX, RD,_r4) #define CVTTSD2SILmr(MD, MB, MI, MS, RD) _SSELmr(0xf2, X86_SSE_CVTTSD2SI, MD, MB, MI, MS, RD,_r4) #define CVTTSD2SIQrr(RS, RD) _SSEQrr(0xf2, X86_SSE_CVTTSD2SI, RS,_rX, RD,_r8) #define CVTTSD2SIQmr(MD, MB, MI, MS, RD) _SSEQmr(0xf2, X86_SSE_CVTTSD2SI, MD, MB, MI, MS, RD,_r8) #define CVTTSS2SILrr(RS, RD) _SSELrr(0xf3, X86_SSE_CVTTSS2SI, RS,_rX, RD,_r4) #define CVTTSS2SILmr(MD, MB, MI, MS, RD) _SSELmr(0xf3, X86_SSE_CVTTSS2SI, MD, MB, MI, MS, RD,_r4) #define CVTTSS2SIQrr(RS, RD) _SSEQrr(0xf3, X86_SSE_CVTTSS2SI, RS,_rX, RD,_r8) #define CVTTSS2SIQmr(MD, MB, MI, MS, RD) _SSEQmr(0xf3, X86_SSE_CVTTSS2SI, MD, MB, MI, MS, RD,_r8) #define MOVDXDrr(RS, RD) _SSELrr(0x66, 0x6e, RS,_r4, RD,_rX) #define MOVDXDmr(MD, MB, MI, MS, RD) _SSELmr(0x66, 0x6e, MD, MB, MI, MS, RD,_rX) #define MOVQXDrr(RS, RD) _SSEQrr(0x66, 0x6e, RS,_r8, RD,_rX) #define MOVQXDmr(MD, MB, MI, MS, RD) _SSEQmr(0x66, 0x6e, MD, MB, MI, MS, RD,_rX) #define MOVDXSrr(RS, RD) _SSELrr(0x66, 0x7e, RD,_r4, RS,_rX) #define MOVDXSrm(RS, MD, MB, MI, MS) _SSELrm(0x66, 0x7e, RS,_rX, MD, MB, MI, MS) #define MOVQXSrr(RS, RD) _SSEQrr(0x66, 0x7e, RD,_r8, RS,_rX) #define MOVQXSrm(RS, MD, MB, MI, MS) _SSEQrm(0x66, 0x7e, RS,_rX, MD, MB, MI, MS) #define MOVDLMrr(RS, RD) __SSELrr( 0x6e, RS,_r4, RD,_rM) #define MOVDLMmr(MD, MB, MI, MS, RD) __SSELmr( 0x6e, MD, MB, MI, MS, RD,_rM) #define MOVDQMrr(RS, RD) __SSEQrr( 0x6e, RS,_r8, RD,_rM) #define MOVDQMmr(MD, MB, MI, MS, RD) __SSEQmr( 0x6e, MD, MB, MI, MS, RD,_rM) #define MOVDMLrr(RS, RD) __SSELrr( 0x7e, RS,_rM, RD,_r4) #define MOVDMLrm(RS, MD, MB, MI, MS) __SSELrm( 0x7e, RS,_rM, MD, MB, MI, MS) #define MOVDMQrr(RS, RD) __SSEQrr( 0x7e, RS,_rM, RD,_r8) #define MOVDMQrm(RS, MD, MB, MI, MS) __SSEQrm( 0x7e, RS,_rM, MD, MB, MI, MS) #define MOVDQ2Qrr(RS, RD) _SSELrr(0xf2, 0xd6, RS,_rX, RD,_rM) #define MOVMSKPSrr(RS, RD) __SSELrr( 0x50, RS,_rX, RD,_r4) #define MOVMSKPDrr(RS, RD) _SSELrr(0x66, 0x50, RS,_rX, RD,_r4) #define MOVHLPSrr(RS, RD) __SSELrr( 0x12, RS,_rX, RD,_rX) #define MOVLHPSrr(RS, RD) __SSELrr( 0x16, RS,_rX, RD,_rX) #define MOVDQArr(RS, RD) _SSELrr(0x66, 0x6f, RS,_rX, RD,_rX) #define MOVDQAmr(MD, MB, MI, MS, RD) _SSELmr(0x66, 0x6f, MD, MB, MI, MS, RD,_rX) #define MOVDQArm(RS, MD, MB, MI, MS) _SSELrm(0x66, 0x7f, RS,_rX, MD, MB, MI, MS) #define MOVDQUrr(RS, RD) _SSELrr(0xf3, 0x6f, RS,_rX, RD,_rX) #define MOVDQUmr(MD, MB, MI, MS, RD) _SSELmr(0xf3, 0x6f, MD, MB, MI, MS, RD,_rX) #define MOVDQUrm(RS, MD, MB, MI, MS) _SSELrm(0xf3, 0x7f, RS,_rX, MD, MB, MI, MS) #define MOVHPDmr(MD, MB, MI, MS, RD) _SSELmr(0x66, 0x16, MD, MB, MI, MS, RD,_rX) #define MOVHPDrm(RS, MD, MB, MI, MS) _SSELrm(0x66, 0x17, RS,_rX, MD, MB, MI, MS) #define MOVHPSmr(MD, MB, MI, MS, RD) __SSELmr( 0x16, MD, MB, MI, MS, RD,_rX) #define MOVHPSrm(RS, MD, MB, MI, MS) __SSELrm( 0x17, RS,_rX, MD, MB, MI, MS) #define MOVLPDmr(MD, MB, MI, MS, RD) _SSELmr(0x66, 0x12, MD, MB, MI, MS, RD,_rX) #define MOVLPDrm(RS, MD, MB, MI, MS) _SSELrm(0x66, 0x13, RS,_rX, MD, MB, MI, MS) #define MOVLPSmr(MD, MB, MI, MS, RD) __SSELmr( 0x12, MD, MB, MI, MS, RD,_rX) #define MOVLPSrm(RS, MD, MB, MI, MS) __SSELrm( 0x13, RS,_rX, MD, MB, MI, MS) /* --- Floating-Point instructions ----------------------------------------- */ enum { X86_F2XM1 = 0xd9f0, X86_FABS = 0xd9e1, X86_FADD = 0xd8c0, // m32fp, m64fp, sti0, st0i, pst0i X86_FIADD = 0xda00, // m32int, m16int X86_FBLD = 0xdf04, // mem X86_FBSTP = 0xdf06, // mem X86_FCHS = 0xd9e0, X86_FCMOVB = 0xdac0, // sti0 X86_FCMOVE = 0xdac8, // sti0 X86_FCMOVBE = 0xdad0, // sti0 X86_FCMOVU = 0xdad8, // sti0 X86_FCMOVNB = 0xdbc0, // sti0 X86_FCMOVNE = 0xdbc8, // sti0 X86_FCMOVNBE = 0xdbd0, // sti0 X86_FCMOVNU = 0xdbd8, // sti0 X86_FCOM = 0xd8d2, // m32fp, m64fp, sti X86_FCOMP = 0xd8db, // m32fp, m64fp, sti X86_FCOMPP = 0xded9, X86_FCOMI = 0xdbf0, // sti0 X86_FCOMIP = 0xdff0, // sti0 X86_FUCOMI = 0xdbe8, // sti0 X86_FUCOMIP = 0xdfe8, // sti0 X86_FCOS = 0xd9ff, X86_FDECSTP = 0xd9f6, X86_FDIV = 0xd8f6, // m32fp, m64fp, sti0, st0i, pst0i X86_FIDIV = 0xda06, // m32int, m16int X86_FDIVR = 0xd8ff, // m32fp, m64fp, sti0, st0i, pst0i X86_FIDIVR = 0xda07, // m32int, m16int X86_FFREE = 0xddc0, // sti X86_FICOM = 0xda02, // m32int, m16int X86_FICOMP = 0xda03, // m32int, m16int X86_FILD = 0xdb00, // m32int, m16int X86_FILDQ = 0xdf05, // mem X86_FINCSTP = 0xd9f7, X86_FIST = 0xdb02, // m32int, m16int X86_FISTP = 0xdb03, // m32int, m16int X86_FISTPQ = 0xdf07, // mem X86_FISTTP = 0xdb01, // m32int, m16int X86_FISTTPQ = 0xdd01, // mem X86_FLD = 0xd900, // m32fp, m64fp X86_FLDT = 0xdb05, // mem X86_FLD1 = 0xd9e8, X86_FLDL2T = 0xd9e9, X86_FLDL2E = 0xd9ea, X86_FLDPI = 0xd9eb, X86_FLDLG2 = 0xd9ec, X86_FLDLN2 = 0xd9ed, X86_FLDZ = 0xd9ee, X86_FMUL = 0xd8c9, // m32fp, m64fp, sti0, st0i, pst0i X86_FIMUL = 0xda01, // m32int, m16int X86_FNOP = 0xd9d0, X86_FPATAN = 0xd9f3, X86_FPREM = 0xd9f8, X86_FPREM1 = 0xd9f5, X86_FPTAN = 0xd9f2, X86_FRNDINT = 0xd9fc, X86_FSCALE = 0xd9fd, X86_FSIN = 0xd9fe, X86_FSINCOS = 0xd9fb, X86_FSQRT = 0xd9fa, X86_FSTS = 0xd902, // mem X86_FSTD = 0xdd02, // mem X86_FST = 0xddd0, // sti X86_FSTPS = 0xd903, // mem X86_FSTPD = 0xdd03, // mem X86_FSTPT = 0xdb07, // mem X86_FSTP = 0xddd8, // sti X86_FSUB = 0xd8e4, // m32fp, m64fp, sti0, st0i, pst0i X86_FISUB = 0xda04, // m32int, m16int X86_FSUBR = 0xd8ed, // m32fp, m64fp, sti0, st0i, pst0i X86_FISUBR = 0xda05, // m32int, m16int X86_FTST = 0xd9e4, X86_FUCOM = 0xdde0, // sti X86_FUCOMP = 0xdde8, // sti X86_FUCOMPP = 0xdae9, X86_FXAM = 0xd9e5, X86_FXCH = 0xd9c8, // sti X86_FXTRACT = 0xd9f4, X86_FYL2X = 0xd9f1, X86_FYL2XP1 = 0xd9f9, }; #define _FPU(OP) _OO(OP) #define _FPUm(OP, MD, MB, MI, MS) (_REXLrm(0, MB, MI), _O_r_X((OP)>>8, (OP)&7, MD, MB, MI, MS)) #define _FPUSm(OP, MD, MB, MI, MS) _FPUm(OP, MD, MB, MI, MS) #define _FPUDm(OP, MD, MB, MI, MS) _FPUm((OP)|0x400, MD, MB, MI, MS) #define _FPULm(OP, MD, MB, MI, MS) _FPUm(OP, MD, MB, MI, MS) #define _FPUWm(OP, MD, MB, MI, MS) _FPUm((OP)|0x400, MD, MB, MI, MS) #define _FPUr(OP, RR) _OOr((OP)&0xfff8, _rF(RR)) #define _FPU0r(OP, RD) _FPUr((OP)|0x400, RD) #define _FPUr0(OP, RS) _FPUr((OP) , RS) #define _FPUrr(OP, RS, RD) (_rST0P(RS) ? _FPU0r(OP, RD) : (_rST0P(RD) ? _FPUr0(OP, RS) : x86_emit_failure("FPU instruction without st0"))) #define _FPUP0r(OP, RD) _FPU0r((OP)|0x200, RD) #define F2XM1() _FPU(X86_F2XM1) #define FABS() _FPU(X86_FABS) #define FADDSm(MD, MB, MI, MS) _FPUSm(X86_FADD, MD, MB, MI, MS) #define FADDDm(MD, MB, MI, MS) _FPUDm(X86_FADD, MD, MB, MI, MS) #define FADDP0r(RD) _FPUP0r(X86_FADD, RD) #define FADDrr(RS, RD) _FPUrr(X86_FADD, RS, RD) #define FADD0r(RD) _FPU0r(X86_FADD, RD) #define FADDr0(RS) _FPUr0(X86_FADD, RS) #define FIADDWm(MD, MB, MI, MS) _FPUWm(X86_FIADD, MD, MB, MI, MS) #define FIADDLm(MD, MB, MI, MS) _FPULm(X86_FIADD, MD, MB, MI, MS) #define FBLDm(MD, MB, MI, MS) _FPUm(X86_FBLD, MD, MB, MI, MS) #define FBSTPm(MD, MB, MI, MS) _FPUm(X86_FBSTP, MD, MB, MI, MS) #define FCHS() _FPU(X86_FCHS) #define FCMOVBr0(RS) _FPUr0(X86_FCMOVB, RS) #define FCMOVEr0(RS) _FPUr0(X86_FCMOVE, RS) #define FCMOVBEr0(RS) _FPUr0(X86_FCMOVBE, RS) #define FCMOVUr0(RS) _FPUr0(X86_FCMOVU, RS) #define FCMOVNBr0(RS) _FPUr0(X86_FCMOVNB, RS) #define FCMOVNEr0(RS) _FPUr0(X86_FCMOVNE, RS) #define FCMOVNBEr0(RS) _FPUr0(X86_FCMOVNBE, RS) #define FCMOVNUr0(RS) _FPUr0(X86_FCMOVNU, RS) #define FCOMSm(MD, MB, MI, MS) _FPUSm(X86_FCOM, MD, MB, MI, MS) #define FCOMDm(MD, MB, MI, MS) _FPUDm(X86_FCOM, MD, MB, MI, MS) #define FCOMr(RD) _FPUr(X86_FCOM, RD) #define FCOMPSm(MD, MB, MI, MS) _FPUSm(X86_FCOMP, MD, MB, MI, MS) #define FCOMPDm(MD, MB, MI, MS) _FPUDm(X86_FCOMP, MD, MB, MI, MS) #define FCOMPr(RD) _FPUr(X86_FCOMP, RD) #define FCOMPP() _FPU(X86_FCOMPP) #define FCOMIr0(RS) _FPUr0(X86_FCOMI, RS) #define FCOMIPr0(RS) _FPUr0(X86_FCOMIP, RS) #define FUCOMIr0(RS) _FPUr0(X86_FUCOMI, RS) #define FUCOMIPr0(RS) _FPUr0(X86_FUCOMIP, RS) #define FCOS() _FPU(X86_FCOS) #define FDECSTP() _FPU(X86_FDECSTP) #define FDIVSm(MD, MB, MI, MS) _FPUSm(X86_FDIV, MD, MB, MI, MS) #define FDIVDm(MD, MB, MI, MS) _FPUDm(X86_FDIV, MD, MB, MI, MS) #define FDIVP0r(RD) _FPUP0r(X86_FDIV, RD) #define FDIVrr(RS, RD) _FPUrr(X86_FDIV, RS, RD) #define FDIV0r(RD) _FPU0r(X86_FDIV, RD) #define FDIVr0(RS) _FPUr0(X86_FDIV, RS) #define FIDIVWm(MD, MB, MI, MS) _FPUWm(X86_FIDIV, MD, MB, MI, MS) #define FIDIVLm(MD, MB, MI, MS) _FPULm(X86_FIDIV, MD, MB, MI, MS) #define FDIVRSm(MD, MB, MI, MS) _FPUSm(X86_FDIVR, MD, MB, MI, MS) #define FDIVRDm(MD, MB, MI, MS) _FPUDm(X86_FDIVR, MD, MB, MI, MS) #define FDIVRP0r(RD) _FPUP0r(X86_FDIVR, RD) #define FDIVRrr(RS, RD) _FPUrr(X86_FDIVR, RS, RD) #define FDIVR0r(RD) _FPU0r(X86_FDIVR, RD) #define FDIVRr0(RS) _FPUr0(X86_FDIVR, RS) #define FIDIVRWm(MD, MB, MI, MS) _FPUWm(X86_FIDIVR, MD, MB, MI, MS) #define FIDIVRLm(MD, MB, MI, MS) _FPULm(X86_FIDIVR, MD, MB, MI, MS) #define FFREEr(RD) _FPUr(X86_FFREE, RD) #define FICOMWm(MD, MB, MI, MS) _FPUWm(X86_FICOM, MD, MB, MI, MS) #define FICOMLm(MD, MB, MI, MS) _FPULm(X86_FICOM, MD, MB, MI, MS) #define FICOMPWm(MD, MB, MI, MS) _FPUWm(X86_FICOMP, MD, MB, MI, MS) #define FICOMPLm(MD, MB, MI, MS) _FPULm(X86_FICOMP, MD, MB, MI, MS) #define FILDWm(MD, MB, MI, MS) _FPUWm(X86_FILD, MD, MB, MI, MS) #define FILDLm(MD, MB, MI, MS) _FPULm(X86_FILD, MD, MB, MI, MS) #define FILDQm(MD, MB, MI, MS) _FPUm(X86_FILDQ, MD, MB, MI, MS) #define FINCSTP() _FPU(X86_FINCSTP) #define FISTWm(MD, MB, MI, MS) _FPUWm(X86_FIST, MD, MB, MI, MS) #define FISTLm(MD, MB, MI, MS) _FPULm(X86_FIST, MD, MB, MI, MS) #define FISTPWm(MD, MB, MI, MS) _FPUWm(X86_FISTP, MD, MB, MI, MS) #define FISTPLm(MD, MB, MI, MS) _FPULm(X86_FISTP, MD, MB, MI, MS) #define FISTPQm(MD, MB, MI, MS) _FPUm(X86_FISTPQ, MD, MB, MI, MS) #define FISTTPWm(MD, MB, MI, MS) _FPUWm(X86_FISTTP, MD, MB, MI, MS) #define FISTTPLm(MD, MB, MI, MS) _FPULm(X86_FISTTP, MD, MB, MI, MS) #define FISTTPQm(MD, MB, MI, MS) _FPUm(X86_FISTTPQ, MD, MB, MI, MS) #define FLDSm(MD, MB, MI, MS) _FPUSm(X86_FLD, MD, MB, MI, MS) #define FLDDm(MD, MB, MI, MS) _FPUDm(X86_FLD, MD, MB, MI, MS) #define FLDTm(MD, MB, MI, MS) _FPUm(X86_FLDT, MD, MB, MI, MS) #define FLD1() _FPU(X86_FLD1) #define FLDL2T() _FPU(X86_FLDL2T) #define FLDL2E() _FPU(X86_FLDL2E) #define FLDPI() _FPU(X86_FLDPI) #define FLDLG2() _FPU(X86_FLDLG2) #define FLDLN2() _FPU(X86_FLDLN2) #define FLDZ() _FPU(X86_FLDZ) #define FMULSm(MD, MB, MI, MS) _FPUSm(X86_FMUL, MD, MB, MI, MS) #define FMULDm(MD, MB, MI, MS) _FPUDm(X86_FMUL, MD, MB, MI, MS) #define FMULP0r(RD) _FPUP0r(X86_FMUL, RD) #define FMULrr(RS, RD) _FPUrr(X86_FMUL, RS, RD) #define FMUL0r(RD) _FPU0r(X86_FMUL, RD) #define FMULr0(RS) _FPUr0(X86_FMUL, RS) #define FIMULWm(MD, MB, MI, MS) _FPUWm(X86_FIMUL, MD, MB, MI, MS) #define FIMULLm(MD, MB, MI, MS) _FPULm(X86_FIMUL, MD, MB, MI, MS) #define FNOP() _FPU(X86_FNOP) #define FPATAN() _FPU(X86_FPATAN) #define FPREM() _FPU(X86_FPREM) #define FPREM1() _FPU(X86_FPREM1) #define FPTAN() _FPU(X86_FPTAN) #define FRNDINT() _FPU(X86_FRNDINT) #define FSCALE() _FPU(X86_FSCALE) #define FSIN() _FPU(X86_FSIN) #define FSINCOS() _FPU(X86_FSINCOS) #define FSQRT() _FPU(X86_FSQRT) #define FSTSm(MD, MB, MI, MS) _FPUm(X86_FSTS, MD, MB, MI, MS) #define FSTDm(MD, MB, MI, MS) _FPUm(X86_FSTD, MD, MB, MI, MS) #define FSTr(RD) _FPUr(X86_FST, RD) #define FSTPSm(MD, MB, MI, MS) _FPUm(X86_FSTPS, MD, MB, MI, MS) #define FSTPDm(MD, MB, MI, MS) _FPUm(X86_FSTPD, MD, MB, MI, MS) #define FSTPTm(MD, MB, MI, MS) _FPUm(X86_FSTPT, MD, MB, MI, MS) #define FSTPr(RD) _FPUr(X86_FSTP, RD) #define FSUBSm(MD, MB, MI, MS) _FPUSm(X86_FSUB, MD, MB, MI, MS) #define FSUBDm(MD, MB, MI, MS) _FPUDm(X86_FSUB, MD, MB, MI, MS) #define FSUBP0r(RD) _FPUP0r(X86_FSUB, RD) #define FSUBrr(RS, RD) _FPUrr(X86_FSUB, RS, RD) #define FSUB0r(RD) _FPU0r(X86_FSUB, RD) #define FSUBr0(RS) _FPUr0(X86_FSUB, RS) #define FISUBWm(MD, MB, MI, MS) _FPUWm(X86_FISUB, MD, MB, MI, MS) #define FISUBLm(MD, MB, MI, MS) _FPULm(X86_FISUB, MD, MB, MI, MS) #define FSUBRSm(MD, MB, MI, MS) _FPUSm(X86_FSUBR, MD, MB, MI, MS) #define FSUBRDm(MD, MB, MI, MS) _FPUDm(X86_FSUBR, MD, MB, MI, MS) #define FSUBRP0r(RD) _FPUP0r(X86_FSUBR, RD) #define FSUBRrr(RS, RD) _FPUrr(X86_FSUBR, RS, RD) #define FSUBR0r(RD) _FPU0r(X86_FSUBR, RD) #define FSUBRr0(RS) _FPUr0(X86_FSUBR, RS) #define FISUBRWm(MD, MB, MI, MS) _FPUWm(X86_FISUBR, MD, MB, MI, MS) #define FISUBRLm(MD, MB, MI, MS) _FPULm(X86_FISUBR, MD, MB, MI, MS) #define FTST() _FPU(X86_FTST) #define FUCOMr(RD) _FPUr(X86_FUCOM, RD) #define FUCOMPr(RD) _FPUr(X86_FUCOMP, RD) #define FUCOMPP() _FPU(X86_FUCOMPP) #define FXAM() _FPU(X86_FXAM) #define FXCHr(RD) _FPUr(X86_FXCH, RD) #define FXTRACT() _FPU(X86_FXTRACT) #define FYL2X() _FPU(X86_FYL2X) #define FYL2XP1() _FPU(X86_FYL2XP1) #endif /* X86_RTASM_H */ BasiliskII/src/uae_cpu/compiler/test_codegen_x86.cpp0000644000175000017500000015106010755660121022645 0ustar centriscentris/******************** -*- mode: C; tab-width: 8 -*- ******************** * * Dumb and Brute Force Run-time assembler verifier for IA-32 and AMD64 * ***********************************************************************/ /*********************************************************************** * * Copyright 2004-2008 Gwenole Beauchesne * * 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 * ***********************************************************************/ /* * STATUS: 26M variations covering unary register based operations, * reg/reg operations, imm/reg operations. * * TODO: * - Rewrite to use internal BFD/opcodes format instead of string compares * - Add reg/mem, imm/mem variations */ #define _BSD_SOURCE 1 #include #include #include #include #include #include #include "sysdeps.h" static int verbose = 2; #define TEST_INST_ALU 1 #define TEST_INST_FPU 1 #define TEST_INST_MMX 1 #define TEST_INST_SSE 1 #if TEST_INST_ALU #define TEST_INST_ALU_REG 1 #define TEST_INST_ALU_REG_REG 1 #define TEST_INST_ALU_CNT_REG 1 #define TEST_INST_ALU_IMM_REG 1 #define TEST_INST_ALU_MEM_REG 1 #endif #if TEST_INST_FPU #define TEST_INST_FPU_UNARY 1 #define TEST_INST_FPU_REG 1 #define TEST_INST_FPU_MEM 1 #endif #if TEST_INST_MMX #define TEST_INST_MMX_REG_REG 1 #define TEST_INST_MMX_IMM_REG 1 #define TEST_INST_MMX_MEM_REG 1 #endif #if TEST_INST_SSE #define TEST_INST_SSE_REG 1 #define TEST_INST_SSE_REG_REG 1 #define TEST_INST_SSE_MEM_REG 1 #endif #undef abort #define abort() do { \ fprintf(stderr, "ABORT: %s, line %d\n", __FILE__, __LINE__); \ (abort)(); \ } while (0) #define X86_TARGET_64BIT 1 #define X86_FLAT_REGISTERS 0 #define X86_OPTIMIZE_ALU 1 #define X86_OPTIMIZE_ROTSHI 1 #define X86_RIP_RELATIVE_ADDR 0 #include "compiler/codegen_x86.h" #if X86_TARGET_64BIT #define X86_MAX_ALU_REGS 16 #define X86_MAX_SSE_REGS 16 #else #define X86_MAX_ALU_REGS 8 #define X86_MAX_SSE_REGS 8 #endif #define X86_MAX_FPU_REGS 8 #define X86_MAX_MMX_REGS 8 #define VALID_REG(r, b, n) (((unsigned)((r) - X86_##b)) < (n)) #if X86_TARGET_64BIT #define VALID_REG8(r) (VALID_REG(r, AL, 16) || VALID_REG(r, AH, 4)) #define VALID_REG64(r) VALID_REG(r, RAX, X86_MAX_ALU_REGS) #else #define VALID_REG8(r) (VALID_REG(r, AL, 4) || VALID_REG(r, AH, 4)) #define VALID_REG64(r) (0) #endif #define VALID_REG16(r) VALID_REG(r, AX, X86_MAX_ALU_REGS) #define VALID_REG32(r) VALID_REG(r, EAX, X86_MAX_ALU_REGS) #define x86_emit_byte(B) emit_byte(B) #define x86_emit_word(W) emit_word(W) #define x86_emit_long(L) emit_long(L) #define x86_emit_quad(Q) emit_quad(Q) #define x86_get_target() get_target() #define x86_emit_failure(MSG) jit_fail(MSG, __FILE__, __LINE__, __FUNCTION__) static void jit_fail(const char *msg, const char *file, int line, const char *function) { fprintf(stderr, "JIT failure in function %s from file %s at line %d: %s\n", function, file, line, msg); abort(); } static uint8 *target; static inline void emit_byte(uint8 x) { *target++ = x; } static inline void emit_word(uint16 x) { *((uint16 *)target) = x; target += 2; } static inline void emit_long(uint32 x) { *((uint32 *)target) = x; target += 4; } static inline void emit_quad(uint64 x) { *((uint64 *)target) = x; target += 8; } static inline void set_target(uint8 *t) { target = t; } static inline uint8 *get_target(void) { return target; } static uint32 mon_read_byte(uintptr addr) { uint8 *m = (uint8 *)addr; return (uint32)(*m); } extern "C" { #include "disass/dis-asm.h" int buffer_read_memory(bfd_vma from, bfd_byte *to, unsigned int length, struct disassemble_info *info) { while (length--) *to++ = mon_read_byte(from++); return 0; } void perror_memory(int status, bfd_vma memaddr, struct disassemble_info *info) { info->fprintf_func(info->stream, "Unknown error %d\n", status); } void generic_print_address(bfd_vma addr, struct disassemble_info *info) { if (addr >= UVAL64(0x100000000)) info->fprintf_func(info->stream, "$%08x%08x", (uint32)(addr >> 32), (uint32)addr); else info->fprintf_func(info->stream, "$%08x", (uint32)addr); } int generic_symbol_at_address(bfd_vma addr, struct disassemble_info *info) { return 0; } } struct SFILE { char *buffer; char *current; }; static int mon_sprintf(SFILE *f, const char *format, ...) { int n; va_list args; va_start(args, format); vsprintf(f->current, format, args); f->current += n = strlen(f->current); va_end(args); return n; } static int disass_x86(char *buf, uintptr adr) { disassemble_info info; SFILE sfile; sfile.buffer = buf; sfile.current = buf; INIT_DISASSEMBLE_INFO(info, (FILE *)&sfile, (fprintf_ftype)mon_sprintf); info.mach = X86_TARGET_64BIT ? bfd_mach_x86_64 : bfd_mach_i386_i386; info.disassembler_options = "suffix"; return print_insn_i386(adr, &info); } enum { op_disp, op_reg, op_base, op_index, op_scale, op_imm, }; struct operand_t { int32 disp; int8 reg; int8 base; int8 index; int8 scale; int64 imm; void clear() { disp = imm = 0; reg = base = index = -1; scale = 1; } void fill(int optype, int value) { switch (optype) { case op_disp: disp = value; break; case op_reg: reg = value; break; case op_base: base = value; break; case op_index: index = value; break; case op_scale: scale = value; break; case op_imm: imm = value; break; default: abort(); } } }; #define MAX_INSNS 1024 #define MAX_INSN_LENGTH 16 #define MAX_INSN_OPERANDS 3 struct insn_t { char name[16]; int n_operands; operand_t operands[MAX_INSN_OPERANDS]; void clear() { memset(name, 0, sizeof(name)); n_operands = 0; for (int i = 0; i < MAX_INSN_OPERANDS; i++) operands[i].clear(); } void pretty_print() { printf("%s, %d operands\n", name, n_operands); for (int i = 0; i < n_operands; i++) { operand_t *op = &operands[i]; if (op->reg != -1) printf(" reg r%d\n", op->reg); else { printf(" mem 0x%08x(", op->disp); if (op->base != -1) printf("r%d", op->base); printf(","); if (op->index != -1) printf("r%d", op->index); printf(","); if (op->base != -1 || op->index != -1) printf("%d", op->scale); printf(")\n"); } } } }; static inline char *find_blanks(char *p) { while (*p && !isspace(*p)) ++p; return p; } static inline char *skip_blanks(char *p) { while (*p && isspace(*p)) ++p; return p; } static int parse_reg(operand_t *op, int optype, char *buf) { int reg = X86_NOREG; int len = 0; char *p = buf; switch (p[0]) { case 'a': case 'A': len = 2; switch (p[1]) { case 'l': case 'L': reg = X86_AL; break; case 'h': case 'H': reg = X86_AH; break; case 'x': case 'X': reg = X86_AX; break; } break; case 'b': case 'B': len = 2; switch (p[1]) { case 'l': case 'L': reg = X86_BL; break; case 'h': case 'H': reg = X86_BH; break; case 'x': case 'X': reg = X86_BX; break; case 'p': case 'P': switch (p[2]) { #if X86_TARGET_64BIT case 'l': case 'L': reg = X86_BPL, ++len; break; #endif default: reg = X86_BP; break; } break; } break; case 'c': case 'C': len = 2; switch (p[1]) { case 'l': case 'L': reg = X86_CL; break; case 'h': case 'H': reg = X86_CH; break; case 'x': case 'X': reg = X86_CX; break; } break; case 'd': case 'D': len = 2; switch (p[1]) { case 'l': case 'L': reg = X86_DL; break; case 'h': case 'H': reg = X86_DH; break; case 'x': case 'X': reg = X86_DX; break; case 'i': case 'I': switch (p[2]) { #if X86_TARGET_64BIT case 'l': case 'L': reg = X86_DIL; ++len; break; #endif default: reg = X86_DI; break; } break; } break; case 's': case 'S': len = 2; switch (p[2]) { #if X86_TARGET_64BIT case 'l': case 'L': ++len; switch (p[1]) { case 'p': case 'P': reg = X86_SPL; break; case 'i': case 'I': reg = X86_SIL; break; } break; #endif case '(': if ((p[1] == 't' || p[1] == 'T') && isdigit(p[3]) && p[4] == ')') len += 3, reg = X86_ST0 + (p[3] - '0'); break; default: switch (p[1]) { case 't': case 'T': reg = X86_ST0; break; case 'p': case 'P': reg = X86_SP; break; case 'i': case 'I': reg = X86_SI; break; } break; } break; case 'e': case 'E': len = 3; switch (p[2]) { case 'x': case 'X': switch (p[1]) { case 'a': case 'A': reg = X86_EAX; break; case 'b': case 'B': reg = X86_EBX; break; case 'c': case 'C': reg = X86_ECX; break; case 'd': case 'D': reg = X86_EDX; break; } break; case 'i': case 'I': switch (p[1]) { case 's': case 'S': reg = X86_ESI; break; case 'd': case 'D': reg = X86_EDI; break; } break; case 'p': case 'P': switch (p[1]) { case 'b': case 'B': reg = X86_EBP; break; case 's': case 'S': reg = X86_ESP; break; } break; } break; #if X86_TARGET_64BIT case 'r': case 'R': len = 3; switch (p[2]) { case 'x': case 'X': switch (p[1]) { case 'a': case 'A': reg = X86_RAX; break; case 'b': case 'B': reg = X86_RBX; break; case 'c': case 'C': reg = X86_RCX; break; case 'd': case 'D': reg = X86_RDX; break; } break; case 'i': case 'I': switch (p[1]) { case 's': case 'S': reg = X86_RSI; break; case 'd': case 'D': reg = X86_RDI; break; } break; case 'p': case 'P': switch (p[1]) { case 'b': case 'B': reg = X86_RBP; break; case 's': case 'S': reg = X86_RSP; break; } break; case 'b': case 'B': switch (p[1]) { case '8': reg = X86_R8B; break; case '9': reg = X86_R9B; break; } break; case 'w': case 'W': switch (p[1]) { case '8': reg = X86_R8W; break; case '9': reg = X86_R9W; break; } break; case 'd': case 'D': switch (p[1]) { case '8': reg = X86_R8D; break; case '9': reg = X86_R9D; break; } break; case '0': case '1': case '2': case '3': case '4': case '5': if (p[1] == '1') { const int r = p[2] - '0'; switch (p[3]) { case 'b': case 'B': reg = X86_R10B + r, ++len; break; case 'w': case 'W': reg = X86_R10W + r, ++len; break; case 'd': case 'D': reg = X86_R10D + r, ++len; break; default: reg = X86_R10 + r; break; } } break; default: switch (p[1]) { case '8': reg = X86_R8, len = 2; break; case '9': reg = X86_R9, len = 2; break; } break; } break; #endif case 'm': case 'M': if ((p[1] == 'm' || p[1] == 'M') && isdigit(p[2])) reg = X86_MM0 + (p[2] - '0'), len = 3; break; case 'x': case 'X': if ((p[1] == 'm' || p[1] == 'M') && (p[2] == 'm' || p[2] == 'M')) { #if X86_TARGET_64BIT if (p[3] == '1' && isdigit(p[4])) reg = X86_XMM10 + (p[4] - '0'), len = 5; else #endif if (isdigit(p[3])) reg = X86_XMM0 + (p[3] - '0'), len = 4; } break; } if (len > 0 && reg != X86_NOREG) { op->fill(optype, reg); return len; } return X86_NOREG; } static unsigned long parse_imm(char *nptr, char **endptr, int base = 0) { errno = 0; #if X86_TARGET_64BIT if (sizeof(unsigned long) != 8) { unsigned long long val = strtoull(nptr, endptr, 0); if (errno == 0) return val; abort(); } #endif unsigned long val = strtoul(nptr, endptr, 0); if (errno == 0) return val; abort(); return 0; } static int parse_mem(operand_t *op, char *buf) { char *p = buf; if (strncmp(buf, "0x", 2) == 0) op->disp = parse_imm(buf, &p, 16); if (*p == '(') { p++; if (*p == '%') { p++; int n = parse_reg(op, op_base, p); if (n <= 0) return -3; p += n; } if (*p == ',') { p++; if (*p == '%') { int n = parse_reg(op, op_index, ++p); if (n <= 0) return -4; p += n; if (*p != ',') return -5; p++; goto do_parse_scale; } else if (isdigit(*p)) { do_parse_scale: long val = strtol(p, &p, 10); if (val == 0 && errno == EINVAL) abort(); op->scale = val; } } if (*p != ')') return -6; p++; } return p - buf; } static void parse_insn(insn_t *ii, char *buf) { char *p = buf; ii->clear(); #if 0 printf("BUF: %s\n", buf); #endif if (strncmp(p, "rex64", 5) == 0) { char *q = find_blanks(p); if (verbose > 1) { char prefix[16]; memset(prefix, 0, sizeof(prefix)); memcpy(prefix, p, q - p); fprintf(stderr, "Instruction '%s', skip REX prefix '%s'\n", buf, prefix); } p = skip_blanks(q); } if (strncmp(p, "rep", 3) == 0) { char *q = find_blanks(p); if (verbose > 1) { char prefix[16]; memset(prefix, 0, sizeof(prefix)); memcpy(prefix, p, q - p); fprintf(stderr, "Instruction '%s', skip REP prefix '%s'\n", buf, prefix); } p = skip_blanks(q); } for (int i = 0; !isspace(*p); i++) ii->name[i] = *p++; while (*p && isspace(*p)) p++; if (*p == '\0') return; int n_operands = 0; int optype = op_reg; bool done = false; while (!done) { int n; switch (*p) { case '%': n = parse_reg(&ii->operands[n_operands], optype, ++p); if (n <= 0) { fprintf(stderr, "parse_reg(%s) error %d\n", p, n); abort(); } p += n; break; case '0': case '(': n = parse_mem(&ii->operands[n_operands], p); if (n <= 0) { fprintf(stderr, "parse_mem(%s) error %d\n", p, n); abort(); } p += n; break; case '$': { ii->operands[n_operands].imm = parse_imm(++p, &p, 0); break; } case '*': p++; break; case ',': n_operands++; p++; break; case ' ': case '\t': p++; break; case '\0': done = true; break; default: fprintf(stderr, "parse error> %s\n", p); abort(); } } ii->n_operands = n_operands + 1; } static unsigned long n_tests, n_failures; static unsigned long n_all_tests, n_all_failures; static bool check_unary(insn_t *ii, const char *name) { if (strcasecmp(ii->name, name) != 0) { fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name); return false; } if (ii->n_operands != 0) { fprintf(stderr, "ERROR: instruction expected 0 operand, got %d\n", ii->n_operands); return false; } return true; } static bool check_reg(insn_t *ii, const char *name, int r) { if (strcasecmp(ii->name, name) != 0) { fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name); return false; } if (ii->n_operands != 1) { fprintf(stderr, "ERROR: instruction expected 1 operand, got %d\n", ii->n_operands); return false; } int reg = ii->operands[0].reg; if (reg != r) { fprintf(stderr, "ERROR: instruction expected r%d as source, got ", r); if (reg == -1) fprintf(stderr, "nothing\n"); else fprintf(stderr, "r%d\n", reg); return false; } return true; } static bool check_reg_reg(insn_t *ii, const char *name, int s, int d) { if (strcasecmp(ii->name, name) != 0) { fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name); return false; } if (ii->n_operands != 2) { fprintf(stderr, "ERROR: instruction expected 2 operands, got %d\n", ii->n_operands); return false; } int srcreg = ii->operands[0].reg; int dstreg = ii->operands[1].reg; if (srcreg != s) { fprintf(stderr, "ERROR: instruction expected r%d as source, got ", s); if (srcreg == -1) fprintf(stderr, "nothing\n"); else fprintf(stderr, "r%d\n", srcreg); return false; } if (dstreg != d) { fprintf(stderr, "ERROR: instruction expected r%d as destination, got ", d); if (dstreg == -1) fprintf(stderr, "nothing\n"); else fprintf(stderr, "r%d\n", dstreg); return false; } return true; } static bool check_imm_reg(insn_t *ii, const char *name, uint32 v, int d, int mode = -1) { if (strcasecmp(ii->name, name) != 0) { fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name); return false; } if (ii->n_operands != 2) { fprintf(stderr, "ERROR: instruction expected 2 operands, got %d\n", ii->n_operands); return false; } uint32 imm = ii->operands[0].imm; int dstreg = ii->operands[1].reg; if (mode == -1) { char suffix = name[strlen(name) - 1]; switch (suffix) { case 'b': mode = 1; break; case 'w': mode = 2; break; case 'l': mode = 4; break; case 'q': mode = 8; break; } } switch (mode) { case 1: v &= 0xff; break; case 2: v &= 0xffff; break; } if (imm != v) { fprintf(stderr, "ERROR: instruction expected 0x%08x as immediate, got ", v); if (imm == -1) fprintf(stderr, "nothing\n"); else fprintf(stderr, "0x%08x\n", imm); return false; } if (dstreg != d) { fprintf(stderr, "ERROR: instruction expected r%d as destination, got ", d); if (dstreg == -1) fprintf(stderr, "nothing\n"); else fprintf(stderr, "%d\n", dstreg); return false; } return true; } static bool do_check_mem(insn_t *ii, uint32 D, int B, int I, int S, int Mpos) { operand_t *mem = &ii->operands[Mpos]; uint32 d = mem->disp; int b = mem->base; int i = mem->index; int s = mem->scale; if (d != D) { fprintf(stderr, "ERROR: instruction expected 0x%08x as displacement, got 0x%08x\n", D, d); return false; } if (b != B) { fprintf(stderr, "ERROR: instruction expected r%d as base, got r%d\n", B, b); return false; } if (i != I) { fprintf(stderr, "ERROR: instruction expected r%d as index, got r%d\n", I, i); return false; } if (s != S) { fprintf(stderr, "ERROR: instruction expected %d as scale factor, got %d\n", S, s); return false; } return true; } static bool check_mem(insn_t *ii, const char *name, uint32 D, int B, int I, int S) { if (strcasecmp(ii->name, name) != 0) { fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name); return false; } if (ii->n_operands != 1) { fprintf(stderr, "ERROR: instruction expected 1 operand, got %d\n", ii->n_operands); return false; } return do_check_mem(ii, D, B, I, S, 0); } static bool check_mem_reg(insn_t *ii, const char *name, uint32 D, int B, int I, int S, int R, int Rpos = 1) { if (strcasecmp(ii->name, name) != 0) { fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name); return false; } if (ii->n_operands != 2) { fprintf(stderr, "ERROR: instruction expected 2 operands, got %d\n", ii->n_operands); return false; } if (!do_check_mem(ii, D, B, I, S, Rpos ^ 1)) return false; int r = ii->operands[Rpos].reg; if (r != R) { fprintf(stderr, "ERROR: instruction expected r%d as reg operand, got r%d\n", R, r); return false; } return true; } static inline bool check_reg_mem(insn_t *ii, const char *name, uint32 D, int B, int I, int S, int R) { return check_mem_reg(ii, name, D, B, I, S, R, 0); } static void show_instruction(const char *buffer, const uint8 *bytes) { if (verbose > 1) { if (1) { for (int j = 0; j < MAX_INSN_LENGTH; j++) fprintf(stderr, "%02x ", bytes[j]); fprintf(stderr, "| "); } fprintf(stderr, "%s\n", buffer); } } static void show_status(unsigned long n_tests) { #if 1 const unsigned long N_STEPS = 100000; static const char cursors[] = { '-', '\\', '|', '/' }; if ((n_tests % N_STEPS) == 0) { printf(" %c (%d)\r", cursors[(n_tests/N_STEPS)%sizeof(cursors)], n_tests); fflush(stdout); } #else const unsigned long N_STEPS = 1000000; if ((n_tests % N_STEPS) == 0) printf(" ... %d\n", n_tests); #endif } int main(void) { static char buffer[1024]; static uint8 block[MAX_INSNS * MAX_INSN_LENGTH]; static char *insns[MAX_INSNS]; static int modes[MAX_INSNS]; n_all_tests = n_all_failures = 0; #if TEST_INST_ALU_REG printf("Testing reg forms\n"); n_tests = n_failures = 0; for (int r = 0; r < X86_MAX_ALU_REGS; r++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP##r(r); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) #define GENA(INSN, GENOP) do { \ if (VALID_REG8(r)) \ GEN(INSN "b", GENOP##B); \ GEN(INSN "w", GENOP##W); \ GEN(INSN "l", GENOP##L); \ GEN64(INSN "q", GENOP##Q); \ } while (0) GENA("not", NOT); GENA("neg", NEG); GENA("mul", MUL); GENA("imul", IMUL); GENA("div", DIV); GENA("idiv", IDIV); GENA("dec", DEC); GENA("inc", INC); if (X86_TARGET_64BIT) { GEN("callq", CALLs); GEN("jmpq", JMPs); GEN("pushq", PUSHQ); GEN("popq", POPQ); } else { GEN("calll", CALLs); GEN("jmpl", JMPs); GEN("pushl", PUSHL); GEN("popl", POPL); } GEN("bswap", BSWAPL); // FIXME: disass bug? no suffix GEN64("bswap", BSWAPQ); // FIXME: disass bug? no suffix if (VALID_REG8(r)) { GEN("seto", SETO); GEN("setno", SETNO); GEN("setb", SETB); GEN("setae", SETAE); GEN("sete", SETE); GEN("setne", SETNE); GEN("setbe", SETBE); GEN("seta", SETA); GEN("sets", SETS); GEN("setns", SETNS); GEN("setp", SETP); GEN("setnp", SETNP); GEN("setl", SETL); GEN("setge", SETGE); GEN("setle", SETLE); GEN("setg", SETG); } #undef GENA #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_reg(&ii, insns[i], r)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_ALU_REG_REG printf("Testing reg,reg forms\n"); n_tests = n_failures = 0; for (int s = 0; s < X86_MAX_ALU_REGS; s++) { for (int d = 0; d < X86_MAX_ALU_REGS; d++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP##rr(s, d); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) #define GEN1(INSN, GENOP, OP) do { \ insns[i++] = INSN; \ GENOP##rr(OP, s, d); \ } while (0) #define GENA(INSN, GENOP) do { \ if (VALID_REG8(s) && VALID_REG8(d)) \ GEN(INSN "b", GENOP##B); \ GEN(INSN "w", GENOP##W); \ GEN(INSN "l", GENOP##L); \ GEN64(INSN "q", GENOP##Q); \ } while (0) GENA("adc", ADC); GENA("add", ADD); GENA("and", AND); GENA("cmp", CMP); GENA("or", OR); GENA("sbb", SBB); GENA("sub", SUB); GENA("xor", XOR); GENA("mov", MOV); GEN("btw", BTW); GEN("btl", BTL); GEN64("btq", BTQ); GEN("btcw", BTCW); GEN("btcl", BTCL); GEN64("btcq", BTCQ); GEN("btrw", BTRW); GEN("btrl", BTRL); GEN64("btrq", BTRQ); GEN("btsw", BTSW); GEN("btsl", BTSL); GEN64("btsq", BTSQ); GEN("imulw", IMULW); GEN("imull", IMULL); GEN64("imulq", IMULQ); GEN1("cmove", CMOVW, X86_CC_Z); GEN1("cmove", CMOVL, X86_CC_Z); if (X86_TARGET_64BIT) GEN1("cmove", CMOVQ, X86_CC_Z); GENA("test", TEST); GENA("cmpxchg", CMPXCHG); GENA("xadd", XADD); GENA("xchg", XCHG); GEN("bsfw", BSFW); GEN("bsfl", BSFL); GEN64("bsfq", BSFQ); GEN("bsrw", BSRW); GEN("bsrl", BSRL); GEN64("bsrq", BSRQ); if (VALID_REG8(s)) { GEN("movsbw", MOVSBW); GEN("movsbl", MOVSBL); GEN64("movsbq", MOVSBQ); GEN("movzbw", MOVZBW); GEN("movzbl", MOVZBL); GEN64("movzbq", MOVZBQ); } GEN("movswl", MOVSWL); GEN64("movswq", MOVSWQ); GEN("movzwl", MOVZWL); GEN64("movzwq", MOVZWQ); GEN64("movslq", MOVSLQ); #undef GENA #undef GEN1 #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_reg_reg(&ii, insns[i], s, d)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_ALU_CNT_REG printf("Testing cl,reg forms\n"); n_tests = n_failures = 0; for (int d = 0; d < X86_MAX_ALU_REGS; d++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP##rr(X86_CL, d); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) #define GENA(INSN, GENOP) do { \ if (VALID_REG8(d)) \ GEN(INSN "b", GENOP##B); \ GEN(INSN "w", GENOP##W); \ GEN(INSN "l", GENOP##L); \ GEN64(INSN "q", GENOP##Q); \ } while (0) GENA("rol", ROL); GENA("ror", ROR); GENA("rcl", RCL); GENA("rcr", RCR); GENA("shl", SHL); GENA("shr", SHR); GENA("sar", SAR); #undef GENA #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_reg_reg(&ii, insns[i], X86_CL, d)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif static const uint32 imm_table[] = { 0x00000000, 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x000000fe, 0x000000ff, 0x00000100, 0x00000101, 0x00000102, 0xfffffffe, 0xffffffff, 0x00000000, 0x10000000, 0x20000000, 0x30000000, 0x40000000, 0x50000000, 0x60000000, 0x70000000, 0x80000000, 0x90000000, 0xa0000000, 0xb0000000, 0xc0000000, 0xd0000000, 0xe0000000, 0xf0000000, 0xfffffffd, 0xfffffffe, 0xffffffff, 0x00000001, 0x00000002, 0x00000003, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, }; const int n_imm_tab_count = sizeof(imm_table)/sizeof(imm_table[0]); #if TEST_INST_ALU_IMM_REG printf("Testing imm,reg forms\n"); n_tests = n_failures = 0; for (int j = 0; j < n_imm_tab_count; j++) { const uint32 value = imm_table[j]; for (int d = 0; d < X86_MAX_ALU_REGS; d++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i] = INSN; \ modes[i] = -1; \ i++; GENOP##ir(value, d); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) #define GENM(INSN, GENOP, MODE) do { \ insns[i] = INSN; \ modes[i] = MODE; \ i++; GENOP##ir(value, d); \ } while (0) #define GENM64(INSN, GENOP, MODE) do { \ if (X86_TARGET_64BIT) \ GENM(INSN, GENOP, MODE); \ } while (0) #define GENA(INSN, GENOP) do { \ if (VALID_REG8(d)) \ GEN(INSN "b", GENOP##B); \ GEN(INSN "w", GENOP##W); \ GEN(INSN "l", GENOP##L); \ GEN64(INSN "q", GENOP##Q); \ } while (0) #define GENAM(INSN, GENOP, MODE) do { \ if (VALID_REG8(d)) \ GENM(INSN "b", GENOP##B, MODE); \ GENM(INSN "w", GENOP##W, MODE); \ GENM(INSN "l", GENOP##L, MODE); \ GENM64(INSN "q", GENOP##Q, MODE); \ } while (0) GENA("adc", ADC); GENA("add", ADD); GENA("and", AND); GENA("cmp", CMP); GENA("or", OR); GENA("sbb", SBB); GENA("sub", SUB); GENA("xor", XOR); GENA("mov", MOV); GENM("btw", BTW, 1); GENM("btl", BTL, 1); GENM64("btq", BTQ, 1); GENM("btcw", BTCW, 1); GENM("btcl", BTCL, 1); GENM64("btcq", BTCQ, 1); GENM("btrw", BTRW, 1); GENM("btrl", BTRL, 1); GENM64("btrq", BTRQ, 1); GENM("btsw", BTSW, 1); GENM("btsl", BTSL, 1); GENM64("btsq", BTSQ, 1); if (value != 1) { GENAM("rol", ROL, 1); GENAM("ror", ROR, 1); GENAM("rcl", RCL, 1); GENAM("rcr", RCR, 1); GENAM("shl", SHL, 1); GENAM("shr", SHR, 1); GENAM("sar", SAR, 1); } GENA("test", TEST); #undef GENAM #undef GENA #undef GENM64 #undef GENM #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_imm_reg(&ii, insns[i], value, d, modes[i])) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif static const uint32 off_table[] = { 0x00000000, 0x00000001, 0x00000040, 0x00000080, 0x000000ff, 0x00000100, 0xfffffffe, 0xffffffff, }; const int off_table_count = sizeof(off_table) / sizeof(off_table[0]); #if TEST_INST_ALU_MEM_REG printf("Testing mem,reg forms\n"); n_tests = n_failures = 0; for (int d = 0; d < off_table_count; d++) { const uint32 D = off_table[d]; for (int B = -1; B < X86_MAX_ALU_REGS; B++) { for (int I = -1; I < X86_MAX_ALU_REGS; I++) { if (I == X86_RSP) continue; for (int S = 1; S < 16; S *= 2) { if (I == -1 && S > 1) continue; for (int r = 0; r < X86_MAX_ALU_REGS; r++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP##mr(D, B, I, S, r); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) #define GENA(INSN, GENOP) do { \ if (VALID_REG8(r)) \ GEN(INSN "b", GENOP##B); \ GEN(INSN "w", GENOP##W); \ GEN(INSN "l", GENOP##L); \ GEN64(INSN "q", GENOP##Q); \ } while (0) GENA("adc", ADC); GENA("add", ADD); GENA("and", AND); GENA("cmp", CMP); GENA("or", OR); GENA("sbb", SBB); GENA("sub", SUB); GENA("xor", XOR); GENA("mov", MOV); GEN("imulw", IMULW); GEN("imull", IMULL); GEN64("imulq", IMULQ); GEN("bsfw", BSFW); GEN("bsfl", BSFL); GEN64("bsfq", BSFQ); GEN("bsrw", BSRW); GEN("bsrl", BSRL); GEN64("bsrq", BSRQ); GEN("movsbw", MOVSBW); GEN("movsbl", MOVSBL); GEN64("movsbq", MOVSBQ); GEN("movzbw", MOVZBW); GEN("movzbl", MOVZBL); GEN64("movzbq", MOVZBQ); GEN("movswl", MOVSWL); GEN64("movswq", MOVSWQ); GEN("movzwl", MOVZWL); GEN64("movzwq", MOVZWQ); GEN64("movslq", MOVSLQ); #undef GENA #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_mem_reg(&ii, insns[i], D, B, I, S, r)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; show_status(n_tests); } if (i != last_insn) abort(); } } } } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_FPU_UNARY printf("Testing FPU unary forms\n"); n_tests = n_failures = 0; { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP(); \ } while (0) GEN("f2xm1", F2XM1); GEN("fabs", FABS); GEN("fchs", FCHS); GEN("fcompp", FCOMPP); GEN("fcos", FCOS); GEN("fdecstp", FDECSTP); GEN("fincstp", FINCSTP); GEN("fld1", FLD1); GEN("fldl2t", FLDL2T); GEN("fldl2e", FLDL2E); GEN("fldpi", FLDPI); GEN("fldlg2", FLDLG2); GEN("fldln2", FLDLN2); GEN("fldz", FLDZ); GEN("fnop", FNOP); GEN("fpatan", FPATAN); GEN("fprem", FPREM); GEN("fprem1", FPREM1); GEN("fptan", FPTAN); GEN("frndint", FRNDINT); GEN("fscale", FSCALE); GEN("fsin", FSIN); GEN("fsincos", FSINCOS); GEN("fsqrt", FSQRT); GEN("ftst", FTST); GEN("fucompp", FUCOMPP); GEN("fxam", FXAM); GEN("fxtract", FXTRACT); GEN("fyl2x", FYL2X); GEN("fyl2xp1", FYL2XP1); #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_unary(&ii, insns[i])) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_FPU_REG printf("Testing FPU reg forms\n"); n_tests = n_failures = 0; for (int r = 0; r < X86_MAX_FPU_REGS; r++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GENr(INSN, GENOP) do { \ insns[i] = INSN; \ modes[i] = 0; \ i++, GENOP##r(r); \ } while (0) #define GENr0(INSN, GENOP) do { \ insns[i] = INSN; \ modes[i] = 1; \ i++, GENOP##r0(r); \ } while (0) #define GEN0r(INSN, GENOP) do { \ insns[i] = INSN; \ modes[i] = 2; \ i++, GENOP##0r(r); \ } while (0) GENr("fcom", FCOM); GENr("fcomp", FCOMP); GENr("ffree", FFREE); GENr("fxch", FXCH); GENr("fst", FST); GENr("fstp", FSTP); GENr("fucom", FUCOM); GENr("fucomp", FUCOMP); GENr0("fadd", FADD); GENr0("fcmovb", FCMOVB); GENr0("fcmove", FCMOVE); GENr0("fcmovbe", FCMOVBE); GENr0("fcmovu", FCMOVU); GENr0("fcmovnb", FCMOVNB); GENr0("fcmovne", FCMOVNE); GENr0("fcmovnbe", FCMOVNBE); GENr0("fcmovnu", FCMOVNU); GENr0("fcomi", FCOMI); GENr0("fcomip", FCOMIP); GENr0("fucomi", FUCOMI); GENr0("fucomip", FUCOMIP); GENr0("fdiv", FDIV); GENr0("fdivr", FDIVR); GENr0("fmul", FMUL); GENr0("fsub", FSUB); GENr0("fsubr", FSUBR); #undef GEN0r #undef GENr0 #undef GENr int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); switch (modes[i]) { case 0: if (!check_reg(&ii, insns[i], r)) { show_instruction(buffer, p); n_failures++; } break; case 1: if (!check_reg_reg(&ii, insns[i], r, 0)) { show_instruction(buffer, p); n_failures++; } break; case 2: if (!check_reg_reg(&ii, insns[i], 0, r)) { show_instruction(buffer, p); n_failures++; } break; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_FPU_MEM printf("Testing FPU mem forms\n"); n_tests = n_failures = 0; for (int d = 0; d < off_table_count; d++) { const uint32 D = off_table[d]; for (int B = -1; B < X86_MAX_ALU_REGS; B++) { for (int I = -1; I < X86_MAX_ALU_REGS; I++) { if (I == X86_RSP) continue; for (int S = 1; S < 16; S *= 2) { if (I == -1 && S > 1) continue; set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP##m(D, B, I, S); \ } while (0) GEN("fadds", FADDS); GEN("faddl", FADDD); GEN("fiadd", FIADDW); GEN("fiaddl", FIADDL); GEN("fbld", FBLD); GEN("fbstp", FBSTP); GEN("fcoms", FCOMS); GEN("fcoml", FCOMD); GEN("fcomps", FCOMPS); GEN("fcompl", FCOMPD); GEN("fdivs", FDIVS); GEN("fdivl", FDIVD); GEN("fidiv", FIDIVW); GEN("fidivl", FIDIVL); GEN("fdivrs", FDIVRS); GEN("fdivrl", FDIVRD); GEN("fidivr", FIDIVRW); GEN("fidivrl", FIDIVRL); GEN("ficom", FICOMW); GEN("ficoml", FICOML); GEN("ficomp", FICOMPW); GEN("ficompl", FICOMPL); GEN("fild", FILDW); GEN("fildl", FILDL); GEN("fildll", FILDQ); GEN("fist", FISTW); GEN("fistl", FISTL); GEN("fistp", FISTPW); GEN("fistpl", FISTPL); GEN("fistpll", FISTPQ); GEN("fisttp", FISTTPW); GEN("fisttpl", FISTTPL); GEN("fisttpll", FISTTPQ); GEN("flds", FLDS); GEN("fldl", FLDD); GEN("fldt", FLDT); GEN("fmuls", FMULS); GEN("fmull", FMULD); GEN("fimul", FIMULW); GEN("fimull", FIMULL); GEN("fsts", FSTS); GEN("fstl", FSTD); GEN("fstps", FSTPS); GEN("fstpl", FSTPD); GEN("fstpt", FSTPT); GEN("fsubs", FSUBS); GEN("fsubl", FSUBD); GEN("fisub", FISUBW); GEN("fisubl", FISUBL); GEN("fsubrs", FSUBRS); GEN("fsubrl", FSUBRD); GEN("fisubr", FISUBRW); GEN("fisubrl", FISUBRL); #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_mem(&ii, insns[i], D, B, I, S)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; show_status(n_tests); } if (i != last_insn) abort(); } } } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_MMX_REG_REG printf("Testing MMX reg,reg forms\n"); n_tests = n_failures = 0; for (int s = 0; s < X86_MAX_MMX_REGS; s++) { for (int d = 0; d < X86_MAX_MMX_REGS; d++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ MMX_##GENOP##rr(s, d); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) GEN("movq", MOVQ); GEN("packsswb", PACKSSWB); GEN("packssdw", PACKSSDW); GEN("packuswb", PACKUSWB); GEN("paddb", PADDB); GEN("paddw", PADDW); GEN("paddd", PADDD); GEN("paddq", PADDQ); GEN("paddsb", PADDSB); GEN("paddsw", PADDSW); GEN("paddusb", PADDUSB); GEN("paddusw", PADDUSW); GEN("pand", PAND); GEN("pandn", PANDN); GEN("pavgb", PAVGB); GEN("pavgw", PAVGW); GEN("pcmpeqb", PCMPEQB); GEN("pcmpeqw", PCMPEQW); GEN("pcmpeqd", PCMPEQD); GEN("pcmpgtb", PCMPGTB); GEN("pcmpgtw", PCMPGTW); GEN("pcmpgtd", PCMPGTD); GEN("pmaddwd", PMADDWD); GEN("pmaxsw", PMAXSW); GEN("pmaxub", PMAXUB); GEN("pminsw", PMINSW); GEN("pminub", PMINUB); GEN("pmulhuw", PMULHUW); GEN("pmulhw", PMULHW); GEN("pmullw", PMULLW); GEN("pmuludq", PMULUDQ); GEN("por", POR); GEN("psadbw", PSADBW); GEN("psllw", PSLLW); GEN("pslld", PSLLD); GEN("psllq", PSLLQ); GEN("psraw", PSRAW); GEN("psrad", PSRAD); GEN("psrlw", PSRLW); GEN("psrld", PSRLD); GEN("psrlq", PSRLQ); GEN("psubb", PSUBB); GEN("psubw", PSUBW); GEN("psubd", PSUBD); GEN("psubq", PSUBQ); GEN("psubsb", PSUBSB); GEN("psubsw", PSUBSW); GEN("psubusb", PSUBUSB); GEN("psubusw", PSUBUSW); GEN("punpckhbw", PUNPCKHBW); GEN("punpckhwd", PUNPCKHWD); GEN("punpckhdq", PUNPCKHDQ); GEN("punpcklbw", PUNPCKLBW); GEN("punpcklwd", PUNPCKLWD); GEN("punpckldq", PUNPCKLDQ); GEN("pxor", PXOR); GEN("pabsb", PABSB); GEN("pabsw", PABSW); GEN("pabsd", PABSD); GEN("phaddw", PHADDW); GEN("phaddd", PHADDD); GEN("phaddsw", PHADDSW); GEN("phsubw", PHSUBW); GEN("phsubd", PHSUBD); GEN("phsubsw", PHSUBSW); GEN("pmaddubsw", PMADDUBSW); GEN("pmulhrsw", PMULHRSW); GEN("pshufb", PSHUFB); GEN("psignb", PSIGNB); GEN("psignw", PSIGNW); GEN("psignd", PSIGND); #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_reg_reg(&ii, insns[i], s, d)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif static const uint8 imm8_table[] = { 0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x08, 0x09, 0x0e, 0x0f, 0x10, 0x11, 0x1e, 0x1f, 0x20, 0x21, 0xfc, 0xfd, 0xfe, 0xff, }; const int n_imm8_tab_count = sizeof(imm8_table)/sizeof(imm8_table[0]); #if TEST_INST_MMX_IMM_REG printf("Testing imm,reg forms\n"); n_tests = n_failures = 0; for (int j = 0; j < n_imm8_tab_count; j++) { const uint8 value = imm8_table[j]; for (int d = 0; d < X86_MAX_MMX_REGS; d++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i] = INSN; \ modes[i] = 1; \ i++; MMX_##GENOP##ir(value, d); \ } while (0) GEN("psllw", PSLLW); GEN("pslld", PSLLD); GEN("psllq", PSLLQ); GEN("psraw", PSRAW); GEN("psrad", PSRAD); GEN("psrlw", PSRLW); GEN("psrld", PSRLD); GEN("psrlq", PSRLQ); #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_imm_reg(&ii, insns[i], value, d, modes[i])) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_MMX_MEM_REG printf("Testing MMX mem,reg forms\n"); n_tests = n_failures = 0; for (int d = 0; d < off_table_count; d++) { const uint32 D = off_table[d]; for (int B = -1; B < X86_MAX_ALU_REGS; B++) { for (int I = -1; I < X86_MAX_ALU_REGS; I++) { if (I == X86_RSP) continue; for (int S = 1; S < 16; S *= 2) { if (I == -1 && S > 1) continue; for (int r = 0; r < X86_MAX_MMX_REGS; r++) { set_target(block); uint8 *b = get_target(); int i = 0; #define _GENrm(INSN, GENOP) do { \ insns[i] = INSN; \ modes[i] = 0; \ i++; MMX_##GENOP##rm(r, D, B, I, S); \ } while (0) #define _GENmr(INSN, GENOP) do { \ insns[i] = INSN; \ modes[i] = 1; \ i++; MMX_##GENOP##mr(D, B, I, S, r); \ } while (0) #define GEN(INSN, GENOP) do { \ _GENmr(INSN, GENOP); \ } while (0) _GENmr("movd", MOVD); _GENrm("movd", MOVD); _GENmr("movq", MOVQ); _GENrm("movq", MOVQ); GEN("packsswb", PACKSSWB); GEN("packssdw", PACKSSDW); GEN("packuswb", PACKUSWB); GEN("paddb", PADDB); GEN("paddw", PADDW); GEN("paddd", PADDD); GEN("paddq", PADDQ); GEN("paddsb", PADDSB); GEN("paddsw", PADDSW); GEN("paddusb", PADDUSB); GEN("paddusw", PADDUSW); GEN("pand", PAND); GEN("pandn", PANDN); GEN("pavgb", PAVGB); GEN("pavgw", PAVGW); GEN("pcmpeqb", PCMPEQB); GEN("pcmpeqw", PCMPEQW); GEN("pcmpeqd", PCMPEQD); GEN("pcmpgtb", PCMPGTB); GEN("pcmpgtw", PCMPGTW); GEN("pcmpgtd", PCMPGTD); GEN("pmaddwd", PMADDWD); GEN("pmaxsw", PMAXSW); GEN("pmaxub", PMAXUB); GEN("pminsw", PMINSW); GEN("pminub", PMINUB); GEN("pmulhuw", PMULHUW); GEN("pmulhw", PMULHW); GEN("pmullw", PMULLW); GEN("pmuludq", PMULUDQ); GEN("por", POR); GEN("psadbw", PSADBW); GEN("psllw", PSLLW); GEN("pslld", PSLLD); GEN("psllq", PSLLQ); GEN("psraw", PSRAW); GEN("psrad", PSRAD); GEN("psrlw", PSRLW); GEN("psrld", PSRLD); GEN("psrlq", PSRLQ); GEN("psubb", PSUBB); GEN("psubw", PSUBW); GEN("psubd", PSUBD); GEN("psubq", PSUBQ); GEN("psubsb", PSUBSB); GEN("psubsw", PSUBSW); GEN("psubusb", PSUBUSB); GEN("psubusw", PSUBUSW); GEN("punpckhbw", PUNPCKHBW); GEN("punpckhwd", PUNPCKHWD); GEN("punpckhdq", PUNPCKHDQ); GEN("punpcklbw", PUNPCKLBW); GEN("punpcklwd", PUNPCKLWD); GEN("punpckldq", PUNPCKLDQ); GEN("pxor", PXOR); GEN("pabsb", PABSB); GEN("pabsw", PABSW); GEN("pabsd", PABSD); GEN("phaddw", PHADDW); GEN("phaddd", PHADDD); GEN("phaddsw", PHADDSW); GEN("phsubw", PHSUBW); GEN("phsubd", PHSUBD); GEN("phsubsw", PHSUBSW); GEN("pmaddubsw", PMADDUBSW); GEN("pmulhrsw", PMULHRSW); GEN("pshufb", PSHUFB); GEN("psignb", PSIGNB); GEN("psignw", PSIGNW); GEN("psignd", PSIGND); #undef GEN #undef _GENmr #undef _GENrm int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_mem_reg(&ii, insns[i], D, B, I, S, r, modes[i])) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; show_status(n_tests); } if (i != last_insn) abort(); } } } } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_SSE_REG_REG printf("Testing SSE reg,reg forms\n"); n_tests = n_failures = 0; for (int s = 0; s < X86_MAX_SSE_REGS; s++) { for (int d = 0; d < X86_MAX_SSE_REGS; d++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP##rr(s, d); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) #define GEN1(INSN, GENOP) do { \ GEN(INSN "s", GENOP##S); \ GEN(INSN "d", GENOP##D); \ } while (0) #define GENA(INSN, GENOP) do { \ GEN1(INSN "s", GENOP##S); \ GEN1(INSN "p", GENOP##P); \ } while (0) #define GENI(INSN, GENOP, IMM) do { \ insns[i++] = INSN; \ GENOP##rr(IMM, s, d); \ } while (0) #define GENI1(INSN, GENOP, IMM) do { \ GENI(INSN "s", GENOP##S, IMM); \ GENI(INSN "d", GENOP##D, IMM); \ } while (0) #define GENIA(INSN, GENOP, IMM) do { \ GENI1(INSN "s", GENOP##S, IMM); \ GENI1(INSN "p", GENOP##P, IMM); \ } while (0) GEN1("andp", ANDP); GEN1("andnp", ANDNP); GEN1("orp", ORP); GEN1("xorp", XORP); GENA("add", ADD); GENA("sub", SUB); GENA("mul", MUL); GENA("div", DIV); GEN1("comis", COMIS); GEN1("ucomis", UCOMIS); GENA("min", MIN); GENA("max", MAX); GEN("rcpss", RCPSS); GEN("rcpps", RCPPS); GEN("rsqrtss", RSQRTSS); GEN("rsqrtps", RSQRTPS); GENA("sqrt", SQRT); GENIA("cmpeq", CMP, X86_SSE_CC_EQ); GENIA("cmplt", CMP, X86_SSE_CC_LT); GENIA("cmple", CMP, X86_SSE_CC_LE); GENIA("cmpunord", CMP, X86_SSE_CC_U); GENIA("cmpneq", CMP, X86_SSE_CC_NEQ); GENIA("cmpnlt", CMP, X86_SSE_CC_NLT); GENIA("cmpnle", CMP, X86_SSE_CC_NLE); GENIA("cmpord", CMP, X86_SSE_CC_O); GEN1("movap", MOVAP); GEN("movdqa", MOVDQA); GEN("movdqu", MOVDQU); GEN("movd", MOVDXD); GEN64("movd", MOVQXD); // FIXME: disass bug? "movq" expected GEN("movd", MOVDXS); GEN64("movd", MOVQXS); // FIXME: disass bug? "movq" expected GEN("cvtdq2pd", CVTDQ2PD); GEN("cvtdq2ps", CVTDQ2PS); GEN("cvtpd2dq", CVTPD2DQ); GEN("cvtpd2ps", CVTPD2PS); GEN("cvtps2dq", CVTPS2DQ); GEN("cvtps2pd", CVTPS2PD); GEN("cvtsd2si", CVTSD2SIL); GEN64("cvtsd2siq", CVTSD2SIQ); GEN("cvtsd2ss", CVTSD2SS); GEN("cvtsi2sd", CVTSI2SDL); GEN64("cvtsi2sdq", CVTSI2SDQ); GEN("cvtsi2ss", CVTSI2SSL); GEN64("cvtsi2ssq", CVTSI2SSQ); GEN("cvtss2sd", CVTSS2SD); GEN("cvtss2si", CVTSS2SIL); GEN64("cvtss2siq", CVTSS2SIQ); GEN("cvttpd2dq", CVTTPD2DQ); GEN("cvttps2dq", CVTTPS2DQ); GEN("cvttsd2si", CVTTSD2SIL); GEN64("cvttsd2siq", CVTTSD2SIQ); GEN("cvttss2si", CVTTSS2SIL); GEN64("cvttss2siq", CVTTSS2SIQ); if (s < 8) { // MMX source register GEN("cvtpi2pd", CVTPI2PD); GEN("cvtpi2ps", CVTPI2PS); } if (d < 8) { // MMX dest register GEN("cvtpd2pi", CVTPD2PI); GEN("cvtps2pi", CVTPS2PI); GEN("cvttpd2pi", CVTTPD2PI); GEN("cvttps2pi", CVTTPS2PI); } #undef GENIA #undef GENI1 #undef GENI #undef GENA #undef GEN1 #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_reg_reg(&ii, insns[i], s, d)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; } if (i != last_insn) abort(); } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif #if TEST_INST_SSE_MEM_REG printf("Testing SSE mem,reg forms\n"); n_tests = n_failures = 0; for (int d = 0; d < off_table_count; d++) { const uint32 D = off_table[d]; for (int B = -1; B < X86_MAX_ALU_REGS; B++) { for (int I = -1; I < X86_MAX_ALU_REGS; I++) { if (I == X86_RSP) continue; for (int S = 1; S < 16; S *= 2) { if (I == -1 && S > 1) continue; for (int r = 0; r < X86_MAX_SSE_REGS; r++) { set_target(block); uint8 *b = get_target(); int i = 0; #define GEN(INSN, GENOP) do { \ insns[i++] = INSN; \ GENOP##mr(D, B, I, S, r); \ } while (0) #define GEN64(INSN, GENOP) do { \ if (X86_TARGET_64BIT) \ GEN(INSN, GENOP); \ } while (0) #define GEN1(INSN, GENOP) do { \ GEN(INSN "s", GENOP##S); \ GEN(INSN "d", GENOP##D); \ } while (0) #define GENA(INSN, GENOP) do { \ GEN1(INSN "s", GENOP##S); \ GEN1(INSN "p", GENOP##P); \ } while (0) #define GENI(INSN, GENOP, IMM) do { \ insns[i++] = INSN; \ GENOP##mr(IMM, D, B, I, S, r); \ } while (0) #define GENI1(INSN, GENOP, IMM) do { \ GENI(INSN "s", GENOP##S, IMM); \ GENI(INSN "d", GENOP##D, IMM); \ } while (0) #define GENIA(INSN, GENOP, IMM) do { \ GENI1(INSN "s", GENOP##S, IMM); \ GENI1(INSN "p", GENOP##P, IMM); \ } while (0) GEN1("andp", ANDP); GEN1("andnp", ANDNP); GEN1("orp", ORP); GEN1("xorp", XORP); GENA("add", ADD); GENA("sub", SUB); GENA("mul", MUL); GENA("div", DIV); GEN1("comis", COMIS); GEN1("ucomis", UCOMIS); GENA("min", MIN); GENA("max", MAX); GEN("rcpss", RCPSS); GEN("rcpps", RCPPS); GEN("rsqrtss", RSQRTSS); GEN("rsqrtps", RSQRTPS); GENA("sqrt", SQRT); GENIA("cmpeq", CMP, X86_SSE_CC_EQ); GENIA("cmplt", CMP, X86_SSE_CC_LT); GENIA("cmple", CMP, X86_SSE_CC_LE); GENIA("cmpunord", CMP, X86_SSE_CC_U); GENIA("cmpneq", CMP, X86_SSE_CC_NEQ); GENIA("cmpnlt", CMP, X86_SSE_CC_NLT); GENIA("cmpnle", CMP, X86_SSE_CC_NLE); GENIA("cmpord", CMP, X86_SSE_CC_O); GEN1("movap", MOVAP); GEN("movdqa", MOVDQA); GEN("movdqu", MOVDQU); #if 0 // FIXME: extraneous REX bits generated GEN("movd", MOVDXD); GEN64("movd", MOVQXD); // FIXME: disass bug? "movq" expected #endif GEN("cvtdq2pd", CVTDQ2PD); GEN("cvtdq2ps", CVTDQ2PS); GEN("cvtpd2dq", CVTPD2DQ); GEN("cvtpd2ps", CVTPD2PS); GEN("cvtps2dq", CVTPS2DQ); GEN("cvtps2pd", CVTPS2PD); GEN("cvtsd2si", CVTSD2SIL); GEN64("cvtsd2siq", CVTSD2SIQ); GEN("cvtsd2ss", CVTSD2SS); GEN("cvtsi2sd", CVTSI2SDL); GEN64("cvtsi2sdq", CVTSI2SDQ); GEN("cvtsi2ss", CVTSI2SSL); GEN64("cvtsi2ssq", CVTSI2SSQ); GEN("cvtss2sd", CVTSS2SD); GEN("cvtss2si", CVTSS2SIL); GEN64("cvtss2siq", CVTSS2SIQ); GEN("cvttpd2dq", CVTTPD2DQ); GEN("cvttps2dq", CVTTPS2DQ); GEN("cvttsd2si", CVTTSD2SIL); GEN64("cvttsd2siq", CVTTSD2SIQ); GEN("cvttss2si", CVTTSS2SIL); GEN64("cvttss2siq", CVTTSS2SIQ); if (r < 8) { // MMX dest register GEN("cvtpd2pi", CVTPD2PI); GEN("cvtps2pi", CVTPS2PI); GEN("cvttpd2pi", CVTTPD2PI); GEN("cvttps2pi", CVTTPS2PI); } #undef GENIA #undef GENI1 #undef GENI #undef GENA #undef GEN1 #undef GEN64 #undef GEN int last_insn = i; uint8 *e = get_target(); uint8 *p = b; i = 0; while (p < e) { int n = disass_x86(buffer, (uintptr)p); insn_t ii; parse_insn(&ii, buffer); if (!check_mem_reg(&ii, insns[i], D, B, I, S, r)) { show_instruction(buffer, p); n_failures++; } p += n; i += 1; n_tests++; show_status(n_tests); } if (i != last_insn) abort(); } } } } } printf(" done %ld/%ld\n", n_tests - n_failures, n_tests); n_all_tests += n_tests; n_all_failures += n_failures; #endif printf("\n"); printf("All %ld tests run, %ld failures\n", n_all_tests, n_all_failures); } BasiliskII/src/uae_cpu/compiler/gencomp.c0000644000175000017500000024506510641234360020572 0ustar centriscentris/* * compiler/gencomp.c - MC680x0 compilation generator * * Based on work Copyright 1995, 1996 Bernd Schmidt * Changes for UAE-JIT Copyright 2000 Bernd Meyer * * Adaptation for Basilisk II and improvements, copyright 2000-2005 * Gwenole Beauchesne * * Basilisk II (C) 1997-2005 Christian Bauer * * 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 */ #include #include #include #include #include #include "sysdeps.h" #include "readcpu.h" #define BOOL_TYPE "int" #define failure global_failure=1 #define FAILURE global_failure=1 #define isjump global_isjump=1 #define is_const_jump global_iscjump=1; #define isaddx global_isaddx=1 #define uses_cmov global_cmov=1 #define mayfail global_mayfail=1 #define uses_fpu global_fpu=1 int hack_opcode; static int global_failure; static int global_isjump; static int global_iscjump; static int global_isaddx; static int global_cmov; static int long_opcode; static int global_mayfail; static int global_fpu; static char endstr[1000]; static char lines[100000]; static int comp_index=0; static int cond_codes_x86[]={-1,-1,7,6,3,2,5,4,-1,-1,9,8,13,12,15,14}; static void comprintf(const char* format, ...) { va_list args; va_start(args,format); comp_index+=vsprintf(lines+comp_index,format,args); } static void com_discard(void) { comp_index=0; } static void com_flush(void) { int i; for (i=0;i 0); n_braces--; comprintf ("}"); } static void finish_braces (void) { while (n_braces > 0) close_brace (); } static void pop_braces (int to) { while (n_braces > to) close_brace (); } static int bit_size (int size) { switch (size) { case sz_byte: return 8; case sz_word: return 16; case sz_long: return 32; default: abort (); } return 0; } static const char * bit_mask (int size) { switch (size) { case sz_byte: return "0xff"; case sz_word: return "0xffff"; case sz_long: return "0xffffffff"; default: abort (); } return 0; } static __inline__ void gen_update_next_handler(void) { return; /* Can anything clever be done here? */ } static void gen_writebyte(char* address, char* source) { comprintf("\twritebyte(%s,%s,scratchie);\n",address,source); } static void gen_writeword(char* address, char* source) { comprintf("\twriteword(%s,%s,scratchie);\n",address,source); } static void gen_writelong(char* address, char* source) { comprintf("\twritelong(%s,%s,scratchie);\n",address,source); } static void gen_readbyte(char* address, char* dest) { comprintf("\treadbyte(%s,%s,scratchie);\n",address,dest); } static void gen_readword(char* address, char* dest) { comprintf("\treadword(%s,%s,scratchie);\n",address,dest); } static void gen_readlong(char* address, char* dest) { comprintf("\treadlong(%s,%s,scratchie);\n",address,dest); } static const char * gen_nextilong (void) { static char buffer[80]; sprintf (buffer, "comp_get_ilong((m68k_pc_offset+=4)-4)"); insn_n_cycles += 4; long_opcode=1; return buffer; } static const char * gen_nextiword (void) { static char buffer[80]; sprintf (buffer, "comp_get_iword((m68k_pc_offset+=2)-2)"); insn_n_cycles+=2; long_opcode=1; return buffer; } static const char * gen_nextibyte (void) { static char buffer[80]; sprintf (buffer, "comp_get_ibyte((m68k_pc_offset+=2)-2)"); insn_n_cycles += 2; long_opcode=1; return buffer; } static void swap_opcode (void) { comprintf("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); comprintf("\topcode = do_byteswap_16(opcode);\n"); comprintf("#endif\n"); } static void sync_m68k_pc (void) { comprintf("\t if (m68k_pc_offset>100) sync_m68k_pc();\n"); } /* getv == 1: fetch data; getv != 0: check for odd address. If movem != 0, * the calling routine handles Apdi and Aipi modes. * gb-- movem == 2 means the same thing but for a MOVE16 instruction */ static void genamode (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem) { start_brace (); switch (mode) { case Dreg: /* Do we need to check dodgy here? */ if (movem) abort (); if (getv == 1 || getv==2) { /* We generate the variable even for getv==2, so we can use it as a destination for MOVE */ comprintf ("\tint %s=%s;\n",name,reg); } return; case Areg: if (movem) abort (); if (getv == 1 || getv==2) { /* see above */ comprintf ("\tint %s=dodgy?scratchie++:%s+8;\n",name,reg); if (getv==1) { comprintf ("\tif (dodgy) \n"); comprintf ("\t\tmov_l_rr(%s,%s+8);\n",name, reg); } } return; case Aind: comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg); comprintf ("\tif (dodgy) \n"); comprintf ("\t\tmov_l_rr(%sa,%s+8);\n",name, reg); break; case Aipi: comprintf ("\tint %sa=scratchie++;\n",name,reg); comprintf ("\tmov_l_rr(%sa,%s+8);\n",name, reg); break; case Apdi: switch (size) { case sz_byte: if (movem) { comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg); comprintf ("\tif (dodgy) \n"); comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg); } else { start_brace(); comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg); comprintf("\tlea_l_brr(%s+8,%s+8,(uae_s32)-areg_byteinc[%s]);\n",reg,reg,reg); comprintf ("\tif (dodgy) \n"); comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg); } break; case sz_word: if (movem) { comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg); comprintf ("\tif (dodgy) \n"); comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg); } else { start_brace(); comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg); comprintf("\tlea_l_brr(%s+8,%s+8,-2);\n",reg,reg); comprintf ("\tif (dodgy) \n"); comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg); } break; case sz_long: if (movem) { comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg); comprintf ("\tif (dodgy) \n"); comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg); } else { start_brace(); comprintf ("\tint %sa=dodgy?scratchie++:%s+8;\n",name,reg); comprintf("\tlea_l_brr(%s+8,%s+8,-4);\n",reg,reg); comprintf ("\tif (dodgy) \n"); comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg); } break; default: abort (); } break; case Ad16: comprintf("\tint %sa=scratchie++;\n",name); comprintf("\tmov_l_rr(%sa,8+%s);\n",name,reg); comprintf("\tlea_l_brr(%sa,%sa,(uae_s32)(uae_s16)%s);\n",name,name,gen_nextiword()); break; case Ad8r: comprintf("\tint %sa=scratchie++;\n",name); comprintf("\tcalc_disp_ea_020(%s+8,%s,%sa,scratchie);\n", reg,gen_nextiword(),name); break; case PC16: comprintf("\tint %sa=scratchie++;\n",name); comprintf("\tuae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n"); comprintf ("\tuae_s32 PC16off = (uae_s32)(uae_s16)%s;\n", gen_nextiword ()); comprintf("\tmov_l_ri(%sa,address+PC16off);\n",name); break; case PC8r: comprintf("\tint pctmp=scratchie++;\n"); comprintf("\tint %sa=scratchie++;\n",name); comprintf("\tuae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n"); start_brace(); comprintf("\tmov_l_ri(pctmp,address);\n"); comprintf("\tcalc_disp_ea_020(pctmp,%s,%sa,scratchie);\n", gen_nextiword(),name); break; case absw: comprintf ("\tint %sa = scratchie++;\n",name); comprintf ("\tmov_l_ri(%sa,(uae_s32)(uae_s16)%s);\n", name, gen_nextiword ()); break; case absl: comprintf ("\tint %sa = scratchie++;\n",name); comprintf ("\tmov_l_ri(%sa,%s); /* absl */\n", name, gen_nextilong ()); break; case imm: if (getv != 1) abort (); switch (size) { case sz_byte: comprintf ("\tint %s = scratchie++;\n",name); comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s8)%s);\n", name, gen_nextibyte ()); break; case sz_word: comprintf ("\tint %s = scratchie++;\n",name); comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s16)%s);\n", name, gen_nextiword ()); break; case sz_long: comprintf ("\tint %s = scratchie++;\n",name); comprintf ("\tmov_l_ri(%s,%s);\n", name, gen_nextilong ()); break; default: abort (); } return; case imm0: if (getv != 1) abort (); comprintf ("\tint %s = scratchie++;\n",name); comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s8)%s);\n", name, gen_nextibyte ()); return; case imm1: if (getv != 1) abort (); comprintf ("\tint %s = scratchie++;\n",name); comprintf ("\tmov_l_ri(%s,(uae_s32)(uae_s16)%s);\n", name, gen_nextiword ()); return; case imm2: if (getv != 1) abort (); comprintf ("\tint %s = scratchie++;\n",name); comprintf ("\tmov_l_ri(%s,%s);\n", name, gen_nextilong ()); return; case immi: if (getv != 1) abort (); comprintf ("\tint %s = scratchie++;\n",name); comprintf ("\tmov_l_ri(%s,%s);\n", name, reg); return; default: abort (); } /* We get here for all non-reg non-immediate addressing modes to * actually fetch the value. */ if (getv == 1) { char astring[80]; sprintf(astring,"%sa",name); switch (size) { case sz_byte: insn_n_cycles += 2; break; case sz_word: insn_n_cycles += 2; break; case sz_long: insn_n_cycles += 4; break; default: abort (); } start_brace (); comprintf("\tint %s=scratchie++;\n",name); switch (size) { case sz_byte: gen_readbyte(astring,name); break; case sz_word: gen_readword(astring,name); break; case sz_long: gen_readlong(astring,name); break; default: abort (); } } /* We now might have to fix up the register for pre-dec or post-inc * addressing modes. */ if (!movem) { char x[160]; switch (mode) { case Aipi: switch (size) { case sz_byte: comprintf("\tlea_l_brr(%s+8,%s+8,areg_byteinc[%s]);\n",reg,reg,reg); break; case sz_word: comprintf("\tlea_l_brr(%s+8,%s+8,2);\n",reg,reg,reg); break; case sz_long: comprintf("\tlea_l_brr(%s+8,%s+8,4);\n",reg,reg); break; default: abort (); } break; case Apdi: break; default: break; } } } static void genastore (char *from, amodes mode, char *reg, wordsizes size, char *to) { switch (mode) { case Dreg: switch (size) { case sz_byte: comprintf("\tif(%s!=%s)\n",reg,from); comprintf ("\t\tmov_b_rr(%s,%s);\n", reg, from); break; case sz_word: comprintf("\tif(%s!=%s)\n",reg,from); comprintf ("\t\tmov_w_rr(%s,%s);\n", reg, from); break; case sz_long: comprintf("\tif(%s!=%s)\n",reg,from); comprintf ("\t\tmov_l_rr(%s,%s);\n", reg, from); break; default: abort (); } break; case Areg: switch (size) { case sz_word: comprintf("\tif(%s+8!=%s)\n",reg,from); comprintf ("\t\tmov_w_rr(%s+8,%s);\n", reg, from); break; case sz_long: comprintf("\tif(%s+8!=%s)\n",reg,from); comprintf ("\t\tmov_l_rr(%s+8,%s);\n", reg, from); break; default: abort (); } break; case Apdi: case absw: case PC16: case PC8r: case Ad16: case Ad8r: case Aipi: case Aind: case absl: { char astring[80]; sprintf(astring,"%sa",to); switch (size) { case sz_byte: insn_n_cycles += 2; gen_writebyte(astring,from); break; case sz_word: insn_n_cycles += 2; gen_writeword(astring,from); break; case sz_long: insn_n_cycles += 4; gen_writelong(astring,from); break; default: abort (); } } break; case imm: case imm0: case imm1: case imm2: case immi: abort (); break; default: abort (); } } static void genmov16(uae_u32 opcode, struct instr *curi) { comprintf("\tint src=scratchie++;\n"); comprintf("\tint dst=scratchie++;\n"); if ((opcode & 0xfff8) == 0xf620) { /* MOVE16 (Ax)+,(Ay)+ */ comprintf("\tuae_u16 dstreg=((%s)>>12)&0x07;\n", gen_nextiword()); comprintf("\tmov_l_rr(src,8+srcreg);\n"); comprintf("\tmov_l_rr(dst,8+dstreg);\n"); } else { /* Other variants */ genamode (curi->smode, "srcreg", curi->size, "src", 0, 2); genamode (curi->dmode, "dstreg", curi->size, "dst", 0, 2); comprintf("\tmov_l_rr(src,srca);\n"); comprintf("\tmov_l_rr(dst,dsta);\n"); } /* Align on 16-byte boundaries */ comprintf("\tand_l_ri(src,~15);\n"); comprintf("\tand_l_ri(dst,~15);\n"); if ((opcode & 0xfff8) == 0xf620) { comprintf("\tif (srcreg != dstreg)\n"); comprintf("\tadd_l_ri(srcreg+8,16);\n"); comprintf("\tadd_l_ri(dstreg+8,16);\n"); } else if ((opcode & 0xfff8) == 0xf600) comprintf("\tadd_l_ri(srcreg+8,16);\n"); else if ((opcode & 0xfff8) == 0xf608) comprintf("\tadd_l_ri(dstreg+8,16);\n"); comprintf("\tint tmp=scratchie;\n"); comprintf("\tscratchie+=4;\n"); comprintf("\tget_n_addr(src,src,scratchie);\n" "\tget_n_addr(dst,dst,scratchie);\n" "\tmov_l_rR(tmp+0,src,0);\n" "\tmov_l_rR(tmp+1,src,4);\n" "\tmov_l_rR(tmp+2,src,8);\n" "\tmov_l_rR(tmp+3,src,12);\n" "\tmov_l_Rr(dst,tmp+0,0);\n" "\tforget_about(tmp+0);\n" "\tmov_l_Rr(dst,tmp+1,4);\n" "\tforget_about(tmp+1);\n" "\tmov_l_Rr(dst,tmp+2,8);\n" "\tforget_about(tmp+2);\n" "\tmov_l_Rr(dst,tmp+3,12);\n"); } static void genmovemel (uae_u16 opcode) { comprintf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); comprintf ("\tint native=scratchie++;\n"); comprintf ("\tint i;\n"); comprintf ("\tsigned char offset=0;\n"); genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); comprintf("\tget_n_addr(srca,native,scratchie);\n"); comprintf("\tfor (i=0;i<16;i++) {\n" "\t\tif ((mask>>i)&1) {\n"); switch(table68k[opcode].size) { case sz_long: comprintf("\t\t\tmov_l_rR(i,native,offset);\n" "\t\t\tbswap_32(i);\n" "\t\t\toffset+=4;\n"); break; case sz_word: comprintf("\t\t\tmov_w_rR(i,native,offset);\n" "\t\t\tbswap_16(i);\n" "\t\t\tsign_extend_16_rr(i,i);\n" "\t\t\toffset+=2;\n"); break; default: abort(); } comprintf("\t\t}\n" "\t}"); if (table68k[opcode].dmode == Aipi) { comprintf("\t\t\tlea_l_brr(8+dstreg,srca,offset);\n"); } } static void genmovemle (uae_u16 opcode) { comprintf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); comprintf ("\tint native=scratchie++;\n"); comprintf ("\tint i;\n"); comprintf ("\tint tmp=scratchie++;\n"); comprintf ("\tsigned char offset=0;\n"); genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); comprintf("\tget_n_addr(srca,native,scratchie);\n"); if (table68k[opcode].dmode!=Apdi) { comprintf("\tfor (i=0;i<16;i++) {\n" "\t\tif ((mask>>i)&1) {\n"); switch(table68k[opcode].size) { case sz_long: comprintf("\t\t\tmov_l_rr(tmp,i);\n" "\t\t\tbswap_32(tmp);\n" "\t\t\tmov_l_Rr(native,tmp,offset);\n" "\t\t\toffset+=4;\n"); break; case sz_word: comprintf("\t\t\tmov_l_rr(tmp,i);\n" "\t\t\tbswap_16(tmp);\n" "\t\t\tmov_w_Rr(native,tmp,offset);\n" "\t\t\toffset+=2;\n"); break; default: abort(); } } else { /* Pre-decrement */ comprintf("\tfor (i=0;i<16;i++) {\n" "\t\tif ((mask>>i)&1) {\n"); switch(table68k[opcode].size) { case sz_long: comprintf("\t\t\toffset-=4;\n" "\t\t\tmov_l_rr(tmp,15-i);\n" "\t\t\tbswap_32(tmp);\n" "\t\t\tmov_l_Rr(native,tmp,offset);\n" ); break; case sz_word: comprintf("\t\t\toffset-=2;\n" "\t\t\tmov_l_rr(tmp,15-i);\n" "\t\t\tbswap_16(tmp);\n" "\t\t\tmov_w_Rr(native,tmp,offset);\n" ); break; default: abort(); } } comprintf("\t\t}\n" "\t}"); if (table68k[opcode].dmode == Apdi) { comprintf("\t\t\tlea_l_brr(8+dstreg,srca,(uae_s32)offset);\n"); } } static void duplicate_carry (void) { comprintf ("\tif (needed_flags&FLAG_X) duplicate_carry();\n"); } typedef enum { flag_logical_noclobber, flag_logical, flag_add, flag_sub, flag_cmp, flag_addx, flag_subx, flag_zn, flag_av, flag_sv, flag_and, flag_or, flag_eor, flag_mov } flagtypes; static void genflags (flagtypes type, wordsizes size, char *value, char *src, char *dst) { if (noflags) { switch(type) { case flag_cmp: comprintf("\tdont_care_flags();\n"); comprintf("/* Weird --- CMP with noflags ;-) */\n"); return; case flag_add: case flag_sub: comprintf("\tdont_care_flags();\n"); { char* op; switch(type) { case flag_add: op="add"; break; case flag_sub: op="sub"; break; default: abort(); } switch (size) { case sz_byte: comprintf("\t%s_b(%s,%s);\n",op,dst,src); break; case sz_word: comprintf("\t%s_w(%s,%s);\n",op,dst,src); break; case sz_long: comprintf("\t%s_l(%s,%s);\n",op,dst,src); break; } return; } break; case flag_and: comprintf("\tdont_care_flags();\n"); switch (size) { case sz_byte: comprintf("if (kill_rodent(dst)) {\n"); comprintf("\tzero_extend_8_rr(scratchie,%s);\n",src); comprintf("\tor_l_ri(scratchie,0xffffff00);\n"); comprintf("\tand_l(%s,scratchie);\n",dst); comprintf("\tforget_about(scratchie);\n"); comprintf("\t} else \n" "\tand_b(%s,%s);\n",dst,src); break; case sz_word: comprintf("if (kill_rodent(dst)) {\n"); comprintf("\tzero_extend_16_rr(scratchie,%s);\n",src); comprintf("\tor_l_ri(scratchie,0xffff0000);\n"); comprintf("\tand_l(%s,scratchie);\n",dst); comprintf("\tforget_about(scratchie);\n"); comprintf("\t} else \n" "\tand_w(%s,%s);\n",dst,src); break; case sz_long: comprintf("\tand_l(%s,%s);\n",dst,src); break; } return; case flag_mov: comprintf("\tdont_care_flags();\n"); switch (size) { case sz_byte: comprintf("if (kill_rodent(dst)) {\n"); comprintf("\tzero_extend_8_rr(scratchie,%s);\n",src); comprintf("\tand_l_ri(%s,0xffffff00);\n",dst); comprintf("\tor_l(%s,scratchie);\n",dst); comprintf("\tforget_about(scratchie);\n"); comprintf("\t} else \n" "\tmov_b_rr(%s,%s);\n",dst,src); break; case sz_word: comprintf("if (kill_rodent(dst)) {\n"); comprintf("\tzero_extend_16_rr(scratchie,%s);\n",src); comprintf("\tand_l_ri(%s,0xffff0000);\n",dst); comprintf("\tor_l(%s,scratchie);\n",dst); comprintf("\tforget_about(scratchie);\n"); comprintf("\t} else \n" "\tmov_w_rr(%s,%s);\n",dst,src); break; case sz_long: comprintf("\tmov_l_rr(%s,%s);\n",dst,src); break; } return; case flag_or: case flag_eor: comprintf("\tdont_care_flags();\n"); start_brace(); { char* op; switch(type) { case flag_or: op="or"; break; case flag_eor: op="xor"; break; default: abort(); } switch (size) { case sz_byte: comprintf("if (kill_rodent(dst)) {\n"); comprintf("\tzero_extend_8_rr(scratchie,%s);\n",src); comprintf("\t%s_l(%s,scratchie);\n",op,dst); comprintf("\tforget_about(scratchie);\n"); comprintf("\t} else \n" "\t%s_b(%s,%s);\n",op,dst,src); break; case sz_word: comprintf("if (kill_rodent(dst)) {\n"); comprintf("\tzero_extend_16_rr(scratchie,%s);\n",src); comprintf("\t%s_l(%s,scratchie);\n",op,dst); comprintf("\tforget_about(scratchie);\n"); comprintf("\t} else \n" "\t%s_w(%s,%s);\n",op,dst,src); break; case sz_long: comprintf("\t%s_l(%s,%s);\n",op,dst,src); break; } close_brace(); return; } case flag_addx: case flag_subx: comprintf("\tdont_care_flags();\n"); { char* op; switch(type) { case flag_addx: op="adc"; break; case flag_subx: op="sbb"; break; default: abort(); } comprintf("\trestore_carry();\n"); /* Reload the X flag into C */ switch (size) { case sz_byte: comprintf("\t%s_b(%s,%s);\n",op,dst,src); break; case sz_word: comprintf("\t%s_w(%s,%s);\n",op,dst,src); break; case sz_long: comprintf("\t%s_l(%s,%s);\n",op,dst,src); break; } return; } break; default: return; } } /* Need the flags, but possibly not all of them */ switch (type) { case flag_logical_noclobber: failure; case flag_and: case flag_or: case flag_eor: comprintf("\tdont_care_flags();\n"); start_brace(); { char* op; switch(type) { case flag_and: op="and"; break; case flag_or: op="or"; break; case flag_eor: op="xor"; break; default: abort(); } switch (size) { case sz_byte: comprintf("\tstart_needflags();\n" "\t%s_b(%s,%s);\n",op,dst,src); break; case sz_word: comprintf("\tstart_needflags();\n" "\t%s_w(%s,%s);\n",op,dst,src); break; case sz_long: comprintf("\tstart_needflags();\n" "\t%s_l(%s,%s);\n",op,dst,src); break; } comprintf("\tlive_flags();\n"); comprintf("\tend_needflags();\n"); close_brace(); return; } case flag_mov: comprintf("\tdont_care_flags();\n"); start_brace(); { switch (size) { case sz_byte: comprintf("\tif (%s!=%s) {\n",src,dst); comprintf("\tmov_b_ri(%s,0);\n" "\tstart_needflags();\n",dst); comprintf("\tor_b(%s,%s);\n",dst,src); comprintf("\t} else {\n"); comprintf("\tmov_b_rr(%s,%s);\n",dst,src); comprintf("\ttest_b_rr(%s,%s);\n",dst,dst); comprintf("\t}\n"); break; case sz_word: comprintf("\tif (%s!=%s) {\n",src,dst); comprintf("\tmov_w_ri(%s,0);\n" "\tstart_needflags();\n",dst); comprintf("\tor_w(%s,%s);\n",dst,src); comprintf("\t} else {\n"); comprintf("\tmov_w_rr(%s,%s);\n",dst,src); comprintf("\ttest_w_rr(%s,%s);\n",dst,dst); comprintf("\t}\n"); break; case sz_long: comprintf("\tif (%s!=%s) {\n",src,dst); comprintf("\tmov_l_ri(%s,0);\n" "\tstart_needflags();\n",dst); comprintf("\tor_l(%s,%s);\n",dst,src); comprintf("\t} else {\n"); comprintf("\tmov_l_rr(%s,%s);\n",dst,src); comprintf("\ttest_l_rr(%s,%s);\n",dst,dst); comprintf("\t}\n"); break; } comprintf("\tlive_flags();\n"); comprintf("\tend_needflags();\n"); close_brace(); return; } case flag_logical: comprintf("\tdont_care_flags();\n"); start_brace(); switch (size) { case sz_byte: comprintf("\tstart_needflags();\n" "\ttest_b_rr(%s,%s);\n",value,value); break; case sz_word: comprintf("\tstart_needflags();\n" "\ttest_w_rr(%s,%s);\n",value,value); break; case sz_long: comprintf("\tstart_needflags();\n" "\ttest_l_rr(%s,%s);\n",value,value); break; } comprintf("\tlive_flags();\n"); comprintf("\tend_needflags();\n"); close_brace(); return; case flag_add: case flag_sub: case flag_cmp: comprintf("\tdont_care_flags();\n"); { char* op; switch(type) { case flag_add: op="add"; break; case flag_sub: op="sub"; break; case flag_cmp: op="cmp"; break; default: abort(); } switch (size) { case sz_byte: comprintf("\tstart_needflags();\n" "\t%s_b(%s,%s);\n",op,dst,src); break; case sz_word: comprintf("\tstart_needflags();\n" "\t%s_w(%s,%s);\n",op,dst,src); break; case sz_long: comprintf("\tstart_needflags();\n" "\t%s_l(%s,%s);\n",op,dst,src); break; } comprintf("\tlive_flags();\n"); comprintf("\tend_needflags();\n"); if (type!=flag_cmp) { duplicate_carry(); } comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); return; } case flag_addx: case flag_subx: uses_cmov; comprintf("\tdont_care_flags();\n"); { char* op; switch(type) { case flag_addx: op="adc"; break; case flag_subx: op="sbb"; break; default: abort(); } start_brace(); comprintf("\tint zero=scratchie++;\n" "\tint one=scratchie++;\n" "\tif (needed_flags&FLAG_Z) {\n" "\tmov_l_ri(zero,0);\n" "\tmov_l_ri(one,-1);\n" "\tmake_flags_live();\n" "\tcmov_l_rr(zero,one,5);\n" "\t}\n"); comprintf("\trestore_carry();\n"); /* Reload the X flag into C */ switch (size) { case sz_byte: comprintf("\tstart_needflags();\n" "\t%s_b(%s,%s);\n",op,dst,src); break; case sz_word: comprintf("\tstart_needflags();\n" "\t%s_w(%s,%s);\n",op,dst,src); break; case sz_long: comprintf("\tstart_needflags();\n" "\t%s_l(%s,%s);\n",op,dst,src); break; } comprintf("\tlive_flags();\n"); comprintf("\tif (needed_flags&FLAG_Z) {\n" "\tcmov_l_rr(zero,one,5);\n" "\tset_zero(zero, one);\n" /* No longer need one */ "\tlive_flags();\n" "\t}\n"); comprintf("\tend_needflags();\n"); duplicate_carry(); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); return; } default: failure; break; } } static void force_range_for_rox (const char *var, wordsizes size) { /* Could do a modulo operation here... which one is faster? */ switch (size) { case sz_long: comprintf ("\tif (%s >= 33) %s -= 33;\n", var, var); break; case sz_word: comprintf ("\tif (%s >= 34) %s -= 34;\n", var, var); comprintf ("\tif (%s >= 17) %s -= 17;\n", var, var); break; case sz_byte: comprintf ("\tif (%s >= 36) %s -= 36;\n", var, var); comprintf ("\tif (%s >= 18) %s -= 18;\n", var, var); comprintf ("\tif (%s >= 9) %s -= 9;\n", var, var); break; } } static const char * cmask (wordsizes size) { switch (size) { case sz_byte: return "0x80"; case sz_word: return "0x8000"; case sz_long: return "0x80000000"; default: abort (); } } static int source_is_imm1_8 (struct instr *i) { return i->stype == 3; } static int /* returns zero for success, non-zero for failure */ gen_opcode (unsigned long int opcode) { struct instr *curi = table68k + opcode; char* ssize=NULL; insn_n_cycles = 2; global_failure=0; long_opcode=0; global_isjump=0; global_iscjump=0; global_isaddx=0; global_cmov=0; global_fpu=0; global_mayfail=0; hack_opcode=opcode; endstr[0]=0; start_brace (); comprintf("\tuae_u8 scratchie=S1;\n"); switch (curi->plev) { case 0: /* not privileged */ break; case 1: /* unprivileged only on 68000 */ if (cpu_level == 0) break; if (next_cpu_level < 0) next_cpu_level = 0; /* fall through */ case 2: /* priviledged */ failure; /* Easy ones first */ break; case 3: /* privileged if size == word */ if (curi->size == sz_byte) break; failure; break; } switch (curi->size) { case sz_byte: ssize="b"; break; case sz_word: ssize="w"; break; case sz_long: ssize="l"; break; default: abort(); } switch (curi->mnemo) { case i_OR: case i_AND: case i_EOR: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); switch(curi->mnemo) { case i_OR: genflags (flag_or, curi->size, "", "src", "dst"); break; case i_AND: genflags (flag_and, curi->size, "", "src", "dst"); break; case i_EOR: genflags (flag_eor, curi->size, "", "src", "dst"); break; } genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_ORSR: case i_EORSR: failure; isjump; break; case i_ANDSR: failure; isjump; break; case i_SUB: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); genflags (flag_sub, curi->size, "", "src", "dst"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_SUBA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); start_brace(); comprintf("\tint tmp=scratchie++;\n"); switch(curi->size) { case sz_byte: comprintf("\tsign_extend_8_rr(tmp,src);\n"); break; case sz_word: comprintf("\tsign_extend_16_rr(tmp,src);\n"); break; case sz_long: comprintf("\ttmp=src;\n"); break; default: abort(); } comprintf("\tsub_l(dst,tmp);\n"); genastore ("dst", curi->dmode, "dstreg", sz_long, "dst"); break; case i_SUBX: isaddx; genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); genflags (flag_subx, curi->size, "", "src", "dst"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_SBCD: failure; /* I don't think so! */ break; case i_ADD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); genflags (flag_add, curi->size, "", "src", "dst"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_ADDA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); start_brace(); comprintf("\tint tmp=scratchie++;\n"); switch(curi->size) { case sz_byte: comprintf("\tsign_extend_8_rr(tmp,src);\n"); break; case sz_word: comprintf("\tsign_extend_16_rr(tmp,src);\n"); break; case sz_long: comprintf("\ttmp=src;\n"); break; default: abort(); } comprintf("\tadd_l(dst,tmp);\n"); genastore ("dst", curi->dmode, "dstreg", sz_long, "dst"); break; case i_ADDX: isaddx; genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace(); genflags (flag_addx, curi->size, "", "src", "dst"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; case i_ABCD: failure; /* No BCD maths for me.... */ break; case i_NEG: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); comprintf("\tint dst=scratchie++;\n"); comprintf("\tmov_l_ri(dst,0);\n"); genflags (flag_sub, curi->size, "", "src", "dst"); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); break; case i_NEGX: isaddx; genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); comprintf("\tint dst=scratchie++;\n"); comprintf("\tmov_l_ri(dst,0);\n"); genflags (flag_subx, curi->size, "", "src", "dst"); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); break; case i_NBCD: failure; /* Nope! */ break; case i_CLR: genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); start_brace(); comprintf("\tint dst=scratchie++;\n"); comprintf("\tmov_l_ri(dst,0);\n"); genflags (flag_logical, curi->size, "dst", "", ""); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); break; case i_NOT: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); comprintf("\tint dst=scratchie++;\n"); comprintf("\tmov_l_ri(dst,0xffffffff);\n"); genflags (flag_eor, curi->size, "", "src", "dst"); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); break; case i_TST: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genflags (flag_logical, curi->size, "src", "", ""); break; case i_BCHG: case i_BCLR: case i_BSET: case i_BTST: /* failure; /* NEW: from "Ipswitch Town" release */ genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace(); comprintf("\tint s=scratchie++;\n" "\tint tmp=scratchie++;\n" "\tmov_l_rr(s,src);\n"); if (curi->size == sz_byte) comprintf("\tand_l_ri(s,7);\n"); else comprintf("\tand_l_ri(s,31);\n"); { char* op; int need_write=1; switch(curi->mnemo) { case i_BCHG: op="btc"; break; case i_BCLR: op="btr"; break; case i_BSET: op="bts"; break; case i_BTST: op="bt"; need_write=0; break; default: abort(); } comprintf("\t%s_l_rr(dst,s);\n" /* Answer now in C */ "\tsbb_l(s,s);\n" /* s is 0 if bit was 0, -1 otherwise */ "\tmake_flags_live();\n" /* Get the flags back */ "\tdont_care_flags();\n",op); if (!noflags) { comprintf("\tstart_needflags();\n" "\tset_zero(s,tmp);\n" "\tlive_flags();\n" "\tend_needflags();\n"); } if (need_write) genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); } break; case i_CMPM: case i_CMP: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); genflags (flag_cmp, curi->size, "", "src", "dst"); break; case i_CMPA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); start_brace(); comprintf("\tint tmps=scratchie++;\n"); switch(curi->size) { case sz_byte: comprintf("\tsign_extend_8_rr(tmps,src);\n"); break; case sz_word: comprintf("\tsign_extend_16_rr(tmps,src);\n"); break; case sz_long: comprintf("tmps=src;\n"); break; default: abort(); } genflags (flag_cmp, sz_long, "", "tmps", "dst"); break; /* The next two are coded a little unconventional, but they are doing * weird things... */ case i_MVPRM: isjump; failure; break; case i_MVPMR: isjump; failure; break; case i_MOVE: switch(curi->dmode) { case Dreg: case Areg: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); genflags (flag_mov, curi->size, "", "src", "dst"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); break; default: /* It goes to memory, not a register */ genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); genflags (flag_logical, curi->size, "src", "", ""); genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); break; } break; case i_MOVEA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); start_brace(); comprintf("\tint tmps=scratchie++;\n"); switch(curi->size) { case sz_word: comprintf("\tsign_extend_16_rr(dst,src);\n"); break; case sz_long: comprintf("\tmov_l_rr(dst,src);\n"); break; default: abort(); } genastore ("dst", curi->dmode, "dstreg", sz_long, "dst"); break; case i_MVSR2: isjump; failure; break; case i_MV2SR: isjump; failure; break; case i_SWAP: genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); comprintf("\tdont_care_flags();\n"); comprintf("\trol_l_ri(src,16);\n"); genflags (flag_logical, sz_long, "src", "", ""); genastore ("src", curi->smode, "srcreg", sz_long, "src"); break; case i_EXG: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace(); comprintf("\tint tmp=scratchie++;\n" "\tmov_l_rr(tmp,src);\n"); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); genastore ("tmp", curi->dmode, "dstreg", curi->size, "dst"); break; case i_EXT: genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); comprintf("\tdont_care_flags();\n"); start_brace (); switch (curi->size) { case sz_byte: comprintf ("\tint dst = src;\n" "\tsign_extend_8_rr(src,src);\n"); break; case sz_word: comprintf ("\tint dst = scratchie++;\n" "\tsign_extend_8_rr(dst,src);\n"); break; case sz_long: comprintf ("\tint dst = src;\n" "\tsign_extend_16_rr(src,src);\n"); break; default: abort (); } genflags (flag_logical, curi->size == sz_word ? sz_word : sz_long, "dst", "", ""); genastore ("dst", curi->smode, "srcreg", curi->size == sz_word ? sz_word : sz_long, "src"); break; case i_MVMEL: genmovemel (opcode); break; case i_MVMLE: genmovemle (opcode); break; case i_TRAP: isjump; failure; break; case i_MVR2USP: isjump; failure; break; case i_MVUSP2R: isjump; failure; break; case i_RESET: isjump; failure; break; case i_NOP: break; case i_STOP: isjump; failure; break; case i_RTE: isjump; failure; break; case i_RTD: /* failure; /* NEW: from "Ipswitch Town" release */ genamode (curi->smode, "srcreg", curi->size, "offs", 1, 0); /* offs is constant */ comprintf("\tadd_l_ri(offs,4);\n"); start_brace(); comprintf("\tint newad=scratchie++;\n" "\treadlong(15,newad,scratchie);\n" "\tmov_l_mr((uintptr)®s.pc,newad);\n" "\tget_n_addr_jmp(newad,PC_P,scratchie);\n" "\tmov_l_mr((uintptr)®s.pc_oldp,PC_P);\n" "\tm68k_pc_offset=0;\n" "\tadd_l(15,offs);\n"); gen_update_next_handler(); isjump; break; case i_LINK: /* failure; /* NEW: from "Ipswitch Town" release */ genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0); comprintf("\tsub_l_ri(15,4);\n" "\twritelong_clobber(15,src,scratchie);\n" "\tmov_l_rr(src,15);\n"); if (curi->size==sz_word) comprintf("\tsign_extend_16_rr(offs,offs);\n"); comprintf("\tadd_l(15,offs);\n"); genastore ("src", curi->smode, "srcreg", sz_long, "src"); break; case i_UNLK: /* failure; /* NEW: from "Ipswitch Town" release */ genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); comprintf("\tmov_l_rr(15,src);\n" "\treadlong(15,src,scratchie);\n" "\tadd_l_ri(15,4);\n"); genastore ("src", curi->smode, "srcreg", curi->size, "src"); break; case i_RTS: comprintf("\tint newad=scratchie++;\n" "\treadlong(15,newad,scratchie);\n" "\tmov_l_mr((uintptr)®s.pc,newad);\n" "\tget_n_addr_jmp(newad,PC_P,scratchie);\n" "\tmov_l_mr((uintptr)®s.pc_oldp,PC_P);\n" "\tm68k_pc_offset=0;\n" "\tlea_l_brr(15,15,4);\n"); gen_update_next_handler(); isjump; break; case i_TRAPV: isjump; failure; break; case i_RTR: isjump; failure; break; case i_JSR: isjump; genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); start_brace(); comprintf("\tuae_u32 retadd=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n"); comprintf("\tint ret=scratchie++;\n" "\tmov_l_ri(ret,retadd);\n" "\tsub_l_ri(15,4);\n" "\twritelong_clobber(15,ret,scratchie);\n"); comprintf("\tmov_l_mr((uintptr)®s.pc,srca);\n" "\tget_n_addr_jmp(srca,PC_P,scratchie);\n" "\tmov_l_mr((uintptr)®s.pc_oldp,PC_P);\n" "\tm68k_pc_offset=0;\n"); gen_update_next_handler(); break; case i_JMP: isjump; genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); comprintf("\tmov_l_mr((uintptr)®s.pc,srca);\n" "\tget_n_addr_jmp(srca,PC_P,scratchie);\n" "\tmov_l_mr((uintptr)®s.pc_oldp,PC_P);\n" "\tm68k_pc_offset=0;\n"); gen_update_next_handler(); break; case i_BSR: is_const_jump; genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace(); comprintf("\tuae_u32 retadd=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;\n"); comprintf("\tint ret=scratchie++;\n" "\tmov_l_ri(ret,retadd);\n" "\tsub_l_ri(15,4);\n" "\twritelong_clobber(15,ret,scratchie);\n"); comprintf("\tadd_l_ri(src,m68k_pc_offset_thisinst+2);\n"); comprintf("\tm68k_pc_offset=0;\n"); comprintf("\tadd_l(PC_P,src);\n"); comprintf("\tcomp_pc_p=(uae_u8*)get_const(PC_P);\n"); break; case i_Bcc: comprintf("\tuae_u32 v,v1,v2;\n"); genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); /* That source is an immediate, so we can clobber it with abandon */ switch(curi->size) { case sz_byte: comprintf("\tsign_extend_8_rr(src,src);\n"); break; case sz_word: comprintf("\tsign_extend_16_rr(src,src);\n"); break; case sz_long: break; } comprintf("\tsub_l_ri(src,m68k_pc_offset-m68k_pc_offset_thisinst-2);\n"); /* Leave the following as "add" --- it will allow it to be optimized away due to src being a constant ;-) */ comprintf("\tadd_l_ri(src,(uintptr)comp_pc_p);\n"); comprintf("\tmov_l_ri(PC_P,(uintptr)comp_pc_p);\n"); /* Now they are both constant. Might as well fold in m68k_pc_offset */ comprintf("\tadd_l_ri(src,m68k_pc_offset);\n"); comprintf("\tadd_l_ri(PC_P,m68k_pc_offset);\n"); comprintf("\tm68k_pc_offset=0;\n"); if (curi->cc>=2) { comprintf("\tv1=get_const(PC_P);\n" "\tv2=get_const(src);\n" "\tregister_branch(v1,v2,%d);\n", cond_codes_x86[curi->cc]); comprintf("\tmake_flags_live();\n"); /* Load the flags */ isjump; } else { is_const_jump; } switch(curi->cc) { case 0: /* Unconditional jump */ comprintf("\tmov_l_rr(PC_P,src);\n"); comprintf("\tcomp_pc_p=(uae_u8*)get_const(PC_P);\n"); break; case 1: break; /* This is silly! */ case 8: failure; break; /* Work out details! FIXME */ case 9: failure; break; /* Not critical, though! */ case 2: case 3: case 4: case 5: case 6: case 7: case 10: case 11: case 12: case 13: case 14: case 15: break; default: abort(); } break; case i_LEA: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); genastore ("srca", curi->dmode, "dstreg", curi->size, "dst"); break; case i_PEA: if (table68k[opcode].smode==Areg || table68k[opcode].smode==Aind || table68k[opcode].smode==Aipi || table68k[opcode].smode==Apdi || table68k[opcode].smode==Ad16 || table68k[opcode].smode==Ad8r) comprintf("if (srcreg==7) dodgy=1;\n"); genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); genamode (Apdi, "7", sz_long, "dst", 2, 0); genastore ("srca", Apdi, "7", sz_long, "dst"); break; case i_DBcc: isjump; uses_cmov; genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0); /* That offs is an immediate, so we can clobber it with abandon */ switch(curi->size) { case sz_word: comprintf("\tsign_extend_16_rr(offs,offs);\n"); break; default: abort(); /* Seems this only comes in word flavour */ } comprintf("\tsub_l_ri(offs,m68k_pc_offset-m68k_pc_offset_thisinst-2);\n"); comprintf("\tadd_l_ri(offs,(uintptr)comp_pc_p);\n"); /* New PC, once the offset_68k is * also added */ /* Let's fold in the m68k_pc_offset at this point */ comprintf("\tadd_l_ri(offs,m68k_pc_offset);\n"); comprintf("\tadd_l_ri(PC_P,m68k_pc_offset);\n"); comprintf("\tm68k_pc_offset=0;\n"); start_brace(); comprintf("\tint nsrc=scratchie++;\n"); if (curi->cc>=2) { comprintf("\tmake_flags_live();\n"); /* Load the flags */ } if (curi->size!=sz_word) abort(); switch(curi->cc) { case 0: /* This is an elaborate nop? */ break; case 1: comprintf("\tstart_needflags();\n"); comprintf("\tsub_w_ri(src,1);\n"); comprintf("\t end_needflags();\n"); start_brace(); comprintf("\tuae_u32 v2,v;\n" "\tuae_u32 v1=get_const(PC_P);\n"); comprintf("\tv2=get_const(offs);\n" "\tregister_branch(v1,v2,3);\n"); break; case 8: failure; break; /* Work out details! FIXME */ case 9: failure; break; /* Not critical, though! */ case 2: case 3: case 4: case 5: case 6: case 7: case 10: case 11: case 12: case 13: case 14: case 15: comprintf("\tmov_l_rr(nsrc,src);\n"); comprintf("\tlea_l_brr(scratchie,src,(uae_s32)-1);\n" "\tmov_w_rr(src,scratchie);\n"); comprintf("\tcmov_l_rr(offs,PC_P,%d);\n", cond_codes_x86[curi->cc]); comprintf("\tcmov_l_rr(src,nsrc,%d);\n", cond_codes_x86[curi->cc]); /* OK, now for cc=true, we have src==nsrc and offs==PC_P, so whether we move them around doesn't matter. However, if cc=false, we have offs==jump_pc, and src==nsrc-1 */ comprintf("\t start_needflags();\n"); comprintf("\ttest_w_rr(nsrc,nsrc);\n"); comprintf("\t end_needflags();\n"); comprintf("\tcmov_l_rr(PC_P,offs,5);\n"); break; default: abort(); } genastore ("src", curi->smode, "srcreg", curi->size, "src"); gen_update_next_handler(); break; case i_Scc: /* failure; /* NEW: from "Ipswitch Town" release */ genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); start_brace (); comprintf ("\tint val = scratchie++;\n"); /* We set val to 0 if we really should use 255, and to 1 for real 0 */ switch(curi->cc) { case 0: /* Unconditional set */ comprintf("\tmov_l_ri(val,0);\n"); break; case 1: /* Unconditional not-set */ comprintf("\tmov_l_ri(val,1);\n"); break; case 8: failure; break; /* Work out details! FIXME */ case 9: failure; break; /* Not critical, though! */ case 2: case 3: case 4: case 5: case 6: case 7: case 10: case 11: case 12: case 13: case 14: case 15: comprintf("\tmake_flags_live();\n"); /* Load the flags */ /* All condition codes can be inverted by changing the LSB */ comprintf("\tsetcc(val,%d);\n", cond_codes_x86[curi->cc]^1); break; default: abort(); } comprintf("\tsub_b_ri(val,1);\n"); genastore ("val", curi->smode, "srcreg", curi->size, "src"); break; case i_DIVU: isjump; failure; break; case i_DIVS: isjump; failure; break; case i_MULU: /* failure; /* NEW: from "Ipswitch Town" release */ comprintf("\tdont_care_flags();\n"); genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0); /* To do 16x16 unsigned multiplication, we actually use 32x32 signed, and zero-extend the registers first. That solves the problem of MUL needing dedicated registers on the x86 */ comprintf("\tzero_extend_16_rr(scratchie,src);\n" "\tzero_extend_16_rr(dst,dst);\n" "\timul_32_32(dst,scratchie);\n"); genflags (flag_logical, sz_long, "dst", "", ""); genastore ("dst", curi->dmode, "dstreg", sz_long, "dst"); break; case i_MULS: /* failure; /* NEW: from "Ipswitch Town" release */ comprintf("\tdont_care_flags();\n"); genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0); comprintf("\tsign_extend_16_rr(scratchie,src);\n" "\tsign_extend_16_rr(dst,dst);\n" "\timul_32_32(dst,scratchie);\n"); genflags (flag_logical, sz_long, "dst", "", ""); genastore ("dst", curi->dmode, "dstreg", sz_long, "dst"); break; case i_CHK: isjump; failure; break; case i_CHK2: isjump; failure; break; case i_ASR: mayfail; if (curi->smode==Dreg) { comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n" " FAIL(1);\n" " return;\n" "} \n"); start_brace(); } comprintf("\tdont_care_flags();\n"); genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); if (curi->smode!=immi) { /* failure; /* UNTESTED: NEW: from "Ipswitch Town" release */ if (!noflags) { uses_cmov; start_brace(); comprintf("\tint highmask;\n" "\tint width;\n" "\tint cdata=scratchie++;\n" "\tint sdata=scratchie++;\n" "\tint tmpcnt=scratchie++;\n"); comprintf("\tmov_l_rr(sdata,data);\n" "\tmov_l_rr(cdata,data);\n" "\tmov_l_rr(tmpcnt,cnt);\n"); switch (curi->size) { case sz_byte: comprintf("\tshra_b_ri(sdata,7);\n"); break; case sz_word: comprintf("\tshra_w_ri(sdata,15);\n"); break; case sz_long: comprintf("\tshra_l_ri(sdata,31);\n"); break; default: abort(); } /* sdata is now the MSB propagated to all bits for the register of specified size */ comprintf("\tand_l_ri(tmpcnt,63);\n"); switch(curi->size) { case sz_byte: comprintf("\tshra_b_rr(data,tmpcnt);\n" "\thighmask=0x38;\n"); break; case sz_word: comprintf("\tshra_w_rr(data,tmpcnt);\n" "\thighmask=0x30;\n"); break; case sz_long: comprintf("\tshra_l_rr(data,tmpcnt);\n" "\thighmask=0x20;\n"); break; } comprintf("\ttest_l_ri(tmpcnt,highmask);\n"); switch (curi->size) { case sz_byte: comprintf("\tcmov_b_rr(data,sdata,NATIVE_CC_NE);\n"); break; case sz_word: comprintf("\tcmov_w_rr(data,sdata,NATIVE_CC_NE);\n"); break; case sz_long: comprintf("\tcmov_l_rr(data,sdata,NATIVE_CC_NE);\n"); break; } /* Result of shift is now in data. Now we need to determine the carry by shifting cdata one less */ /* NOTE: carry bit is cleared if shift count is zero */ comprintf("\tmov_l_ri(scratchie,0);\n" "\ttest_l_rr(tmpcnt,tmpcnt);\n" "\tcmov_l_rr(sdata,scratchie,NATIVE_CC_EQ);\n" "\tforget_about(scratchie);\n"); comprintf("\tsub_l_ri(tmpcnt,1);\n"); switch(curi->size) { case sz_byte: comprintf("\tshra_b_rr(cdata,tmpcnt);\n");break; case sz_word: comprintf("\tshra_w_rr(cdata,tmpcnt);\n");break; case sz_long: comprintf("\tshra_l_rr(cdata,tmpcnt);\n");break; default: abort(); } /* If the shift count was higher than the width, we need to pick up the sign from original data (sdata) */ /* NOTE: for shift count of zero, the following holds true and cdata contains 0 so that carry bit is cleared */ comprintf("\ttest_l_ri(tmpcnt,highmask);\n" "\tforget_about(tmpcnt);\n" "\tcmov_l_rr(cdata,sdata,NATIVE_CC_NE);\n"); /* And create the flags (preserve X flag if shift count is zero) */ comprintf("\ttest_l_ri(cnt,63);\n" "\tcmov_l_rr(FLAGX,cdata,NATIVE_CC_NE);\n"); comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(cdata,0);\n"); /* Set C */ comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } else { uses_cmov; start_brace(); comprintf("\tint highmask;\n" "\tint width;\n" "\tint highshift=scratchie++;\n"); switch(curi->size) { case sz_byte: comprintf("\tshra_b_rr(data,cnt);\n" "\thighmask=0x38;\n" "\twidth=8;\n"); break; case sz_word: comprintf("\tshra_w_rr(data,cnt);\n" "\thighmask=0x30;\n" "\twidth=16;\n"); break; case sz_long: comprintf("\tshra_l_rr(data,cnt);\n" "\thighmask=0x20;\n" "\twidth=32;\n"); break; default: abort(); } comprintf("test_l_ri(cnt,highmask);\n" "mov_l_ri(highshift,0);\n" "mov_l_ri(scratchie,width/2);\n" "cmov_l_rr(highshift,scratchie,5);\n"); /* The x86 masks out bits, so we now make sure that things really get shifted as much as planned */ switch(curi->size) { case sz_byte: comprintf("\tshra_b_rr(data,highshift);\n");break; case sz_word: comprintf("\tshra_w_rr(data,highshift);\n");break; case sz_long: comprintf("\tshra_l_rr(data,highshift);\n");break; default: abort(); } /* And again */ switch(curi->size) { case sz_byte: comprintf("\tshra_b_rr(data,highshift);\n");break; case sz_word: comprintf("\tshra_w_rr(data,highshift);\n");break; case sz_long: comprintf("\tshra_l_rr(data,highshift);\n");break; default: abort(); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } } else { start_brace(); comprintf("\tint tmp=scratchie++;\n" "\tint bp;\n" "\tmov_l_rr(tmp,data);\n"); switch(curi->size) { case sz_byte: comprintf("\tshra_b_ri(data,srcreg);\n" "\tbp=srcreg-1;\n"); break; case sz_word: comprintf("\tshra_w_ri(data,srcreg);\n" "\tbp=srcreg-1;\n"); break; case sz_long: comprintf("\tshra_l_ri(data,srcreg);\n" "\tbp=srcreg-1;\n"); break; default: abort(); } if (!noflags) { comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */ comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("\t duplicate_carry();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } break; case i_ASL: /* failure; /* NEW: from "Ipswitch Town" release */ mayfail; if (curi->smode==Dreg) { comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n" " FAIL(1);\n" " return;\n" "} \n"); start_brace(); } comprintf("\tdont_care_flags();\n"); /* Except for the handling of the V flag, this is identical to LSL. The handling of V is, uhm, unpleasant, so if it's needed, let the normal emulation handle it. Shoulders of giants kinda thing ;-) */ comprintf("if (needed_flags & FLAG_V) {\n" " FAIL(1);\n" " return;\n" "} \n"); genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); if (curi->smode!=immi) { if (!noflags) { uses_cmov; start_brace(); comprintf("\tint highmask;\n" "\tint cdata=scratchie++;\n" "\tint tmpcnt=scratchie++;\n"); comprintf("\tmov_l_rr(tmpcnt,cnt);\n" "\tand_l_ri(tmpcnt,63);\n" "\tmov_l_ri(cdata,0);\n" "\tcmov_l_rr(cdata,data,5);\n"); /* cdata is now either data (for shift count!=0) or 0 (for shift count==0) */ switch(curi->size) { case sz_byte: comprintf("\tshll_b_rr(data,cnt);\n" "\thighmask=0x38;\n"); break; case sz_word: comprintf("\tshll_w_rr(data,cnt);\n" "\thighmask=0x30;\n"); break; case sz_long: comprintf("\tshll_l_rr(data,cnt);\n" "\thighmask=0x20;\n"); break; default: abort(); } comprintf("test_l_ri(cnt,highmask);\n" "mov_l_ri(scratchie,0);\n" "cmov_l_rr(scratchie,data,4);\n"); switch(curi->size) { case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break; case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break; case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break; default: abort(); } /* Result of shift is now in data. Now we need to determine the carry by shifting cdata one less */ comprintf("\tsub_l_ri(tmpcnt,1);\n"); switch(curi->size) { case sz_byte: comprintf("\tshll_b_rr(cdata,tmpcnt);\n");break; case sz_word: comprintf("\tshll_w_rr(cdata,tmpcnt);\n");break; case sz_long: comprintf("\tshll_l_rr(cdata,tmpcnt);\n");break; default: abort(); } comprintf("test_l_ri(tmpcnt,highmask);\n" "mov_l_ri(scratchie,0);\n" "cmov_l_rr(cdata,scratchie,5);\n"); /* And create the flags */ comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); comprintf("\t bt_l_ri(cdata,7);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); comprintf("\t bt_l_ri(cdata,15);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); comprintf("\t bt_l_ri(cdata,31);\n"); break; } comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("\t duplicate_carry();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } else { uses_cmov; start_brace(); comprintf("\tint highmask;\n"); switch(curi->size) { case sz_byte: comprintf("\tshll_b_rr(data,cnt);\n" "\thighmask=0x38;\n"); break; case sz_word: comprintf("\tshll_w_rr(data,cnt);\n" "\thighmask=0x30;\n"); break; case sz_long: comprintf("\tshll_l_rr(data,cnt);\n" "\thighmask=0x20;\n"); break; default: abort(); } comprintf("test_l_ri(cnt,highmask);\n" "mov_l_ri(scratchie,0);\n" "cmov_l_rr(scratchie,data,4);\n"); switch(curi->size) { case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break; case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break; case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break; default: abort(); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } } else { start_brace(); comprintf("\tint tmp=scratchie++;\n" "\tint bp;\n" "\tmov_l_rr(tmp,data);\n"); switch(curi->size) { case sz_byte: comprintf("\tshll_b_ri(data,srcreg);\n" "\tbp=8-srcreg;\n"); break; case sz_word: comprintf("\tshll_w_ri(data,srcreg);\n" "\tbp=16-srcreg;\n"); break; case sz_long: comprintf("\tshll_l_ri(data,srcreg);\n" "\tbp=32-srcreg;\n"); break; default: abort(); } if (!noflags) { comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */ comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("\t duplicate_carry();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } break; case i_LSR: /* failure; /* NEW: from "Ipswitch Town" release */ mayfail; if (curi->smode==Dreg) { comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n" " FAIL(1);\n" " return;\n" "} \n"); start_brace(); } comprintf("\tdont_care_flags();\n"); genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); if (curi->smode!=immi) { if (!noflags) { uses_cmov; start_brace(); comprintf("\tint highmask;\n" "\tint cdata=scratchie++;\n" "\tint tmpcnt=scratchie++;\n"); comprintf("\tmov_l_rr(tmpcnt,cnt);\n" "\tand_l_ri(tmpcnt,63);\n" "\tmov_l_ri(cdata,0);\n" "\tcmov_l_rr(cdata,data,NATIVE_CC_NE);\n"); /* cdata is now either data (for shift count!=0) or 0 (for shift count==0) */ switch(curi->size) { case sz_byte: comprintf("\tshrl_b_rr(data,tmpcnt);\n" "\thighmask=0x38;\n"); break; case sz_word: comprintf("\tshrl_w_rr(data,tmpcnt);\n" "\thighmask=0x30;\n"); break; case sz_long: comprintf("\tshrl_l_rr(data,tmpcnt);\n" "\thighmask=0x20;\n"); break; default: abort(); } comprintf("\ttest_l_ri(tmpcnt,highmask);\n" "\rmov_l_ri(scratchie,0);\n"); if (curi->size == sz_long) comprintf("\tcmov_l_rr(data,scratchie,NATIVE_CC_NE);\n"); else { comprintf("\tcmov_l_rr(scratchie,data,NATIVE_CC_EQ);\n"); switch(curi->size) { case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break; case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break; default: abort(); } } /* Result of shift is now in data. Now we need to determine the carry by shifting cdata one less */ comprintf("\tsub_l_ri(tmpcnt,1);\n"); comprintf("\tshrl_l_rr(cdata,tmpcnt);\n"); comprintf("\ttest_l_ri(tmpcnt,highmask);\n"); comprintf("\tforget_about(tmpcnt);\n"); if (curi->size != sz_long) /* scratchie is still live for LSR.L */ comprintf("\tmov_l_ri(scratchie,0);\n"); comprintf("\tcmov_l_rr(cdata,scratchie,NATIVE_CC_NE);\n"); comprintf("\tforget_about(scratchie);\n"); /* And create the flags (preserve X flag if shift count is zero) */ comprintf("\ttest_l_ri(cnt,63);\n" "\tcmov_l_rr(FLAGX,cdata,NATIVE_CC_NE);\n"); comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(cdata,0);\n"); /* Set C */ comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } else { uses_cmov; start_brace(); comprintf("\tint highmask;\n"); switch(curi->size) { case sz_byte: comprintf("\tshrl_b_rr(data,cnt);\n" "\thighmask=0x38;\n"); break; case sz_word: comprintf("\tshrl_w_rr(data,cnt);\n" "\thighmask=0x30;\n"); break; case sz_long: comprintf("\tshrl_l_rr(data,cnt);\n" "\thighmask=0x20;\n"); break; default: abort(); } comprintf("test_l_ri(cnt,highmask);\n" "mov_l_ri(scratchie,0);\n" "cmov_l_rr(scratchie,data,4);\n"); switch(curi->size) { case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break; case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break; case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break; default: abort(); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } } else { start_brace(); comprintf("\tint tmp=scratchie++;\n" "\tint bp;\n" "\tmov_l_rr(tmp,data);\n"); switch(curi->size) { case sz_byte: comprintf("\tshrl_b_ri(data,srcreg);\n" "\tbp=srcreg-1;\n"); break; case sz_word: comprintf("\tshrl_w_ri(data,srcreg);\n" "\tbp=srcreg-1;\n"); break; case sz_long: comprintf("\tshrl_l_ri(data,srcreg);\n" "\tbp=srcreg-1;\n"); break; default: abort(); } if (!noflags) { comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */ comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("\t duplicate_carry();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } break; case i_LSL: mayfail; if (curi->smode==Dreg) { comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n" " FAIL(1);\n" " return;\n" "} \n"); start_brace(); } comprintf("\tdont_care_flags();\n"); genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); if (curi->smode!=immi) { /* failure; /* UNTESTED: NEW: from "Ipswitch Town" release */ if (!noflags) { uses_cmov; start_brace(); comprintf("\tint highmask;\n" "\tint cdata=scratchie++;\n" "\tint tmpcnt=scratchie++;\n"); comprintf("\tmov_l_rr(tmpcnt,cnt);\n" "\tand_l_ri(tmpcnt,63);\n" "\tmov_l_ri(cdata,0);\n" "\tcmov_l_rr(cdata,data,NATIVE_CC_NE);\n"); /* cdata is now either data (for shift count!=0) or 0 (for shift count==0) */ switch(curi->size) { case sz_byte: comprintf("\tshll_b_rr(data,tmpcnt);\n" "\thighmask=0x38;\n"); break; case sz_word: comprintf("\tshll_w_rr(data,tmpcnt);\n" "\thighmask=0x30;\n"); break; case sz_long: comprintf("\tshll_l_rr(data,tmpcnt);\n" "\thighmask=0x20;\n"); break; default: abort(); } comprintf("\ttest_l_ri(tmpcnt,highmask);\n" "\tmov_l_ri(scratchie,0);\n"); if (curi->size == sz_long) comprintf("\tcmov_l_rr(data,scratchie,NATIVE_CC_NE);\n"); else { comprintf("\tcmov_l_rr(scratchie,data,NATIVE_CC_EQ);\n"); switch(curi->size) { case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break; case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break; default: abort(); } } /* Result of shift is now in data. Now we need to determine the carry by shifting cdata one less */ comprintf("\tsub_l_ri(tmpcnt,1);\n"); comprintf("\tshll_l_rr(cdata,tmpcnt);\n"); comprintf("\ttest_l_ri(tmpcnt,highmask);\n"); comprintf("\tforget_about(tmpcnt);\n"); if (curi->size != sz_long) /* scratchie is still live for LSL.L */ comprintf("\tmov_l_ri(scratchie,0);\n"); comprintf("\tcmov_l_rr(cdata,scratchie,NATIVE_CC_NE);\n"); comprintf("\tforget_about(scratchie);\n"); /* And create the flags (preserve X flag if shift count is zero) */ switch (curi->size) { case sz_byte: comprintf("\tshrl_l_ri(cdata,7);\n"); break; case sz_word: comprintf("\tshrl_l_ri(cdata,15);\n"); break; case sz_long: comprintf("\tshrl_l_ri(cdata,31);\n"); break; } comprintf("\ttest_l_ri(cnt,63);\n" "\tcmov_l_rr(FLAGX,cdata,NATIVE_CC_NE);\n"); comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(cdata,0);\n"); comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } else { uses_cmov; start_brace(); comprintf("\tint highmask;\n"); switch(curi->size) { case sz_byte: comprintf("\tshll_b_rr(data,cnt);\n" "\thighmask=0x38;\n"); break; case sz_word: comprintf("\tshll_w_rr(data,cnt);\n" "\thighmask=0x30;\n"); break; case sz_long: comprintf("\tshll_l_rr(data,cnt);\n" "\thighmask=0x20;\n"); break; default: abort(); } comprintf("test_l_ri(cnt,highmask);\n" "mov_l_ri(scratchie,0);\n" "cmov_l_rr(scratchie,data,4);\n"); switch(curi->size) { case sz_byte: comprintf("\tmov_b_rr(data,scratchie);\n");break; case sz_word: comprintf("\tmov_w_rr(data,scratchie);\n");break; case sz_long: comprintf("\tmov_l_rr(data,scratchie);\n");break; default: abort(); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } } else { start_brace(); comprintf("\tint tmp=scratchie++;\n" "\tint bp;\n" "\tmov_l_rr(tmp,data);\n"); switch(curi->size) { case sz_byte: comprintf("\tshll_b_ri(data,srcreg);\n" "\tbp=8-srcreg;\n"); break; case sz_word: comprintf("\tshll_w_ri(data,srcreg);\n" "\tbp=16-srcreg;\n"); break; case sz_long: comprintf("\tshll_l_ri(data,srcreg);\n" "\tbp=32-srcreg;\n"); break; default: abort(); } if (!noflags) { comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(tmp,bp);\n"); /* Set C */ comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); comprintf("\t duplicate_carry();\n"); comprintf("if (!(needed_flags & FLAG_CZNV)) dont_care_flags();\n"); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); } break; case i_ROL: mayfail; if (curi->smode==Dreg) { comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n" " FAIL(1);\n" " return;\n" "} \n"); start_brace(); } comprintf("\tdont_care_flags();\n"); genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch(curi->size) { case sz_long: comprintf("\t rol_l_rr(data,cnt);\n"); break; case sz_word: comprintf("\t rol_w_rr(data,cnt);\n"); break; case sz_byte: comprintf("\t rol_b_rr(data,cnt);\n"); break; } if (!noflags) { comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } comprintf("\t bt_l_ri(data,0x00);\n"); /* Set C */ comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); break; case i_ROR: mayfail; if (curi->smode==Dreg) { comprintf("if ((uae_u32)srcreg==(uae_u32)dstreg) {\n" " FAIL(1);\n" " return;\n" "} \n"); start_brace(); } comprintf("\tdont_care_flags();\n"); genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "data", 1, 0); start_brace (); switch(curi->size) { case sz_long: comprintf("\t ror_l_rr(data,cnt);\n"); break; case sz_word: comprintf("\t ror_w_rr(data,cnt);\n"); break; case sz_byte: comprintf("\t ror_b_rr(data,cnt);\n"); break; } if (!noflags) { comprintf("\tstart_needflags();\n"); comprintf("\tif (needed_flags & FLAG_ZNV)\n"); switch(curi->size) { case sz_byte: comprintf("\t test_b_rr(data,data);\n"); break; case sz_word: comprintf("\t test_w_rr(data,data);\n"); break; case sz_long: comprintf("\t test_l_rr(data,data);\n"); break; } switch(curi->size) { case sz_byte: comprintf("\t bt_l_ri(data,0x07);\n"); break; case sz_word: comprintf("\t bt_l_ri(data,0x0f);\n"); break; case sz_long: comprintf("\t bt_l_ri(data,0x1f);\n"); break; } comprintf("\t live_flags();\n"); comprintf("\t end_needflags();\n"); } genastore ("data", curi->dmode, "dstreg", curi->size, "data"); break; case i_ROXL: failure; break; case i_ROXR: failure; break; case i_ASRW: failure; break; case i_ASLW: failure; break; case i_LSRW: failure; break; case i_LSLW: failure; break; case i_ROLW: failure; break; case i_RORW: failure; break; case i_ROXLW: failure; break; case i_ROXRW: failure; break; case i_MOVEC2: isjump; failure; break; case i_MOVE2C: isjump; failure; break; case i_CAS: failure; break; case i_CAS2: failure; break; case i_MOVES: /* ignore DFC and SFC because we have no MMU */ isjump; failure; break; case i_BKPT: /* only needed for hardware emulators */ isjump; failure; break; case i_CALLM: /* not present in 68030 */ isjump; failure; break; case i_RTM: /* not present in 68030 */ isjump; failure; break; case i_TRAPcc: isjump; failure; break; case i_DIVL: isjump; failure; break; case i_MULL: /* failure; /* NEW: from "Ipswitch Town" release */ if (!noflags) { failure; break; } comprintf("\tuae_u16 extra=%s;\n",gen_nextiword()); comprintf("\tint r2=(extra>>12)&7;\n" "\tint tmp=scratchie++;\n"); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); /* The two operands are in dst and r2 */ comprintf("\tif (extra&0x0400) {\n" /* Need full 64 bit result */ "\tint r3=(extra&7);\n" "\tmov_l_rr(r3,dst);\n"); /* operands now in r3 and r2 */ comprintf("\tif (extra&0x0800) { \n" /* signed */ "\t\timul_64_32(r2,r3);\n" "\t} else { \n" "\t\tmul_64_32(r2,r3);\n" "\t} \n"); /* The result is in r2/tmp, with r2 holding the lower 32 bits */ comprintf("\t} else {\n"); /* Only want 32 bit result */ /* operands in dst and r2, result foes into r2 */ /* shouldn't matter whether it's signed or unsigned?!? */ comprintf("\timul_32_32(r2,dst);\n" "\t}\n"); break; case i_BFTST: case i_BFEXTU: case i_BFCHG: case i_BFEXTS: case i_BFCLR: case i_BFFFO: case i_BFSET: case i_BFINS: failure; break; case i_PACK: failure; break; case i_UNPK: failure; break; case i_TAS: failure; break; case i_FPP: uses_fpu; #ifdef USE_JIT_FPU mayfail; comprintf("\tuae_u16 extra=%s;\n",gen_nextiword()); swap_opcode(); comprintf("\tcomp_fpp_opp(opcode,extra);\n"); #else failure; #endif break; case i_FBcc: uses_fpu; #ifdef USE_JIT_FPU isjump; uses_cmov; mayfail; swap_opcode(); comprintf("\tcomp_fbcc_opp(opcode);\n"); #else isjump; failure; #endif break; case i_FDBcc: uses_fpu; isjump; failure; break; case i_FScc: uses_fpu; #ifdef USE_JIT_FPU mayfail; uses_cmov; comprintf("\tuae_u16 extra=%s;\n",gen_nextiword()); swap_opcode(); comprintf("\tcomp_fscc_opp(opcode,extra);\n"); #else failure; #endif break; case i_FTRAPcc: uses_fpu; isjump; failure; break; case i_FSAVE: uses_fpu; failure; break; case i_FRESTORE: uses_fpu; failure; break; case i_CINVL: case i_CINVP: case i_CINVA: isjump; /* Not really, but it's probably a good idea to stop translating at this point */ failure; comprintf ("\tflush_icache();\n"); /* Differentiate a bit more? */ break; case i_CPUSHL: case i_CPUSHP: case i_CPUSHA: isjump; /* Not really, but it's probably a good idea to stop translating at this point */ failure; break; case i_MOVE16: genmov16(opcode, curi); break; case i_EMULOP_RETURN: isjump; failure; break; case i_EMULOP: failure; break; case i_MMUOP: isjump; failure; break; default: abort (); break; } comprintf("%s",endstr); finish_braces (); sync_m68k_pc (); if (global_mayfail) comprintf("\tif (failure) m68k_pc_offset=m68k_pc_offset_thisinst;\n"); return global_failure; } static void generate_includes (FILE * f) { fprintf (f, "#include \"sysdeps.h\"\n"); fprintf (f, "#include \"m68k.h\"\n"); fprintf (f, "#include \"memory.h\"\n"); fprintf (f, "#include \"readcpu.h\"\n"); fprintf (f, "#include \"newcpu.h\"\n"); fprintf (f, "#include \"comptbl.h\"\n"); } static int postfix; static void generate_one_opcode (int rp, int noflags) { uae_u16 smsk, dmsk; const long int opcode = opcode_map[rp]; const char *opcode_str; int aborted=0; int have_srcreg=0; int have_dstreg=0; if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level) return; if (table68k[opcode].handler != -1) return; switch (table68k[opcode].stype) { case 0: smsk = 7; break; case 1: smsk = 255; break; case 2: smsk = 15; break; case 3: smsk = 7; break; case 4: smsk = 7; break; case 5: smsk = 63; break; case 6: smsk = 255; break; case 7: smsk = 3; break; default: abort (); } dmsk = 7; next_cpu_level = -1; if (table68k[opcode].suse && table68k[opcode].smode != imm && table68k[opcode].smode != imm0 && table68k[opcode].smode != imm1 && table68k[opcode].smode != imm2 && table68k[opcode].smode != absw && table68k[opcode].smode != absl && table68k[opcode].smode != PC8r && table68k[opcode].smode != PC16) { have_srcreg=1; if (table68k[opcode].spos == -1) { if (((int) table68k[opcode].sreg) >= 128) comprintf ("\tuae_s32 srcreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].sreg); else comprintf ("\tuae_s32 srcreg = %d;\n", (int) table68k[opcode].sreg); } else { char source[100]; int pos = table68k[opcode].spos; comprintf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); if (pos < 8 && (smsk >> (8 - pos)) != 0) sprintf (source, "(((opcode >> %d) | (opcode << %d)) & %d)", pos ^ 8, 8 - pos, dmsk); else if (pos != 8) sprintf (source, "((opcode >> %d) & %d)", pos ^ 8, smsk); else sprintf (source, "(opcode & %d)", smsk); if (table68k[opcode].stype == 3) comprintf ("\tuae_u32 srcreg = imm8_table[%s];\n", source); else if (table68k[opcode].stype == 1) comprintf ("\tuae_u32 srcreg = (uae_s32)(uae_s8)%s;\n", source); else comprintf ("\tuae_u32 srcreg = %s;\n", source); comprintf ("#else\n"); if (pos) sprintf (source, "((opcode >> %d) & %d)", pos, smsk); else sprintf (source, "(opcode & %d)", smsk); if (table68k[opcode].stype == 3) comprintf ("\tuae_s32 srcreg = imm8_table[%s];\n", source); else if (table68k[opcode].stype == 1) comprintf ("\tuae_s32 srcreg = (uae_s32)(uae_s8)%s;\n", source); else comprintf ("\tuae_s32 srcreg = %s;\n", source); comprintf ("#endif\n"); } } if (table68k[opcode].duse /* Yes, the dmode can be imm, in case of LINK or DBcc */ && table68k[opcode].dmode != imm && table68k[opcode].dmode != imm0 && table68k[opcode].dmode != imm1 && table68k[opcode].dmode != imm2 && table68k[opcode].dmode != absw && table68k[opcode].dmode != absl) { have_dstreg=1; if (table68k[opcode].dpos == -1) { if (((int) table68k[opcode].dreg) >= 128) comprintf ("\tuae_s32 dstreg = (uae_s32)(uae_s8)%d;\n", (int) table68k[opcode].dreg); else comprintf ("\tuae_s32 dstreg = %d;\n", (int) table68k[opcode].dreg); } else { int pos = table68k[opcode].dpos; comprintf ("#ifdef HAVE_GET_WORD_UNSWAPPED\n"); if (pos < 8 && (dmsk >> (8 - pos)) != 0) comprintf ("\tuae_u32 dstreg = ((opcode >> %d) | (opcode << %d)) & %d;\n", pos ^ 8, 8 - pos, dmsk); else if (pos != 8) comprintf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n", pos ^ 8, dmsk); else comprintf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk); comprintf ("#else\n"); if (pos) comprintf ("\tuae_u32 dstreg = (opcode >> %d) & %d;\n", pos, dmsk); else comprintf ("\tuae_u32 dstreg = opcode & %d;\n", dmsk); comprintf ("#endif\n"); } } if (have_srcreg && have_dstreg && (table68k[opcode].dmode==Areg || table68k[opcode].dmode==Aind || table68k[opcode].dmode==Aipi || table68k[opcode].dmode==Apdi || table68k[opcode].dmode==Ad16 || table68k[opcode].dmode==Ad8r) && (table68k[opcode].smode==Areg || table68k[opcode].smode==Aind || table68k[opcode].smode==Aipi || table68k[opcode].smode==Apdi || table68k[opcode].smode==Ad16 || table68k[opcode].smode==Ad8r) ) { comprintf("\tuae_u32 dodgy=(srcreg==(uae_s32)dstreg);\n"); } else { comprintf("\tuae_u32 dodgy=0;\n"); } comprintf("\tuae_u32 m68k_pc_offset_thisinst=m68k_pc_offset;\n"); comprintf("\tm68k_pc_offset+=2;\n"); opcode_str = get_instruction_string (opcode); aborted=gen_opcode (opcode); { int flags=0; if (global_isjump) flags|=1; if (long_opcode) flags|=2; if (global_cmov) flags|=4; if (global_isaddx) flags|=8; if (global_iscjump) flags|=16; if (global_fpu) flags|=32; comprintf ("}\n"); if (aborted) { fprintf (stblfile, "{ NULL, 0x%08x, %ld }, /* %s */\n", flags, opcode, opcode_str); com_discard(); } else { if (noflags) { fprintf (stblfile, "{ op_%lx_%d_comp_nf, 0x%08x, %ld }, /* %s */\n", opcode, postfix, flags, opcode, opcode_str); fprintf (headerfile, "extern compop_func op_%lx_%d_comp_nf;\n", opcode, postfix); printf ("void REGPARAM2 op_%lx_%d_comp_nf(uae_u32 opcode) /* %s */\n{\n", opcode, postfix, opcode_str); } else { fprintf (stblfile, "{ op_%lx_%d_comp_ff, 0x%08x, %ld }, /* %s */\n", opcode, postfix, flags, opcode, opcode_str); fprintf (headerfile, "extern compop_func op_%lx_%d_comp_ff;\n", opcode, postfix); printf ("void REGPARAM2 op_%lx_%d_comp_ff(uae_u32 opcode) /* %s */\n{\n", opcode, postfix, opcode_str); } com_flush(); } } opcode_next_clev[rp] = next_cpu_level; opcode_last_postfix[rp] = postfix; } static void generate_func (int noflags) { int i, j, rp; using_prefetch = 0; using_exception_3 = 0; for (i = 0; i < 1; i++) /* We only do one level! */ { cpu_level = 4 - i; postfix = i; if (noflags) fprintf (stblfile, "struct comptbl op_smalltbl_%d_comp_nf[] = {\n", postfix); else fprintf (stblfile, "struct comptbl op_smalltbl_%d_comp_ff[] = {\n", postfix); /* sam: this is for people with low memory (eg. me :)) */ !printf ("\n" "#if !defined(PART_1) && !defined(PART_2) && " "!defined(PART_3) && !defined(PART_4) && " "!defined(PART_5) && !defined(PART_6) && " "!defined(PART_7) && !defined(PART_8)" "\n" "#define PART_1 1\n" "#define PART_2 1\n" "#define PART_3 1\n" "#define PART_4 1\n" "#define PART_5 1\n" "#define PART_6 1\n" "#define PART_7 1\n" "#define PART_8 1\n" "#endif\n\n"); rp = 0; for (j = 1; j <= 8; ++j) { int k = (j * nr_cpuop_funcs) / 8; printf ("#ifdef PART_%d\n", j); for (; rp < k; rp++) generate_one_opcode (rp,noflags); printf ("#endif\n\n"); } fprintf (stblfile, "{ 0, 0,65536 }};\n"); } } int main (int argc, char **argv) { read_table68k (); do_merges (); opcode_map = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_last_postfix = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_next_clev = (int *) malloc (sizeof (int) * nr_cpuop_funcs); counts = (unsigned long *) malloc (65536 * sizeof (unsigned long)); read_counts (); /* It would be a lot nicer to put all in one file (we'd also get rid of * cputbl.h that way), but cpuopti can't cope. That could be fixed, but * I don't dare to touch the 68k version. */ headerfile = fopen ("comptbl.h", "wb"); stblfile = fopen ("compstbl.cpp", "wb"); freopen ("compemu.cpp", "wb", stdout); generate_includes (stdout); generate_includes (stblfile); printf("#include \"compiler/compemu.h\"\n"); noflags=0; generate_func (noflags); free(opcode_map); free(opcode_last_postfix); free(opcode_next_clev); free(counts); opcode_map = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_last_postfix = (int *) malloc (sizeof (int) * nr_cpuop_funcs); opcode_next_clev = (int *) malloc (sizeof (int) * nr_cpuop_funcs); counts = (unsigned long *) malloc (65536 * sizeof (unsigned long)); read_counts (); noflags=1; generate_func (noflags); free(opcode_map); free(opcode_last_postfix); free(opcode_next_clev); free(counts); free (table68k); fclose (stblfile); fclose (headerfile); fflush (stdout); return 0; } BasiliskII/src/uae_cpu/compiler/compemu_support.cpp0000644000175000017500000046117310736405223022746 0ustar centriscentris/* * compiler/compemu_support.cpp - Core dynamic translation engine * * Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer * * Adaptation for Basilisk II and improvements, copyright 2000-2005 * Gwenole Beauchesne * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #if !REAL_ADDRESSING && !DIRECT_ADDRESSING #error "Only Real or Direct Addressing is supported with the JIT Compiler" #endif #if X86_ASSEMBLY && !SAHF_SETO_PROFITABLE #error "Only [LS]AHF scheme to [gs]et flags is supported with the JIT Compiler" #endif /* NOTE: support for AMD64 assumes translation cache and other code * buffers are allocated into a 32-bit address space because (i) B2/JIT * code is not 64-bit clean and (ii) it's faster to resolve branches * that way. */ #if !defined(__i386__) && !defined(__x86_64__) #error "Only IA-32 and X86-64 targets are supported with the JIT Compiler" #endif #define USE_MATCH 0 /* kludge for Brian, so he can compile under MSVC++ */ #define USE_NORMAL_CALLING_CONVENTION 0 #ifndef WIN32 #include #include #include #endif #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "user_strings.h" #include "vm_alloc.h" #include "m68k.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" #include "comptbl.h" #include "compiler/compemu.h" #include "fpu/fpu.h" #include "fpu/flags.h" #define DEBUG 1 #include "debug.h" #ifdef ENABLE_MON #include "mon.h" #endif #ifndef WIN32 #define PROFILE_COMPILE_TIME 1 #define PROFILE_UNTRANSLATED_INSNS 1 #endif #if defined(__x86_64__) && 0 #define RECORD_REGISTER_USAGE 1 #endif #ifdef WIN32 #undef write_log #define write_log dummy_write_log static void dummy_write_log(const char *, ...) { } #endif #if JIT_DEBUG #undef abort #define abort() do { \ fprintf(stderr, "Abort in file %s at line %d\n", __FILE__, __LINE__); \ exit(EXIT_FAILURE); \ } while (0) #endif #if RECORD_REGISTER_USAGE static uint64 reg_count[16]; static int reg_count_local[16]; static int reg_count_compare(const void *ap, const void *bp) { const int a = *((int *)ap); const int b = *((int *)bp); return reg_count[b] - reg_count[a]; } #endif #if PROFILE_COMPILE_TIME #include static uae_u32 compile_count = 0; static clock_t compile_time = 0; static clock_t emul_start_time = 0; static clock_t emul_end_time = 0; #endif #if PROFILE_UNTRANSLATED_INSNS const int untranslated_top_ten = 20; static uae_u32 raw_cputbl_count[65536] = { 0, }; static uae_u16 opcode_nums[65536]; static int untranslated_compfn(const void *e1, const void *e2) { return raw_cputbl_count[*(const uae_u16 *)e1] < raw_cputbl_count[*(const uae_u16 *)e2]; } #endif static compop_func *compfunctbl[65536]; static compop_func *nfcompfunctbl[65536]; static cpuop_func *nfcpufunctbl[65536]; uae_u8* comp_pc_p; // From newcpu.cpp extern bool quit_program; // gb-- Extra data for Basilisk II/JIT #if JIT_DEBUG static bool JITDebug = false; // Enable runtime disassemblers through mon? #else const bool JITDebug = false; // Don't use JIT debug mode at all #endif #if USE_INLINING static bool follow_const_jumps = true; // Flag: translation through constant jumps #else const bool follow_const_jumps = false; #endif const uae_u32 MIN_CACHE_SIZE = 1024; // Minimal translation cache size (1 MB) static uae_u32 cache_size = 0; // Size of total cache allocated for compiled blocks static uae_u32 current_cache_size = 0; // Cache grows upwards: how much has been consumed already static bool lazy_flush = true; // Flag: lazy translation cache invalidation static bool avoid_fpu = true; // Flag: compile FPU instructions ? static bool have_cmov = false; // target has CMOV instructions ? static bool have_lahf_lm = true; // target has LAHF supported in long mode ? static bool have_rat_stall = true; // target has partial register stalls ? const bool tune_alignment = true; // Tune code alignments for running CPU ? const bool tune_nop_fillers = true; // Tune no-op fillers for architecture static bool setzflg_uses_bsf = false; // setzflg virtual instruction can use native BSF instruction correctly? static int align_loops = 32; // Align the start of loops static int align_jumps = 32; // Align the start of jumps static int optcount[10] = { 10, // How often a block has to be executed before it is translated 0, // How often to use naive translation 0, 0, 0, 0, -1, -1, -1, -1 }; struct op_properties { uae_u8 use_flags; uae_u8 set_flags; uae_u8 is_addx; uae_u8 cflow; }; static op_properties prop[65536]; static inline int end_block(uae_u32 opcode) { return (prop[opcode].cflow & fl_end_block); } static inline bool is_const_jump(uae_u32 opcode) { return (prop[opcode].cflow == fl_const_jump); } static inline bool may_trap(uae_u32 opcode) { return (prop[opcode].cflow & fl_trap); } static inline unsigned int cft_map (unsigned int f) { #ifndef HAVE_GET_WORD_UNSWAPPED return f; #else return ((f >> 8) & 255) | ((f & 255) << 8); #endif } uae_u8* start_pc_p; uae_u32 start_pc; uae_u32 current_block_pc_p; static uintptr current_block_start_target; uae_u32 needed_flags; static uintptr next_pc_p; static uintptr taken_pc_p; static int branch_cc; static int redo_current_block; int segvcount=0; int soft_flush_count=0; int hard_flush_count=0; int checksum_count=0; static uae_u8* current_compile_p=NULL; static uae_u8* max_compile_start; static uae_u8* compiled_code=NULL; static uae_s32 reg_alloc_run; const int POPALLSPACE_SIZE = 1024; /* That should be enough space */ static uae_u8* popallspace=NULL; void* pushall_call_handler=NULL; static void* popall_do_nothing=NULL; static void* popall_exec_nostats=NULL; static void* popall_execute_normal=NULL; static void* popall_cache_miss=NULL; static void* popall_recompile_block=NULL; static void* popall_check_checksum=NULL; /* The 68k only ever executes from even addresses. So right now, we * waste half the entries in this array * UPDATE: We now use those entries to store the start of the linked * lists that we maintain for each hash result. */ cacheline cache_tags[TAGSIZE]; int letit=0; blockinfo* hold_bi[MAX_HOLD_BI]; blockinfo* active; blockinfo* dormant; /* 68040 */ extern struct cputbl op_smalltbl_0_nf[]; extern struct comptbl op_smalltbl_0_comp_nf[]; extern struct comptbl op_smalltbl_0_comp_ff[]; /* 68020 + 68881 */ extern struct cputbl op_smalltbl_1_nf[]; /* 68020 */ extern struct cputbl op_smalltbl_2_nf[]; /* 68010 */ extern struct cputbl op_smalltbl_3_nf[]; /* 68000 */ extern struct cputbl op_smalltbl_4_nf[]; /* 68000 slow but compatible. */ extern struct cputbl op_smalltbl_5_nf[]; static void flush_icache_hard(int n); static void flush_icache_lazy(int n); static void flush_icache_none(int n); void (*flush_icache)(int n) = flush_icache_none; bigstate live; smallstate empty_ss; smallstate default_ss; static int optlev; static int writereg(int r, int size); static void unlock2(int r); static void setlock(int r); static int readreg_specific(int r, int size, int spec); static int writereg_specific(int r, int size, int spec); static void prepare_for_call_1(void); static void prepare_for_call_2(void); static void align_target(uae_u32 a); static uae_s32 nextused[VREGS]; uae_u32 m68k_pc_offset; /* Some arithmetic ooperations can be optimized away if the operands * are known to be constant. But that's only a good idea when the * side effects they would have on the flags are not important. This * variable indicates whether we need the side effects or not */ uae_u32 needflags=0; /* Flag handling is complicated. * * x86 instructions create flags, which quite often are exactly what we * want. So at times, the "68k" flags are actually in the x86 flags. * * Then again, sometimes we do x86 instructions that clobber the x86 * flags, but don't represent a corresponding m68k instruction. In that * case, we have to save them. * * We used to save them to the stack, but now store them back directly * into the regflags.cznv of the traditional emulation. Thus some odd * names. * * So flags can be in either of two places (used to be three; boy were * things complicated back then!); And either place can contain either * valid flags or invalid trash (and on the stack, there was also the * option of "nothing at all", now gone). A couple of variables keep * track of the respective states. * * To make things worse, we might or might not be interested in the flags. * by default, we are, but a call to dont_care_flags can change that * until the next call to live_flags. If we are not, pretty much whatever * is in the register and/or the native flags is seen as valid. */ static __inline__ blockinfo* get_blockinfo(uae_u32 cl) { return cache_tags[cl+1].bi; } static __inline__ blockinfo* get_blockinfo_addr(void* addr) { blockinfo* bi=get_blockinfo(cacheline(addr)); while (bi) { if (bi->pc_p==addr) return bi; bi=bi->next_same_cl; } return NULL; } /******************************************************************* * All sorts of list related functions for all of the lists * *******************************************************************/ static __inline__ void remove_from_cl_list(blockinfo* bi) { uae_u32 cl=cacheline(bi->pc_p); if (bi->prev_same_cl_p) *(bi->prev_same_cl_p)=bi->next_same_cl; if (bi->next_same_cl) bi->next_same_cl->prev_same_cl_p=bi->prev_same_cl_p; if (cache_tags[cl+1].bi) cache_tags[cl].handler=cache_tags[cl+1].bi->handler_to_use; else cache_tags[cl].handler=(cpuop_func *)popall_execute_normal; } static __inline__ void remove_from_list(blockinfo* bi) { if (bi->prev_p) *(bi->prev_p)=bi->next; if (bi->next) bi->next->prev_p=bi->prev_p; } static __inline__ void remove_from_lists(blockinfo* bi) { remove_from_list(bi); remove_from_cl_list(bi); } static __inline__ void add_to_cl_list(blockinfo* bi) { uae_u32 cl=cacheline(bi->pc_p); if (cache_tags[cl+1].bi) cache_tags[cl+1].bi->prev_same_cl_p=&(bi->next_same_cl); bi->next_same_cl=cache_tags[cl+1].bi; cache_tags[cl+1].bi=bi; bi->prev_same_cl_p=&(cache_tags[cl+1].bi); cache_tags[cl].handler=bi->handler_to_use; } static __inline__ void raise_in_cl_list(blockinfo* bi) { remove_from_cl_list(bi); add_to_cl_list(bi); } static __inline__ void add_to_active(blockinfo* bi) { if (active) active->prev_p=&(bi->next); bi->next=active; active=bi; bi->prev_p=&active; } static __inline__ void add_to_dormant(blockinfo* bi) { if (dormant) dormant->prev_p=&(bi->next); bi->next=dormant; dormant=bi; bi->prev_p=&dormant; } static __inline__ void remove_dep(dependency* d) { if (d->prev_p) *(d->prev_p)=d->next; if (d->next) d->next->prev_p=d->prev_p; d->prev_p=NULL; d->next=NULL; } /* This block's code is about to be thrown away, so it no longer depends on anything else */ static __inline__ void remove_deps(blockinfo* bi) { remove_dep(&(bi->dep[0])); remove_dep(&(bi->dep[1])); } static __inline__ void adjust_jmpdep(dependency* d, cpuop_func* a) { *(d->jmp_off)=(uintptr)a-((uintptr)d->jmp_off+4); } /******************************************************************** * Soft flush handling support functions * ********************************************************************/ static __inline__ void set_dhtu(blockinfo* bi, cpuop_func* dh) { //write_log("bi is %p\n",bi); if (dh!=bi->direct_handler_to_use) { dependency* x=bi->deplist; //write_log("bi->deplist=%p\n",bi->deplist); while (x) { //write_log("x is %p\n",x); //write_log("x->next is %p\n",x->next); //write_log("x->prev_p is %p\n",x->prev_p); if (x->jmp_off) { adjust_jmpdep(x,dh); } x=x->next; } bi->direct_handler_to_use=dh; } } static __inline__ void invalidate_block(blockinfo* bi) { int i; bi->optlevel=0; bi->count=optcount[0]-1; bi->handler=NULL; bi->handler_to_use=(cpuop_func *)popall_execute_normal; bi->direct_handler=NULL; set_dhtu(bi,bi->direct_pen); bi->needed_flags=0xff; bi->status=BI_INVALID; for (i=0;i<2;i++) { bi->dep[i].jmp_off=NULL; bi->dep[i].target=NULL; } remove_deps(bi); } static __inline__ void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target) { blockinfo* tbi=get_blockinfo_addr((void*)(uintptr)target); Dif(!tbi) { write_log("Could not create jmpdep!\n"); abort(); } bi->dep[i].jmp_off=jmpaddr; bi->dep[i].source=bi; bi->dep[i].target=tbi; bi->dep[i].next=tbi->deplist; if (bi->dep[i].next) bi->dep[i].next->prev_p=&(bi->dep[i].next); bi->dep[i].prev_p=&(tbi->deplist); tbi->deplist=&(bi->dep[i]); } static __inline__ void block_need_recompile(blockinfo * bi) { uae_u32 cl = cacheline(bi->pc_p); set_dhtu(bi, bi->direct_pen); bi->direct_handler = bi->direct_pen; bi->handler_to_use = (cpuop_func *)popall_execute_normal; bi->handler = (cpuop_func *)popall_execute_normal; if (bi == cache_tags[cl + 1].bi) cache_tags[cl].handler = (cpuop_func *)popall_execute_normal; bi->status = BI_NEED_RECOMP; } static __inline__ void mark_callers_recompile(blockinfo * bi) { dependency *x = bi->deplist; while (x) { dependency *next = x->next; /* This disappears when we mark for * recompilation and thus remove the * blocks from the lists */ if (x->jmp_off) { blockinfo *cbi = x->source; Dif(cbi->status == BI_INVALID) { // write_log("invalid block in dependency list\n"); // FIXME? // abort(); } if (cbi->status == BI_ACTIVE || cbi->status == BI_NEED_CHECK) { block_need_recompile(cbi); mark_callers_recompile(cbi); } else if (cbi->status == BI_COMPILING) { redo_current_block = 1; } else if (cbi->status == BI_NEED_RECOMP) { /* nothing */ } else { //write_log("Status %d in mark_callers\n",cbi->status); // FIXME? } } x = next; } } static __inline__ blockinfo* get_blockinfo_addr_new(void* addr, int setstate) { blockinfo* bi=get_blockinfo_addr(addr); int i; if (!bi) { for (i=0;ipc_p=(uae_u8 *)addr; invalidate_block(bi); add_to_active(bi); add_to_cl_list(bi); } } } if (!bi) { write_log("Looking for blockinfo, can't find free one\n"); abort(); } return bi; } static void prepare_block(blockinfo* bi); /* Managment of blockinfos. A blockinfo struct is allocated whenever a new block has to be compiled. If the list of free blockinfos is empty, we allocate a new pool of blockinfos and link the newly created blockinfos altogether into the list of free blockinfos. Otherwise, we simply pop a structure off the free list. Blockinfo are lazily deallocated, i.e. chained altogether in the list of free blockinfos whenvever a translation cache flush (hard or soft) request occurs. */ template< class T > class LazyBlockAllocator { enum { kPoolSize = 1 + 4096 / sizeof(T) }; struct Pool { T chunk[kPoolSize]; Pool * next; }; Pool * mPools; T * mChunks; public: LazyBlockAllocator() : mPools(0), mChunks(0) { } ~LazyBlockAllocator(); T * acquire(); void release(T * const); }; template< class T > LazyBlockAllocator::~LazyBlockAllocator() { Pool * currentPool = mPools; while (currentPool) { Pool * deadPool = currentPool; currentPool = currentPool->next; free(deadPool); } } template< class T > T * LazyBlockAllocator::acquire() { if (!mChunks) { // There is no chunk left, allocate a new pool and link the // chunks into the free list Pool * newPool = (Pool *)malloc(sizeof(Pool)); for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) { chunk->next = mChunks; mChunks = chunk; } newPool->next = mPools; mPools = newPool; } T * chunk = mChunks; mChunks = chunk->next; return chunk; } template< class T > void LazyBlockAllocator::release(T * const chunk) { chunk->next = mChunks; mChunks = chunk; } template< class T > class HardBlockAllocator { public: T * acquire() { T * data = (T *)current_compile_p; current_compile_p += sizeof(T); return data; } void release(T * const chunk) { // Deallocated on invalidation } }; #if USE_SEPARATE_BIA static LazyBlockAllocator BlockInfoAllocator; static LazyBlockAllocator ChecksumInfoAllocator; #else static HardBlockAllocator BlockInfoAllocator; static HardBlockAllocator ChecksumInfoAllocator; #endif static __inline__ checksum_info *alloc_checksum_info(void) { checksum_info *csi = ChecksumInfoAllocator.acquire(); csi->next = NULL; return csi; } static __inline__ void free_checksum_info(checksum_info *csi) { csi->next = NULL; ChecksumInfoAllocator.release(csi); } static __inline__ void free_checksum_info_chain(checksum_info *csi) { while (csi != NULL) { checksum_info *csi2 = csi->next; free_checksum_info(csi); csi = csi2; } } static __inline__ blockinfo *alloc_blockinfo(void) { blockinfo *bi = BlockInfoAllocator.acquire(); #if USE_CHECKSUM_INFO bi->csi = NULL; #endif return bi; } static __inline__ void free_blockinfo(blockinfo *bi) { #if USE_CHECKSUM_INFO free_checksum_info_chain(bi->csi); bi->csi = NULL; #endif BlockInfoAllocator.release(bi); } static __inline__ void alloc_blockinfos(void) { int i; blockinfo* bi; for (i=0;i>24)&0xff) | ((v>>8)&0xff00) | ((v<<8)&0xff0000) | ((v<<24)&0xff000000); #endif } /******************************************************************** * Getting the information about the target CPU * ********************************************************************/ #include "codegen_x86.cpp" void set_target(uae_u8* t) { target=t; } static __inline__ uae_u8* get_target_noopt(void) { return target; } __inline__ uae_u8* get_target(void) { return get_target_noopt(); } /******************************************************************** * Flags status handling. EMIT TIME! * ********************************************************************/ static void bt_l_ri_noclobber(R4 r, IMM i); static void make_flags_live_internal(void) { if (live.flags_in_flags==VALID) return; Dif (live.flags_on_stack==TRASH) { write_log("Want flags, got something on stack, but it is TRASH\n"); abort(); } if (live.flags_on_stack==VALID) { int tmp; tmp=readreg_specific(FLAGTMP,4,FLAG_NREG2); raw_reg_to_flags(tmp); unlock2(tmp); live.flags_in_flags=VALID; return; } write_log("Huh? live.flags_in_flags=%d, live.flags_on_stack=%d, but need to make live\n", live.flags_in_flags,live.flags_on_stack); abort(); } static void flags_to_stack(void) { if (live.flags_on_stack==VALID) return; if (!live.flags_are_important) { live.flags_on_stack=VALID; return; } Dif (live.flags_in_flags!=VALID) abort(); else { int tmp; tmp=writereg_specific(FLAGTMP,4,FLAG_NREG1); raw_flags_to_reg(tmp); unlock2(tmp); } live.flags_on_stack=VALID; } static __inline__ void clobber_flags(void) { if (live.flags_in_flags==VALID && live.flags_on_stack!=VALID) flags_to_stack(); live.flags_in_flags=TRASH; } /* Prepare for leaving the compiled stuff */ static __inline__ void flush_flags(void) { flags_to_stack(); return; } int touchcnt; /******************************************************************** * Partial register flushing for optimized calls * ********************************************************************/ struct regusage { uae_u16 rmask; uae_u16 wmask; }; static inline void ru_set(uae_u16 *mask, int reg) { #if USE_OPTIMIZED_CALLS *mask |= 1 << reg; #endif } static inline bool ru_get(const uae_u16 *mask, int reg) { #if USE_OPTIMIZED_CALLS return (*mask & (1 << reg)); #else /* Default: instruction reads & write to register */ return true; #endif } static inline void ru_set_read(regusage *ru, int reg) { ru_set(&ru->rmask, reg); } static inline void ru_set_write(regusage *ru, int reg) { ru_set(&ru->wmask, reg); } static inline bool ru_read_p(const regusage *ru, int reg) { return ru_get(&ru->rmask, reg); } static inline bool ru_write_p(const regusage *ru, int reg) { return ru_get(&ru->wmask, reg); } static void ru_fill_ea(regusage *ru, int reg, amodes mode, wordsizes size, int write_mode) { switch (mode) { case Areg: reg += 8; /* fall through */ case Dreg: ru_set(write_mode ? &ru->wmask : &ru->rmask, reg); break; case Ad16: /* skip displacment */ m68k_pc_offset += 2; case Aind: case Aipi: case Apdi: ru_set_read(ru, reg+8); break; case Ad8r: ru_set_read(ru, reg+8); /* fall through */ case PC8r: { uae_u16 dp = comp_get_iword((m68k_pc_offset+=2)-2); reg = (dp >> 12) & 15; ru_set_read(ru, reg); if (dp & 0x100) m68k_pc_offset += (((dp & 0x30) >> 3) & 7) + ((dp & 3) * 2); break; } case PC16: case absw: case imm0: case imm1: m68k_pc_offset += 2; break; case absl: case imm2: m68k_pc_offset += 4; break; case immi: m68k_pc_offset += (size == sz_long) ? 4 : 2; break; } } /* TODO: split into a static initialization part and a dynamic one (instructions depending on extension words) */ static void ru_fill(regusage *ru, uae_u32 opcode) { m68k_pc_offset += 2; /* Default: no register is used or written to */ ru->rmask = 0; ru->wmask = 0; uae_u32 real_opcode = cft_map(opcode); struct instr *dp = &table68k[real_opcode]; bool rw_dest = true; bool handled = false; /* Handle some instructions specifically */ uae_u16 reg, ext; switch (dp->mnemo) { case i_BFCHG: case i_BFCLR: case i_BFEXTS: case i_BFEXTU: case i_BFFFO: case i_BFINS: case i_BFSET: case i_BFTST: ext = comp_get_iword((m68k_pc_offset+=2)-2); if (ext & 0x800) ru_set_read(ru, (ext >> 6) & 7); if (ext & 0x020) ru_set_read(ru, ext & 7); ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1); if (dp->dmode == Dreg) ru_set_read(ru, dp->dreg); switch (dp->mnemo) { case i_BFEXTS: case i_BFEXTU: case i_BFFFO: ru_set_write(ru, (ext >> 12) & 7); break; case i_BFINS: ru_set_read(ru, (ext >> 12) & 7); /* fall through */ case i_BFCHG: case i_BFCLR: case i_BSET: if (dp->dmode == Dreg) ru_set_write(ru, dp->dreg); break; } handled = true; rw_dest = false; break; case i_BTST: rw_dest = false; break; case i_CAS: { ext = comp_get_iword((m68k_pc_offset+=2)-2); int Du = ext & 7; ru_set_read(ru, Du); int Dc = (ext >> 6) & 7; ru_set_read(ru, Dc); ru_set_write(ru, Dc); break; } case i_CAS2: { int Dc1, Dc2, Du1, Du2, Rn1, Rn2; ext = comp_get_iword((m68k_pc_offset+=2)-2); Rn1 = (ext >> 12) & 15; Du1 = (ext >> 6) & 7; Dc1 = ext & 7; ru_set_read(ru, Rn1); ru_set_read(ru, Du1); ru_set_read(ru, Dc1); ru_set_write(ru, Dc1); ext = comp_get_iword((m68k_pc_offset+=2)-2); Rn2 = (ext >> 12) & 15; Du2 = (ext >> 6) & 7; Dc2 = ext & 7; ru_set_read(ru, Rn2); ru_set_read(ru, Du2); ru_set_write(ru, Dc2); break; } case i_DIVL: case i_MULL: m68k_pc_offset += 2; break; case i_LEA: case i_MOVE: case i_MOVEA: case i_MOVE16: rw_dest = false; break; case i_PACK: case i_UNPK: rw_dest = false; m68k_pc_offset += 2; break; case i_TRAPcc: m68k_pc_offset += (dp->size == sz_long) ? 4 : 2; break; case i_RTR: /* do nothing, just for coverage debugging */ break; /* TODO: handle EXG instruction */ } /* Handle A-Traps better */ if ((real_opcode & 0xf000) == 0xa000) { handled = true; } /* Handle EmulOps better */ if ((real_opcode & 0xff00) == 0x7100) { handled = true; ru->rmask = 0xffff; ru->wmask = 0; } if (dp->suse && !handled) ru_fill_ea(ru, dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0); if (dp->duse && !handled) ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1); if (rw_dest) ru->rmask |= ru->wmask; handled = handled || dp->suse || dp->duse; /* Mark all registers as used/written if the instruction may trap */ if (may_trap(opcode)) { handled = true; ru->rmask = 0xffff; ru->wmask = 0xffff; } if (!handled) { write_log("ru_fill: %04x = { %04x, %04x }\n", real_opcode, ru->rmask, ru->wmask); abort(); } } /******************************************************************** * register allocation per block logging * ********************************************************************/ static uae_s8 vstate[VREGS]; static uae_s8 vwritten[VREGS]; static uae_s8 nstate[N_REGS]; #define L_UNKNOWN -127 #define L_UNAVAIL -1 #define L_NEEDED -2 #define L_UNNEEDED -3 static __inline__ void big_to_small_state(bigstate * b, smallstate * s) { int i; for (i = 0; i < VREGS; i++) s->virt[i] = vstate[i]; for (i = 0; i < N_REGS; i++) s->nat[i] = nstate[i]; } static __inline__ int callers_need_recompile(bigstate * b, smallstate * s) { int i; int reverse = 0; for (i = 0; i < VREGS; i++) { if (vstate[i] != L_UNNEEDED && s->virt[i] == L_UNNEEDED) return 1; if (vstate[i] == L_UNNEEDED && s->virt[i] != L_UNNEEDED) reverse++; } for (i = 0; i < N_REGS; i++) { if (nstate[i] >= 0 && nstate[i] != s->nat[i]) return 1; if (nstate[i] < 0 && s->nat[i] >= 0) reverse++; } if (reverse >= 2 && USE_MATCH) return 1; /* In this case, it might be worth recompiling the * callers */ return 0; } static __inline__ void log_startblock(void) { int i; for (i = 0; i < VREGS; i++) { vstate[i] = L_UNKNOWN; vwritten[i] = 0; } for (i = 0; i < N_REGS; i++) nstate[i] = L_UNKNOWN; } /* Using an n-reg for a temp variable */ static __inline__ void log_isused(int n) { if (nstate[n] == L_UNKNOWN) nstate[n] = L_UNAVAIL; } static __inline__ void log_visused(int r) { if (vstate[r] == L_UNKNOWN) vstate[r] = L_NEEDED; } static __inline__ void do_load_reg(int n, int r) { if (r == FLAGTMP) raw_load_flagreg(n, r); else if (r == FLAGX) raw_load_flagx(n, r); else raw_mov_l_rm(n, (uintptr) live.state[r].mem); } static __inline__ void check_load_reg(int n, int r) { raw_mov_l_rm(n, (uintptr) live.state[r].mem); } static __inline__ void log_vwrite(int r) { vwritten[r] = 1; } /* Using an n-reg to hold a v-reg */ static __inline__ void log_isreg(int n, int r) { static int count = 0; if (nstate[n] == L_UNKNOWN && r < 16 && !vwritten[r] && USE_MATCH) nstate[n] = r; else { do_load_reg(n, r); if (nstate[n] == L_UNKNOWN) nstate[n] = L_UNAVAIL; } if (vstate[r] == L_UNKNOWN) vstate[r] = L_NEEDED; } static __inline__ void log_clobberreg(int r) { if (vstate[r] == L_UNKNOWN) vstate[r] = L_UNNEEDED; } /* This ends all possibility of clever register allocation */ static __inline__ void log_flush(void) { int i; for (i = 0; i < VREGS; i++) if (vstate[i] == L_UNKNOWN) vstate[i] = L_NEEDED; for (i = 0; i < N_REGS; i++) if (nstate[i] == L_UNKNOWN) nstate[i] = L_UNAVAIL; } static __inline__ void log_dump(void) { int i; return; write_log("----------------------\n"); for (i = 0; i < N_REGS; i++) { switch (nstate[i]) { case L_UNKNOWN: write_log("Nat %d : UNKNOWN\n", i); break; case L_UNAVAIL: write_log("Nat %d : UNAVAIL\n", i); break; default: write_log("Nat %d : %d\n", i, nstate[i]); break; } } for (i = 0; i < VREGS; i++) { if (vstate[i] == L_UNNEEDED) write_log("Virt %d: UNNEEDED\n", i); } } /******************************************************************** * register status handling. EMIT TIME! * ********************************************************************/ static __inline__ void set_status(int r, int status) { if (status == ISCONST) log_clobberreg(r); live.state[r].status=status; } static __inline__ int isinreg(int r) { return live.state[r].status==CLEAN || live.state[r].status==DIRTY; } static __inline__ void adjust_nreg(int r, uae_u32 val) { if (!val) return; raw_lea_l_brr(r,r,val); } static void tomem(int r) { int rr=live.state[r].realreg; if (isinreg(r)) { if (live.state[r].val && live.nat[rr].nholds==1 && !live.nat[rr].locked) { // write_log("RemovingA offset %x from reg %d (%d) at %p\n", // live.state[r].val,r,rr,target); adjust_nreg(rr,live.state[r].val); live.state[r].val=0; live.state[r].dirtysize=4; set_status(r,DIRTY); } } if (live.state[r].status==DIRTY) { switch (live.state[r].dirtysize) { case 1: raw_mov_b_mr((uintptr)live.state[r].mem,rr); break; case 2: raw_mov_w_mr((uintptr)live.state[r].mem,rr); break; case 4: raw_mov_l_mr((uintptr)live.state[r].mem,rr); break; default: abort(); } log_vwrite(r); set_status(r,CLEAN); live.state[r].dirtysize=0; } } static __inline__ int isconst(int r) { return live.state[r].status==ISCONST; } int is_const(int r) { return isconst(r); } static __inline__ void writeback_const(int r) { if (!isconst(r)) return; Dif (live.state[r].needflush==NF_HANDLER) { write_log("Trying to write back constant NF_HANDLER!\n"); abort(); } raw_mov_l_mi((uintptr)live.state[r].mem,live.state[r].val); log_vwrite(r); live.state[r].val=0; set_status(r,INMEM); } static __inline__ void tomem_c(int r) { if (isconst(r)) { writeback_const(r); } else tomem(r); } static void evict(int r) { int rr; if (!isinreg(r)) return; tomem(r); rr=live.state[r].realreg; Dif (live.nat[rr].locked && live.nat[rr].nholds==1) { write_log("register %d in nreg %d is locked!\n",r,live.state[r].realreg); abort(); } live.nat[rr].nholds--; if (live.nat[rr].nholds!=live.state[r].realind) { /* Was not last */ int topreg=live.nat[rr].holds[live.nat[rr].nholds]; int thisind=live.state[r].realind; live.nat[rr].holds[thisind]=topreg; live.state[topreg].realind=thisind; } live.state[r].realreg=-1; set_status(r,INMEM); } static __inline__ void free_nreg(int r) { int i=live.nat[r].nholds; while (i) { int vr; --i; vr=live.nat[r].holds[i]; evict(vr); } Dif (live.nat[r].nholds!=0) { write_log("Failed to free nreg %d, nholds is %d\n",r,live.nat[r].nholds); abort(); } } /* Use with care! */ static __inline__ void isclean(int r) { if (!isinreg(r)) return; live.state[r].validsize=4; live.state[r].dirtysize=0; live.state[r].val=0; set_status(r,CLEAN); } static __inline__ void disassociate(int r) { isclean(r); evict(r); } static __inline__ void set_const(int r, uae_u32 val) { disassociate(r); live.state[r].val=val; set_status(r,ISCONST); } static __inline__ uae_u32 get_offset(int r) { return live.state[r].val; } static int alloc_reg_hinted(int r, int size, int willclobber, int hint) { int bestreg; uae_s32 when; int i; uae_s32 badness=0; /* to shut up gcc */ bestreg=-1; when=2000000000; /* XXX use a regalloc_order table? */ for (i=0;i0) { free_nreg(bestreg); } if (isinreg(r)) { int rr=live.state[r].realreg; /* This will happen if we read a partially dirty register at a bigger size */ Dif (willclobber || live.state[r].validsize>=size) abort(); Dif (live.nat[rr].nholds!=1) abort(); if (size==4 && live.state[r].validsize==2) { log_isused(bestreg); log_visused(r); raw_mov_l_rm(bestreg,(uintptr)live.state[r].mem); raw_bswap_32(bestreg); raw_zero_extend_16_rr(rr,rr); raw_zero_extend_16_rr(bestreg,bestreg); raw_bswap_32(bestreg); raw_lea_l_brr_indexed(rr,rr,bestreg,1,0); live.state[r].validsize=4; live.nat[rr].touched=touchcnt++; return rr; } if (live.state[r].validsize==1) { /* Nothing yet */ } evict(r); } if (!willclobber) { if (live.state[r].status!=UNDEF) { if (isconst(r)) { raw_mov_l_ri(bestreg,live.state[r].val); live.state[r].val=0; live.state[r].dirtysize=4; set_status(r,DIRTY); log_isused(bestreg); } else { log_isreg(bestreg, r); /* This will also load it! */ live.state[r].dirtysize=0; set_status(r,CLEAN); } } else { live.state[r].val=0; live.state[r].dirtysize=0; set_status(r,CLEAN); log_isused(bestreg); } live.state[r].validsize=4; } else { /* this is the easiest way, but not optimal. FIXME! */ /* Now it's trickier, but hopefully still OK */ if (!isconst(r) || size==4) { live.state[r].validsize=size; live.state[r].dirtysize=size; live.state[r].val=0; set_status(r,DIRTY); if (size == 4) { log_clobberreg(r); log_isused(bestreg); } else { log_visused(r); log_isused(bestreg); } } else { if (live.state[r].status!=UNDEF) raw_mov_l_ri(bestreg,live.state[r].val); live.state[r].val=0; live.state[r].validsize=4; live.state[r].dirtysize=4; set_status(r,DIRTY); log_isused(bestreg); } } live.state[r].realreg=bestreg; live.state[r].realind=live.nat[bestreg].nholds; live.nat[bestreg].touched=touchcnt++; live.nat[bestreg].holds[live.nat[bestreg].nholds]=r; live.nat[bestreg].nholds++; return bestreg; } static int alloc_reg(int r, int size, int willclobber) { return alloc_reg_hinted(r,size,willclobber,-1); } static void unlock2(int r) { Dif (!live.nat[r].locked) abort(); live.nat[r].locked--; } static void setlock(int r) { live.nat[r].locked++; } static void mov_nregs(int d, int s) { int ns=live.nat[s].nholds; int nd=live.nat[d].nholds; int i; if (s==d) return; if (nd>0) free_nreg(d); log_isused(d); raw_mov_l_rr(d,s); for (i=0;i=size) { n=live.state[r].realreg; switch(size) { case 1: if (live.nat[n].canbyte || spec>=0) { answer=n; } break; case 2: if (live.nat[n].canword || spec>=0) { answer=n; } break; case 4: answer=n; break; default: abort(); } if (answer<0) evict(r); } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) { answer=alloc_reg_hinted(r,spec>=0?4:size,0,spec); } if (spec>=0 && spec!=answer) { /* Too bad */ mov_nregs(spec,answer); answer=spec; } live.nat[answer].locked++; live.nat[answer].touched=touchcnt++; return answer; } static int readreg(int r, int size) { return readreg_general(r,size,-1,0); } static int readreg_specific(int r, int size, int spec) { return readreg_general(r,size,spec,0); } static int readreg_offset(int r, int size) { return readreg_general(r,size,-1,1); } /* writereg_general(r, size, spec) * * INPUT * - r : mid-layer register * - size : requested size (1/2/4) * - spec : -1 if find or make a register free, otherwise specifies * the physical register to use in any case * * OUTPUT * - hard (physical, x86 here) register allocated to virtual register r */ static __inline__ int writereg_general(int r, int size, int spec) { int n; int answer=-1; record_register(r); if (size<4) { remove_offset(r,spec); } make_exclusive(r,size,spec); if (isinreg(r)) { int nvsize=size>live.state[r].validsize?size:live.state[r].validsize; int ndsize=size>live.state[r].dirtysize?size:live.state[r].dirtysize; n=live.state[r].realreg; Dif (live.nat[n].nholds!=1) abort(); switch(size) { case 1: if (live.nat[n].canbyte || spec>=0) { live.state[r].dirtysize=ndsize; live.state[r].validsize=nvsize; answer=n; } break; case 2: if (live.nat[n].canword || spec>=0) { live.state[r].dirtysize=ndsize; live.state[r].validsize=nvsize; answer=n; } break; case 4: live.state[r].dirtysize=ndsize; live.state[r].validsize=nvsize; answer=n; break; default: abort(); } if (answer<0) evict(r); } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) { answer=alloc_reg_hinted(r,size,1,spec); } if (spec>=0 && spec!=answer) { mov_nregs(spec,answer); answer=spec; } if (live.state[r].status==UNDEF) live.state[r].validsize=4; live.state[r].dirtysize=size>live.state[r].dirtysize?size:live.state[r].dirtysize; live.state[r].validsize=size>live.state[r].validsize?size:live.state[r].validsize; live.nat[answer].locked++; live.nat[answer].touched=touchcnt++; if (size==4) { live.state[r].val=0; } else { Dif (live.state[r].val) { write_log("Problem with val\n"); abort(); } } set_status(r,DIRTY); return answer; } static int writereg(int r, int size) { return writereg_general(r,size,-1); } static int writereg_specific(int r, int size, int spec) { return writereg_general(r,size,spec); } static __inline__ int rmw_general(int r, int wsize, int rsize, int spec) { int n; int answer=-1; record_register(r); if (live.state[r].status==UNDEF) { write_log("WARNING: Unexpected read of undefined register %d\n",r); } remove_offset(r,spec); make_exclusive(r,0,spec); Dif (wsize=rsize) { n=live.state[r].realreg; Dif (live.nat[n].nholds!=1) abort(); switch(rsize) { case 1: if (live.nat[n].canbyte || spec>=0) { answer=n; } break; case 2: if (live.nat[n].canword || spec>=0) { answer=n; } break; case 4: answer=n; break; default: abort(); } if (answer<0) evict(r); } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) { answer=alloc_reg_hinted(r,spec>=0?4:rsize,0,spec); } if (spec>=0 && spec!=answer) { /* Too bad */ mov_nregs(spec,answer); answer=spec; } if (wsize>live.state[r].dirtysize) live.state[r].dirtysize=wsize; if (wsize>live.state[r].validsize) live.state[r].validsize=wsize; set_status(r,DIRTY); live.nat[answer].locked++; live.nat[answer].touched=touchcnt++; Dif (live.state[r].val) { write_log("Problem with val(rmw)\n"); abort(); } return answer; } static int rmw(int r, int wsize, int rsize) { return rmw_general(r,wsize,rsize,-1); } static int rmw_specific(int r, int wsize, int rsize, int spec) { return rmw_general(r,wsize,rsize,spec); } /* needed for restoring the carry flag on non-P6 cores */ static void bt_l_ri_noclobber(R4 r, IMM i) { int size=4; if (i<16) size=2; r=readreg(r,size); raw_bt_l_ri(r,i); unlock2(r); } /******************************************************************** * FPU register status handling. EMIT TIME! * ********************************************************************/ static void f_tomem(int r) { if (live.fate[r].status==DIRTY) { #if USE_LONG_DOUBLE raw_fmov_ext_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); #else raw_fmov_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); #endif live.fate[r].status=CLEAN; } } static void f_tomem_drop(int r) { if (live.fate[r].status==DIRTY) { #if USE_LONG_DOUBLE raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); #else raw_fmov_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); #endif live.fate[r].status=INMEM; } } static __inline__ int f_isinreg(int r) { return live.fate[r].status==CLEAN || live.fate[r].status==DIRTY; } static void f_evict(int r) { int rr; if (!f_isinreg(r)) return; rr=live.fate[r].realreg; if (live.fat[rr].nholds==1) f_tomem_drop(r); else f_tomem(r); Dif (live.fat[rr].locked && live.fat[rr].nholds==1) { write_log("FPU register %d in nreg %d is locked!\n",r,live.fate[r].realreg); abort(); } live.fat[rr].nholds--; if (live.fat[rr].nholds!=live.fate[r].realind) { /* Was not last */ int topreg=live.fat[rr].holds[live.fat[rr].nholds]; int thisind=live.fate[r].realind; live.fat[rr].holds[thisind]=topreg; live.fate[topreg].realind=thisind; } live.fate[r].status=INMEM; live.fate[r].realreg=-1; } static __inline__ void f_free_nreg(int r) { int i=live.fat[r].nholds; while (i) { int vr; --i; vr=live.fat[r].holds[i]; f_evict(vr); } Dif (live.fat[r].nholds!=0) { write_log("Failed to free nreg %d, nholds is %d\n",r,live.fat[r].nholds); abort(); } } /* Use with care! */ static __inline__ void f_isclean(int r) { if (!f_isinreg(r)) return; live.fate[r].status=CLEAN; } static __inline__ void f_disassociate(int r) { f_isclean(r); f_evict(r); } static int f_alloc_reg(int r, int willclobber) { int bestreg; uae_s32 when; int i; uae_s32 badness; bestreg=-1; when=2000000000; for (i=N_FREGS;i--;) { badness=live.fat[i].touched; if (live.fat[i].nholds==0) badness=0; if (!live.fat[i].locked && badness0) { f_free_nreg(bestreg); } if (f_isinreg(r)) { f_evict(r); } if (!willclobber) { if (live.fate[r].status!=UNDEF) { #if USE_LONG_DOUBLE raw_fmov_ext_rm(bestreg,(uintptr)live.fate[r].mem); #else raw_fmov_rm(bestreg,(uintptr)live.fate[r].mem); #endif } live.fate[r].status=CLEAN; } else { live.fate[r].status=DIRTY; } live.fate[r].realreg=bestreg; live.fate[r].realind=live.fat[bestreg].nholds; live.fat[bestreg].touched=touchcnt++; live.fat[bestreg].holds[live.fat[bestreg].nholds]=r; live.fat[bestreg].nholds++; return bestreg; } static void f_unlock(int r) { Dif (!live.fat[r].locked) abort(); live.fat[r].locked--; } static void f_setlock(int r) { live.fat[r].locked++; } static __inline__ int f_readreg(int r) { int n; int answer=-1; if (f_isinreg(r)) { n=live.fate[r].realreg; answer=n; } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) answer=f_alloc_reg(r,0); live.fat[answer].locked++; live.fat[answer].touched=touchcnt++; return answer; } static __inline__ void f_make_exclusive(int r, int clobber) { freg_status oldstate; int rr=live.fate[r].realreg; int nr; int nind; int ndirt=0; int i; if (!f_isinreg(r)) return; if (live.fat[rr].nholds==1) return; for (i=0;i>=i; return; } CLOBBER_SHRL; r=rmw(r,4,4); raw_shrl_l_ri(r,i); unlock2(r); } MENDFUNC(2,shrl_l_ri,(RW4 r, IMM i)) MIDFUNC(2,shrl_w_ri,(RW2 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRL; r=rmw(r,2,2); raw_shrl_w_ri(r,i); unlock2(r); } MENDFUNC(2,shrl_w_ri,(RW2 r, IMM i)) MIDFUNC(2,shrl_b_ri,(RW1 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRL; r=rmw(r,1,1); raw_shrl_b_ri(r,i); unlock2(r); } MENDFUNC(2,shrl_b_ri,(RW1 r, IMM i)) MIDFUNC(2,shra_l_ri,(RW4 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRA; r=rmw(r,4,4); raw_shra_l_ri(r,i); unlock2(r); } MENDFUNC(2,shra_l_ri,(RW4 r, IMM i)) MIDFUNC(2,shra_w_ri,(RW2 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRA; r=rmw(r,2,2); raw_shra_w_ri(r,i); unlock2(r); } MENDFUNC(2,shra_w_ri,(RW2 r, IMM i)) MIDFUNC(2,shra_b_ri,(RW1 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRA; r=rmw(r,1,1); raw_shra_b_ri(r,i); unlock2(r); } MENDFUNC(2,shra_b_ri,(RW1 r, IMM i)) MIDFUNC(2,shra_l_rr,(RW4 d, R1 r)) { if (isconst(r)) { COMPCALL(shra_l_ri)(d,(uae_u8)live.state[r].val); return; } CLOBBER_SHRA; r=readreg_specific(r,1,SHIFTCOUNT_NREG); d=rmw(d,4,4); Dif (r!=1) { write_log("Illegal register %d in raw_rol_b\n",r); abort(); } raw_shra_l_rr(d,r) ; unlock2(r); unlock2(d); } MENDFUNC(2,shra_l_rr,(RW4 d, R1 r)) MIDFUNC(2,shra_w_rr,(RW2 d, R1 r)) { /* Can only do this with r==1, i.e. cl */ if (isconst(r)) { COMPCALL(shra_w_ri)(d,(uae_u8)live.state[r].val); return; } CLOBBER_SHRA; r=readreg_specific(r,1,SHIFTCOUNT_NREG); d=rmw(d,2,2); Dif (r!=1) { write_log("Illegal register %d in raw_shra_b\n",r); abort(); } raw_shra_w_rr(d,r) ; unlock2(r); unlock2(d); } MENDFUNC(2,shra_w_rr,(RW2 d, R1 r)) MIDFUNC(2,shra_b_rr,(RW1 d, R1 r)) { /* Can only do this with r==1, i.e. cl */ if (isconst(r)) { COMPCALL(shra_b_ri)(d,(uae_u8)live.state[r].val); return; } CLOBBER_SHRA; r=readreg_specific(r,1,SHIFTCOUNT_NREG); d=rmw(d,1,1); Dif (r!=1) { write_log("Illegal register %d in raw_shra_b\n",r); abort(); } raw_shra_b_rr(d,r) ; unlock2(r); unlock2(d); } MENDFUNC(2,shra_b_rr,(RW1 d, R1 r)) MIDFUNC(2,setcc,(W1 d, IMM cc)) { CLOBBER_SETCC; d=writereg(d,1); raw_setcc(d,cc); unlock2(d); } MENDFUNC(2,setcc,(W1 d, IMM cc)) MIDFUNC(2,setcc_m,(IMM d, IMM cc)) { CLOBBER_SETCC; raw_setcc_m(d,cc); } MENDFUNC(2,setcc_m,(IMM d, IMM cc)) MIDFUNC(3,cmov_b_rr,(RW1 d, R1 s, IMM cc)) { if (d==s) return; CLOBBER_CMOV; s=readreg(s,1); d=rmw(d,1,1); raw_cmov_b_rr(d,s,cc); unlock2(s); unlock2(d); } MENDFUNC(3,cmov_b_rr,(RW1 d, R1 s, IMM cc)) MIDFUNC(3,cmov_w_rr,(RW2 d, R2 s, IMM cc)) { if (d==s) return; CLOBBER_CMOV; s=readreg(s,2); d=rmw(d,2,2); raw_cmov_w_rr(d,s,cc); unlock2(s); unlock2(d); } MENDFUNC(3,cmov_w_rr,(RW2 d, R2 s, IMM cc)) MIDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc)) { if (d==s) return; CLOBBER_CMOV; s=readreg(s,4); d=rmw(d,4,4); raw_cmov_l_rr(d,s,cc); unlock2(s); unlock2(d); } MENDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc)) MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc)) { CLOBBER_CMOV; d=rmw(d,4,4); raw_cmov_l_rm(d,s,cc); unlock2(d); } MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc)) MIDFUNC(2,bsf_l_rr,(W4 d, W4 s)) { CLOBBER_BSF; s = readreg(s, 4); d = writereg(d, 4); raw_bsf_l_rr(d, s); unlock2(s); unlock2(d); } MENDFUNC(2,bsf_l_rr,(W4 d, W4 s)) /* Set the Z flag depending on the value in s. Note that the value has to be 0 or -1 (or, more precisely, for non-zero values, bit 14 must be set)! */ MIDFUNC(2,simulate_bsf,(W4 tmp, RW4 s)) { CLOBBER_BSF; s=rmw_specific(s,4,4,FLAG_NREG3); tmp=writereg(tmp,4); raw_flags_set_zero(s, tmp); unlock2(tmp); unlock2(s); } MENDFUNC(2,simulate_bsf,(W4 tmp, RW4 s)) MIDFUNC(2,imul_32_32,(RW4 d, R4 s)) { CLOBBER_MUL; s=readreg(s,4); d=rmw(d,4,4); raw_imul_32_32(d,s); unlock2(s); unlock2(d); } MENDFUNC(2,imul_32_32,(RW4 d, R4 s)) MIDFUNC(2,imul_64_32,(RW4 d, RW4 s)) { CLOBBER_MUL; s=rmw_specific(s,4,4,MUL_NREG2); d=rmw_specific(d,4,4,MUL_NREG1); raw_imul_64_32(d,s); unlock2(s); unlock2(d); } MENDFUNC(2,imul_64_32,(RW4 d, RW4 s)) MIDFUNC(2,mul_64_32,(RW4 d, RW4 s)) { CLOBBER_MUL; s=rmw_specific(s,4,4,MUL_NREG2); d=rmw_specific(d,4,4,MUL_NREG1); raw_mul_64_32(d,s); unlock2(s); unlock2(d); } MENDFUNC(2,mul_64_32,(RW4 d, RW4 s)) MIDFUNC(2,mul_32_32,(RW4 d, R4 s)) { CLOBBER_MUL; s=readreg(s,4); d=rmw(d,4,4); raw_mul_32_32(d,s); unlock2(s); unlock2(d); } MENDFUNC(2,mul_32_32,(RW4 d, R4 s)) #if SIZEOF_VOID_P == 8 MIDFUNC(2,sign_extend_32_rr,(W4 d, R2 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_s32)live.state[s].val); return; } CLOBBER_SE32; isrmw=(s==d); if (!isrmw) { s=readreg(s,4); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,4); } raw_sign_extend_32_rr(d,s); if (!isrmw) { unlock2(d); unlock2(s); } else { unlock2(s); } } MENDFUNC(2,sign_extend_32_rr,(W4 d, R2 s)) #endif MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_s32)(uae_s16)live.state[s].val); return; } CLOBBER_SE16; isrmw=(s==d); if (!isrmw) { s=readreg(s,2); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,2); } raw_sign_extend_16_rr(d,s); if (!isrmw) { unlock2(d); unlock2(s); } else { unlock2(s); } } MENDFUNC(2,sign_extend_16_rr,(W4 d, R2 s)) MIDFUNC(2,sign_extend_8_rr,(W4 d, R1 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_s32)(uae_s8)live.state[s].val); return; } isrmw=(s==d); CLOBBER_SE8; if (!isrmw) { s=readreg(s,1); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,1); } raw_sign_extend_8_rr(d,s); if (!isrmw) { unlock2(d); unlock2(s); } else { unlock2(s); } } MENDFUNC(2,sign_extend_8_rr,(W4 d, R1 s)) MIDFUNC(2,zero_extend_16_rr,(W4 d, R2 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_u32)(uae_u16)live.state[s].val); return; } isrmw=(s==d); CLOBBER_ZE16; if (!isrmw) { s=readreg(s,2); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,2); } raw_zero_extend_16_rr(d,s); if (!isrmw) { unlock2(d); unlock2(s); } else { unlock2(s); } } MENDFUNC(2,zero_extend_16_rr,(W4 d, R2 s)) MIDFUNC(2,zero_extend_8_rr,(W4 d, R1 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_u32)(uae_u8)live.state[s].val); return; } isrmw=(s==d); CLOBBER_ZE8; if (!isrmw) { s=readreg(s,1); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,1); } raw_zero_extend_8_rr(d,s); if (!isrmw) { unlock2(d); unlock2(s); } else { unlock2(s); } } MENDFUNC(2,zero_extend_8_rr,(W4 d, R1 s)) MIDFUNC(2,mov_b_rr,(W1 d, R1 s)) { if (d==s) return; if (isconst(s)) { COMPCALL(mov_b_ri)(d,(uae_u8)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,1); d=writereg(d,1); raw_mov_b_rr(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,mov_b_rr,(W1 d, R1 s)) MIDFUNC(2,mov_w_rr,(W2 d, R2 s)) { if (d==s) return; if (isconst(s)) { COMPCALL(mov_w_ri)(d,(uae_u16)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,2); d=writereg(d,2); raw_mov_w_rr(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,mov_w_rr,(W2 d, R2 s)) MIDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); d=writereg(d,4); raw_mov_l_rrm_indexed(d,baser,index,factor); unlock2(d); unlock2(baser); unlock2(index); } MENDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) MIDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); d=writereg(d,2); raw_mov_w_rrm_indexed(d,baser,index,factor); unlock2(d); unlock2(baser); unlock2(index); } MENDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) MIDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); d=writereg(d,1); raw_mov_b_rrm_indexed(d,baser,index,factor); unlock2(d); unlock2(baser); unlock2(index); } MENDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) MIDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); s=readreg(s,4); Dif (baser==s || index==s) abort(); raw_mov_l_mrr_indexed(baser,index,factor,s); unlock2(s); unlock2(baser); unlock2(index); } MENDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) MIDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); s=readreg(s,2); raw_mov_w_mrr_indexed(baser,index,factor,s); unlock2(s); unlock2(baser); unlock2(index); } MENDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) MIDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) { CLOBBER_MOV; s=readreg(s,1); baser=readreg(baser,4); index=readreg(index,4); raw_mov_b_mrr_indexed(baser,index,factor,s); unlock2(s); unlock2(baser); unlock2(index); } MENDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) MIDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; s=readreg(s,4); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); raw_mov_l_bmrr_indexed(base,baser,index,factor,s); unlock2(s); unlock2(baser); unlock2(index); } MENDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) MIDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; s=readreg(s,2); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); raw_mov_w_bmrr_indexed(base,baser,index,factor,s); unlock2(s); unlock2(baser); unlock2(index); } MENDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) MIDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; s=readreg(s,1); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); raw_mov_b_bmrr_indexed(base,baser,index,factor,s); unlock2(s); unlock2(baser); unlock2(index); } MENDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) /* Read a long from base+baser+factor*index */ MIDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); d=writereg(d,4); raw_mov_l_brrm_indexed(d,base,baser,index,factor); unlock2(d); unlock2(baser); unlock2(index); } MENDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) MIDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; remove_offset(d,-1); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); d=writereg(d,2); raw_mov_w_brrm_indexed(d,base,baser,index,factor); unlock2(d); unlock2(baser); unlock2(index); } MENDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) MIDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; remove_offset(d,-1); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); d=writereg(d,1); raw_mov_b_brrm_indexed(d,base,baser,index,factor); unlock2(d); unlock2(baser); unlock2(index); } MENDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) /* Read a long from base+factor*index */ MIDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) { int indexreg=index; if (isconst(index)) { COMPCALL(mov_l_rm)(d,base+factor*live.state[index].val); return; } CLOBBER_MOV; index=readreg_offset(index,4); base+=get_offset(indexreg)*factor; d=writereg(d,4); raw_mov_l_rm_indexed(d,base,index,factor); unlock2(index); unlock2(d); } MENDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) /* read the long at the address contained in s+offset and store in d */ MIDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_l_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg(s,4); d=writereg(d,4); raw_mov_l_rR(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_w_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg(s,4); d=writereg(d,2); raw_mov_w_rR(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_b_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg(s,4); d=writereg(d,1); raw_mov_b_rR(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset)) /* read the long at the address contained in s+offset and store in d */ MIDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset)) { int sreg=s; if (isconst(s)) { COMPCALL(mov_l_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg_offset(s,4); offset+=get_offset(sreg); d=writereg(d,4); raw_mov_l_brR(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset)) { int sreg=s; if (isconst(s)) { COMPCALL(mov_w_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; remove_offset(d,-1); s=readreg_offset(s,4); offset+=get_offset(sreg); d=writereg(d,2); raw_mov_w_brR(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset)) { int sreg=s; if (isconst(s)) { COMPCALL(mov_b_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; remove_offset(d,-1); s=readreg_offset(s,4); offset+=get_offset(sreg); d=writereg(d,1); raw_mov_b_brR(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset)) MIDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_l_mi)(live.state[d].val+offset,i); return; } CLOBBER_MOV; d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_l_Ri(d,i,offset); unlock2(d); } MENDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset)) MIDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_w_mi)(live.state[d].val+offset,i); return; } CLOBBER_MOV; d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_w_Ri(d,i,offset); unlock2(d); } MENDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset)) MIDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_b_mi)(live.state[d].val+offset,i); return; } CLOBBER_MOV; d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_b_Ri(d,i,offset); unlock2(d); } MENDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset)) /* Warning! OFFSET is byte sized only! */ MIDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset)) { if (isconst(d)) { COMPCALL(mov_l_mr)(live.state[d].val+offset,s); return; } if (isconst(s)) { COMPCALL(mov_l_Ri)(d,live.state[s].val,offset); return; } CLOBBER_MOV; s=readreg(s,4); d=readreg(d,4); raw_mov_l_Rr(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset)) MIDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset)) { if (isconst(d)) { COMPCALL(mov_w_mr)(live.state[d].val+offset,s); return; } if (isconst(s)) { COMPCALL(mov_w_Ri)(d,(uae_u16)live.state[s].val,offset); return; } CLOBBER_MOV; s=readreg(s,2); d=readreg(d,4); raw_mov_w_Rr(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset)) MIDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset)) { if (isconst(d)) { COMPCALL(mov_b_mr)(live.state[d].val+offset,s); return; } if (isconst(s)) { COMPCALL(mov_b_Ri)(d,(uae_u8)live.state[s].val,offset); return; } CLOBBER_MOV; s=readreg(s,1); d=readreg(d,4); raw_mov_b_Rr(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset)) MIDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_l_ri)(d,live.state[s].val+offset); return; } #if USE_OFFSET if (d==s) { add_offset(d,offset); return; } #endif CLOBBER_LEA; s=readreg(s,4); d=writereg(d,4); raw_lea_l_brr(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset)) MIDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) { if (!offset) { COMPCALL(lea_l_rr_indexed)(d,s,index,factor); return; } CLOBBER_LEA; s=readreg(s,4); index=readreg(index,4); d=writereg(d,4); raw_lea_l_brr_indexed(d,s,index,factor,offset); unlock2(d); unlock2(index); unlock2(s); } MENDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) MIDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) { CLOBBER_LEA; s=readreg(s,4); index=readreg(index,4); d=writereg(d,4); raw_lea_l_rr_indexed(d,s,index,factor); unlock2(d); unlock2(index); unlock2(s); } MENDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) /* write d to the long at the address contained in s+offset */ MIDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_l_mr)(live.state[d].val+offset,s); return; } CLOBBER_MOV; s=readreg(s,4); d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_l_bRr(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset)) /* write the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_w_mr)(live.state[d].val+offset,s); return; } CLOBBER_MOV; s=readreg(s,2); d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_w_bRr(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset)) MIDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_b_mr)(live.state[d].val+offset,s); return; } CLOBBER_MOV; s=readreg(s,1); d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_b_bRr(d,s,offset); unlock2(d); unlock2(s); } MENDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset)) MIDFUNC(1,bswap_32,(RW4 r)) { int reg=r; if (isconst(r)) { uae_u32 oldv=live.state[r].val; live.state[r].val=reverse32(oldv); return; } CLOBBER_SW32; r=rmw(r,4,4); raw_bswap_32(r); unlock2(r); } MENDFUNC(1,bswap_32,(RW4 r)) MIDFUNC(1,bswap_16,(RW2 r)) { if (isconst(r)) { uae_u32 oldv=live.state[r].val; live.state[r].val=((oldv>>8)&0xff) | ((oldv<<8)&0xff00) | (oldv&0xffff0000); return; } CLOBBER_SW16; r=rmw(r,2,2); raw_bswap_16(r); unlock2(r); } MENDFUNC(1,bswap_16,(RW2 r)) MIDFUNC(2,mov_l_rr,(W4 d, R4 s)) { int olds; if (d==s) { /* How pointless! */ return; } if (isconst(s)) { COMPCALL(mov_l_ri)(d,live.state[s].val); return; } olds=s; disassociate(d); s=readreg_offset(s,4); live.state[d].realreg=s; live.state[d].realind=live.nat[s].nholds; live.state[d].val=live.state[olds].val; live.state[d].validsize=4; live.state[d].dirtysize=4; set_status(d,DIRTY); live.nat[s].holds[live.nat[s].nholds]=d; live.nat[s].nholds++; log_clobberreg(d); /* write_log("Added %d to nreg %d(%d), now holds %d regs\n", d,s,live.state[d].realind,live.nat[s].nholds); */ unlock2(s); } MENDFUNC(2,mov_l_rr,(W4 d, R4 s)) MIDFUNC(2,mov_l_mr,(IMM d, R4 s)) { if (isconst(s)) { COMPCALL(mov_l_mi)(d,live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,4); raw_mov_l_mr(d,s); unlock2(s); } MENDFUNC(2,mov_l_mr,(IMM d, R4 s)) MIDFUNC(2,mov_w_mr,(IMM d, R2 s)) { if (isconst(s)) { COMPCALL(mov_w_mi)(d,(uae_u16)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,2); raw_mov_w_mr(d,s); unlock2(s); } MENDFUNC(2,mov_w_mr,(IMM d, R2 s)) MIDFUNC(2,mov_w_rm,(W2 d, IMM s)) { CLOBBER_MOV; d=writereg(d,2); raw_mov_w_rm(d,s); unlock2(d); } MENDFUNC(2,mov_w_rm,(W2 d, IMM s)) MIDFUNC(2,mov_b_mr,(IMM d, R1 s)) { if (isconst(s)) { COMPCALL(mov_b_mi)(d,(uae_u8)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,1); raw_mov_b_mr(d,s); unlock2(s); } MENDFUNC(2,mov_b_mr,(IMM d, R1 s)) MIDFUNC(2,mov_b_rm,(W1 d, IMM s)) { CLOBBER_MOV; d=writereg(d,1); raw_mov_b_rm(d,s); unlock2(d); } MENDFUNC(2,mov_b_rm,(W1 d, IMM s)) MIDFUNC(2,mov_l_ri,(W4 d, IMM s)) { set_const(d,s); return; } MENDFUNC(2,mov_l_ri,(W4 d, IMM s)) MIDFUNC(2,mov_w_ri,(W2 d, IMM s)) { CLOBBER_MOV; d=writereg(d,2); raw_mov_w_ri(d,s); unlock2(d); } MENDFUNC(2,mov_w_ri,(W2 d, IMM s)) MIDFUNC(2,mov_b_ri,(W1 d, IMM s)) { CLOBBER_MOV; d=writereg(d,1); raw_mov_b_ri(d,s); unlock2(d); } MENDFUNC(2,mov_b_ri,(W1 d, IMM s)) MIDFUNC(2,add_l_mi,(IMM d, IMM s)) { CLOBBER_ADD; raw_add_l_mi(d,s) ; } MENDFUNC(2,add_l_mi,(IMM d, IMM s)) MIDFUNC(2,add_w_mi,(IMM d, IMM s)) { CLOBBER_ADD; raw_add_w_mi(d,s) ; } MENDFUNC(2,add_w_mi,(IMM d, IMM s)) MIDFUNC(2,add_b_mi,(IMM d, IMM s)) { CLOBBER_ADD; raw_add_b_mi(d,s) ; } MENDFUNC(2,add_b_mi,(IMM d, IMM s)) MIDFUNC(2,test_l_ri,(R4 d, IMM i)) { CLOBBER_TEST; d=readreg(d,4); raw_test_l_ri(d,i); unlock2(d); } MENDFUNC(2,test_l_ri,(R4 d, IMM i)) MIDFUNC(2,test_l_rr,(R4 d, R4 s)) { CLOBBER_TEST; d=readreg(d,4); s=readreg(s,4); raw_test_l_rr(d,s);; unlock2(d); unlock2(s); } MENDFUNC(2,test_l_rr,(R4 d, R4 s)) MIDFUNC(2,test_w_rr,(R2 d, R2 s)) { CLOBBER_TEST; d=readreg(d,2); s=readreg(s,2); raw_test_w_rr(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,test_w_rr,(R2 d, R2 s)) MIDFUNC(2,test_b_rr,(R1 d, R1 s)) { CLOBBER_TEST; d=readreg(d,1); s=readreg(s,1); raw_test_b_rr(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,test_b_rr,(R1 d, R1 s)) MIDFUNC(2,and_l_ri,(RW4 d, IMM i)) { if (isconst(d) && !needflags) { live.state[d].val &= i; return; } CLOBBER_AND; d=rmw(d,4,4); raw_and_l_ri(d,i); unlock2(d); } MENDFUNC(2,and_l_ri,(RW4 d, IMM i)) MIDFUNC(2,and_l,(RW4 d, R4 s)) { CLOBBER_AND; s=readreg(s,4); d=rmw(d,4,4); raw_and_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,and_l,(RW4 d, R4 s)) MIDFUNC(2,and_w,(RW2 d, R2 s)) { CLOBBER_AND; s=readreg(s,2); d=rmw(d,2,2); raw_and_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,and_w,(RW2 d, R2 s)) MIDFUNC(2,and_b,(RW1 d, R1 s)) { CLOBBER_AND; s=readreg(s,1); d=rmw(d,1,1); raw_and_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,and_b,(RW1 d, R1 s)) // gb-- used for making an fpcr value in compemu_fpp.cpp MIDFUNC(2,or_l_rm,(RW4 d, IMM s)) { CLOBBER_OR; d=rmw(d,4,4); raw_or_l_rm(d,s); unlock2(d); } MENDFUNC(2,or_l_rm,(RW4 d, IMM s)) MIDFUNC(2,or_l_ri,(RW4 d, IMM i)) { if (isconst(d) && !needflags) { live.state[d].val|=i; return; } CLOBBER_OR; d=rmw(d,4,4); raw_or_l_ri(d,i); unlock2(d); } MENDFUNC(2,or_l_ri,(RW4 d, IMM i)) MIDFUNC(2,or_l,(RW4 d, R4 s)) { if (isconst(d) && isconst(s) && !needflags) { live.state[d].val|=live.state[s].val; return; } CLOBBER_OR; s=readreg(s,4); d=rmw(d,4,4); raw_or_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,or_l,(RW4 d, R4 s)) MIDFUNC(2,or_w,(RW2 d, R2 s)) { CLOBBER_OR; s=readreg(s,2); d=rmw(d,2,2); raw_or_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,or_w,(RW2 d, R2 s)) MIDFUNC(2,or_b,(RW1 d, R1 s)) { CLOBBER_OR; s=readreg(s,1); d=rmw(d,1,1); raw_or_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,or_b,(RW1 d, R1 s)) MIDFUNC(2,adc_l,(RW4 d, R4 s)) { CLOBBER_ADC; s=readreg(s,4); d=rmw(d,4,4); raw_adc_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,adc_l,(RW4 d, R4 s)) MIDFUNC(2,adc_w,(RW2 d, R2 s)) { CLOBBER_ADC; s=readreg(s,2); d=rmw(d,2,2); raw_adc_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,adc_w,(RW2 d, R2 s)) MIDFUNC(2,adc_b,(RW1 d, R1 s)) { CLOBBER_ADC; s=readreg(s,1); d=rmw(d,1,1); raw_adc_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,adc_b,(RW1 d, R1 s)) MIDFUNC(2,add_l,(RW4 d, R4 s)) { if (isconst(s)) { COMPCALL(add_l_ri)(d,live.state[s].val); return; } CLOBBER_ADD; s=readreg(s,4); d=rmw(d,4,4); raw_add_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,add_l,(RW4 d, R4 s)) MIDFUNC(2,add_w,(RW2 d, R2 s)) { if (isconst(s)) { COMPCALL(add_w_ri)(d,(uae_u16)live.state[s].val); return; } CLOBBER_ADD; s=readreg(s,2); d=rmw(d,2,2); raw_add_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,add_w,(RW2 d, R2 s)) MIDFUNC(2,add_b,(RW1 d, R1 s)) { if (isconst(s)) { COMPCALL(add_b_ri)(d,(uae_u8)live.state[s].val); return; } CLOBBER_ADD; s=readreg(s,1); d=rmw(d,1,1); raw_add_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,add_b,(RW1 d, R1 s)) MIDFUNC(2,sub_l_ri,(RW4 d, IMM i)) { if (!i && !needflags) return; if (isconst(d) && !needflags) { live.state[d].val-=i; return; } #if USE_OFFSET if (!needflags) { add_offset(d,-i); return; } #endif CLOBBER_SUB; d=rmw(d,4,4); raw_sub_l_ri(d,i); unlock2(d); } MENDFUNC(2,sub_l_ri,(RW4 d, IMM i)) MIDFUNC(2,sub_w_ri,(RW2 d, IMM i)) { if (!i && !needflags) return; CLOBBER_SUB; d=rmw(d,2,2); raw_sub_w_ri(d,i); unlock2(d); } MENDFUNC(2,sub_w_ri,(RW2 d, IMM i)) MIDFUNC(2,sub_b_ri,(RW1 d, IMM i)) { if (!i && !needflags) return; CLOBBER_SUB; d=rmw(d,1,1); raw_sub_b_ri(d,i); unlock2(d); } MENDFUNC(2,sub_b_ri,(RW1 d, IMM i)) MIDFUNC(2,add_l_ri,(RW4 d, IMM i)) { if (!i && !needflags) return; if (isconst(d) && !needflags) { live.state[d].val+=i; return; } #if USE_OFFSET if (!needflags) { add_offset(d,i); return; } #endif CLOBBER_ADD; d=rmw(d,4,4); raw_add_l_ri(d,i); unlock2(d); } MENDFUNC(2,add_l_ri,(RW4 d, IMM i)) MIDFUNC(2,add_w_ri,(RW2 d, IMM i)) { if (!i && !needflags) return; CLOBBER_ADD; d=rmw(d,2,2); raw_add_w_ri(d,i); unlock2(d); } MENDFUNC(2,add_w_ri,(RW2 d, IMM i)) MIDFUNC(2,add_b_ri,(RW1 d, IMM i)) { if (!i && !needflags) return; CLOBBER_ADD; d=rmw(d,1,1); raw_add_b_ri(d,i); unlock2(d); } MENDFUNC(2,add_b_ri,(RW1 d, IMM i)) MIDFUNC(2,sbb_l,(RW4 d, R4 s)) { CLOBBER_SBB; s=readreg(s,4); d=rmw(d,4,4); raw_sbb_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,sbb_l,(RW4 d, R4 s)) MIDFUNC(2,sbb_w,(RW2 d, R2 s)) { CLOBBER_SBB; s=readreg(s,2); d=rmw(d,2,2); raw_sbb_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,sbb_w,(RW2 d, R2 s)) MIDFUNC(2,sbb_b,(RW1 d, R1 s)) { CLOBBER_SBB; s=readreg(s,1); d=rmw(d,1,1); raw_sbb_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,sbb_b,(RW1 d, R1 s)) MIDFUNC(2,sub_l,(RW4 d, R4 s)) { if (isconst(s)) { COMPCALL(sub_l_ri)(d,live.state[s].val); return; } CLOBBER_SUB; s=readreg(s,4); d=rmw(d,4,4); raw_sub_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,sub_l,(RW4 d, R4 s)) MIDFUNC(2,sub_w,(RW2 d, R2 s)) { if (isconst(s)) { COMPCALL(sub_w_ri)(d,(uae_u16)live.state[s].val); return; } CLOBBER_SUB; s=readreg(s,2); d=rmw(d,2,2); raw_sub_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,sub_w,(RW2 d, R2 s)) MIDFUNC(2,sub_b,(RW1 d, R1 s)) { if (isconst(s)) { COMPCALL(sub_b_ri)(d,(uae_u8)live.state[s].val); return; } CLOBBER_SUB; s=readreg(s,1); d=rmw(d,1,1); raw_sub_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,sub_b,(RW1 d, R1 s)) MIDFUNC(2,cmp_l,(R4 d, R4 s)) { CLOBBER_CMP; s=readreg(s,4); d=readreg(d,4); raw_cmp_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,cmp_l,(R4 d, R4 s)) MIDFUNC(2,cmp_l_ri,(R4 r, IMM i)) { CLOBBER_CMP; r=readreg(r,4); raw_cmp_l_ri(r,i); unlock2(r); } MENDFUNC(2,cmp_l_ri,(R4 r, IMM i)) MIDFUNC(2,cmp_w,(R2 d, R2 s)) { CLOBBER_CMP; s=readreg(s,2); d=readreg(d,2); raw_cmp_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,cmp_w,(R2 d, R2 s)) MIDFUNC(2,cmp_b,(R1 d, R1 s)) { CLOBBER_CMP; s=readreg(s,1); d=readreg(d,1); raw_cmp_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,cmp_b,(R1 d, R1 s)) MIDFUNC(2,xor_l,(RW4 d, R4 s)) { CLOBBER_XOR; s=readreg(s,4); d=rmw(d,4,4); raw_xor_l(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,xor_l,(RW4 d, R4 s)) MIDFUNC(2,xor_w,(RW2 d, R2 s)) { CLOBBER_XOR; s=readreg(s,2); d=rmw(d,2,2); raw_xor_w(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,xor_w,(RW2 d, R2 s)) MIDFUNC(2,xor_b,(RW1 d, R1 s)) { CLOBBER_XOR; s=readreg(s,1); d=rmw(d,1,1); raw_xor_b(d,s); unlock2(d); unlock2(s); } MENDFUNC(2,xor_b,(RW1 d, R1 s)) MIDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize)) { clobber_flags(); remove_all_offsets(); if (osize==4) { if (out1!=in1 && out1!=r) { COMPCALL(forget_about)(out1); } } else { tomem_c(out1); } in1=readreg_specific(in1,isize,REG_PAR1); r=readreg(r,4); prepare_for_call_1(); /* This should ensure that there won't be any need for swapping nregs in prepare_for_call_2 */ #if USE_NORMAL_CALLING_CONVENTION raw_push_l_r(in1); #endif unlock2(in1); unlock2(r); prepare_for_call_2(); raw_call_r(r); #if USE_NORMAL_CALLING_CONVENTION raw_inc_sp(4); #endif live.nat[REG_RESULT].holds[0]=out1; live.nat[REG_RESULT].nholds=1; live.nat[REG_RESULT].touched=touchcnt++; live.state[out1].realreg=REG_RESULT; live.state[out1].realind=0; live.state[out1].val=0; live.state[out1].validsize=osize; live.state[out1].dirtysize=osize; set_status(out1,DIRTY); } MENDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize)) MIDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2)) { clobber_flags(); remove_all_offsets(); in1=readreg_specific(in1,isize1,REG_PAR1); in2=readreg_specific(in2,isize2,REG_PAR2); r=readreg(r,4); prepare_for_call_1(); /* This should ensure that there won't be any need for swapping nregs in prepare_for_call_2 */ #if USE_NORMAL_CALLING_CONVENTION raw_push_l_r(in2); raw_push_l_r(in1); #endif unlock2(r); unlock2(in1); unlock2(in2); prepare_for_call_2(); raw_call_r(r); #if USE_NORMAL_CALLING_CONVENTION raw_inc_sp(8); #endif } MENDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2)) /* forget_about() takes a mid-layer register */ MIDFUNC(1,forget_about,(W4 r)) { if (isinreg(r)) disassociate(r); live.state[r].val=0; set_status(r,UNDEF); } MENDFUNC(1,forget_about,(W4 r)) MIDFUNC(0,nop,(void)) { raw_nop(); } MENDFUNC(0,nop,(void)) MIDFUNC(1,f_forget_about,(FW r)) { if (f_isinreg(r)) f_disassociate(r); live.fate[r].status=UNDEF; } MENDFUNC(1,f_forget_about,(FW r)) MIDFUNC(1,fmov_pi,(FW r)) { r=f_writereg(r); raw_fmov_pi(r); f_unlock(r); } MENDFUNC(1,fmov_pi,(FW r)) MIDFUNC(1,fmov_log10_2,(FW r)) { r=f_writereg(r); raw_fmov_log10_2(r); f_unlock(r); } MENDFUNC(1,fmov_log10_2,(FW r)) MIDFUNC(1,fmov_log2_e,(FW r)) { r=f_writereg(r); raw_fmov_log2_e(r); f_unlock(r); } MENDFUNC(1,fmov_log2_e,(FW r)) MIDFUNC(1,fmov_loge_2,(FW r)) { r=f_writereg(r); raw_fmov_loge_2(r); f_unlock(r); } MENDFUNC(1,fmov_loge_2,(FW r)) MIDFUNC(1,fmov_1,(FW r)) { r=f_writereg(r); raw_fmov_1(r); f_unlock(r); } MENDFUNC(1,fmov_1,(FW r)) MIDFUNC(1,fmov_0,(FW r)) { r=f_writereg(r); raw_fmov_0(r); f_unlock(r); } MENDFUNC(1,fmov_0,(FW r)) MIDFUNC(2,fmov_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmov_rm(r,m); f_unlock(r); } MENDFUNC(2,fmov_rm,(FW r, MEMR m)) MIDFUNC(2,fmovi_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmovi_rm(r,m); f_unlock(r); } MENDFUNC(2,fmovi_rm,(FW r, MEMR m)) MIDFUNC(2,fmovi_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmovi_mr(m,r); f_unlock(r); } MENDFUNC(2,fmovi_mr,(MEMW m, FR r)) MIDFUNC(2,fmovs_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmovs_rm(r,m); f_unlock(r); } MENDFUNC(2,fmovs_rm,(FW r, MEMR m)) MIDFUNC(2,fmovs_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmovs_mr(m,r); f_unlock(r); } MENDFUNC(2,fmovs_mr,(MEMW m, FR r)) MIDFUNC(2,fmov_ext_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmov_ext_mr(m,r); f_unlock(r); } MENDFUNC(2,fmov_ext_mr,(MEMW m, FR r)) MIDFUNC(2,fmov_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmov_mr(m,r); f_unlock(r); } MENDFUNC(2,fmov_mr,(MEMW m, FR r)) MIDFUNC(2,fmov_ext_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmov_ext_rm(r,m); f_unlock(r); } MENDFUNC(2,fmov_ext_rm,(FW r, MEMR m)) MIDFUNC(2,fmov_rr,(FW d, FR s)) { if (d==s) { /* How pointless! */ return; } #if USE_F_ALIAS f_disassociate(d); s=f_readreg(s); live.fate[d].realreg=s; live.fate[d].realind=live.fat[s].nholds; live.fate[d].status=DIRTY; live.fat[s].holds[live.fat[s].nholds]=d; live.fat[s].nholds++; f_unlock(s); #else s=f_readreg(s); d=f_writereg(d); raw_fmov_rr(d,s); f_unlock(s); f_unlock(d); #endif } MENDFUNC(2,fmov_rr,(FW d, FR s)) MIDFUNC(2,fldcw_m_indexed,(R4 index, IMM base)) { index=readreg(index,4); raw_fldcw_m_indexed(index,base); unlock2(index); } MENDFUNC(2,fldcw_m_indexed,(R4 index, IMM base)) MIDFUNC(1,ftst_r,(FR r)) { r=f_readreg(r); raw_ftst_r(r); f_unlock(r); } MENDFUNC(1,ftst_r,(FR r)) MIDFUNC(0,dont_care_fflags,(void)) { f_disassociate(FP_RESULT); } MENDFUNC(0,dont_care_fflags,(void)) MIDFUNC(2,fsqrt_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fsqrt_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fsqrt_rr,(FW d, FR s)) MIDFUNC(2,fabs_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fabs_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fabs_rr,(FW d, FR s)) MIDFUNC(2,fsin_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fsin_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fsin_rr,(FW d, FR s)) MIDFUNC(2,fcos_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fcos_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fcos_rr,(FW d, FR s)) MIDFUNC(2,ftwotox_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_ftwotox_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,ftwotox_rr,(FW d, FR s)) MIDFUNC(2,fetox_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fetox_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fetox_rr,(FW d, FR s)) MIDFUNC(2,frndint_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_frndint_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,frndint_rr,(FW d, FR s)) MIDFUNC(2,flog2_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_flog2_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,flog2_rr,(FW d, FR s)) MIDFUNC(2,fneg_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fneg_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fneg_rr,(FW d, FR s)) MIDFUNC(2,fadd_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fadd_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fadd_rr,(FRW d, FR s)) MIDFUNC(2,fsub_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fsub_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fsub_rr,(FRW d, FR s)) MIDFUNC(2,fcmp_rr,(FR d, FR s)) { d=f_readreg(d); s=f_readreg(s); raw_fcmp_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fcmp_rr,(FR d, FR s)) MIDFUNC(2,fdiv_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fdiv_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fdiv_rr,(FRW d, FR s)) MIDFUNC(2,frem_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_frem_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,frem_rr,(FRW d, FR s)) MIDFUNC(2,frem1_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_frem1_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,frem1_rr,(FRW d, FR s)) MIDFUNC(2,fmul_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fmul_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fmul_rr,(FRW d, FR s)) /******************************************************************** * Support functions exposed to gencomp. CREATE time * ********************************************************************/ void set_zero(int r, int tmp) { if (setzflg_uses_bsf) bsf_l_rr(r,r); else simulate_bsf(tmp,r); } int kill_rodent(int r) { return KILLTHERAT && have_rat_stall && (live.state[r].status==INMEM || live.state[r].status==CLEAN || live.state[r].status==ISCONST || live.state[r].dirtysize==4); } uae_u32 get_const(int r) { Dif (!isconst(r)) { write_log("Register %d should be constant, but isn't\n",r); abort(); } return live.state[r].val; } void sync_m68k_pc(void) { if (m68k_pc_offset) { add_l_ri(PC_P,m68k_pc_offset); comp_pc_p+=m68k_pc_offset; m68k_pc_offset=0; } } /******************************************************************** * Scratch registers management * ********************************************************************/ struct scratch_t { uae_u32 regs[VREGS]; fpu_register fregs[VFREGS]; }; static scratch_t scratch; /******************************************************************** * Support functions exposed to newcpu * ********************************************************************/ static inline const char *str_on_off(bool b) { return b ? "on" : "off"; } void compiler_init(void) { static bool initialized = false; if (initialized) return; #if JIT_DEBUG // JIT debug mode ? JITDebug = PrefsFindBool("jitdebug"); #endif write_log(" : enable runtime disassemblers : %s\n", JITDebug ? "yes" : "no"); #ifdef USE_JIT_FPU // Use JIT compiler for FPU instructions ? avoid_fpu = !PrefsFindBool("jitfpu"); #else // JIT FPU is always disabled avoid_fpu = true; #endif write_log(" : compile FPU instructions : %s\n", !avoid_fpu ? "yes" : "no"); // Get size of the translation cache (in KB) cache_size = PrefsFindInt32("jitcachesize"); write_log(" : requested translation cache size : %d KB\n", cache_size); // Initialize target CPU (check for features, e.g. CMOV, rat stalls) raw_init_cpu(); setzflg_uses_bsf = target_check_bsf(); write_log(" : target processor has CMOV instructions : %s\n", have_cmov ? "yes" : "no"); write_log(" : target processor can suffer from partial register stalls : %s\n", have_rat_stall ? "yes" : "no"); write_log(" : alignment for loops, jumps are %d, %d\n", align_loops, align_jumps); // Translation cache flush mechanism lazy_flush = PrefsFindBool("jitlazyflush"); write_log(" : lazy translation cache invalidation : %s\n", str_on_off(lazy_flush)); flush_icache = lazy_flush ? flush_icache_lazy : flush_icache_hard; // Compiler features write_log(" : register aliasing : %s\n", str_on_off(1)); write_log(" : FP register aliasing : %s\n", str_on_off(USE_F_ALIAS)); write_log(" : lazy constant offsetting : %s\n", str_on_off(USE_OFFSET)); #if USE_INLINING follow_const_jumps = PrefsFindBool("jitinline"); #endif write_log(" : translate through constant jumps : %s\n", str_on_off(follow_const_jumps)); write_log(" : separate blockinfo allocation : %s\n", str_on_off(USE_SEPARATE_BIA)); // Build compiler tables build_comp(); initialized = true; #if PROFILE_UNTRANSLATED_INSNS write_log(" : gather statistics on untranslated insns count\n"); #endif #if PROFILE_COMPILE_TIME write_log(" : gather statistics on translation time\n"); emul_start_time = clock(); #endif } void compiler_exit(void) { #if PROFILE_COMPILE_TIME emul_end_time = clock(); #endif // Deallocate translation cache if (compiled_code) { vm_release(compiled_code, cache_size * 1024); compiled_code = 0; } // Deallocate popallspace if (popallspace) { vm_release(popallspace, POPALLSPACE_SIZE); popallspace = 0; } #if PROFILE_COMPILE_TIME write_log("### Compile Block statistics\n"); write_log("Number of calls to compile_block : %d\n", compile_count); uae_u32 emul_time = emul_end_time - emul_start_time; write_log("Total emulation time : %.1f sec\n", double(emul_time)/double(CLOCKS_PER_SEC)); write_log("Total compilation time : %.1f sec (%.1f%%)\n", double(compile_time)/double(CLOCKS_PER_SEC), 100.0*double(compile_time)/double(emul_time)); write_log("\n"); #endif #if PROFILE_UNTRANSLATED_INSNS uae_u64 untranslated_count = 0; for (int i = 0; i < 65536; i++) { opcode_nums[i] = i; untranslated_count += raw_cputbl_count[i]; } write_log("Sorting out untranslated instructions count...\n"); qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn); write_log("\nRank Opc Count Name\n"); for (int i = 0; i < untranslated_top_ten; i++) { uae_u32 count = raw_cputbl_count[opcode_nums[i]]; struct instr *dp; struct mnemolookup *lookup; if (!count) break; dp = table68k + opcode_nums[i]; for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++) ; write_log("%03d: %04x %10lu %s\n", i, opcode_nums[i], count, lookup->name); } #endif #if RECORD_REGISTER_USAGE int reg_count_ids[16]; uint64 tot_reg_count = 0; for (int i = 0; i < 16; i++) { reg_count_ids[i] = i; tot_reg_count += reg_count[i]; } qsort(reg_count_ids, 16, sizeof(int), reg_count_compare); uint64 cum_reg_count = 0; for (int i = 0; i < 16; i++) { int r = reg_count_ids[i]; cum_reg_count += reg_count[r]; printf("%c%d : %16ld %2.1f%% [%2.1f]\n", r < 8 ? 'D' : 'A', r % 8, reg_count[r], 100.0*double(reg_count[r])/double(tot_reg_count), 100.0*double(cum_reg_count)/double(tot_reg_count)); } #endif } bool compiler_use_jit(void) { // Check for the "jit" prefs item if (!PrefsFindBool("jit")) return false; // Don't use JIT if translation cache size is less then MIN_CACHE_SIZE KB if (PrefsFindInt32("jitcachesize") < MIN_CACHE_SIZE) { write_log(" : translation cache size is less than %d KB. Disabling JIT.\n", MIN_CACHE_SIZE); return false; } // Enable JIT for 68020+ emulation only if (CPUType < 2) { write_log(" : JIT is not supported in 680%d0 emulation mode, disabling.\n", CPUType); return false; } return true; } void init_comp(void) { int i; uae_s8* cb=can_byte; uae_s8* cw=can_word; uae_s8* au=always_used; #if RECORD_REGISTER_USAGE for (i=0;i<16;i++) reg_count_local[i] = 0; #endif for (i=0;i= (uintptr)ROMBaseHost) && (addr < (uintptr)ROMBaseHost + ROMSize)); } static void flush_all(void) { int i; log_flush(); for (i=0;i0) free_nreg(i); for (i=0;i0) f_free_nreg(i); live.flags_in_flags=TRASH; /* Note: We assume we already rescued the flags at the very start of the call_r functions! */ } /******************************************************************** * Memory access and related functions, CREATE time * ********************************************************************/ void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond) { next_pc_p=not_taken; taken_pc_p=taken; branch_cc=cond; } static uae_u32 get_handler_address(uae_u32 addr) { uae_u32 cl=cacheline(addr); blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0); return (uintptr)&(bi->direct_handler_to_use); } static uae_u32 get_handler(uae_u32 addr) { uae_u32 cl=cacheline(addr); blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0); return (uintptr)bi->direct_handler_to_use; } static void load_handler(int reg, uae_u32 addr) { mov_l_rm(reg,get_handler_address(addr)); } /* This version assumes that it is writing *real* memory, and *will* fail * if that assumption is wrong! No branches, no second chances, just * straight go-for-it attitude */ static void writemem_real(int address, int source, int size, int tmp, int clobber) { int f=tmp; if (clobber) f=source; switch(size) { case 1: mov_b_bRr(address,source,MEMBaseDiff); break; case 2: mov_w_rr(f,source); bswap_16(f); mov_w_bRr(address,f,MEMBaseDiff); break; case 4: mov_l_rr(f,source); bswap_32(f); mov_l_bRr(address,f,MEMBaseDiff); break; } forget_about(tmp); forget_about(f); } void writebyte(int address, int source, int tmp) { writemem_real(address,source,1,tmp,0); } static __inline__ void writeword_general(int address, int source, int tmp, int clobber) { writemem_real(address,source,2,tmp,clobber); } void writeword_clobber(int address, int source, int tmp) { writeword_general(address,source,tmp,1); } void writeword(int address, int source, int tmp) { writeword_general(address,source,tmp,0); } static __inline__ void writelong_general(int address, int source, int tmp, int clobber) { writemem_real(address,source,4,tmp,clobber); } void writelong_clobber(int address, int source, int tmp) { writelong_general(address,source,tmp,1); } void writelong(int address, int source, int tmp) { writelong_general(address,source,tmp,0); } /* This version assumes that it is reading *real* memory, and *will* fail * if that assumption is wrong! No branches, no second chances, just * straight go-for-it attitude */ static void readmem_real(int address, int dest, int size, int tmp) { int f=tmp; if (size==4 && address!=dest) f=dest; switch(size) { case 1: mov_b_brR(dest,address,MEMBaseDiff); break; case 2: mov_w_brR(dest,address,MEMBaseDiff); bswap_16(dest); break; case 4: mov_l_brR(dest,address,MEMBaseDiff); bswap_32(dest); break; } forget_about(tmp); } void readbyte(int address, int dest, int tmp) { readmem_real(address,dest,1,tmp); } void readword(int address, int dest, int tmp) { readmem_real(address,dest,2,tmp); } void readlong(int address, int dest, int tmp) { readmem_real(address,dest,4,tmp); } void get_n_addr(int address, int dest, int tmp) { // a is the register containing the virtual address // after the offset had been fetched int a=tmp; // f is the register that will contain the offset int f=tmp; // a == f == tmp if (address == dest) if (address!=dest) { a=address; f=dest; } #if REAL_ADDRESSING mov_l_rr(dest, address); #elif DIRECT_ADDRESSING lea_l_brr(dest,address,MEMBaseDiff); #endif forget_about(tmp); } void get_n_addr_jmp(int address, int dest, int tmp) { /* For this, we need to get the same address as the rest of UAE would --- otherwise we end up translating everything twice */ get_n_addr(address,dest,tmp); } /* base is a register, but dp is an actual value. target is a register, as is tmp */ void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp) { int reg = (dp >> 12) & 15; int regd_shift=(dp >> 9) & 3; if (dp & 0x100) { int ignorebase=(dp&0x80); int ignorereg=(dp&0x40); int addbase=0; int outer=0; if ((dp & 0x30) == 0x20) addbase = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); if ((dp & 0x30) == 0x30) addbase = comp_get_ilong((m68k_pc_offset+=4)-4); if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); if ((dp & 0x3) == 0x3) outer = comp_get_ilong((m68k_pc_offset+=4)-4); if ((dp & 0x4) == 0) { /* add regd *before* the get_long */ if (!ignorereg) { if ((dp & 0x800) == 0) sign_extend_16_rr(target,reg); else mov_l_rr(target,reg); shll_l_ri(target,regd_shift); } else mov_l_ri(target,0); /* target is now regd */ if (!ignorebase) add_l(target,base); add_l_ri(target,addbase); if (dp&0x03) readlong(target,target,tmp); } else { /* do the getlong first, then add regd */ if (!ignorebase) { mov_l_rr(target,base); add_l_ri(target,addbase); } else mov_l_ri(target,addbase); if (dp&0x03) readlong(target,target,tmp); if (!ignorereg) { if ((dp & 0x800) == 0) sign_extend_16_rr(tmp,reg); else mov_l_rr(tmp,reg); shll_l_ri(tmp,regd_shift); /* tmp is now regd */ add_l(target,tmp); } } add_l_ri(target,outer); } else { /* 68000 version */ if ((dp & 0x800) == 0) { /* Sign extend */ sign_extend_16_rr(target,reg); lea_l_brr_indexed(target,base,target,1<= CODE_ALLOC_MAX_ATTEMPTS) return NULL; return do_alloc_code(size, depth + 1); #else uint8 *code = (uint8 *)vm_acquire(size); return code == VM_MAP_FAILED ? NULL : code; #endif } static inline uint8 *alloc_code(uint32 size) { uint8 *ptr = do_alloc_code(size, 0); /* allocated code must fit in 32-bit boundaries */ assert((uintptr)ptr <= 0xffffffff); return ptr; } void alloc_cache(void) { if (compiled_code) { flush_icache_hard(6); vm_release(compiled_code, cache_size * 1024); compiled_code = 0; } if (cache_size == 0) return; while (!compiled_code && cache_size) { if ((compiled_code = alloc_code(cache_size * 1024)) == NULL) { compiled_code = 0; cache_size /= 2; } } vm_protect(compiled_code, cache_size * 1024, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE); if (compiled_code) { write_log(" : actual translation cache size : %d KB at 0x%08X\n", cache_size, compiled_code); max_compile_start = compiled_code + cache_size*1024 - BYTES_PER_INST; current_compile_p = compiled_code; current_cache_size = 0; } } extern void op_illg_1 (uae_u32 opcode) REGPARAM; static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2) { uae_u32 k1 = 0; uae_u32 k2 = 0; #if USE_CHECKSUM_INFO checksum_info *csi = bi->csi; Dif(!csi) abort(); while (csi) { uae_s32 len = csi->length; uintptr tmp = (uintptr)csi->start_p; #else uae_s32 len = bi->len; uintptr tmp = (uintptr)bi->min_pcp; #endif uae_u32*pos; len += (tmp & 3); tmp &= ~((uintptr)3); pos = (uae_u32 *)tmp; if (len >= 0 && len <= MAX_CHECKSUM_LEN) { while (len > 0) { k1 += *pos; k2 ^= *pos; pos++; len -= 4; } } #if USE_CHECKSUM_INFO csi = csi->next; } #endif *c1 = k1; *c2 = k2; } #if 0 static void show_checksum(CSI_TYPE* csi) { uae_u32 k1=0; uae_u32 k2=0; uae_s32 len=CSI_LENGTH(csi); uae_u32 tmp=(uintptr)CSI_START_P(csi); uae_u32* pos; len+=(tmp&3); tmp&=(~3); pos=(uae_u32*)tmp; if (len<0 || len>MAX_CHECKSUM_LEN) { return; } else { while (len>0) { write_log("%08x ",*pos); pos++; len-=4; } write_log(" bla\n"); } } #endif int check_for_cache_miss(void) { blockinfo* bi=get_blockinfo_addr(regs.pc_p); if (bi) { int cl=cacheline(regs.pc_p); if (bi!=cache_tags[cl+1].bi) { raise_in_cl_list(bi); return 1; } } return 0; } static void recompile_block(void) { /* An existing block's countdown code has expired. We need to make sure that execute_normal doesn't refuse to recompile due to a perceived cache miss... */ blockinfo* bi=get_blockinfo_addr(regs.pc_p); Dif (!bi) abort(); raise_in_cl_list(bi); execute_normal(); return; } static void cache_miss(void) { blockinfo* bi=get_blockinfo_addr(regs.pc_p); uae_u32 cl=cacheline(regs.pc_p); blockinfo* bi2=get_blockinfo(cl); if (!bi) { execute_normal(); /* Compile this block now */ return; } Dif (!bi2 || bi==bi2) { write_log("Unexplained cache miss %p %p\n",bi,bi2); abort(); } raise_in_cl_list(bi); return; } static int called_check_checksum(blockinfo* bi); static inline int block_check_checksum(blockinfo* bi) { uae_u32 c1,c2; bool isgood; if (bi->status!=BI_NEED_CHECK) return 1; /* This block is in a checked state */ checksum_count++; if (bi->c1 || bi->c2) calc_checksum(bi,&c1,&c2); else { c1=c2=1; /* Make sure it doesn't match */ } isgood=(c1==bi->c1 && c2==bi->c2); if (isgood) { /* This block is still OK. So we reactivate. Of course, that means we have to move it into the needs-to-be-flushed list */ bi->handler_to_use=bi->handler; set_dhtu(bi,bi->direct_handler); bi->status=BI_CHECKING; isgood=called_check_checksum(bi); } if (isgood) { /* write_log("reactivate %p/%p (%x %x/%x %x)\n",bi,bi->pc_p, c1,c2,bi->c1,bi->c2);*/ remove_from_list(bi); add_to_active(bi); raise_in_cl_list(bi); bi->status=BI_ACTIVE; } else { /* This block actually changed. We need to invalidate it, and set it up to be recompiled */ /* write_log("discard %p/%p (%x %x/%x %x)\n",bi,bi->pc_p, c1,c2,bi->c1,bi->c2); */ invalidate_block(bi); raise_in_cl_list(bi); } return isgood; } static int called_check_checksum(blockinfo* bi) { dependency* x=bi->deplist; int isgood=1; int i; for (i=0;i<2 && isgood;i++) { if (bi->dep[i].jmp_off) { isgood=block_check_checksum(bi->dep[i].target); } } return isgood; } static void check_checksum(void) { blockinfo* bi=get_blockinfo_addr(regs.pc_p); uae_u32 cl=cacheline(regs.pc_p); blockinfo* bi2=get_blockinfo(cl); /* These are not the droids you are looking for... */ if (!bi) { /* Whoever is the primary target is in a dormant state, but calling it was accidental, and we should just compile this new block */ execute_normal(); return; } if (bi!=bi2) { /* The block was hit accidentally, but it does exist. Cache miss */ cache_miss(); return; } if (!block_check_checksum(bi)) execute_normal(); } static __inline__ void match_states(blockinfo* bi) { int i; smallstate* s=&(bi->env); if (bi->status==BI_NEED_CHECK) { block_check_checksum(bi); } if (bi->status==BI_ACTIVE || bi->status==BI_FINALIZING) { /* Deal with the *promises* the block makes (about not using certain vregs) */ for (i=0;i<16;i++) { if (s->virt[i]==L_UNNEEDED) { // write_log("unneeded reg %d at %p\n",i,target); COMPCALL(forget_about)(i); // FIXME } } } flush(1); /* And now deal with the *demands* the block makes */ for (i=0;inat[i]; if (v>=0) { // printf("Loading reg %d into %d at %p\n",v,i,target); readreg_specific(v,4,i); // do_load_reg(i,v); // setlock(i); } } for (i=0;inat[i]; if (v>=0) { unlock2(i); } } } static __inline__ void create_popalls(void) { int i,r; if ((popallspace = alloc_code(POPALLSPACE_SIZE)) == NULL) { write_log("FATAL: Could not allocate popallspace!\n"); abort(); } vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_WRITE); int stack_space = STACK_OFFSET; for (i=0;idirect_pen=(cpuop_func *)get_target(); raw_mov_l_rm(0,(uintptr)&(bi->pc_p)); raw_mov_l_mr((uintptr)®s.pc_p,0); raw_jmp((uintptr)popall_execute_normal); align_target(align_jumps); bi->direct_pcc=(cpuop_func *)get_target(); raw_mov_l_rm(0,(uintptr)&(bi->pc_p)); raw_mov_l_mr((uintptr)®s.pc_p,0); raw_jmp((uintptr)popall_check_checksum); current_compile_p=get_target(); bi->deplist=NULL; for (i=0;i<2;i++) { bi->dep[i].prev_p=NULL; bi->dep[i].next=NULL; } bi->env=default_ss; bi->status=BI_INVALID; bi->havestate=0; //bi->env=empty_ss; } // OPCODE is in big endian format, use cft_map() beforehand, if needed. static inline void reset_compop(int opcode) { compfunctbl[opcode] = NULL; nfcompfunctbl[opcode] = NULL; } static int read_opcode(const char *p) { int opcode = 0; for (int i = 0; i < 4; i++) { int op = p[i]; switch (op) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': opcode = (opcode << 4) | (op - '0'); break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': opcode = (opcode << 4) | ((op - 'a') + 10); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': opcode = (opcode << 4) | ((op - 'A') + 10); break; default: return -1; } } return opcode; } static bool merge_blacklist() { const char *blacklist = PrefsFindString("jitblacklist"); if (blacklist) { const char *p = blacklist; for (;;) { if (*p == 0) return true; int opcode1 = read_opcode(p); if (opcode1 < 0) return false; p += 4; int opcode2 = opcode1; if (*p == '-') { p++; opcode2 = read_opcode(p); if (opcode2 < 0) return false; p += 4; } if (*p == 0 || *p == ',' || *p == ';') { write_log(" : blacklist opcodes : %04x-%04x\n", opcode1, opcode2); for (int opcode = opcode1; opcode <= opcode2; opcode++) reset_compop(cft_map(opcode)); if (*p == ',' || *p++ == ';') continue; return true; } return false; } } return true; } void build_comp(void) { int i; int jumpcount=0; unsigned long opcode; struct comptbl* tbl=op_smalltbl_0_comp_ff; struct comptbl* nftbl=op_smalltbl_0_comp_nf; int count; int cpu_level = 0; // 68000 (default) if (CPUType == 4) cpu_level = 4; // 68040 with FPU else { if (FPUType) cpu_level = 3; // 68020 with FPU else if (CPUType >= 2) cpu_level = 2; // 68020 else if (CPUType == 1) cpu_level = 1; } struct cputbl *nfctbl = ( cpu_level == 4 ? op_smalltbl_0_nf : cpu_level == 3 ? op_smalltbl_1_nf : cpu_level == 2 ? op_smalltbl_2_nf : cpu_level == 1 ? op_smalltbl_3_nf : op_smalltbl_4_nf); write_log (" : building compiler function tables\n"); for (opcode = 0; opcode < 65536; opcode++) { reset_compop(opcode); nfcpufunctbl[opcode] = op_illg_1; prop[opcode].use_flags = 0x1f; prop[opcode].set_flags = 0x1f; prop[opcode].cflow = fl_trap; // ILLEGAL instructions do trap } for (i = 0; tbl[i].opcode < 65536; i++) { int cflow = table68k[tbl[i].opcode].cflow; if (follow_const_jumps && (tbl[i].specific & 16)) cflow = fl_const_jump; else cflow &= ~fl_const_jump; prop[cft_map(tbl[i].opcode)].cflow = cflow; int uses_fpu = tbl[i].specific & 32; if (uses_fpu && avoid_fpu) compfunctbl[cft_map(tbl[i].opcode)] = NULL; else compfunctbl[cft_map(tbl[i].opcode)] = tbl[i].handler; } for (i = 0; nftbl[i].opcode < 65536; i++) { int uses_fpu = tbl[i].specific & 32; if (uses_fpu && avoid_fpu) nfcompfunctbl[cft_map(nftbl[i].opcode)] = NULL; else nfcompfunctbl[cft_map(nftbl[i].opcode)] = nftbl[i].handler; nfcpufunctbl[cft_map(nftbl[i].opcode)] = nfctbl[i].handler; } for (i = 0; nfctbl[i].handler; i++) { nfcpufunctbl[cft_map(nfctbl[i].opcode)] = nfctbl[i].handler; } for (opcode = 0; opcode < 65536; opcode++) { compop_func *f; compop_func *nff; cpuop_func *nfcf; int isaddx,cflow; if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level) continue; if (table68k[opcode].handler != -1) { f = compfunctbl[cft_map(table68k[opcode].handler)]; nff = nfcompfunctbl[cft_map(table68k[opcode].handler)]; nfcf = nfcpufunctbl[cft_map(table68k[opcode].handler)]; cflow = prop[cft_map(table68k[opcode].handler)].cflow; isaddx = prop[cft_map(table68k[opcode].handler)].is_addx; prop[cft_map(opcode)].cflow = cflow; prop[cft_map(opcode)].is_addx = isaddx; compfunctbl[cft_map(opcode)] = f; nfcompfunctbl[cft_map(opcode)] = nff; Dif (nfcf == op_illg_1) abort(); nfcpufunctbl[cft_map(opcode)] = nfcf; } prop[cft_map(opcode)].set_flags = table68k[opcode].flagdead; prop[cft_map(opcode)].use_flags = table68k[opcode].flaglive; /* Unconditional jumps don't evaluate condition codes, so they * don't actually use any flags themselves */ if (prop[cft_map(opcode)].cflow & fl_const_jump) prop[cft_map(opcode)].use_flags = 0; } for (i = 0; nfctbl[i].handler != NULL; i++) { if (nfctbl[i].specific) nfcpufunctbl[cft_map(tbl[i].opcode)] = nfctbl[i].handler; } /* Merge in blacklist */ if (!merge_blacklist()) write_log(" : blacklist merge failure!\n"); count=0; for (opcode = 0; opcode < 65536; opcode++) { if (compfunctbl[cft_map(opcode)]) count++; } write_log(" : supposedly %d compileable opcodes!\n",count); /* Initialise state */ create_popalls(); alloc_cache(); reset_lists(); for (i=0;ipc_p)].handler=(cpuop_func *)popall_execute_normal; cache_tags[cacheline(bi->pc_p)+1].bi=NULL; dbi=bi; bi=bi->next; free_blockinfo(dbi); } bi=dormant; while(bi) { cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func *)popall_execute_normal; cache_tags[cacheline(bi->pc_p)+1].bi=NULL; dbi=bi; bi=bi->next; free_blockinfo(dbi); } reset_lists(); if (!compiled_code) return; current_compile_p=compiled_code; SPCFLAGS_SET( SPCFLAG_JIT_EXEC_RETURN ); /* To get out of compiled code */ } /* "Soft flushing" --- instead of actually throwing everything away, we simply mark everything as "needs to be checked". */ static inline void flush_icache_lazy(int n) { uae_u32 i; blockinfo* bi; blockinfo* bi2; soft_flush_count++; if (!active) return; bi=active; while (bi) { uae_u32 cl=cacheline(bi->pc_p); if (bi->status==BI_INVALID || bi->status==BI_NEED_RECOMP) { if (bi==cache_tags[cl+1].bi) cache_tags[cl].handler=(cpuop_func *)popall_execute_normal; bi->handler_to_use=(cpuop_func *)popall_execute_normal; set_dhtu(bi,bi->direct_pen); bi->status=BI_INVALID; } else { if (bi==cache_tags[cl+1].bi) cache_tags[cl].handler=(cpuop_func *)popall_check_checksum; bi->handler_to_use=(cpuop_func *)popall_check_checksum; set_dhtu(bi,bi->direct_pcc); bi->status=BI_NEED_CHECK; } bi2=bi; bi=bi->next; } /* bi2 is now the last entry in the active list */ bi2->next=dormant; if (dormant) dormant->prev_p=&(bi2->next); dormant=active; active->prev_p=&dormant; active=NULL; } void flush_icache_range(uae_u8 *start_p, uae_u32 length) { if (!active) return; #if LAZY_FLUSH_ICACHE_RANGE blockinfo *bi = active; while (bi) { #if USE_CHECKSUM_INFO bool candidate = false; for (checksum_info *csi = bi->csi; csi; csi = csi->next) { if (((start_p - csi->start_p) < csi->length) || ((csi->start_p - start_p) < length)) { candidate = true; break; } } #else // Assume system is consistent and would invalidate the right range const bool candidate = (bi->pc_p - start_p) < length; #endif blockinfo *dbi = bi; bi = bi->next; if (candidate) { uae_u32 cl = cacheline(dbi->pc_p); if (dbi->status == BI_INVALID || dbi->status == BI_NEED_RECOMP) { if (dbi == cache_tags[cl+1].bi) cache_tags[cl].handler = (cpuop_func *)popall_execute_normal; dbi->handler_to_use = (cpuop_func *)popall_execute_normal; set_dhtu(dbi, dbi->direct_pen); dbi->status = BI_INVALID; } else { if (dbi == cache_tags[cl+1].bi) cache_tags[cl].handler = (cpuop_func *)popall_check_checksum; dbi->handler_to_use = (cpuop_func *)popall_check_checksum; set_dhtu(dbi, dbi->direct_pcc); dbi->status = BI_NEED_CHECK; } remove_from_list(dbi); add_to_dormant(dbi); } } return; #endif flush_icache(-1); } static void catastrophe(void) { abort(); } int failure; #define TARGET_M68K 0 #define TARGET_POWERPC 1 #define TARGET_X86 2 #define TARGET_X86_64 3 #if defined(i386) || defined(__i386__) #define TARGET_NATIVE TARGET_X86 #endif #if defined(powerpc) || defined(__powerpc__) #define TARGET_NATIVE TARGET_POWERPC #endif #if defined(x86_64) || defined(__x86_64__) #define TARGET_NATIVE TARGET_X86_64 #endif #ifdef ENABLE_MON static uae_u32 mon_read_byte_jit(uintptr addr) { uae_u8 *m = (uae_u8 *)addr; return (uintptr)(*m); } static void mon_write_byte_jit(uintptr addr, uae_u32 b) { uae_u8 *m = (uae_u8 *)addr; *m = b; } #endif void disasm_block(int target, uint8 * start, size_t length) { if (!JITDebug) return; #if defined(JIT_DEBUG) && defined(ENABLE_MON) char disasm_str[200]; sprintf(disasm_str, "%s $%x $%x", target == TARGET_M68K ? "d68" : target == TARGET_X86 ? "d86" : target == TARGET_X86_64 ? "d8664" : target == TARGET_POWERPC ? "d" : "x", start, start + length - 1); uae_u32 (*old_mon_read_byte)(uintptr) = mon_read_byte; void (*old_mon_write_byte)(uintptr, uae_u32) = mon_write_byte; mon_read_byte = mon_read_byte_jit; mon_write_byte = mon_write_byte_jit; char *arg[5] = {"mon", "-m", "-r", disasm_str, NULL}; mon(4, arg); mon_read_byte = old_mon_read_byte; mon_write_byte = old_mon_write_byte; #endif } static void disasm_native_block(uint8 *start, size_t length) { disasm_block(TARGET_NATIVE, start, length); } static void disasm_m68k_block(uint8 *start, size_t length) { disasm_block(TARGET_M68K, start, length); } #ifdef HAVE_GET_WORD_UNSWAPPED # define DO_GET_OPCODE(a) (do_get_mem_word_unswapped((uae_u16 *)(a))) #else # define DO_GET_OPCODE(a) (do_get_mem_word((uae_u16 *)(a))) #endif #if JIT_DEBUG static uae_u8 *last_regs_pc_p = 0; static uae_u8 *last_compiled_block_addr = 0; void compiler_dumpstate(void) { if (!JITDebug) return; write_log("### Host addresses\n"); write_log("MEM_BASE : %x\n", MEMBaseDiff); write_log("PC_P : %p\n", ®s.pc_p); write_log("SPCFLAGS : %p\n", ®s.spcflags); write_log("D0-D7 : %p-%p\n", ®s.regs[0], ®s.regs[7]); write_log("A0-A7 : %p-%p\n", ®s.regs[8], ®s.regs[15]); write_log("\n"); write_log("### M68k processor state\n"); m68k_dumpstate(0); write_log("\n"); write_log("### Block in Mac address space\n"); write_log("M68K block : %p\n", (void *)(uintptr)get_virtual_address(last_regs_pc_p)); write_log("Native block : %p (%d bytes)\n", (void *)(uintptr)get_virtual_address(last_compiled_block_addr), get_blockinfo_addr(last_regs_pc_p)->direct_handler_size); write_log("\n"); } #endif static void compile_block(cpu_history* pc_hist, int blocklen) { if (letit && compiled_code) { #if PROFILE_COMPILE_TIME compile_count++; clock_t start_time = clock(); #endif #if JIT_DEBUG bool disasm_block = false; #endif /* OK, here we need to 'compile' a block */ int i; int r; int was_comp=0; uae_u8 liveflags[MAXRUN+1]; #if USE_CHECKSUM_INFO bool trace_in_rom = isinrom((uintptr)pc_hist[0].location); uintptr max_pcp=(uintptr)pc_hist[blocklen - 1].location; uintptr min_pcp=max_pcp; #else uintptr max_pcp=(uintptr)pc_hist[0].location; uintptr min_pcp=max_pcp; #endif uae_u32 cl=cacheline(pc_hist[0].location); void* specflags=(void*)®s.spcflags; blockinfo* bi=NULL; blockinfo* bi2; int extra_len=0; redo_current_block=0; if (current_compile_p>=max_compile_start) flush_icache_hard(7); alloc_blockinfos(); bi=get_blockinfo_addr_new(pc_hist[0].location,0); bi2=get_blockinfo(cl); optlev=bi->optlevel; if (bi->status!=BI_INVALID) { Dif (bi!=bi2) { /* I don't think it can happen anymore. Shouldn't, in any case. So let's make sure... */ write_log("WOOOWOO count=%d, ol=%d %p %p\n", bi->count,bi->optlevel,bi->handler_to_use, cache_tags[cl].handler); abort(); } Dif (bi->count!=-1 && bi->status!=BI_NEED_RECOMP) { write_log("bi->count=%d, bi->status=%d\n",bi->count,bi->status); /* What the heck? We are not supposed to be here! */ abort(); } } if (bi->count==-1) { optlev++; while (!optcount[optlev]) optlev++; bi->count=optcount[optlev]-1; } current_block_pc_p=(uintptr)pc_hist[0].location; remove_deps(bi); /* We are about to create new code */ bi->optlevel=optlev; bi->pc_p=(uae_u8*)pc_hist[0].location; #if USE_CHECKSUM_INFO free_checksum_info_chain(bi->csi); bi->csi = NULL; #endif liveflags[blocklen]=0x1f; /* All flags needed afterwards */ i=blocklen; while (i--) { uae_u16* currpcp=pc_hist[i].location; uae_u32 op=DO_GET_OPCODE(currpcp); #if USE_CHECKSUM_INFO trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp); if (follow_const_jumps && is_const_jump(op)) { checksum_info *csi = alloc_checksum_info(); csi->start_p = (uae_u8 *)min_pcp; csi->length = max_pcp - min_pcp + LONGEST_68K_INST; csi->next = bi->csi; bi->csi = csi; max_pcp = (uintptr)currpcp; } min_pcp = (uintptr)currpcp; #else if ((uintptr)currpcpmax_pcp) max_pcp=(uintptr)currpcp; #endif liveflags[i]=((liveflags[i+1]& (~prop[op].set_flags))| prop[op].use_flags); if (prop[op].is_addx && (liveflags[i+1]&FLAG_Z)==0) liveflags[i]&= ~FLAG_Z; } #if USE_CHECKSUM_INFO checksum_info *csi = alloc_checksum_info(); csi->start_p = (uae_u8 *)min_pcp; csi->length = max_pcp - min_pcp + LONGEST_68K_INST; csi->next = bi->csi; bi->csi = csi; #endif bi->needed_flags=liveflags[0]; align_target(align_loops); was_comp=0; bi->direct_handler=(cpuop_func *)get_target(); set_dhtu(bi,bi->direct_handler); bi->status=BI_COMPILING; current_block_start_target=(uintptr)get_target(); log_startblock(); if (bi->count>=0) { /* Need to generate countdown code */ raw_mov_l_mi((uintptr)®s.pc_p,(uintptr)pc_hist[0].location); raw_sub_l_mi((uintptr)&(bi->count),1); raw_jl((uintptr)popall_recompile_block); } if (optlev==0) { /* No need to actually translate */ /* Execute normally without keeping stats */ raw_mov_l_mi((uintptr)®s.pc_p,(uintptr)pc_hist[0].location); raw_jmp((uintptr)popall_exec_nostats); } else { reg_alloc_run=0; next_pc_p=0; taken_pc_p=0; branch_cc=0; comp_pc_p=(uae_u8*)pc_hist[0].location; init_comp(); was_comp=1; #ifdef USE_CPU_EMUL_SERVICES raw_sub_l_mi((uintptr)&emulated_ticks,blocklen); raw_jcc_b_oponly(NATIVE_CC_GT); uae_s8 *branchadd=(uae_s8*)get_target(); emit_byte(0); raw_call((uintptr)cpu_do_check_ticks); *branchadd=(uintptr)get_target()-((uintptr)branchadd+1); #endif #if JIT_DEBUG if (JITDebug) { raw_mov_l_mi((uintptr)&last_regs_pc_p,(uintptr)pc_hist[0].location); raw_mov_l_mi((uintptr)&last_compiled_block_addr,current_block_start_target); } #endif for (i=0;i1) { failure=0; if (!was_comp) { comp_pc_p=(uae_u8*)pc_hist[i].location; init_comp(); } was_comp=1; comptbl[opcode](opcode); freescratch(); if (!(liveflags[i+1] & FLAG_CZNV)) { /* We can forget about flags */ dont_care_flags(); } #if INDIVIDUAL_INST flush(1); nop(); flush(1); was_comp=0; #endif } if (failure) { if (was_comp) { flush(1); was_comp=0; } raw_mov_l_ri(REG_PAR1,(uae_u32)opcode); #if USE_NORMAL_CALLING_CONVENTION raw_push_l_r(REG_PAR1); #endif raw_mov_l_mi((uintptr)®s.pc_p, (uintptr)pc_hist[i].location); raw_call((uintptr)cputbl[opcode]); #if PROFILE_UNTRANSLATED_INSNS // raw_cputbl_count[] is indexed with plain opcode (in m68k order) raw_add_l_mi((uintptr)&raw_cputbl_count[cft_map(opcode)],1); #endif #if USE_NORMAL_CALLING_CONVENTION raw_inc_sp(4); #endif if (i < blocklen - 1) { uae_s8* branchadd; raw_mov_l_rm(0,(uintptr)specflags); raw_test_l_rr(0,0); raw_jz_b_oponly(); branchadd=(uae_s8 *)get_target(); emit_byte(0); raw_jmp((uintptr)popall_do_nothing); *branchadd=(uintptr)get_target()-(uintptr)branchadd-1; } } } #if 1 /* This isn't completely kosher yet; It really needs to be be integrated into a general inter-block-dependency scheme */ if (next_pc_p && taken_pc_p && was_comp && taken_pc_p==current_block_pc_p) { blockinfo* bi1=get_blockinfo_addr_new((void*)next_pc_p,0); blockinfo* bi2=get_blockinfo_addr_new((void*)taken_pc_p,0); uae_u8 x=bi1->needed_flags; if (x==0xff || 1) { /* To be on the safe side */ uae_u16* next=(uae_u16*)next_pc_p; uae_u32 op=DO_GET_OPCODE(next); x=0x1f; x&=(~prop[op].set_flags); x|=prop[op].use_flags; } x|=bi2->needed_flags; if (!(x & FLAG_CZNV)) { /* We can forget about flags */ dont_care_flags(); extra_len+=2; /* The next instruction now is part of this block */ } } #endif log_flush(); if (next_pc_p) { /* A branch was registered */ uintptr t1=next_pc_p; uintptr t2=taken_pc_p; int cc=branch_cc; uae_u32* branchadd; uae_u32* tba; bigstate tmp; blockinfo* tbi; if (taken_pc_penv))) { mark_callers_recompile(bi); } big_to_small_state(&live,&(bi->env)); #endif #if USE_CHECKSUM_INFO remove_from_list(bi); if (trace_in_rom) { // No need to checksum that block trace on cache invalidation free_checksum_info_chain(bi->csi); bi->csi = NULL; add_to_dormant(bi); } else { calc_checksum(bi,&(bi->c1),&(bi->c2)); add_to_active(bi); } #else if (next_pc_p+extra_len>=max_pcp && next_pc_p+extra_lenlen=max_pcp-min_pcp; bi->min_pcp=min_pcp; remove_from_list(bi); if (isinrom(min_pcp) && isinrom(max_pcp)) { add_to_dormant(bi); /* No need to checksum it on cache flush. Please don't start changing ROMs in flight! */ } else { calc_checksum(bi,&(bi->c1),&(bi->c2)); add_to_active(bi); } #endif current_cache_size += get_target() - (uae_u8 *)current_compile_p; #if JIT_DEBUG if (JITDebug) bi->direct_handler_size = get_target() - (uae_u8 *)current_block_start_target; if (JITDebug && disasm_block) { uaecptr block_addr = start_pc + ((char *)pc_hist[0].location - (char *)start_pc_p); D(bug("M68K block @ 0x%08x (%d insns)\n", block_addr, blocklen)); uae_u32 block_size = ((uae_u8 *)pc_hist[blocklen - 1].location - (uae_u8 *)pc_hist[0].location) + 1; disasm_m68k_block((uae_u8 *)pc_hist[0].location, block_size); D(bug("Compiled block @ 0x%08x\n", pc_hist[0].location)); disasm_native_block((uae_u8 *)current_block_start_target, bi->direct_handler_size); getchar(); } #endif log_dump(); align_target(align_jumps); /* This is the non-direct handler */ bi->handler= bi->handler_to_use=(cpuop_func *)get_target(); raw_cmp_l_mi((uintptr)®s.pc_p,(uintptr)pc_hist[0].location); raw_jnz((uintptr)popall_cache_miss); comp_pc_p=(uae_u8*)pc_hist[0].location; bi->status=BI_FINALIZING; init_comp(); match_states(bi); flush(1); raw_jmp((uintptr)bi->direct_handler); current_compile_p=get_target(); raise_in_cl_list(bi); /* We will flush soon, anyway, so let's do it now */ if (current_compile_p>=max_compile_start) flush_icache_hard(7); bi->status=BI_ACTIVE; if (redo_current_block) block_need_recompile(bi); #if PROFILE_COMPILE_TIME compile_time += (clock() - start_time); #endif } /* Account for compilation time */ cpu_do_check_ticks(); } void do_nothing(void) { /* What did you expect this to do? */ } void exec_nostats(void) { for (;;) { uae_u32 opcode = GET_OPCODE; #if FLIGHT_RECORDER m68k_record_step(m68k_getpc()); #endif (*cpufunctbl[opcode])(opcode); cpu_check_ticks(); if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) { return; /* We will deal with the spcflags in the caller */ } } } void execute_normal(void) { if (!check_for_cache_miss()) { cpu_history pc_hist[MAXRUN]; int blocklen = 0; #if REAL_ADDRESSING || DIRECT_ADDRESSING start_pc_p = regs.pc_p; start_pc = get_virtual_address(regs.pc_p); #else start_pc_p = regs.pc_oldp; start_pc = regs.pc; #endif for (;;) { /* Take note: This is the do-it-normal loop */ pc_hist[blocklen++].location = (uae_u16 *)regs.pc_p; uae_u32 opcode = GET_OPCODE; #if FLIGHT_RECORDER m68k_record_step(m68k_getpc()); #endif (*cpufunctbl[opcode])(opcode); cpu_check_ticks(); if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) { compile_block(pc_hist, blocklen); return; /* We will deal with the spcflags in the caller */ } /* No need to check regs.spcflags, because if they were set, we'd have ended up inside that "if" */ } } } typedef void (*compiled_handler)(void); static void m68k_do_compile_execute(void) { for (;;) { ((compiled_handler)(pushall_call_handler))(); /* Whenever we return from that, we should check spcflags */ if (SPCFLAGS_TEST(SPCFLAG_ALL)) { if (m68k_do_specialties ()) return; } } } void m68k_compile_execute (void) { for (;;) { if (quit_program) break; m68k_do_compile_execute(); } } BasiliskII/src/uae_cpu/compiler/flags_x86.h0000644000175000017500000000262310736405224020743 0ustar centriscentris/* * compiler/flags_x86.h - Native flags definitions for IA-32 * * Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer * * Adaptation for Basilisk II and improvements, copyright 2000-2005 * Gwenole Beauchesne * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef NATIVE_FLAGS_X86_H #define NATIVE_FLAGS_X86_H /* Native integer code conditions */ enum { NATIVE_CC_HI = 7, NATIVE_CC_LS = 6, NATIVE_CC_CC = 3, NATIVE_CC_CS = 2, NATIVE_CC_NE = 5, NATIVE_CC_EQ = 4, NATIVE_CC_VC = 11, NATIVE_CC_VS = 10, NATIVE_CC_PL = 9, NATIVE_CC_MI = 8, NATIVE_CC_GE = 13, NATIVE_CC_LT = 12, NATIVE_CC_GT = 15, NATIVE_CC_LE = 14 }; #endif /* NATIVE_FLAGS_X86_H */ BasiliskII/src/uae_cpu/compiler/compemu_fpp.cpp0000644000175000017500000011372310736405223022012 0ustar centriscentris/* * compiler/compemu_fpp.cpp - Dynamic translation of FPU instructions * * Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer * * Adaptation for Basilisk II and improvements, copyright 2000-2005 * Gwenole Beauchesne * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * UAE - The Un*x Amiga Emulator * * MC68881 emulation * * Copyright 1996 Herman ten Brugge * Adapted for JIT compilation (c) Bernd Meyer, 2000 */ #include "sysdeps.h" #include #include #include "memory.h" #include "readcpu.h" #include "newcpu.h" #include "main.h" #include "compiler/compemu.h" #include "fpu/fpu.h" #include "fpu/flags.h" #include "fpu/exceptions.h" #include "fpu/rounding.h" #define DEBUG 0 #include "debug.h" // gb-- WARNING: get_fpcr() and set_fpcr() support is experimental #define HANDLE_FPCR 0 // - IEEE-based fpu core must be used #if defined(FPU_IEEE) # define CAN_HANDLE_FPCR #endif // - Generic rounding mode and precision modes are supported if set together #if defined(FPU_USE_GENERIC_ROUNDING_MODE) && defined(FPU_USE_GENERIC_ROUNDING_PRECISION) # define CAN_HANDLE_FPCR #endif // - X86 rounding mode and precision modes are *not* supported but might work (?!) #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION) # define CAN_HANDLE_FPCR #endif #if HANDLE_FPCR && !defined(CAN_HANDLE_FPCR) # warning "Can't handle FPCR, will FAIL(1) at runtime" # undef HANDLE_FPCR # define HANDLE_FPCR 0 #endif #define STATIC_INLINE static inline #define MAKE_FPSR(r) do { fmov_rr(FP_RESULT,r); } while (0) #define delay nop() ;nop() #define delay2 nop() ;nop() #define UNKNOWN_EXTRA 0xFFFFFFFF static void fpuop_illg(uae_u32 opcode, uae_u32 extra) { /* if (extra == UNKNOWN_EXTRA) printf("FPU opcode %x, extra UNKNOWN_EXTRA\n",opcode & 0xFFFF); else printf("FPU opcode %x, extra %x\n",opcode & 0xFFFF,extra & 0xFFFF); */ op_illg(opcode); } static uae_s32 temp_fp[4]; /* To convert between FP/integer */ /* return register number, or -1 for failure */ STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra) { uaecptr tmppc; uae_u16 tmp; int size; int mode; int reg; double* src; uae_u32 ad = 0; static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; if ((extra & 0x4000) == 0) { return ((extra >> 10) & 7); } mode = (opcode >> 3) & 7; reg = opcode & 7; size = (extra >> 10) & 7; switch (mode) { case 0: switch (size) { case 6: sign_extend_8_rr(S1,reg); mov_l_mr((uintptr)temp_fp,S1); delay2; fmovi_rm(FS1,(uintptr)temp_fp); return FS1; case 4: sign_extend_16_rr(S1,reg); mov_l_mr((uintptr)temp_fp,S1); delay2; fmovi_rm(FS1,(uintptr)temp_fp); return FS1; case 0: mov_l_mr((uintptr)temp_fp,reg); delay2; fmovi_rm(FS1,(uintptr)temp_fp); return FS1; case 1: mov_l_mr((uintptr)temp_fp,reg); delay2; fmovs_rm(FS1,(uintptr)temp_fp); return FS1; default: return -1; } return -1; /* Should be unreachable */ case 1: return -1; /* Genuine invalid instruction */ default: break; } /* OK, we *will* have to load something from an address. Let's make sure we know how to handle that, or quit early --- i.e. *before* we do any postincrement/predecrement that we may regret */ switch (size) { case 3: return -1; case 0: case 1: case 2: case 4: case 5: case 6: break; default: return -1; } switch (mode) { case 2: ad=S1; /* We will change it, anyway ;-) */ mov_l_rr(ad,reg+8); break; case 3: ad=S1; mov_l_rr(ad,reg+8); lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size])); break; case 4: ad=S1; lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size])); mov_l_rr(ad,reg+8); break; case 5: { uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); ad=S1; mov_l_rr(ad,reg+8); lea_l_brr(ad,ad,off); break; } case 6: { uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2); ad=S1; calc_disp_ea_020(reg+8,dp,ad,S2); break; } case 7: switch (reg) { case 0: { uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); ad=S1; mov_l_ri(ad,off); break; } case 1: { uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4); ad=S1; mov_l_ri(ad,off); break; } case 2: { uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+ m68k_pc_offset; uae_s32 PC16off =(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2) -2); ad=S1; mov_l_ri(ad,address+PC16off); break; } case 3: return -1; tmppc = m68k_getpc (); tmp = next_iword (); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: { uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+ m68k_pc_offset; ad=S1; // Immediate addressing mode && Operation Length == Byte -> // Use the low-order byte of the extension word. if (size == 6) address++; mov_l_ri(ad,address); m68k_pc_offset+=sz2[size]; break; } default: return -1; } } switch (size) { case 0: readlong(ad,S2,S3); mov_l_mr((uintptr)temp_fp,S2); delay2; fmovi_rm(FS1,(uintptr)temp_fp); break; case 1: readlong(ad,S2,S3); mov_l_mr((uintptr)temp_fp,S2); delay2; fmovs_rm(FS1,(uintptr)temp_fp); break; case 2: readword(ad,S2,S3); mov_w_mr(((uintptr)temp_fp)+8,S2); add_l_ri(ad,4); readlong(ad,S2,S3); mov_l_mr((uintptr)(temp_fp)+4,S2); add_l_ri(ad,4); readlong(ad,S2,S3); mov_l_mr((uintptr)(temp_fp),S2); delay2; fmov_ext_rm(FS1,(uintptr)(temp_fp)); break; case 3: return -1; /* Some silly "packed" stuff */ case 4: readword(ad,S2,S3); sign_extend_16_rr(S2,S2); mov_l_mr((uintptr)temp_fp,S2); delay2; fmovi_rm(FS1,(uintptr)temp_fp); break; case 5: readlong(ad,S2,S3); mov_l_mr(((uintptr)temp_fp)+4,S2); add_l_ri(ad,4); readlong(ad,S2,S3); mov_l_mr((uintptr)(temp_fp),S2); delay2; fmov_rm(FS1,(uintptr)(temp_fp)); break; case 6: readbyte(ad,S2,S3); sign_extend_8_rr(S2,S2); mov_l_mr((uintptr)temp_fp,S2); delay2; fmovi_rm(FS1,(uintptr)temp_fp); break; default: return -1; } return FS1; } /* return of -1 means failure, >=0 means OK */ STATIC_INLINE int put_fp_value (int val, uae_u32 opcode, uae_u16 extra) { uae_u16 tmp; uaecptr tmppc; int size; int mode; int reg; uae_u32 ad; static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 }; static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 }; if ((extra & 0x4000) == 0) { const int dest_reg = (extra >> 10) & 7; fmov_rr(dest_reg, val); // gb-- status register is affected MAKE_FPSR(dest_reg); return 0; } mode = (opcode >> 3) & 7; reg = opcode & 7; size = (extra >> 10) & 7; ad = (uae_u32)-1; switch (mode) { case 0: switch (size) { case 6: fmovi_mr((uintptr)temp_fp,val); delay; mov_b_rm(reg,(uintptr)temp_fp); return 0; case 4: fmovi_mr((uintptr)temp_fp,val); delay; mov_w_rm(reg,(uintptr)temp_fp); return 0; case 0: fmovi_mr((uintptr)temp_fp,val); delay; mov_l_rm(reg,(uintptr)temp_fp); return 0; case 1: fmovs_mr((uintptr)temp_fp,val); delay; mov_l_rm(reg,(uintptr)temp_fp); return 0; default: return -1; } case 1: return -1; /* genuine invalid instruction */ default: break; } /* Let's make sure we get out *before* doing something silly if we can't handle the size */ switch (size) { case 0: case 4: case 5: case 6: case 2: case 1: break; case 3: default: return -1; } switch (mode) { case 2: ad=S1; mov_l_rr(ad,reg+8); break; case 3: ad=S1; mov_l_rr(ad,reg+8); lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size])); break; case 4: ad=S1; lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size])); mov_l_rr(ad,reg+8); break; case 5: { uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); ad=S1; mov_l_rr(ad,reg+8); add_l_ri(ad,off); break; } case 6: { uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2); ad=S1; calc_disp_ea_020(reg+8,dp,ad,S2); break; } case 7: switch (reg) { case 0: { uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); ad=S1; mov_l_ri(ad,off); break; } case 1: { uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4); ad=S1; mov_l_ri(ad,off); break; } case 2: { uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+ m68k_pc_offset; uae_s32 PC16off =(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); ad=S1; mov_l_ri(ad,address+PC16off); break; } case 3: return -1; tmppc = m68k_getpc (); tmp = next_iword (); ad = get_disp_ea_020 (tmppc, tmp); break; case 4: { uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+ m68k_pc_offset; ad=S1; mov_l_ri(ad,address); m68k_pc_offset+=sz2[size]; break; } default: return -1; } } switch (size) { case 0: fmovi_mr((uintptr)temp_fp,val); delay; mov_l_rm(S2,(uintptr)temp_fp); writelong_clobber(ad,S2,S3); break; case 1: fmovs_mr((uintptr)temp_fp,val); delay; mov_l_rm(S2,(uintptr)temp_fp); writelong_clobber(ad,S2,S3); break; case 2: fmov_ext_mr((uintptr)temp_fp,val); delay; mov_w_rm(S2,(uintptr)temp_fp+8); writeword_clobber(ad,S2,S3); add_l_ri(ad,4); mov_l_rm(S2,(uintptr)temp_fp+4); writelong_clobber(ad,S2,S3); add_l_ri(ad,4); mov_l_rm(S2,(uintptr)temp_fp); writelong_clobber(ad,S2,S3); break; case 3: return -1; /* Packed */ case 4: fmovi_mr((uintptr)temp_fp,val); delay; mov_l_rm(S2,(uintptr)temp_fp); writeword_clobber(ad,S2,S3); break; case 5: fmov_mr((uintptr)temp_fp,val); delay; mov_l_rm(S2,(uintptr)temp_fp+4); writelong_clobber(ad,S2,S3); add_l_ri(ad,4); mov_l_rm(S2,(uintptr)temp_fp); writelong_clobber(ad,S2,S3); break; case 6: fmovi_mr((uintptr)temp_fp,val); delay; mov_l_rm(S2,(uintptr)temp_fp); writebyte(ad,S2,S3); break; default: return -1; } return 0; } /* return -1 for failure, or register number for success */ STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad) { uae_u16 tmp; uaecptr tmppc; int mode; int reg; uae_s32 off; mode = (opcode >> 3) & 7; reg = opcode & 7; switch (mode) { case 0: case 1: return -1; case 2: case 3: case 4: mov_l_rr(S1,8+reg); return S1; *ad = m68k_areg (regs, reg); break; case 5: off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); mov_l_rr(S1,8+reg); add_l_ri(S1,off); return S1; case 6: return -1; break; case 7: switch (reg) { case 0: off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); mov_l_ri(S1,off); return S1; case 1: off=comp_get_ilong((m68k_pc_offset+=4)-4); mov_l_ri(S1,off); return S1; case 2: return -1; // *ad = m68k_getpc (); // *ad += (uae_s32) (uae_s16) next_iword (); off=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset; off+=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); mov_l_ri(S1,off); return S1; case 3: return -1; tmppc = m68k_getpc (); tmp = next_iword (); *ad = get_disp_ea_020 (tmppc, tmp); break; default: return -1; } } abort(); } void comp_fdbcc_opp (uae_u32 opcode, uae_u16 extra) { FAIL(1); return; } void comp_fscc_opp (uae_u32 opcode, uae_u16 extra) { uae_u32 ad; int cc; int reg; #if DEBUG_FPP printf ("fscc_opp at %08lx\n", m68k_getpc ()); fflush (stdout); #endif if (extra&0x20) { /* only cc from 00 to 1f are defined */ FAIL(1); return; } if ((opcode & 0x38) != 0) { /* We can only do to integer register */ FAIL(1); return; } fflags_into_flags(S2); reg=(opcode&7); mov_l_ri(S1,255); mov_l_ri(S4,0); switch(extra&0x0f) { /* according to fpp.c, the 0x10 bit is ignored */ case 0: break; /* set never */ case 1: mov_l_rr(S2,S4); cmov_l_rr(S4,S1,4); cmov_l_rr(S4,S2,10); break; case 2: cmov_l_rr(S4,S1,7); break; case 3: cmov_l_rr(S4,S1,3); break; case 4: mov_l_rr(S2,S4); cmov_l_rr(S4,S1,2); cmov_l_rr(S4,S2,10); break; case 5: mov_l_rr(S2,S4); cmov_l_rr(S4,S1,6); cmov_l_rr(S4,S2,10); break; case 6: cmov_l_rr(S4,S1,5); break; case 7: cmov_l_rr(S4,S1,11); break; case 8: cmov_l_rr(S4,S1,10); break; case 9: cmov_l_rr(S4,S1,4); break; case 10: cmov_l_rr(S4,S1,10); cmov_l_rr(S4,S1,7); break; case 11: cmov_l_rr(S4,S1,4); cmov_l_rr(S4,S1,3); break; case 12: cmov_l_rr(S4,S1,2); break; case 13: cmov_l_rr(S4,S1,6); break; case 14: cmov_l_rr(S4,S1,5); cmov_l_rr(S4,S1,10); break; case 15: mov_l_rr(S4,S1); break; } if ((opcode & 0x38) == 0) { mov_b_rr(reg,S4); } else { abort(); if (get_fp_ad (opcode, &ad) == 0) { m68k_setpc (m68k_getpc () - 4); fpuop_illg (opcode,extra); } else put_byte (ad, cc ? 0xff : 0x00); } } void comp_ftrapcc_opp (uae_u32 opcode, uaecptr oldpc) { int cc; FAIL(1); return; } void comp_fbcc_opp (uae_u32 opcode) { uae_u32 start_68k_offset=m68k_pc_offset; uae_u32 off; uae_u32 v1; uae_u32 v2; uae_u32 nh; int cc; // comp_pc_p is expected to be bound to 32-bit addresses assert((uintptr)comp_pc_p <= 0xffffffffUL); if (opcode&0x20) { /* only cc from 00 to 1f are defined */ FAIL(1); return; } if ((opcode&0x40)==0) { off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); } else { off=comp_get_ilong((m68k_pc_offset+=4)-4); } mov_l_ri(S1,(uintptr) (comp_pc_p+off-(m68k_pc_offset-start_68k_offset))); mov_l_ri(PC_P,(uintptr)comp_pc_p); /* Now they are both constant. Might as well fold in m68k_pc_offset */ add_l_ri(S1,m68k_pc_offset); add_l_ri(PC_P,m68k_pc_offset); m68k_pc_offset=0; /* according to fpp.c, the 0x10 bit is ignored (it handles exception handling, which we don't do, anyway ;-) */ cc=opcode&0x0f; v1=get_const(PC_P); v2=get_const(S1); fflags_into_flags(S2); switch(cc) { case 0: break; /* jump never */ case 1: mov_l_rr(S2,PC_P); cmov_l_rr(PC_P,S1,4); cmov_l_rr(PC_P,S2,10); break; case 2: register_branch(v1,v2,7); break; case 3: register_branch(v1,v2,3); break; case 4: mov_l_rr(S2,PC_P); cmov_l_rr(PC_P,S1,2); cmov_l_rr(PC_P,S2,10); break; case 5: mov_l_rr(S2,PC_P); cmov_l_rr(PC_P,S1,6); cmov_l_rr(PC_P,S2,10); break; case 6: register_branch(v1,v2,5); break; case 7: register_branch(v1,v2,11); break; case 8: register_branch(v1,v2,10); break; case 9: register_branch(v1,v2,4); break; case 10: cmov_l_rr(PC_P,S1,10); cmov_l_rr(PC_P,S1,7); break; case 11: cmov_l_rr(PC_P,S1,4); cmov_l_rr(PC_P,S1,3); break; case 12: register_branch(v1,v2,2); break; case 13: register_branch(v1,v2,6); break; case 14: cmov_l_rr(PC_P,S1,5); cmov_l_rr(PC_P,S1,10); break; case 15: mov_l_rr(PC_P,S1); break; } } /* Floating point conditions The "NotANumber" part could be problematic; Howver, when NaN is encountered, the ftst instruction sets bot N and Z to 1 on the x87, so quite often things just fall into place. This is probably not accurate wrt the 68k FPU, but it is *as* accurate as this was before. However, some more thought should go into fixing this stuff up so it accurately emulates the 68k FPU. >==> 13) & 0x7) { case 3: /* 2nd most common */ if (put_fp_value ((extra >> 7)&7 , opcode, extra) < 0) { FAIL(1); return; } return; case 6: case 7: { uae_u32 ad, list = 0; int incr = 0; if (extra & 0x2000) { uae_u32 ad; /* FMOVEM FPP->memory */ switch ((extra >> 11) & 3) { /* Get out early if failure */ case 0: case 2: break; case 1: case 3: default: FAIL(1); return; } ad=get_fp_ad (opcode, &ad); if (ad<0) { abort(); m68k_setpc (m68k_getpc () - 4); fpuop_illg (opcode,extra); return; } switch ((extra >> 11) & 3) { case 0: /* static pred */ list = extra & 0xff; incr = -1; break; case 2: /* static postinc */ list = extra & 0xff; incr = 1; break; case 1: /* dynamic pred */ case 3: /* dynamic postinc */ abort(); } if (incr < 0) { /* Predecrement */ for (reg = 7; reg >= 0; reg--) { if (list & 0x80) { fmov_ext_mr((uintptr)temp_fp,reg); delay; sub_l_ri(ad,4); mov_l_rm(S2,(uintptr)temp_fp); writelong_clobber(ad,S2,S3); sub_l_ri(ad,4); mov_l_rm(S2,(uintptr)temp_fp+4); writelong_clobber(ad,S2,S3); sub_l_ri(ad,4); mov_w_rm(S2,(uintptr)temp_fp+8); writeword_clobber(ad,S2,S3); } list <<= 1; } } else { /* Postincrement */ for (reg = 0; reg < 8; reg++) { if (list & 0x80) { fmov_ext_mr((uintptr)temp_fp,reg); delay; mov_w_rm(S2,(uintptr)temp_fp+8); writeword_clobber(ad,S2,S3); add_l_ri(ad,4); mov_l_rm(S2,(uintptr)temp_fp+4); writelong_clobber(ad,S2,S3); add_l_ri(ad,4); mov_l_rm(S2,(uintptr)temp_fp); writelong_clobber(ad,S2,S3); add_l_ri(ad,4); } list <<= 1; } } if ((opcode & 0x38) == 0x18) mov_l_rr((opcode & 7)+8,ad); if ((opcode & 0x38) == 0x20) mov_l_rr((opcode & 7)+8,ad); } else { /* FMOVEM memory->FPP */ uae_u32 ad; switch ((extra >> 11) & 3) { /* Get out early if failure */ case 0: case 2: break; case 1: case 3: default: FAIL(1); return; } ad=get_fp_ad (opcode, &ad); if (ad<0) { abort(); m68k_setpc (m68k_getpc () - 4); write_log("no ad\n"); fpuop_illg (opcode,extra); return; } switch ((extra >> 11) & 3) { case 0: /* static pred */ list = extra & 0xff; incr = -1; break; case 2: /* static postinc */ list = extra & 0xff; incr = 1; break; case 1: /* dynamic pred */ case 3: /* dynamic postinc */ abort(); } if (incr < 0) { // not reached for (reg = 7; reg >= 0; reg--) { uae_u32 wrd1, wrd2, wrd3; if (list & 0x80) { sub_l_ri(ad,4); readlong(ad,S2,S3); mov_l_mr((uintptr)(temp_fp),S2); sub_l_ri(ad,4); readlong(ad,S2,S3); mov_l_mr((uintptr)(temp_fp)+4,S2); sub_l_ri(ad,4); readword(ad,S2,S3); mov_w_mr(((uintptr)temp_fp)+8,S2); delay2; fmov_ext_rm(reg,(uintptr)(temp_fp)); } list <<= 1; } } else { for (reg = 0; reg < 8; reg++) { uae_u32 wrd1, wrd2, wrd3; if (list & 0x80) { readword(ad,S2,S3); mov_w_mr(((uintptr)temp_fp)+8,S2); add_l_ri(ad,4); readlong(ad,S2,S3); mov_l_mr((uintptr)(temp_fp)+4,S2); add_l_ri(ad,4); readlong(ad,S2,S3); mov_l_mr((uintptr)(temp_fp),S2); add_l_ri(ad,4); delay2; fmov_ext_rm(reg,(uintptr)(temp_fp)); } list <<= 1; } } if ((opcode & 0x38) == 0x18) mov_l_rr((opcode & 7)+8,ad); if ((opcode & 0x38) == 0x20) mov_l_rr((opcode & 7)+8,ad); } } return; case 4: case 5: /* rare */ if ((opcode & 0x30) == 0) { if (extra & 0x2000) { if (extra & 0x1000) { #if HANDLE_FPCR mov_l_rm(opcode & 15, (uintptr)&fpu.fpcr.rounding_mode); or_l_rm(opcode & 15, (uintptr)&fpu.fpcr.rounding_precision); #else FAIL(1); return; #endif } if (extra & 0x0800) { FAIL(1); return; } if (extra & 0x0400) { mov_l_rm(opcode & 15,(uintptr)&fpu.instruction_address); return; } } else { // gb-- moved here so that we may FAIL() without generating any code if (extra & 0x0800) { // set_fpsr(m68k_dreg (regs, opcode & 15)); FAIL(1); return; } if (extra & 0x1000) { #if HANDLE_FPCR #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION) FAIL(1); return; #endif mov_l_rr(S1,opcode & 15); mov_l_rr(S2,opcode & 15); and_l_ri(S1,FPCR_ROUNDING_PRECISION); and_l_ri(S2,FPCR_ROUNDING_MODE); mov_l_mr((uintptr)&fpu.fpcr.rounding_precision,S1); mov_l_mr((uintptr)&fpu.fpcr.rounding_mode,S2); #else FAIL(1); return; #endif // return; gb-- FMOVEM could also operate on fpiar } if (extra & 0x0400) { mov_l_mr((uintptr)&fpu.instruction_address,opcode & 15); // return; gb-- we have to process all FMOVEM bits before returning } return; } } else if ((opcode & 0x3f) == 0x3c) { if ((extra & 0x2000) == 0) { // gb-- moved here so that we may FAIL() without generating any code if (extra & 0x0800) { FAIL(1); return; } if (extra & 0x1000) { uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4); #if HANDLE_FPCR #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION) FAIL(1); return; #endif // mov_l_mi((uintptr)®s.fpcr,val); mov_l_ri(S1,val); mov_l_ri(S2,val); and_l_ri(S1,FPCR_ROUNDING_PRECISION); and_l_ri(S2,FPCR_ROUNDING_MODE); mov_l_mr((uintptr)&fpu.fpcr.rounding_precision,S1); mov_l_mr((uintptr)&fpu.fpcr.rounding_mode,S2); #else FAIL(1); return; #endif // return; gb-- FMOVEM could also operate on fpiar } if (extra & 0x0400) { uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4); mov_l_mi((uintptr)&fpu.instruction_address,val); // return; gb-- we have to process all FMOVEM bits before returning } return; } FAIL(1); return; } else if (extra & 0x2000) { FAIL(1); return; } else { FAIL(1); return; } FAIL(1); return; case 0: case 2: /* Extremely common */ reg = (extra >> 7) & 7; if ((extra & 0xfc00) == 0x5c00) { switch (extra & 0x7f) { case 0x00: fmov_pi(reg); break; case 0x0b: fmov_log10_2(reg); break; case 0x0c: #if USE_LONG_DOUBLE fmov_ext_rm(reg,(uintptr)&const_e); #else fmov_rm(reg,(uintptr)&const_e); #endif break; case 0x0d: fmov_log2_e(reg); break; case 0x0e: #if USE_LONG_DOUBLE fmov_ext_rm(reg,(uintptr)&const_log10_e); #else fmov_rm(reg,(uintptr)&const_log10_e); #endif break; case 0x0f: fmov_0(reg); break; case 0x30: fmov_loge_2(reg); break; case 0x31: #if USE_LONG_DOUBLE fmov_ext_rm(reg,(uintptr)&const_loge_10); #else fmov_rm(reg,(uintptr)&const_loge_10); #endif break; case 0x32: fmov_1(reg); break; case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: #if USE_LONG_DOUBLE case 0x3c: case 0x3d: case 0x3e: case 0x3f: fmov_ext_rm(reg,(uintptr)(power10+(extra & 0x7f)-0x32)); #else fmov_rm(reg,(uintptr)(power10+(extra & 0x7f)-0x32)); #endif break; default: /* This is not valid, so we fail */ FAIL(1); return; } return; } switch (extra & 0x7f) { case 0x00: /* FMOVE */ case 0x40: /* Explicit rounding. This is just a quick fix. Same * for all other cases that have three choices */ case 0x44: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fmov_rr(reg,src); MAKE_FPSR (src); break; case 0x01: /* FINT */ FAIL(1); return; dont_care_fflags(); case 0x02: /* FSINH */ FAIL(1); return; dont_care_fflags(); break; case 0x03: /* FINTRZ */ #if USE_X86_FPUCW /* If we have control over the CW, we can do this */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } mov_l_ri(S1,16); /* Switch to "round to zero" mode */ fldcw_m_indexed(S1,(uae_u32)x86_fpucw); frndint_rr(reg,src); /* restore control word */ mov_l_rm(S1,(uintptr)®s.fpcr); and_l_ri(S1,0x000000f0); fldcw_m_indexed(S1,(uintptr)x86_fpucw); MAKE_FPSR (reg); break; #endif FAIL(1); return; break; case 0x04: /* FSQRT */ case 0x41: case 0x45: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fsqrt_rr(reg,src); MAKE_FPSR (reg); break; case 0x06: /* FLOGNP1 */ FAIL(1); return; dont_care_fflags(); break; case 0x08: /* FETOXM1 */ FAIL(1); return; dont_care_fflags(); break; case 0x09: /* FTANH */ FAIL(1); return; dont_care_fflags(); break; case 0x0a: /* FATAN */ FAIL(1); return; dont_care_fflags(); break; case 0x0c: /* FASIN */ FAIL(1); return; dont_care_fflags(); break; case 0x0d: /* FATANH */ FAIL(1); return; dont_care_fflags(); break; case 0x0e: /* FSIN */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fsin_rr(reg,src); MAKE_FPSR (reg); break; case 0x0f: /* FTAN */ FAIL(1); return; dont_care_fflags(); break; case 0x10: /* FETOX */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fetox_rr(reg,src); MAKE_FPSR (reg); break; case 0x11: /* FTWOTOX */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } ftwotox_rr(reg,src); MAKE_FPSR (reg); break; case 0x12: /* FTENTOX */ FAIL(1); return; dont_care_fflags(); break; case 0x14: /* FLOGN */ FAIL(1); return; dont_care_fflags(); break; case 0x15: /* FLOG10 */ FAIL(1); return; dont_care_fflags(); break; case 0x16: /* FLOG2 */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } flog2_rr(reg,src); MAKE_FPSR (reg); break; case 0x18: /* FABS */ case 0x58: case 0x5c: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fabs_rr(reg,src); MAKE_FPSR (reg); break; case 0x19: /* FCOSH */ FAIL(1); return; dont_care_fflags(); break; case 0x1a: /* FNEG */ case 0x5a: case 0x5e: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fneg_rr(reg,src); MAKE_FPSR (reg); break; case 0x1c: /* FACOS */ FAIL(1); return; dont_care_fflags(); break; case 0x1d: /* FCOS */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fcos_rr(reg,src); MAKE_FPSR (reg); break; case 0x1e: /* FGETEXP */ FAIL(1); return; dont_care_fflags(); break; case 0x1f: /* FGETMAN */ FAIL(1); return; dont_care_fflags(); break; case 0x20: /* FDIV */ case 0x60: case 0x64: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fdiv_rr(reg,src); MAKE_FPSR (reg); break; case 0x21: /* FMOD */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } frem_rr(reg,src); MAKE_FPSR (reg); break; case 0x22: /* FADD */ case 0x62: case 0x66: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fadd_rr(reg,src); MAKE_FPSR (reg); break; case 0x23: /* FMUL */ case 0x63: case 0x67: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fmul_rr(reg,src); MAKE_FPSR (reg); break; case 0x24: /* FSGLDIV */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fdiv_rr(reg,src); MAKE_FPSR (reg); break; case 0x25: /* FREM */ // gb-- disabled because the quotient byte must be computed // otherwise, free rotation in ClarisWorks doesn't work. FAIL(1); return; dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } frem1_rr(reg,src); MAKE_FPSR (reg); break; case 0x26: /* FSCALE */ dont_care_fflags(); FAIL(1); return; break; case 0x27: /* FSGLMUL */ dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fmul_rr(reg,src); MAKE_FPSR (reg); break; case 0x28: /* FSUB */ case 0x68: case 0x6c: dont_care_fflags(); src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fsub_rr(reg,src); MAKE_FPSR (reg); break; case 0x30: /* FSINCOS */ case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: FAIL(1); return; dont_care_fflags(); break; case 0x38: /* FCMP */ src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fmov_rr(FP_RESULT,reg); fsub_rr(FP_RESULT,src); /* Right way? */ break; case 0x3a: /* FTST */ src=get_fp_value (opcode, extra); if (src < 0) { FAIL(1); /* Illegal instruction */ return; } fmov_rr(FP_RESULT,src); break; default: FAIL(1); return; break; } return; } m68k_setpc (m68k_getpc () - 4); fpuop_illg (opcode,extra); } BasiliskII/src/uae_cpu/m68k.h0000644000175000017500000007212711735673707016140 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * MC68000 emulation - machine dependent bits * * Copyright 1996 Bernd Schmidt * * 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 */ #ifndef M68K_FLAGS_H #define M68K_FLAGS_H #ifdef OPTIMIZED_FLAGS #if (defined(__i386__) && defined(X86_ASSEMBLY)) || (defined(__x86_64__) && defined(X86_64_ASSEMBLY)) #ifndef SAHF_SETO_PROFITABLE /* PUSH/POP instructions are naturally 64-bit sized on x86-64, thus unsigned long hereunder is either 64-bit or 32-bit wide depending on the target. */ struct flag_struct { unsigned long cznv; unsigned long x; }; #define FLAGVAL_Z 0x40 #define FLAGVAL_N 0x80 #define SET_ZFLG(y) (regflags.cznv = (((uae_u32)regflags.cznv) & ~0x40) | (((y) & 1) << 6)) #define SET_CFLG(y) (regflags.cznv = (((uae_u32)regflags.cznv) & ~1) | ((y) & 1)) #define SET_VFLG(y) (regflags.cznv = (((uae_u32)regflags.cznv) & ~0x800) | (((y) & 1) << 11)) #define SET_NFLG(y) (regflags.cznv = (((uae_u32)regflags.cznv) & ~0x80) | (((y) & 1) << 7)) #define SET_XFLG(y) (regflags.x = (y)) #define GET_ZFLG ((regflags.cznv >> 6) & 1) #define GET_CFLG (regflags.cznv & 1) #define GET_VFLG ((regflags.cznv >> 11) & 1) #define GET_NFLG ((regflags.cznv >> 7) & 1) #define GET_XFLG (regflags.x & 1) #define CLEAR_CZNV (regflags.cznv = 0) #define GET_CZNV (regflags.cznv) #define IOR_CZNV(X) (regflags.cznv |= (X)) #define SET_CZNV(X) (regflags.cznv = (X)) #define COPY_CARRY (regflags.x = regflags.cznv) extern struct flag_struct regflags __asm__ ("regflags"); static __inline__ int cctrue(int cc) { uae_u32 cznv = regflags.cznv; switch(cc){ case 0: return 1; /* T */ case 1: return 0; /* F */ case 2: return (cznv & 0x41) == 0; /* !GET_CFLG && !GET_ZFLG; HI */ case 3: return (cznv & 0x41) != 0; /* GET_CFLG || GET_ZFLG; LS */ case 4: return (cznv & 1) == 0; /* !GET_CFLG; CC */ case 5: return (cznv & 1) != 0; /* GET_CFLG; CS */ case 6: return (cznv & 0x40) == 0; /* !GET_ZFLG; NE */ case 7: return (cznv & 0x40) != 0; /* GET_ZFLG; EQ */ case 8: return (cznv & 0x800) == 0;/* !GET_VFLG; VC */ case 9: return (cznv & 0x800) != 0;/* GET_VFLG; VS */ case 10:return (cznv & 0x80) == 0; /* !GET_NFLG; PL */ case 11:return (cznv & 0x80) != 0; /* GET_NFLG; MI */ case 12:return (((cznv << 4) ^ cznv) & 0x800) == 0; /* GET_NFLG == GET_VFLG; GE */ case 13:return (((cznv << 4) ^ cznv) & 0x800) != 0;/* GET_NFLG != GET_VFLG; LT */ case 14: cznv &= 0x8c0; return (((cznv << 4) ^ cznv) & 0x840) == 0; /* !GET_ZFLG && (GET_NFLG == GET_VFLG); GT */ case 15: cznv &= 0x8c0; return (((cznv << 4) ^ cznv) & 0x840) != 0; /* GET_ZFLG || (GET_NFLG != GET_VFLG); LE */ } return 0; } #define optflag_testl(v) \ __asm__ __volatile__ ("andl %1,%1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv) : "r" (v) : "cc") #define optflag_testw(v) \ __asm__ __volatile__ ("andw %w1,%w1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv) : "r" (v) : "cc") #define optflag_testb(v) \ __asm__ __volatile__ ("andb %b1,%b1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv) : "q" (v) : "cc") #define optflag_addl(v, s, d) do { \ __asm__ __volatile__ ("addl %k2,%k1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv), "=r" (v) : "rmi" (s), "1" (d) : "cc"); \ COPY_CARRY; \ } while (0) #define optflag_addw(v, s, d) do { \ __asm__ __volatile__ ("addw %w2,%w1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv), "=r" (v) : "rmi" (s), "1" (d) : "cc"); \ COPY_CARRY; \ } while (0) #define optflag_addb(v, s, d) do { \ __asm__ __volatile__ ("addb %b2,%b1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv), "=q" (v) : "qmi" (s), "1" (d) : "cc"); \ COPY_CARRY; \ } while (0) #define optflag_subl(v, s, d) do { \ __asm__ __volatile__ ("subl %k2,%k1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv), "=r" (v) : "rmi" (s), "1" (d) : "cc"); \ COPY_CARRY; \ } while (0) #define optflag_subw(v, s, d) do { \ __asm__ __volatile__ ("subw %w2,%w1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv), "=r" (v) : "rmi" (s), "1" (d) : "cc"); \ COPY_CARRY; \ } while (0) #define optflag_subb(v, s, d) do { \ __asm__ __volatile__ ("subb %b2,%b1\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv), "=q" (v) : "qmi" (s), "1" (d) : "cc"); \ COPY_CARRY; \ } while (0) #define optflag_cmpl(s, d) \ __asm__ __volatile__ ("cmpl %k1,%k2\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv) : "rmi" (s), "r" (d) : "cc") #define optflag_cmpw(s, d) \ __asm__ __volatile__ ("cmpw %w1,%w2\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv) : "rmi" (s), "r" (d) : "cc") #define optflag_cmpb(s, d) \ __asm__ __volatile__ ("cmpb %b1,%b2\n\t" \ "pushf\n\t" \ "pop %0\n\t" \ : "=r" (regflags.cznv) : "qmi" (s), "q" (d) : "cc") #else struct flag_struct { uae_u32 cznv; uae_u32 x; }; #define FLAGVAL_Z 0x4000 #define FLAGVAL_N 0x8000 #define SET_ZFLG(y) (regflags.cznv = (regflags.cznv & ~0x4000) | (((y) & 1) << 14)) #define SET_CFLG(y) (regflags.cznv = (regflags.cznv & ~0x100) | (((y) & 1) << 8)) #define SET_VFLG(y) (regflags.cznv = (regflags.cznv & ~0x1) | (((y) & 1))) #define SET_NFLG(y) (regflags.cznv = (regflags.cznv & ~0x8000) | (((y) & 1) << 15)) #define SET_XFLG(y) (regflags.x = (y)) #define GET_ZFLG ((regflags.cznv >> 14) & 1) #define GET_CFLG ((regflags.cznv >> 8) & 1) #define GET_VFLG ((regflags.cznv >> 0) & 1) #define GET_NFLG ((regflags.cznv >> 15) & 1) #define GET_XFLG (regflags.x & 1) #define CLEAR_CZNV (regflags.cznv = 0) #define GET_CZNV (regflags.cznv) #define IOR_CZNV(X) (regflags.cznv |= (X)) #define SET_CZNV(X) (regflags.cznv = (X)) #define COPY_CARRY (regflags.x = (regflags.cznv)>>8) extern struct flag_struct regflags __asm__ ("regflags"); static __inline__ int cctrue(int cc) { uae_u32 cznv = regflags.cznv; switch(cc){ case 0: return 1; /* T */ case 1: return 0; /* F */ case 2: return (cznv & 0x4100) == 0; /* !GET_CFLG && !GET_ZFLG; HI */ case 3: return (cznv & 0x4100) != 0; /* GET_CFLG || GET_ZFLG; LS */ case 4: return (cznv & 0x100) == 0; /* !GET_CFLG; CC */ case 5: return (cznv & 0x100) != 0; /* GET_CFLG; CS */ case 6: return (cznv & 0x4000) == 0; /* !GET_ZFLG; NE */ case 7: return (cznv & 0x4000) != 0; /* GET_ZFLG; EQ */ case 8: return (cznv & 0x01) == 0; /* !GET_VFLG; VC */ case 9: return (cznv & 0x01) != 0; /* GET_VFLG; VS */ case 10:return (cznv & 0x8000) == 0; /* !GET_NFLG; PL */ case 11:return (cznv & 0x8000) != 0; /* GET_NFLG; MI */ case 12:return (((cznv << 15) ^ cznv) & 0x8000) == 0; /* GET_NFLG == GET_VFLG; GE */ case 13:return (((cznv << 15) ^ cznv) & 0x8000) != 0;/* GET_NFLG != GET_VFLG; LT */ case 14: cznv &= 0xc001; return (((cznv << 15) ^ cznv) & 0xc000) == 0; /* !GET_ZFLG && (GET_NFLG == GET_VFLG); GT */ case 15: cznv &= 0xc001; return (((cznv << 15) ^ cznv) & 0xc000) != 0; /* GET_ZFLG || (GET_NFLG != GET_VFLG); LE */ } abort(); return 0; } /* Manually emit LAHF instruction so that 64-bit assemblers can grok it */ #if defined __x86_64__ && defined __GNUC__ #define ASM_LAHF ".byte 0x9f" #else #define ASM_LAHF "lahf" #endif /* Is there any way to do this without declaring *all* memory clobbered? I.e. any way to tell gcc that some byte-sized value is in %al? */ #define optflag_testl(v) \ __asm__ __volatile__ ("andl %0,%0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : : "r" (v) : "%eax","cc","memory") #define optflag_testw(v) \ __asm__ __volatile__ ("andw %w0,%w0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : : "r" (v) : "%eax","cc","memory") #define optflag_testb(v) \ __asm__ __volatile__ ("andb %b0,%b0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : : "q" (v) : "%eax","cc","memory") #define optflag_addl(v, s, d) do { \ __asm__ __volatile__ ("addl %k1,%k0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ COPY_CARRY; \ } while (0) #define optflag_addw(v, s, d) do { \ __asm__ __volatile__ ("addw %w1,%w0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ COPY_CARRY; \ } while (0) #define optflag_addb(v, s, d) do { \ __asm__ __volatile__ ("addb %b1,%b0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : "=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \ COPY_CARRY; \ } while (0) #define optflag_subl(v, s, d) do { \ __asm__ __volatile__ ("subl %k1,%k0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ COPY_CARRY; \ } while (0) #define optflag_subw(v, s, d) do { \ __asm__ __volatile__ ("subw %w1,%w0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \ COPY_CARRY; \ } while (0) #define optflag_subb(v, s, d) do { \ __asm__ __volatile__ ("subb %b1,%b0\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : "=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \ COPY_CARRY; \ } while (0) #define optflag_cmpl(s, d) \ __asm__ __volatile__ ("cmpl %k0,%k1\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : : "rmi" (s), "r" (d) : "%eax","cc","memory") #define optflag_cmpw(s, d) \ __asm__ __volatile__ ("cmpw %w0,%w1\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : : "rmi" (s), "r" (d) : "%eax","cc","memory"); #define optflag_cmpb(s, d) \ __asm__ __volatile__ ("cmpb %b0,%b1\n\t" \ ASM_LAHF "\n\t" \ "seto %%al\n\t" \ "movb %%al,regflags\n\t" \ "movb %%ah,regflags+1\n\t" \ : : "qmi" (s), "q" (d) : "%eax","cc","memory") #endif #elif defined(__sparc__) && (defined(SPARC_V8_ASSEMBLY) || defined(SPARC_V9_ASSEMBLY)) struct flag_struct { unsigned char nzvc; unsigned char x; }; extern struct flag_struct regflags; #define FLAGVAL_Z 0x04 #define FLAGVAL_N 0x08 #define SET_ZFLG(y) (regflags.nzvc = (regflags.nzvc & ~0x04) | (((y) & 1) << 2)) #define SET_CFLG(y) (regflags.nzvc = (regflags.nzvc & ~1) | ((y) & 1)) #define SET_VFLG(y) (regflags.nzvc = (regflags.nzvc & ~0x02) | (((y) & 1) << 1)) #define SET_NFLG(y) (regflags.nzvc = (regflags.nzvc & ~0x08) | (((y) & 1) << 3)) #define SET_XFLG(y) (regflags.x = (y)) #define GET_ZFLG ((regflags.nzvc >> 2) & 1) #define GET_CFLG (regflags.nzvc & 1) #define GET_VFLG ((regflags.nzvc >> 1) & 1) #define GET_NFLG ((regflags.nzvc >> 3) & 1) #define GET_XFLG (regflags.x & 1) #define CLEAR_CZNV (regflags.nzvc = 0) #define GET_CZNV (reflags.nzvc) #define IOR_CZNV(X) (refglags.nzvc |= (X)) #define SET_CZNV(X) (regflags.nzvc = (X)) #define COPY_CARRY (regflags.x = regflags.nzvc) static __inline__ int cctrue(int cc) { uae_u32 nzvc = regflags.nzvc; switch(cc){ case 0: return 1; /* T */ case 1: return 0; /* F */ case 2: return (nzvc & 0x05) == 0; /* !GET_CFLG && !GET_ZFLG; HI */ case 3: return (nzvc & 0x05) != 0; /* GET_CFLG || GET_ZFLG; LS */ case 4: return (nzvc & 1) == 0; /* !GET_CFLG; CC */ case 5: return (nzvc & 1) != 0; /* GET_CFLG; CS */ case 6: return (nzvc & 0x04) == 0; /* !GET_ZFLG; NE */ case 7: return (nzvc & 0x04) != 0; /* GET_ZFLG; EQ */ case 8: return (nzvc & 0x02) == 0;/* !GET_VFLG; VC */ case 9: return (nzvc & 0x02) != 0;/* GET_VFLG; VS */ case 10:return (nzvc & 0x08) == 0; /* !GET_NFLG; PL */ case 11:return (nzvc & 0x08) != 0; /* GET_NFLG; MI */ case 12:return (((nzvc << 2) ^ nzvc) & 0x08) == 0; /* GET_NFLG == GET_VFLG; GE */ case 13:return (((nzvc << 2) ^ nzvc) & 0x08) != 0;/* GET_NFLG != GET_VFLG; LT */ case 14: nzvc &= 0x0e; return (((nzvc << 2) ^ nzvc) & 0x0c) == 0; /* !GET_ZFLG && (GET_NFLG == GET_VFLG); GT */ case 15: nzvc &= 0x0e; return (((nzvc << 2) ^ nzvc) & 0x0c) != 0; /* GET_ZFLG || (GET_NFLG != GET_VFLG); LE */ } return 0; } #ifdef SPARC_V8_ASSEMBLY static inline uae_u32 sparc_v8_flag_add_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 24, %%o0\n" " sll %3, 24, %%o1\n" " addcc %%o0, %%o1, %%o0\n" " addx %%g0, %%g0, %%o1 ! X,C flags\n" " srl %%o0, 24, %0\n" " stb %%o1, [%1 + 1]\n" " bl,a .+8\n" " or %%o1, 0x08, %%o1 ! N flag\n" " bz,a .+8\n" " or %%o1, 0x04, %%o1 ! Z flag\n" " bvs,a .+8\n" " or %%o1, 0x02, %%o1 ! V flag\n" " stb %%o1, [%1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v8_flag_add_16(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 16, %%o0\n" " sll %3, 16, %%o1\n" " addcc %%o0, %%o1, %%o0\n" " addx %%g0, %%g0, %%o1 ! X,C flags\n" " srl %%o0, 16, %0\n" " stb %%o1, [%1 + 1]\n" " bl,a .+8\n" " or %%o1, 0x08, %%o1 ! N flag\n" " bz,a .+8\n" " or %%o1, 0x04, %%o1 ! Z flag\n" " bvs,a .+8\n" " or %%o1, 0x02, %%o1 ! V flag\n" " stb %%o1, [%1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v8_flag_add_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " addcc %2, %3, %0\n" " addx %%g0, %%g0, %%o0 ! X,C flags\n" " stb %%o0, [%1 + 1]\n" " bl,a .+8\n" " or %%o0, 0x08, %%o0 ! N flag\n" " bz,a .+8\n" " or %%o0, 0x04, %%o0 ! Z flag\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0 ! V flag\n" " stb %%o0, [%1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0" ); return value; } static inline uae_u32 sparc_v8_flag_sub_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 24, %%o0\n" " sll %3, 24, %%o1\n" " subcc %%o0, %%o1, %%o0\n" " addx %%g0, %%g0, %%o1 ! X,C flags\n" " srl %%o0, 24, %0\n" " stb %%o1, [%1 + 1]\n" " bl,a .+8\n" " or %%o1, 0x08, %%o1 ! N flag\n" " bz,a .+8\n" " or %%o1, 0x04, %%o1 ! Z flag\n" " bvs,a .+8\n" " or %%o1, 0x02, %%o1 ! V flag\n" " stb %%o1, [%1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v8_flag_sub_16(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 16, %%o0\n" " sll %3, 16, %%o1\n" " subcc %%o0, %%o1, %%o0\n" " addx %%g0, %%g0, %%o1 ! X,C flags\n" " srl %%o0, 16, %0\n" " stb %%o1, [%1 + 1]\n" " bl,a .+8\n" " or %%o1, 0x08, %%o1 ! N flag\n" " bz,a .+8\n" " or %%o1, 0x04, %%o1 ! Z flag\n" " bvs,a .+8\n" " or %%o1, 0x02, %%o1 ! V flag\n" " stb %%o1, [%1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v8_flag_sub_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " subcc %2, %3, %0\n" " addx %%g0, %%g0, %%o0 ! X,C flags\n" " stb %%o0, [%1 + 1]\n" " bl,a .+8\n" " or %%o0, 0x08, %%o0 ! N flag\n" " bz,a .+8\n" " or %%o0, 0x04, %%o0 ! Z flag\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0 ! V flag\n" " stb %%o0, [%1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0" ); return value; } static inline void sparc_v8_flag_cmp_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { __asm__ ("\n" " sll %1, 24, %%o0\n" " sll %2, 24, %%o1\n" " subcc %%o0, %%o1, %%g0\n" " addx %%g0, %%g0, %%o0 ! C flag\n" " bl,a .+8\n" " or %%o0, 0x08, %%o0 ! N flag\n" " bz,a .+8\n" " or %%o0, 0x04, %%o0 ! Z flag\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0 ! V flag\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); } static inline void sparc_v8_flag_cmp_16(flag_struct *flags, uae_u32 src, uae_u32 dst) { __asm__ ("\n" " sll %1, 16, %%o0\n" " sll %2, 16, %%o1\n" " subcc %%o0, %%o1, %%g0\n" " addx %%g0, %%g0, %%o0 ! C flag\n" " bl,a .+8\n" " or %%o0, 0x08, %%o0 ! N flag\n" " bz,a .+8\n" " or %%o0, 0x04, %%o0 ! Z flag\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0 ! V flag\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); } static inline void sparc_v8_flag_cmp_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { __asm__ ("\n" " subcc %1, %2, %%o1\n" " srl %%o1, 31, %%o0\n" " sll %%o0, 3, %%o0\n" " addx %%o0, %%g0, %%o0\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0\n" " subcc %%g0, %%o1, %%g0\n" " addx %%g0, 7, %%o1\n" " and %%o1, 0x04, %%o1\n" " or %%o0, %%o1, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); } static inline uae_u32 sparc_v8_flag_addx_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " ldub [%1 + 1], %%o1 ! Get the X Flag\n" " subcc %%g0, %%o1, %%g0 ! Set the SPARC carry flag, if X set\n" " addxcc %2, %3, %0\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } #if 0 VERY SLOW... static inline uae_u32 sparc_v8_flag_addx_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 24, %%o0\n" " sll %3, 24, %%o1\n" " addcc %%o0, %%o1, %%o0\n" " addx %%g0, %%g0, %%o1 ! X,C flags\n" " bvs,a .+8\n" " or %%o1, 0x02, %%o1 ! V flag\n" " ldub [%1 + 1], %%o2\n" " subcc %%g0, %%o2, %%g0\n" " addx %%g0, %%g0, %%o2\n" " sll %%o2, 24, %%o2\n" " addcc %%o0, %%o2, %%o0\n" " srl %%o0, 24, %0\n" " addx %%g0, %%g0, %%o2\n" " or %%o1, %%o2, %%o1 ! update X,C flags\n" " bl,a .+8\n" " or %%o1, 0x08, %%o1 ! N flag\n" " ldub [%1], %%o0 ! retreive the old NZVC flags (XXX)\n" " bvs,a .+8\n" " or %%o1, 0x02, %%o1 ! update V flag\n" " and %%o0, 0x04, %%o0 ! (XXX) but keep only Z flag\n" " and %%o1, 1, %%o2 ! keep C flag in %%o2\n" " bnz,a .+8\n" " or %%g0, %%g0, %%o0 ! Z flag cleared if non-zero result\n" " stb %%o2, [%1 + 1] ! store the X flag\n" " or %%o1, %%o0, %%o1\n" " stb %%o1, [%1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1", "o2" ); return value; } #endif static inline uae_u32 sparc_v8_flag_addx_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " ldub [%1 + 1], %%o0 ! Get the X Flag\n" " subcc %%g0, %%o0, %%g0 ! Set the SPARC carry flag, if X set\n" " addxcc %2, %3, %0\n" " ldub [%1], %%o0 ! retreive the old NZVC flags\n" " and %%o0, 0x04, %%o0 ! but keep only Z flag\n" " addx %%o0, %%g0, %%o0 ! X,C flags\n" " bl,a .+8\n" " or %%o0, 0x08, %%o0 ! N flag\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0 ! V flag\n" " bnz,a .+8\n" " and %%o0, 0x0B, %%o0 ! Z flag cleared if result is non-zero\n" " stb %%o0, [%1]\n" " stb %%o0, [%1 + 1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0" ); return value; } #endif /* SPARC_V8_ASSEMBLY */ #ifdef SPARC_V9_ASSEMBLY static inline uae_u32 sparc_v9_flag_add_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 24, %%o0\n" " sll %3, 24, %%o1\n" " addcc %%o0, %%o1, %%o0\n" " rd %%ccr, %%o1\n" " srl %%o0, 24, %0\n" " stb %%o1, [%1]\n" " stb %%o1, [%1+1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v9_flag_add_16(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 16, %%o0\n" " sll %3, 16, %%o1\n" " addcc %%o0, %%o1, %%o0\n" " rd %%ccr, %%o1\n" " srl %%o0, 16, %0\n" " stb %%o1, [%1]\n" " stb %%o1, [%1+1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v9_flag_add_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " addcc %2, %3, %0\n" " rd %%ccr, %%o0\n" " stb %%o0, [%1]\n" " stb %%o0, [%1+1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0" ); return value; } static inline uae_u32 sparc_v9_flag_sub_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 24, %%o0\n" " sll %3, 24, %%o1\n" " subcc %%o0, %%o1, %%o0\n" " rd %%ccr, %%o1\n" " srl %%o0, 24, %0\n" " stb %%o1, [%1]\n" " stb %%o1, [%1+1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v9_flag_sub_16(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " sll %2, 16, %%o0\n" " sll %3, 16, %%o1\n" " subcc %%o0, %%o1, %%o0\n" " rd %%ccr, %%o1\n" " srl %%o0, 16, %0\n" " stb %%o1, [%1]\n" " stb %%o1, [%1+1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v9_flag_sub_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " subcc %2, %3, %0\n" " rd %%ccr, %%o0\n" " stb %%o0, [%1]\n" " stb %%o0, [%1+1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0" ); return value; } static inline void sparc_v9_flag_cmp_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { __asm__ ("\n" " sll %1, 24, %%o0\n" " sll %2, 24, %%o1\n" " subcc %%o0, %%o1, %%g0\n" " rd %%ccr, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); } static inline void sparc_v9_flag_cmp_16(flag_struct *flags, uae_u32 src, uae_u32 dst) { __asm__ ("\n" " sll %1, 16, %%o0\n" " sll %2, 16, %%o1\n" " subcc %%o0, %%o1, %%g0\n" " rd %%ccr, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); } static inline void sparc_v9_flag_cmp_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { __asm__ ("\n" " subcc %1, %2, %%g0\n" #if 0 " subcc %1, %2, %%o1\n" " srl %%o1, 31, %%o0\n" " sll %%o0, 3, %%o0\n" " addx %%o0, %%g0, %%o0\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0\n" " subcc %%g0, %%o1, %%g0\n" " addx %%g0, 7, %%o1\n" " and %%o1, 0x04, %%o1\n" " or %%o0, %%o1, %%o0\n" #endif #if 0 " subcc %1, %2, %%o1\n" " srl %%o1, 31, %%o0\n" " sll %%o0, 3, %%o0\n" " addx %%o0, %%g0, %%o0\n" " bvs,pt,a .+8\n" " or %%o0, 0x02, %%o0\n" " subcc %%g0, %%o1, %%g0\n" " addx %%g0, 7, %%o1\n" " and %%o1, 0x04, %%o1\n" " or %%o0, %%o1, %%o0\n" " stb %%o0, [%0]\n" #endif " rd %%ccr, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); } #if 1 static inline void sparc_v9_flag_test_8(flag_struct *flags, uae_u32 val) { __asm__ ("\n" " sll %1, 24, %%o0\n" " subcc %%o0, %%g0, %%g0\n" " rd %%ccr, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (val) : "cc", "o0" ); } static inline void sparc_v9_flag_test_16(flag_struct *flags, uae_u32 val) { __asm__ ("\n" " sll %1, 16, %%o0\n" " subcc %%o0, %%g0, %%g0\n" " rd %%ccr, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (val) : "cc", "o0" ); } static inline void sparc_v9_flag_test_32(flag_struct *flags, uae_u32 val) { __asm__ ("\n" " subcc %1, %%g0, %%g0\n" " rd %%ccr, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (val) : "cc", "o0" ); } #else static inline void sparc_v9_flag_test_8(flag_struct *flags, uae_u32 val) { __asm__ ("\n" " sll %1, 24, %%o0\n" " subcc %%o0, %%g0, %%o1\n" " srl %%o1, 31, %%o0\n" " sll %%o0, 3, %%o0\n" " addx %%o0, %%g0, %%o0\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0\n" " subcc %%g0, %%o1, %%g0\n" " addx %%g0, 7, %%o1\n" " and %%o1, 0x04, %%o1\n" " or %%o0, %%o1, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (val) : "cc", "o0", "o1" ); } static inline void sparc_v9_flag_test_16(flag_struct *flags, uae_u32 val) { __asm__ ("\n" " sll %1, 16, %%o0\n" " subcc %%o0, %%g0, %%o1\n" " srl %%o1, 31, %%o0\n" " sll %%o0, 3, %%o0\n" " addx %%o0, %%g0, %%o0\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0\n" " subcc %%g0, %%o1, %%g0\n" " addx %%g0, 7, %%o1\n" " and %%o1, 0x04, %%o1\n" " or %%o0, %%o1, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (val) : "cc", "o0", "o1" ); } static inline void sparc_v9_flag_test_32(flag_struct *flags, uae_u32 val) { __asm__ ("\n" " subcc %1, %%g0, %%o1\n" " srl %%o1, 31, %%o0\n" " sll %%o0, 3, %%o0\n" " addx %%o0, %%g0, %%o0\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0\n" " subcc %%g0, %%o1, %%g0\n" " addx %%g0, 7, %%o1\n" " and %%o1, 0x04, %%o1\n" " or %%o0, %%o1, %%o0\n" " stb %%o0, [%0]\n" : /* no outputs */ : "r" (flags), "r" (val) : "cc", "o0", "o1" ); } #endif static inline uae_u32 sparc_v9_flag_addx_8(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " ldub [%1 + 1], %%o1 ! Get the X Flag\n" " subcc %%g0, %%o1, %%g0 ! Set the SPARC carry flag, if X set\n" " addxcc %2, %3, %0\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0", "o1" ); return value; } static inline uae_u32 sparc_v9_flag_addx_32(flag_struct *flags, uae_u32 src, uae_u32 dst) { uae_u32 value; __asm__ ("\n" " ldub [%1 + 1], %%o0 ! Get the X Flag\n" " subcc %%g0, %%o0, %%g0 ! Set the SPARC carry flag, if X set\n" " addxcc %2, %3, %0\n" " ldub [%1], %%o0 ! retreive the old NZVC flags\n" " and %%o0, 0x04, %%o0 ! but keep only Z flag\n" " addx %%o0, %%g0, %%o0 ! X,C flags\n" " bl,a .+8\n" " or %%o0, 0x08, %%o0 ! N flag\n" " bvs,a .+8\n" " or %%o0, 0x02, %%o0 ! V flag\n" " bnz,a .+8\n" " and %%o0, 0x0B, %%o0 ! Z flag cleared if result is non-zero\n" " stb %%o0, [%1]\n" " stb %%o0, [%1 + 1]\n" : "=&r" (value) : "r" (flags), "r" (dst), "r" (src) : "cc", "o0" ); return value; } #endif /* SPARC_V9_ASSEMBLY */ #endif #else struct flag_struct { unsigned int c; unsigned int z; unsigned int n; unsigned int v; unsigned int x; }; extern struct flag_struct regflags; #define ZFLG (regflags.z) #define NFLG (regflags.n) #define CFLG (regflags.c) #define VFLG (regflags.v) #define XFLG (regflags.x) #define SET_CFLG(x) (CFLG = (x)) #define SET_NFLG(x) (NFLG = (x)) #define SET_VFLG(x) (VFLG = (x)) #define SET_ZFLG(x) (ZFLG = (x)) #define SET_XFLG(x) (XFLG = (x)) #define GET_CFLG CFLG #define GET_NFLG NFLG #define GET_VFLG VFLG #define GET_ZFLG ZFLG #define GET_XFLG XFLG #define CLEAR_CZNV do { \ SET_CFLG (0); \ SET_ZFLG (0); \ SET_NFLG (0); \ SET_VFLG (0); \ } while (0) #define COPY_CARRY (SET_XFLG (GET_CFLG)) static __inline__ int cctrue(const int cc) { switch(cc){ case 0: return 1; /* T */ case 1: return 0; /* F */ case 2: return !CFLG && !ZFLG; /* HI */ case 3: return CFLG || ZFLG; /* LS */ case 4: return !CFLG; /* CC */ case 5: return CFLG; /* CS */ case 6: return !ZFLG; /* NE */ case 7: return ZFLG; /* EQ */ case 8: return !VFLG; /* VC */ case 9: return VFLG; /* VS */ case 10:return !NFLG; /* PL */ case 11:return NFLG; /* MI */ case 12:return NFLG == VFLG; /* GE */ case 13:return NFLG != VFLG; /* LT */ case 14:return !ZFLG && (NFLG == VFLG); /* GT */ case 15:return ZFLG || (NFLG != VFLG); /* LE */ } return 0; } #endif /* OPTIMIZED_FLAGS */ #endif /* M68K_FLAGS_H */ BasiliskII/src/uae_cpu/table68k0000644000175000017500000003222407534427571016535 0ustar centriscentris% 0: bit 0 % 1: bit 1 % c: condition code % C: condition codes, except F % f: direction % i: immediate % E: immediate, except 00 (for EmulOp instructions) % I: immediate, except 00 and ff % j: immediate 1..8 % J: immediate 0..15 % k: immediate 0..7 % K: immediate 0..63 % p: immediate 0..3 (CINV and CPUSH instructions: Cache Field) % s: source mode % S: source reg % d: dest mode % D: dest reg % r: reg % z: size % % Actually, a sssSSS may appear as a destination, and % vice versa. The only difference between sssSSS and % dddDDD are the valid addressing modes. There is % no match for immediate and pc-rel. addressing modes % in case of dddDDD. % % Arp: --> -(Ar) % ArP: --> (Ar)+ % L: --> (xxx.L) % % Fields on a line: % 16 chars bitpattern : % CPU level / privilege level : % CPU level 0: 68000 % 1: 68010 % 2: 68020 % 3: 68020/68881 % 4: 68040 % privilege level 0: not privileged % 1: unprivileged only on 68000 (check regs.s) % 2: privileged (check regs.s) % 3: privileged if size == word (check regs.s) % Flags set by instruction: XNZVC : % Flags used by instruction: XNZVC : % - means flag unaffected / unused % 0 means flag reset % 1 means flag set % ? means programmer was too lazy to check or instruction may trap % everything else means flag set/used % x means flag is unknown and well-behaved programs shouldn't check it % % Control flow % two letters, combination of % - nothing % T the instruction may trap or cause an exception % B branch instruction % J jump instruction % R return instruction % % srcaddr status destaddr status : % bitmasks of % 1 means fetched % 2 means stored % 4 means jump offset % 8 means jump address % instruction % 0000 0000 0011 1100:00:XNZVC:XNZVC:--:10: ORSR.B #1 0000 0000 0111 1100:02:XNZVC:XNZVC:T-:10: ORSR.W #1 0000 0zz0 11ss sSSS:20:-?Z?C:-----:T-:11: CHK2.z #1,s[!Dreg,Areg,Aipi,Apdi,Immd] 0000 0000 zzdd dDDD:00:-NZ00:-----:--:13: OR.z #z,d[!Areg] 0000 0010 0011 1100:00:XNZVC:XNZVC:--:10: ANDSR.B #1 0000 0010 0111 1100:02:XNZVC:XNZVC:T-:10: ANDSR.W #1 0000 0010 zzdd dDDD:00:-NZ00:-----:--:13: AND.z #z,d[!Areg] 0000 0100 zzdd dDDD:00:XNZVC:-----:--:13: SUB.z #z,d[!Areg] 0000 0110 zzdd dDDD:00:XNZVC:-----:--:13: ADD.z #z,d[!Areg] 0000 0110 11ss sSSS:20:-----:XNZVC:--:10: CALLM s[!Dreg,Areg,Aipi,Apdi,Immd] 0000 0110 11ss sSSS:20:XNZVC:-----:-R:10: RTM s[Dreg,Areg] 0000 1000 00ss sSSS:00:--Z--:-----:--:11: BTST #1,s[!Areg] 0000 1000 01ss sSSS:00:--Z--:-----:--:13: BCHG #1,s[!Areg,Immd] 0000 1000 10ss sSSS:00:--Z--:-----:--:13: BCLR #1,s[!Areg,Immd] 0000 1000 11ss sSSS:00:--Z--:-----:--:13: BSET #1,s[!Areg,Immd] 0000 1010 0011 1100:00:XNZVC:XNZVC:--:10: EORSR.B #1 0000 1010 0111 1100:02:XNZVC:XNZVC:T-:10: EORSR.W #1 0000 1010 zzdd dDDD:00:-NZ00:-----:--:13: EOR.z #z,d[!Areg] 0000 1100 zzss sSSS:00:-NZVC:-----:--:11: CMP.z #z,s[!Areg,Immd] 0000 1010 11ss sSSS:20:-NZVC:-----:--:13: CAS.B #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1100 11ss sSSS:20:-NZVC:-----:--:13: CAS.W #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1100 1111 1100:20:-NZVC:-----:--:10: CAS2.W #2 0000 1110 zzss sSSS:22:-----:-----:T-:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1110 11ss sSSS:20:-NZVC:-----:--:13: CAS.L #1,s[!Dreg,Areg,Immd,PC8r,PC16] 0000 1110 1111 1100:20:-NZVC:-----:--:10: CAS2.L #2 0000 rrr1 00dd dDDD:00:-----:-----:--:12: MVPMR.W d[Areg-Ad16],Dr 0000 rrr1 01dd dDDD:00:-----:-----:--:12: MVPMR.L d[Areg-Ad16],Dr 0000 rrr1 10dd dDDD:00:-----:-----:--:12: MVPRM.W Dr,d[Areg-Ad16] 0000 rrr1 11dd dDDD:00:-----:-----:--:12: MVPRM.L Dr,d[Areg-Ad16] 0000 rrr1 00ss sSSS:00:--Z--:-----:--:11: BTST Dr,s[!Areg] 0000 rrr1 01ss sSSS:00:--Z--:-----:--:13: BCHG Dr,s[!Areg,Immd] 0000 rrr1 10ss sSSS:00:--Z--:-----:--:13: BCLR Dr,s[!Areg,Immd] 0000 rrr1 11ss sSSS:00:--Z--:-----:--:13: BSET Dr,s[!Areg,Immd] 0001 DDDd ddss sSSS:00:-NZ00:-----:--:12: MOVE.B s,d[!Areg] 0010 DDDd ddss sSSS:00:-----:-----:--:12: MOVEA.L s,d[Areg] 0010 DDDd ddss sSSS:00:-NZ00:-----:--:12: MOVE.L s,d[!Areg] 0011 DDDd ddss sSSS:00:-----:-----:--:12: MOVEA.W s,d[Areg] 0011 DDDd ddss sSSS:00:-NZ00:-----:--:12: MOVE.W s,d[!Areg] 0100 0000 zzdd dDDD:00:XxZxC:X-Z--:--:30: NEGX.z d[!Areg] 0100 0000 11dd dDDD:01:-----:XNZVC:T-:10: MVSR2.W d[!Areg] 0100 0010 zzdd dDDD:00:-0100:-----:--:20: CLR.z d[!Areg] 0100 0010 11dd dDDD:10:-----:XNZVC:--:10: MVSR2.B d[!Areg] 0100 0100 zzdd dDDD:00:XNZVC:-----:--:30: NEG.z d[!Areg] 0100 0100 11ss sSSS:00:XNZVC:-----:--:10: MV2SR.B s[!Areg] 0100 0110 zzdd dDDD:00:-NZ00:-----:--:30: NOT.z d[!Areg] 0100 0110 11ss sSSS:02:XNZVC:XNZVC:T-:10: MV2SR.W s[!Areg] 0100 1000 0000 1rrr:20:-----:-----:--:31: LINK.L Ar,#2 0100 1000 00dd dDDD:00:X?Z?C:X-Z--:--:30: NBCD.B d[!Areg] 0100 1000 0100 1kkk:20:-----:-----:T-:10: BKPT #k 0100 1000 01ss sSSS:00:-NZ00:-----:--:30: SWAP.W s[Dreg] 0100 1000 01ss sSSS:00:-----:-----:--:00: PEA.L s[!Dreg,Areg,Aipi,Apdi,Immd] 0100 1000 10dd dDDD:00:-NZ00:-----:--:30: EXT.W d[Dreg] 0100 1000 10dd dDDD:00:-----:-----:--:02: MVMLE.W #1,d[!Dreg,Areg,Aipi] 0100 1000 11dd dDDD:00:-NZ00:-----:--:30: EXT.L d[Dreg] 0100 1000 11dd dDDD:00:-----:-----:--:02: MVMLE.L #1,d[!Dreg,Areg,Aipi] 0100 1001 11dd dDDD:00:-NZ00:-----:--:30: EXT.B d[Dreg] 0100 1010 zzss sSSS:00:-NZ00:-----:--:10: TST.z s 0100 1010 11dd dDDD:00:-NZ00:-----:--:30: TAS.B d[!Areg] 0100 1010 1111 1100:00:-----:-----:T-:00: ILLEGAL 0100 1100 00ss sSSS:20:-NZVC:-----:--:13: MULL.L #1,s[!Areg] 0100 1100 01ss sSSS:20:-NZV0:-----:T-:13: DIVL.L #1,s[!Areg] 0100 1100 10ss sSSS:00:-----:-----:--:01: MVMEL.W #1,s[!Dreg,Areg,Apdi,Immd] 0100 1100 11ss sSSS:00:-----:-----:--:01: MVMEL.L #1,s[!Dreg,Areg,Apdi,Immd] 0100 1110 0100 JJJJ:00:-----:XNZVC:--:10: TRAP #J 0100 1110 0101 0rrr:00:-----:-----:--:31: LINK.W Ar,#1 0100 1110 0101 1rrr:00:-----:-----:--:30: UNLK.L Ar 0100 1110 0110 0rrr:02:-----:-----:T-:10: MVR2USP.L Ar 0100 1110 0110 1rrr:02:-----:-----:T-:20: MVUSP2R.L Ar 0100 1110 0111 0000:02:-----:-----:T-:00: RESET 0100 1110 0111 0001:00:-----:-----:--:00: NOP 0100 1110 0111 0010:02:XNZVC:-----:T-:10: STOP #1 0100 1110 0111 0011:02:XNZVC:-----:TR:00: RTE 0100 1110 0111 0100:00:-----:-----:-R:10: RTD #1 0100 1110 0111 0101:00:-----:-----:-R:00: RTS 0100 1110 0111 0110:00:-----:XNZVC:T-:00: TRAPV 0100 1110 0111 0111:00:XNZVC:-----:-R:00: RTR 0100 1110 0111 1010:12:-----:-----:T-:10: MOVEC2 #1 0100 1110 0111 1011:12:-----:-----:T-:10: MOVE2C #1 0100 1110 10ss sSSS:00:-----:-----:-J:80: JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd] 0100 rrr1 00ss sSSS:00:-N???:-----:T-:11: CHK.L s[!Areg],Dr 0100 rrr1 10ss sSSS:00:-N???:-----:T-:11: CHK.W s[!Areg],Dr 0100 1110 11ss sSSS:00:-----:-----:-J:80: JMP.L s[!Dreg,Areg,Aipi,Apdi,Immd] 0100 rrr1 11ss sSSS:00:-----:-----:--:02: LEA.L s[!Dreg,Areg,Aipi,Apdi,Immd],Ar 0101 jjj0 01dd dDDD:00:-----:-----:--:13: ADDA.W #j,d[Areg] 0101 jjj0 10dd dDDD:00:-----:-----:--:13: ADDA.L #j,d[Areg] 0101 jjj0 zzdd dDDD:00:XNZVC:-----:--:13: ADD.z #j,d[!Areg] 0101 jjj1 01dd dDDD:00:-----:-----:--:13: SUBA.W #j,d[Areg] 0101 jjj1 10dd dDDD:00:-----:-----:--:13: SUBA.L #j,d[Areg] 0101 jjj1 zzdd dDDD:00:XNZVC:-----:--:13: SUB.z #j,d[!Areg] 0101 cccc 1100 1rrr:00:-----:-????:-B:31: DBcc.W Dr,#1 0101 cccc 11dd dDDD:00:-----:-????:--:20: Scc.B d[!Areg] 0101 cccc 1111 1010:20:-----:-????:T-:10: TRAPcc #1 0101 cccc 1111 1011:20:-----:-????:T-:10: TRAPcc #2 0101 cccc 1111 1100:20:-----:-????:T-:00: TRAPcc % Bxx.L is 68020 only, but setting the CPU level to 2 would give illegal % instruction exceptions when compiling a 68000 only emulation, which isn't % what we want either. 0110 0001 0000 0000:00:-----:-----:-B:40: BSR.W #1 0110 0001 IIII IIII:00:-----:-----:-B:40: BSR.B #i 0110 0001 1111 1111:00:-----:-----:-B:40: BSR.L #2 0110 CCCC 0000 0000:00:-----:-????:-B:40: Bcc.W #1 0110 CCCC IIII IIII:00:-----:-????:-B:40: Bcc.B #i 0110 CCCC 1111 1111:00:-----:-????:-B:40: Bcc.L #2 0111 rrr0 iiii iiii:00:-NZ00:-----:--:12: MOVE.L #i,Dr 1000 rrr0 zzss sSSS:00:-NZ00:-----:--:13: OR.z s[!Areg],Dr 1000 rrr0 11ss sSSS:00:-NZV0:-----:T-:13: DIVU.W s[!Areg],Dr 1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: SBCD.B d[Dreg],Dr 1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: SBCD.B d[Areg-Apdi],Arp 1000 rrr1 zzdd dDDD:00:-NZ00:-----:--:13: OR.z Dr,d[!Areg,Dreg] 1000 rrr1 01dd dDDD:20:-----:-----:--:12: PACK d[Dreg],Dr 1000 rrr1 01dd dDDD:20:-----:-----:--:12: PACK d[Areg-Apdi],Arp 1000 rrr1 10dd dDDD:20:-----:-----:--:12: UNPK d[Dreg],Dr 1000 rrr1 10dd dDDD:20:-----:-----:--:12: UNPK d[Areg-Apdi],Arp 1000 rrr1 11ss sSSS:00:-NZV0:-----:T-:13: DIVS.W s[!Areg],Dr 1001 rrr0 zzss sSSS:00:XNZVC:-----:--:13: SUB.z s,Dr 1001 rrr0 11ss sSSS:00:-----:-----:--:13: SUBA.W s,Ar 1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: SUBX.z d[Dreg],Dr 1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: SUBX.z d[Areg-Apdi],Arp 1001 rrr1 zzdd dDDD:00:XNZVC:-----:--:13: SUB.z Dr,d[!Areg,Dreg] 1001 rrr1 11ss sSSS:00:-----:-----:--:13: SUBA.L s,Ar 1011 rrr0 zzss sSSS:00:-NZVC:-----:--:11: CMP.z s,Dr 1011 rrr0 11ss sSSS:00:-NZVC:-----:--:11: CMPA.W s,Ar 1011 rrr1 11ss sSSS:00:-NZVC:-----:--:11: CMPA.L s,Ar 1011 rrr1 zzdd dDDD:00:-NZVC:-----:--:11: CMPM.z d[Areg-Aipi],ArP 1011 rrr1 zzdd dDDD:00:-NZ00:-----:--:13: EOR.z Dr,d[!Areg] 1100 rrr0 zzss sSSS:00:-NZ00:-----:--:13: AND.z s[!Areg],Dr 1100 rrr0 11ss sSSS:00:-NZ00:-----:--:13: MULU.W s[!Areg],Dr 1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: ABCD.B d[Dreg],Dr 1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:--:13: ABCD.B d[Areg-Apdi],Arp 1100 rrr1 zzdd dDDD:00:-NZ00:-----:--:13: AND.z Dr,d[!Areg,Dreg] 1100 rrr1 01dd dDDD:00:-----:-----:--:33: EXG.L Dr,d[Dreg] 1100 rrr1 01dd dDDD:00:-----:-----:--:33: EXG.L Ar,d[Areg] 1100 rrr1 10dd dDDD:00:-----:-----:--:33: EXG.L Dr,d[Areg] 1100 rrr1 11ss sSSS:00:-NZ00:-----:--:13: MULS.W s[!Areg],Dr 1101 rrr0 zzss sSSS:00:XNZVC:-----:--:13: ADD.z s,Dr 1101 rrr0 11ss sSSS:00:-----:-----:--:13: ADDA.W s,Ar 1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: ADDX.z d[Dreg],Dr 1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:--:13: ADDX.z d[Areg-Apdi],Arp 1101 rrr1 zzdd dDDD:00:XNZVC:-----:--:13: ADD.z Dr,d[!Areg,Dreg] 1101 rrr1 11ss sSSS:00:-----:-----:--:13: ADDA.L s,Ar 1110 jjjf zz00 0RRR:00:XNZVC:-----:--:13: ASf.z #j,DR 1110 jjjf zz00 1RRR:00:XNZ0C:-----:--:13: LSf.z #j,DR 1110 jjjf zz01 0RRR:00:XNZ0C:X----:--:13: ROXf.z #j,DR 1110 jjjf zz01 1RRR:00:-NZ0C:-----:--:13: ROf.z #j,DR 1110 rrrf zz10 0RRR:00:XNZVC:-----:--:13: ASf.z Dr,DR 1110 rrrf zz10 1RRR:00:XNZ0C:-----:--:13: LSf.z Dr,DR 1110 rrrf zz11 0RRR:00:XNZ0C:X----:--:13: ROXf.z Dr,DR 1110 rrrf zz11 1RRR:00:-NZ0C:-----:--:13: ROf.z Dr,DR 1110 000f 11dd dDDD:00:XNZVC:-----:--:13: ASfW.W d[!Dreg,Areg] 1110 001f 11dd dDDD:00:XNZ0C:-----:--:13: LSfW.W d[!Dreg,Areg] 1110 010f 11dd dDDD:00:XNZ0C:X----:--:13: ROXfW.W d[!Dreg,Areg] 1110 011f 11dd dDDD:00:-NZ0C:-----:--:13: ROfW.W d[!Dreg,Areg] 1110 1000 11ss sSSS:20:-NZ00:-----:--:11: BFTST #1,s[!Areg,Apdi,Aipi,Immd] 1110 1001 11ss sSSS:20:-NZ00:-----:--:11: BFEXTU #1,s[!Areg,Apdi,Aipi,Immd] 1110 1010 11ss sSSS:20:-NZ00:-----:--:13: BFCHG #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] 1110 1011 11ss sSSS:20:-NZ00:-----:--:11: BFEXTS #1,s[!Areg,Apdi,Aipi,Immd] 1110 1100 11ss sSSS:20:-NZ00:-----:--:13: BFCLR #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] 1110 1101 11ss sSSS:20:-NZ00:-----:--:11: BFFFO #1,s[!Areg,Apdi,Aipi,Immd] 1110 1110 11ss sSSS:20:-NZ00:-----:--:13: BFSET #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] 1110 1111 11ss sSSS:20:-NZ00:-----:--:13: BFINS #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16] % floating point co processor 1111 0010 00ss sSSS:30:-----:-----:--:11: FPP #1,s 1111 0010 01ss sSSS:30:-----:-----:-B:11: FDBcc #1,s[Areg-Dreg] 1111 0010 01ss sSSS:30:-----:-----:--:11: FScc #1,s[!Areg,Immd,PC8r,PC16] 1111 0010 0111 1010:30:-----:-----:T-:10: FTRAPcc #1 1111 0010 0111 1011:30:-----:-----:T-:10: FTRAPcc #2 1111 0010 0111 1100:30:-----:-----:T-:00: FTRAPcc 1111 0010 10KK KKKK:30:-----:-----:-B:11: FBcc #K,#1 1111 0010 11KK KKKK:30:-----:-----:-B:11: FBcc #K,#2 1111 0011 00ss sSSS:32:-----:-----:--:20: FSAVE s[!Dreg,Areg,Aipi,Immd,PC8r,PC16] 1111 0011 01ss sSSS:32:-----:-----:--:10: FRESTORE s[!Dreg,Areg,Apdi,Immd] % 68040 instructions 1111 0101 iiii iSSS:40:-----:-----:T-:11: MMUOP #i,s 1111 0100 pp00 1rrr:42:-----:-----:T-:02: CINVL #p,Ar 1111 0100 pp01 0rrr:42:-----:-----:T-:02: CINVP #p,Ar 1111 0100 pp01 1rrr:42:-----:-----:T-:00: CINVA #p 1111 0100 pp10 1rrr:42:-----:-----:T-:02: CPUSHL #p,Ar 1111 0100 pp11 0rrr:42:-----:-----:T-:02: CPUSHP #p,Ar 1111 0100 pp11 1rrr:42:-----:-----:T-:00: CPUSHA #p % destination register number is encoded in the following word 1111 0110 0010 0rrr:40:-----:-----:--:12: MOVE16 ArP,AxP 1111 0110 00ss sSSS:40:-----:-----:--:12: MOVE16 s[Dreg-Aipi],L 1111 0110 00dd dDDD:40:-----:-----:--:12: MOVE16 L,d[Areg-Aipi] 1111 0110 00ss sSSS:40:-----:-----:--:12: MOVE16 s[Aind],L 1111 0110 00dd dDDD:40:-----:-----:--:12: MOVE16 L,d[Aipi-Aind] % EmulOp instructions 0111 0001 0000 0000:00:-----:-----:-R:00: EMULOP_RETURN 0111 0001 EEEE EEEE:00:-----:-----:-J:10: EMULOP #E BasiliskII/src/uae_cpu/spcflags.h0000644000175000017500000000507511735673707017153 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * MC68000 emulation * * Copyright 1995 Bernd Schmidt * * 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 */ #ifndef SPCFLAGS_H #define SPCFLAGS_H typedef uae_u32 spcflags_t; enum { SPCFLAG_STOP = 0x01, SPCFLAG_INT = 0x02, SPCFLAG_BRK = 0x04, SPCFLAG_TRACE = 0x08, SPCFLAG_DOTRACE = 0x10, SPCFLAG_DOINT = 0x20, #if USE_JIT SPCFLAG_JIT_END_COMPILE = 0x40, SPCFLAG_JIT_EXEC_RETURN = 0x80, #else SPCFLAG_JIT_END_COMPILE = 0, SPCFLAG_JIT_EXEC_RETURN = 0, #endif SPCFLAG_ALL = SPCFLAG_STOP | SPCFLAG_INT | SPCFLAG_BRK | SPCFLAG_TRACE | SPCFLAG_DOTRACE | SPCFLAG_DOINT | SPCFLAG_JIT_END_COMPILE | SPCFLAG_JIT_EXEC_RETURN , SPCFLAG_ALL_BUT_EXEC_RETURN = SPCFLAG_ALL & ~SPCFLAG_JIT_EXEC_RETURN }; #define SPCFLAGS_TEST(m) \ ((regs.spcflags & (m)) != 0) /* Macro only used in m68k_reset() */ #define SPCFLAGS_INIT(m) do { \ regs.spcflags = (m); \ } while (0) #if !(ENABLE_EXCLUSIVE_SPCFLAGS) #define SPCFLAGS_SET(m) do { \ regs.spcflags |= (m); \ } while (0) #define SPCFLAGS_CLEAR(m) do { \ regs.spcflags &= ~(m); \ } while (0) #elif (defined(__i386__) || defined(__x86_64__)) && defined(X86_ASSEMBLY) #define HAVE_HARDWARE_LOCKS #define SPCFLAGS_SET(m) do { \ __asm__ __volatile__("lock\n\torl %1,%0" : "=m" (regs.spcflags) : "i" ((m))); \ } while (0) #define SPCFLAGS_CLEAR(m) do { \ __asm__ __volatile__("lock\n\tandl %1,%0" : "=m" (regs.spcflags) : "i" (~(m))); \ } while (0) #else #undef HAVE_HARDWARE_LOCKS #include "main.h" extern B2_mutex *spcflags_lock; #define SPCFLAGS_SET(m) do { \ B2_lock_mutex(spcflags_lock); \ regs.spcflags |= (m); \ B2_unlock_mutex(spcflags_lock); \ } while (0) #define SPCFLAGS_CLEAR(m) do { \ B2_lock_mutex(spcflags_lock); \ regs.spcflags &= ~(m); \ B2_unlock_mutex(spcflags_lock); \ } while (0) #endif #endif /* SPCFLAGS_H */ BasiliskII/src/uae_cpu/basilisk_glue.cpp0000644000175000017500000001241410736405223020476 0ustar centriscentris/* * basilisk_glue.cpp - Glue UAE CPU to Basilisk II CPU engine interface * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "prefs.h" #include "emul_op.h" #include "rom_patches.h" #include "timer.h" #include "m68k.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" #include "compiler/compemu.h" // RAM and ROM pointers uint32 RAMBaseMac = 0; // RAM base (Mac address space) gb-- initializer is important uint8 *RAMBaseHost; // RAM base (host address space) uint32 RAMSize; // Size of RAM uint32 ROMBaseMac; // ROM base (Mac address space) uint8 *ROMBaseHost; // ROM base (host address space) uint32 ROMSize; // Size of ROM #if !REAL_ADDRESSING // Mac frame buffer uint8 *MacFrameBaseHost; // Frame buffer base (host address space) uint32 MacFrameSize; // Size of frame buffer int MacFrameLayout; // Frame buffer layout #endif #if DIRECT_ADDRESSING uintptr MEMBaseDiff; // Global offset between a Mac address and its Host equivalent #endif #if USE_JIT bool UseJIT = false; #endif // From newcpu.cpp extern bool quit_program; /* * Initialize 680x0 emulation, CheckROM() must have been called first */ bool Init680x0(void) { #if REAL_ADDRESSING // Mac address space = host address space RAMBaseMac = (uintptr)RAMBaseHost; ROMBaseMac = (uintptr)ROMBaseHost; #elif DIRECT_ADDRESSING // Mac address space = host address space minus constant offset (MEMBaseDiff) // NOTE: MEMBaseDiff is set up in main_unix.cpp/main() RAMBaseMac = 0; ROMBaseMac = Host2MacAddr(ROMBaseHost); #else // Initialize UAE memory banks RAMBaseMac = 0; switch (ROMVersion) { case ROM_VERSION_64K: case ROM_VERSION_PLUS: case ROM_VERSION_CLASSIC: ROMBaseMac = 0x00400000; break; case ROM_VERSION_II: ROMBaseMac = 0x00a00000; break; case ROM_VERSION_32: ROMBaseMac = 0x40800000; break; default: return false; } memory_init(); #endif init_m68k(); #if USE_JIT UseJIT = compiler_use_jit(); if (UseJIT) compiler_init(); #endif return true; } /* * Deinitialize 680x0 emulation */ void Exit680x0(void) { #if USE_JIT if (UseJIT) compiler_exit(); #endif exit_m68k(); } /* * Initialize memory mapping of frame buffer (called upon video mode change) */ void InitFrameBufferMapping(void) { #if !REAL_ADDRESSING && !DIRECT_ADDRESSING memory_init(); #endif } /* * Reset and start 680x0 emulation (doesn't return) */ void Start680x0(void) { m68k_reset(); #if USE_JIT if (UseJIT) m68k_compile_execute(); else #endif m68k_execute(); } /* * Trigger interrupt */ void TriggerInterrupt(void) { idle_resume(); SPCFLAGS_SET( SPCFLAG_INT ); } void TriggerNMI(void) { //!! not implemented yet } /* * Get 68k interrupt level */ int intlev(void) { return InterruptFlags ? 1 : 0; } /* * Execute MacOS 68k trap * r->a[7] and r->sr are unused! */ void Execute68kTrap(uint16 trap, struct M68kRegisters *r) { int i; // Save old PC uaecptr oldpc = m68k_getpc(); // Set registers for (i=0; i<8; i++) m68k_dreg(regs, i) = r->d[i]; for (i=0; i<7; i++) m68k_areg(regs, i) = r->a[i]; // Push trap and EXEC_RETURN on stack m68k_areg(regs, 7) -= 2; put_word(m68k_areg(regs, 7), M68K_EXEC_RETURN); m68k_areg(regs, 7) -= 2; put_word(m68k_areg(regs, 7), trap); // Execute trap m68k_setpc(m68k_areg(regs, 7)); fill_prefetch_0(); quit_program = false; m68k_execute(); // Clean up stack m68k_areg(regs, 7) += 4; // Restore old PC m68k_setpc(oldpc); fill_prefetch_0(); // Get registers for (i=0; i<8; i++) r->d[i] = m68k_dreg(regs, i); for (i=0; i<7; i++) r->a[i] = m68k_areg(regs, i); quit_program = false; } /* * Execute 68k subroutine * The executed routine must reside in UAE memory! * r->a[7] and r->sr are unused! */ void Execute68k(uint32 addr, struct M68kRegisters *r) { int i; // Save old PC uaecptr oldpc = m68k_getpc(); // Set registers for (i=0; i<8; i++) m68k_dreg(regs, i) = r->d[i]; for (i=0; i<7; i++) m68k_areg(regs, i) = r->a[i]; // Push EXEC_RETURN and faked return address (points to EXEC_RETURN) on stack m68k_areg(regs, 7) -= 2; put_word(m68k_areg(regs, 7), M68K_EXEC_RETURN); m68k_areg(regs, 7) -= 4; put_long(m68k_areg(regs, 7), m68k_areg(regs, 7) + 4); // Execute routine m68k_setpc(addr); fill_prefetch_0(); quit_program = false; m68k_execute(); // Clean up stack m68k_areg(regs, 7) += 2; // Restore old PC m68k_setpc(oldpc); fill_prefetch_0(); // Get registers for (i=0; i<8; i++) r->d[i] = m68k_dreg(regs, i); for (i=0; i<7; i++) r->a[i] = m68k_areg(regs, i); quit_program = false; } BasiliskII/src/uae_cpu/newcpu.cpp0000644000175000017500000011366211735673707017207 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * MC68000 emulation * * (c) 1995 Bernd Schmidt * * 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 */ #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "emul_op.h" extern int intlev(void); // From baisilisk_glue.cpp #include "m68k.h" #include "memory.h" #include "readcpu.h" #include "newcpu.h" #include "compiler/compemu.h" #include "fpu/fpu.h" #if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) B2_mutex *spcflags_lock = NULL; #endif #if ENABLE_MON #include "mon.h" #include "mon_disass.h" #endif bool quit_program = false; struct flag_struct regflags; /* Opcode of faulting instruction */ uae_u16 last_op_for_exception_3; /* PC at fault time */ uaecptr last_addr_for_exception_3; /* Address that generated the exception */ uaecptr last_fault_for_exception_3; int areg_byteinc[] = { 1,1,1,1,1,1,1,2 }; int imm8_table[] = { 8,1,2,3,4,5,6,7 }; int movem_index1[256]; int movem_index2[256]; int movem_next[256]; cpuop_func *cpufunctbl[65536]; #if FLIGHT_RECORDER struct rec_step { uae_u32 pc; #if FLIGHT_RECORDER >= 2 uae_u32 d[8]; uae_u32 a[8]; #endif }; const int LOG_SIZE = 32768; static rec_step log[LOG_SIZE]; static int log_ptr = -1; // First time initialization static const char *log_filename(void) { const char *name = getenv("M68K_LOG_FILE"); return name ? name : "log.68k"; } void m68k_record_step(uaecptr pc) { #if FLIGHT_RECORDER >= 2 /* XXX: if LSB is set, we are recording from generated code and we don't support registers recording yet. */ if ((pc & 1) == 0) { for (int i = 0; i < 8; i++) { log[log_ptr].d[i] = m68k_dreg(regs, i); log[log_ptr].a[i] = m68k_areg(regs, i); } } #endif log[log_ptr].pc = pc; log_ptr = (log_ptr + 1) % LOG_SIZE; } static void dump_log(void) { FILE *f = fopen(log_filename(), "w"); if (f == NULL) return; for (int i = 0; i < LOG_SIZE; i++) { int j = (i + log_ptr) % LOG_SIZE; uae_u32 pc = log[j].pc & ~1; fprintf(f, "pc %08x", pc); #if FLIGHT_RECORDER >= 2 fprintf(f, "\n"); if ((log[j].pc & 1) == 0) { fprintf(f, "d0 %08x d1 %08x d2 %08x d3 %08x\n", log[j].d[0], log[j].d[1], log[j].d[2], log[j].d[3]); fprintf(f, "d4 %08x d5 %08x d6 %08x d7 %08x\n", log[j].d[4], log[j].d[5], log[j].d[6], log[j].d[7]); fprintf(f, "a0 %08x a1 %08x a2 %08x a3 %08x\n", log[j].a[0], log[j].a[1], log[j].a[2], log[j].a[3]); fprintf(f, "a4 %08x a5 %08x a6 %08x a7 %08x\n", log[j].a[4], log[j].a[5], log[j].a[6], log[j].a[7]); } #else fprintf(f, " | "); #endif #if ENABLE_MON disass_68k(f, pc); #endif } fclose(f); } #endif #if ENABLE_MON static void dump_regs(void) { m68k_dumpstate(NULL); } #endif #define COUNT_INSTRS 0 #if COUNT_INSTRS static unsigned long int instrcount[65536]; static uae_u16 opcodenums[65536]; static int compfn (const void *el1, const void *el2) { return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2]; } static char *icountfilename (void) { char *name = getenv ("INSNCOUNT"); if (name) return name; return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount"; } void dump_counts (void) { FILE *f = fopen (icountfilename (), "w"); unsigned long int total; int i; write_log ("Writing instruction count file...\n"); for (i = 0; i < 65536; i++) { opcodenums[i] = i; total += instrcount[i]; } qsort (opcodenums, 65536, sizeof(uae_u16), compfn); fprintf (f, "Total: %lu\n", total); for (i=0; i < 65536; i++) { unsigned long int cnt = instrcount[opcodenums[i]]; struct instr *dp; struct mnemolookup *lookup; if (!cnt) break; dp = table68k + opcodenums[i]; for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) ; fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name); } fclose (f); } #else void dump_counts (void) { } #endif int broken_in; static __inline__ unsigned int cft_map (unsigned int f) { #ifndef HAVE_GET_WORD_UNSWAPPED return f; #else return ((f >> 8) & 255) | ((f & 255) << 8); #endif } void REGPARAM2 op_illg_1 (uae_u32 opcode) REGPARAM; void REGPARAM2 op_illg_1 (uae_u32 opcode) { op_illg (cft_map (opcode)); } static void build_cpufunctbl (void) { int i; unsigned long opcode; int cpu_level = 0; // 68000 (default) if (CPUType == 4) cpu_level = 4; // 68040 with FPU else { if (FPUType) cpu_level = 3; // 68020 with FPU else if (CPUType >= 2) cpu_level = 2; // 68020 else if (CPUType == 1) cpu_level = 1; } struct cputbl *tbl = ( cpu_level == 4 ? op_smalltbl_0_ff : cpu_level == 3 ? op_smalltbl_1_ff : cpu_level == 2 ? op_smalltbl_2_ff : cpu_level == 1 ? op_smalltbl_3_ff : op_smalltbl_4_ff); for (opcode = 0; opcode < 65536; opcode++) cpufunctbl[cft_map (opcode)] = op_illg_1; for (i = 0; tbl[i].handler != NULL; i++) { if (! tbl[i].specific) cpufunctbl[cft_map (tbl[i].opcode)] = tbl[i].handler; } for (opcode = 0; opcode < 65536; opcode++) { cpuop_func *f; if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level) continue; if (table68k[opcode].handler != -1) { f = cpufunctbl[cft_map (table68k[opcode].handler)]; if (f == op_illg_1) abort(); cpufunctbl[cft_map (opcode)] = f; } } for (i = 0; tbl[i].handler != NULL; i++) { if (tbl[i].specific) cpufunctbl[cft_map (tbl[i].opcode)] = tbl[i].handler; } } void init_m68k (void) { int i; for (i = 0 ; i < 256 ; i++) { int j; for (j = 0 ; j < 8 ; j++) { if (i & (1 << j)) break; } movem_index1[i] = j; movem_index2[i] = 7-j; movem_next[i] = i & (~(1 << j)); } #if COUNT_INSTRS { FILE *f = fopen (icountfilename (), "r"); memset (instrcount, 0, sizeof instrcount); if (f) { uae_u32 opcode, count, total; char name[20]; write_log ("Reading instruction count file...\n"); fscanf (f, "Total: %lu\n", &total); while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) { instrcount[opcode] = count; } fclose(f); } } #endif read_table68k (); do_merges (); build_cpufunctbl (); #if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) spcflags_lock = B2_create_mutex(); #endif fpu_init(CPUType == 4); } void exit_m68k (void) { fpu_exit (); #if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) B2_delete_mutex(spcflags_lock); #endif } struct regstruct regs, lastint_regs; static struct regstruct regs_backup[16]; static int backup_pointer = 0; static long int m68kpc_offset; int lastint_no; #if REAL_ADDRESSING || DIRECT_ADDRESSING #define get_ibyte_1(o) get_byte(get_virtual_address(regs.pc_p) + (o) + 1) #define get_iword_1(o) get_word(get_virtual_address(regs.pc_p) + (o)) #define get_ilong_1(o) get_long(get_virtual_address(regs.pc_p) + (o)) #else #define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1) #define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) #define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) #endif uae_s32 ShowEA (int reg, amodes mode, wordsizes size, char *buf) { uae_u16 dp; uae_s8 disp8; uae_s16 disp16; int r; uae_u32 dispreg; uaecptr addr; uae_s32 offset = 0; char buffer[80]; switch (mode){ case Dreg: sprintf (buffer,"D%d", reg); break; case Areg: sprintf (buffer,"A%d", reg); break; case Aind: sprintf (buffer,"(A%d)", reg); break; case Aipi: sprintf (buffer,"(A%d)+", reg); break; case Apdi: sprintf (buffer,"-(A%d)", reg); break; case Ad16: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; addr = m68k_areg(regs,reg) + (uae_s16)disp16; sprintf (buffer,"(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff, (unsigned long)addr); break; case Ad8r: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; disp8 = dp & 0xFF; r = (dp & 0x7000) >> 12; dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); dispreg <<= (dp >> 9) & 3; if (dp & 0x100) { uae_s32 outer = 0, disp = 0; uae_s32 base = m68k_areg(regs,reg); char name[10]; sprintf (name,"A%d, ",reg); if (dp & 0x80) { base = 0; name[0] = 0; } if (dp & 0x40) dispreg = 0; if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } base += disp; if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } if (!(dp & 4)) base += dispreg; if (dp & 3) base = get_long (base); if (dp & 4) base += dispreg; addr = base + outer; sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name, dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), disp,outer, (unsigned long)addr); } else { addr = m68k_areg(regs,reg) + (uae_s32)((uae_s8)disp8) + dispreg; sprintf (buffer,"(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg, dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), disp8, (unsigned long)addr); } break; case PC16: addr = m68k_getpc () + m68kpc_offset; disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; addr += (uae_s16)disp16; sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(unsigned long)addr); break; case PC8r: addr = m68k_getpc () + m68kpc_offset; dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; disp8 = dp & 0xFF; r = (dp & 0x7000) >> 12; dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); dispreg <<= (dp >> 9) & 3; if (dp & 0x100) { uae_s32 outer = 0,disp = 0; uae_s32 base = addr; char name[10]; sprintf (name,"PC, "); if (dp & 0x80) { base = 0; name[0] = 0; } if (dp & 0x40) dispreg = 0; if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } base += disp; if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } if (!(dp & 4)) base += dispreg; if (dp & 3) base = get_long (base); if (dp & 4) base += dispreg; addr = base + outer; sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name, dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), disp,outer, (unsigned long)addr); } else { addr += (uae_s32)((uae_s8)disp8) + dispreg; sprintf (buffer,"(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), disp8, (unsigned long)addr); } break; case absw: sprintf (buffer,"$%08lx", (unsigned long)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset)); m68kpc_offset += 2; break; case absl: sprintf (buffer,"$%08lx", (unsigned long)get_ilong_1 (m68kpc_offset)); m68kpc_offset += 4; break; case imm: switch (size){ case sz_byte: sprintf (buffer,"#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff)); m68kpc_offset += 2; break; case sz_word: sprintf (buffer,"#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff)); m68kpc_offset += 2; break; case sz_long: sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset))); m68kpc_offset += 4; break; default: break; } break; case imm0: offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; sprintf (buffer,"#$%02x", (unsigned int)(offset & 0xff)); break; case imm1: offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; sprintf (buffer,"#$%04x", (unsigned int)(offset & 0xffff)); break; case imm2: offset = (uae_s32)get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; sprintf (buffer,"#$%08lx", (unsigned long)offset); break; case immi: offset = (uae_s32)(uae_s8)(reg & 0xff); sprintf (buffer,"#$%08lx", (unsigned long)offset); break; default: break; } if (buf == 0) printf ("%s", buffer); else strcat (buf, buffer); return offset; } /* The plan is that this will take over the job of exception 3 handling - * the CPU emulation functions will just do a longjmp to m68k_go whenever * they hit an odd address. */ static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val) { uae_u16 dp; uae_s8 disp8; uae_s16 disp16; int r; uae_u32 dispreg; uaecptr addr; uae_s32 offset = 0; switch (mode){ case Dreg: *val = m68k_dreg (regs, reg); return 1; case Areg: *val = m68k_areg (regs, reg); return 1; case Aind: case Aipi: addr = m68k_areg (regs, reg); break; case Apdi: addr = m68k_areg (regs, reg); break; case Ad16: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; addr = m68k_areg(regs,reg) + (uae_s16)disp16; break; case Ad8r: addr = m68k_areg (regs, reg); d8r_common: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; disp8 = dp & 0xFF; r = (dp & 0x7000) >> 12; dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); dispreg <<= (dp >> 9) & 3; if (dp & 0x100) { uae_s32 outer = 0, disp = 0; uae_s32 base = addr; if (dp & 0x80) base = 0; if (dp & 0x40) dispreg = 0; if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } base += disp; if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } if (!(dp & 4)) base += dispreg; if (dp & 3) base = get_long (base); if (dp & 4) base += dispreg; addr = base + outer; } else { addr += (uae_s32)((uae_s8)disp8) + dispreg; } break; case PC16: addr = m68k_getpc () + m68kpc_offset; disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; addr += (uae_s16)disp16; break; case PC8r: addr = m68k_getpc () + m68kpc_offset; goto d8r_common; case absw: addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; break; case absl: addr = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; break; case imm: switch (size){ case sz_byte: *val = get_iword_1 (m68kpc_offset) & 0xff; m68kpc_offset += 2; break; case sz_word: *val = get_iword_1 (m68kpc_offset) & 0xffff; m68kpc_offset += 2; break; case sz_long: *val = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; break; default: break; } return 1; case imm0: *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; return 1; case imm1: *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; return 1; case imm2: *val = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; return 1; case immi: *val = (uae_s32)(uae_s8)(reg & 0xff); return 1; default: addr = 0; break; } if ((addr & 1) == 0) return 1; last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset; last_fault_for_exception_3 = addr; return 0; } uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp) { int reg = (dp >> 12) & 15; uae_s32 regd = regs.regs[reg]; if ((dp & 0x800) == 0) regd = (uae_s32)(uae_s16)regd; regd <<= (dp >> 9) & 3; if (dp & 0x100) { uae_s32 outer = 0; if (dp & 0x80) base = 0; if (dp & 0x40) regd = 0; if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword(); if ((dp & 0x30) == 0x30) base += next_ilong(); if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword(); if ((dp & 0x3) == 0x3) outer = next_ilong(); if ((dp & 0x4) == 0) base += regd; if (dp & 0x3) base = get_long (base); if (dp & 0x4) base += regd; return base + outer; } else { return base + (uae_s32)((uae_s8)dp) + regd; } } uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp) { int reg = (dp >> 12) & 15; uae_s32 regd = regs.regs[reg]; #if 1 if ((dp & 0x800) == 0) regd = (uae_s32)(uae_s16)regd; return base + (uae_s8)dp + regd; #else /* Branch-free code... benchmark this again now that * things are no longer inline. */ uae_s32 regd16; uae_u32 mask; mask = ((dp & 0x800) >> 11) - 1; regd16 = (uae_s32)(uae_s16)regd; regd16 &= mask; mask = ~mask; base += (uae_s8)dp; regd &= mask; regd |= regd16; return base + regd; #endif } void MakeSR (void) { #if 0 assert((regs.t1 & 1) == regs.t1); assert((regs.t0 & 1) == regs.t0); assert((regs.s & 1) == regs.s); assert((regs.m & 1) == regs.m); assert((XFLG & 1) == XFLG); assert((NFLG & 1) == NFLG); assert((ZFLG & 1) == ZFLG); assert((VFLG & 1) == VFLG); assert((CFLG & 1) == CFLG); #endif regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) | (GET_XFLG << 4) | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1) | GET_CFLG); } void MakeFromSR (void) { int oldm = regs.m; int olds = regs.s; regs.t1 = (regs.sr >> 15) & 1; regs.t0 = (regs.sr >> 14) & 1; regs.s = (regs.sr >> 13) & 1; regs.m = (regs.sr >> 12) & 1; regs.intmask = (regs.sr >> 8) & 7; SET_XFLG ((regs.sr >> 4) & 1); SET_NFLG ((regs.sr >> 3) & 1); SET_ZFLG ((regs.sr >> 2) & 1); SET_VFLG ((regs.sr >> 1) & 1); SET_CFLG (regs.sr & 1); if (CPUType >= 2) { if (olds != regs.s) { if (olds) { if (oldm) regs.msp = m68k_areg(regs, 7); else regs.isp = m68k_areg(regs, 7); m68k_areg(regs, 7) = regs.usp; } else { regs.usp = m68k_areg(regs, 7); m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; } } else if (olds && oldm != regs.m) { if (oldm) { regs.msp = m68k_areg(regs, 7); m68k_areg(regs, 7) = regs.isp; } else { regs.isp = m68k_areg(regs, 7); m68k_areg(regs, 7) = regs.msp; } } } else { if (olds != regs.s) { if (olds) { regs.isp = m68k_areg(regs, 7); m68k_areg(regs, 7) = regs.usp; } else { regs.usp = m68k_areg(regs, 7); m68k_areg(regs, 7) = regs.isp; } } } SPCFLAGS_SET( SPCFLAG_INT ); if (regs.t1 || regs.t0) SPCFLAGS_SET( SPCFLAG_TRACE ); else /* Keep SPCFLAG_DOTRACE, we still want a trace exception for SR-modifying instructions (including STOP). */ SPCFLAGS_CLEAR( SPCFLAG_TRACE ); } void Exception(int nr, uaecptr oldpc) { uae_u32 currpc = m68k_getpc (); MakeSR(); if (!regs.s) { regs.usp = m68k_areg(regs, 7); if (CPUType >= 2) m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; else m68k_areg(regs, 7) = regs.isp; regs.s = 1; } if (CPUType > 0) { if (nr == 2 || nr == 3) { int i; /* @@@ this is probably wrong (?) */ for (i = 0 ; i < 12 ; i++) { m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), 0); } m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), 0xa000 + nr * 4); } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) { m68k_areg(regs, 7) -= 4; put_long (m68k_areg(regs, 7), oldpc); m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), 0x2000 + nr * 4); } else if (regs.m && nr >= 24 && nr < 32) { m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), nr * 4); m68k_areg(regs, 7) -= 4; put_long (m68k_areg(regs, 7), currpc); m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), regs.sr); regs.sr |= (1 << 13); regs.msp = m68k_areg(regs, 7); m68k_areg(regs, 7) = regs.isp; m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), 0x1000 + nr * 4); } else { m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), nr * 4); } } else { if (nr == 2 || nr == 3) { m68k_areg(regs, 7) -= 12; /* ??????? */ if (nr == 3) { put_long (m68k_areg(regs, 7), last_fault_for_exception_3); put_word (m68k_areg(regs, 7)+4, last_op_for_exception_3); put_long (m68k_areg(regs, 7)+8, last_addr_for_exception_3); } write_log ("Exception!\n"); goto kludge_me_do; } } m68k_areg(regs, 7) -= 4; put_long (m68k_areg(regs, 7), currpc); kludge_me_do: m68k_areg(regs, 7) -= 2; put_word (m68k_areg(regs, 7), regs.sr); m68k_setpc (get_long (regs.vbr + 4*nr)); SPCFLAGS_SET( SPCFLAG_JIT_END_COMPILE ); fill_prefetch_0 (); regs.t1 = regs.t0 = regs.m = 0; SPCFLAGS_CLEAR( SPCFLAG_TRACE | SPCFLAG_DOTRACE ); } static void Interrupt(int nr) { assert(nr < 8 && nr >= 0); lastint_regs = regs; lastint_no = nr; Exception(nr+24, 0); regs.intmask = nr; SPCFLAGS_SET( SPCFLAG_INT ); } static int caar, cacr, tc, itt0, itt1, dtt0, dtt1, mmusr, urp, srp; static int movec_illg (int regno) { switch (CPUType) { case 1: if ((regno & 0x7ff) <= 1) return 0; break; case 2: case 3: if ((regno & 0x7ff) <= 2) return 0; if (regno == 3 || regno == 4) return 0; break; case 4: if ((regno & 0x7ff) <= 7) { if (regno != 0x802) return 0; } break; } return 1; } int m68k_move2c (int regno, uae_u32 *regp) { if (movec_illg (regno)) { op_illg (0x4E7B); return 0; } else { switch (regno) { case 0: regs.sfc = *regp & 7; break; case 1: regs.dfc = *regp & 7; break; case 2: cacr = *regp & (CPUType < 4 ? 0x3 : 0x80008000); #if USE_JIT if (CPUType < 4) { set_cache_state(cacr&1); if (*regp & 0x08) flush_icache(1); } else { set_cache_state(cacr&0x8000); } #endif break; case 3: tc = *regp & 0xc000; break; case 4: itt0 = *regp & 0xffffe364; break; case 5: itt1 = *regp & 0xffffe364; break; case 6: dtt0 = *regp & 0xffffe364; break; case 7: dtt1 = *regp & 0xffffe364; break; case 0x800: regs.usp = *regp; break; case 0x801: regs.vbr = *regp; break; case 0x802: caar = *regp &0xfc; break; case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break; case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break; case 0x805: mmusr = *regp; break; case 0x806: urp = *regp; break; case 0x807: srp = *regp; break; default: op_illg (0x4E7B); return 0; } } return 1; } int m68k_movec2 (int regno, uae_u32 *regp) { if (movec_illg (regno)) { op_illg (0x4E7A); return 0; } else { switch (regno) { case 0: *regp = regs.sfc; break; case 1: *regp = regs.dfc; break; case 2: *regp = cacr; break; case 3: *regp = tc; break; case 4: *regp = itt0; break; case 5: *regp = itt1; break; case 6: *regp = dtt0; break; case 7: *regp = dtt1; break; case 0x800: *regp = regs.usp; break; case 0x801: *regp = regs.vbr; break; case 0x802: *regp = caar; break; case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break; case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break; case 0x805: *regp = mmusr; break; case 0x806: *regp = urp; break; case 0x807: *regp = srp; break; default: op_illg (0x4E7A); return 0; } } return 1; } static __inline__ int div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem) { uae_u32 q = 0, cbit = 0; int i; if (div <= src_hi) { return 1; } for (i = 0 ; i < 32 ; i++) { cbit = src_hi & 0x80000000ul; src_hi <<= 1; if (src_lo & 0x80000000ul) src_hi++; src_lo <<= 1; q = q << 1; if (cbit || div <= src_hi) { q |= 1; src_hi -= div; } } *quot = q; *rem = src_hi; return 0; } void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc) { #if defined(uae_s64) if (src == 0) { Exception (5, oldpc); return; } if (extra & 0x800) { /* signed variant */ uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); uae_s64 quot, rem; if (extra & 0x400) { a &= 0xffffffffu; a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32; } rem = a % (uae_s64)(uae_s32)src; quot = a / (uae_s64)(uae_s32)src; if ((quot & UVAL64(0xffffffff80000000)) != 0 && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else { if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; SET_VFLG (0); SET_CFLG (0); SET_ZFLG (((uae_s32)quot) == 0); SET_NFLG (((uae_s32)quot) < 0); m68k_dreg(regs, extra & 7) = rem; m68k_dreg(regs, (extra >> 12) & 7) = quot; } } else { /* unsigned */ uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); uae_u64 quot, rem; if (extra & 0x400) { a &= 0xffffffffu; a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32; } rem = a % (uae_u64)src; quot = a / (uae_u64)src; if (quot > 0xffffffffu) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else { SET_VFLG (0); SET_CFLG (0); SET_ZFLG (((uae_s32)quot) == 0); SET_NFLG (((uae_s32)quot) < 0); m68k_dreg(regs, extra & 7) = rem; m68k_dreg(regs, (extra >> 12) & 7) = quot; } } #else if (src == 0) { Exception (5, oldpc); return; } if (extra & 0x800) { /* signed variant */ uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); uae_s32 hi = lo < 0 ? -1 : 0; uae_s32 save_high; uae_u32 quot, rem; uae_u32 sign; if (extra & 0x400) { hi = (uae_s32)m68k_dreg(regs, extra & 7); } save_high = hi; sign = (hi ^ src); if (hi < 0) { hi = ~hi; lo = -lo; if (lo == 0) hi++; } if ((uae_s32)src < 0) src = -src; if (div_unsigned(hi, lo, src, ", &rem) || (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else { if (sign & 0x80000000) quot = -quot; if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; SET_VFLG (0); SET_CFLG (0); SET_ZFLG (((uae_s32)quot) == 0); SET_NFLG (((uae_s32)quot) < 0); m68k_dreg(regs, extra & 7) = rem; m68k_dreg(regs, (extra >> 12) & 7) = quot; } } else { /* unsigned */ uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7); uae_u32 hi = 0; uae_u32 quot, rem; if (extra & 0x400) { hi = (uae_u32)m68k_dreg(regs, extra & 7); } if (div_unsigned(hi, lo, src, ", &rem)) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else { SET_VFLG (0); SET_CFLG (0); SET_ZFLG (((uae_s32)quot) == 0); SET_NFLG (((uae_s32)quot) < 0); m68k_dreg(regs, extra & 7) = rem; m68k_dreg(regs, (extra >> 12) & 7) = quot; } } #endif } static __inline__ void mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) { uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff); uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff); uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff); uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff); uae_u32 lo; lo = r0 + ((r1 << 16) & 0xffff0000ul); if (lo < r0) r3++; r0 = lo; lo = r0 + ((r2 << 16) & 0xffff0000ul); if (lo < r0) r3++; r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff); *dst_lo = lo; *dst_hi = r3; } void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) { #if defined(uae_s64) if (extra & 0x800) { /* signed variant */ uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); a *= (uae_s64)(uae_s32)src; SET_VFLG (0); SET_CFLG (0); SET_ZFLG (a == 0); SET_NFLG (a < 0); if (extra & 0x400) m68k_dreg(regs, extra & 7) = a >> 32; else if ((a & UVAL64(0xffffffff80000000)) != 0 && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) { SET_VFLG (1); } m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; } else { /* unsigned */ uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); a *= (uae_u64)src; SET_VFLG (0); SET_CFLG (0); SET_ZFLG (a == 0); SET_NFLG (((uae_s64)a) < 0); if (extra & 0x400) m68k_dreg(regs, extra & 7) = a >> 32; else if ((a & UVAL64(0xffffffff00000000)) != 0) { SET_VFLG (1); } m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; } #else if (extra & 0x800) { /* signed variant */ uae_s32 src1,src2; uae_u32 dst_lo,dst_hi; uae_u32 sign; src1 = (uae_s32)src; src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); sign = (src1 ^ src2); if (src1 < 0) src1 = -src1; if (src2 < 0) src2 = -src2; mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo); if (sign & 0x80000000) { dst_hi = ~dst_hi; dst_lo = -dst_lo; if (dst_lo == 0) dst_hi++; } SET_VFLG (0); SET_CFLG (0); SET_ZFLG (dst_hi == 0 && dst_lo == 0); SET_NFLG (((uae_s32)dst_hi) < 0); if (extra & 0x400) m68k_dreg(regs, extra & 7) = dst_hi; else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) && ((dst_hi & 0xffffffff) != 0xffffffff || (dst_lo & 0x80000000) != 0x80000000)) { SET_VFLG (1); } m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; } else { /* unsigned */ uae_u32 dst_lo,dst_hi; mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo); SET_VFLG (0); SET_CFLG (0); SET_ZFLG (dst_hi == 0 && dst_lo == 0); SET_NFLG (((uae_s32)dst_hi) < 0); if (extra & 0x400) m68k_dreg(regs, extra & 7) = dst_hi; else if (dst_hi != 0) { SET_VFLG (1); } m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; } #endif } static char* ccnames[] = { "T ","F ","HI","LS","CC","CS","NE","EQ", "VC","VS","PL","MI","GE","LT","GT","LE" }; // If value is greater than zero, this means we are still processing an EmulOp // because the counter is incremented only in m68k_execute(), i.e. interpretive // execution only static int m68k_execute_depth = 0; void m68k_reset (void) { m68k_areg (regs, 7) = 0x2000; m68k_setpc (ROMBaseMac + 0x2a); fill_prefetch_0 (); regs.s = 1; regs.m = 0; regs.stopped = 0; regs.t1 = 0; regs.t0 = 0; SET_ZFLG (0); SET_XFLG (0); SET_CFLG (0); SET_VFLG (0); SET_NFLG (0); SPCFLAGS_INIT( 0 ); regs.intmask = 7; regs.vbr = regs.sfc = regs.dfc = 0; fpu_reset(); #if FLIGHT_RECORDER log_ptr = 0; memset(log, 0, sizeof(log)); #endif #if ENABLE_MON static bool first_time = true; if (first_time) { first_time = false; mon_add_command("regs", dump_regs, "regs Dump m68k emulator registers\n"); #if FLIGHT_RECORDER // Install "log" command in mon mon_add_command("log", dump_log, "log Dump m68k emulation log\n"); #endif } #endif } void m68k_emulop_return(void) { SPCFLAGS_SET( SPCFLAG_BRK ); quit_program = true; } void m68k_emulop(uae_u32 opcode) { struct M68kRegisters r; int i; for (i=0; i<8; i++) { r.d[i] = m68k_dreg(regs, i); r.a[i] = m68k_areg(regs, i); } MakeSR(); r.sr = regs.sr; EmulOp(opcode, &r); for (i=0; i<8; i++) { m68k_dreg(regs, i) = r.d[i]; m68k_areg(regs, i) = r.a[i]; } regs.sr = r.sr; MakeFromSR(); } void REGPARAM2 op_illg (uae_u32 opcode) { uaecptr pc = m68k_getpc (); if ((opcode & 0xF000) == 0xA000) { Exception(0xA,0); return; } if ((opcode & 0xF000) == 0xF000) { Exception(0xB,0); return; } write_log ("Illegal instruction: %04x at %08lx\n", opcode, pc); #if USE_JIT && JIT_DEBUG compiler_dumpstate(); #endif Exception (4,0); return; } void mmu_op(uae_u32 opcode, uae_u16 extra) { if ((opcode & 0xFE0) == 0x0500) { /* PFLUSH */ mmusr = 0; } else if ((opcode & 0x0FD8) == 0x548) { /* PTEST */ } else op_illg (opcode); } static int n_insns = 0, n_spcinsns = 0; static uaecptr last_trace_ad = 0; static void do_trace (void) { if (regs.t0 && CPUType >= 2) { uae_u16 opcode; /* should also include TRAP, CHK, SR modification FPcc */ /* probably never used so why bother */ /* We can afford this to be inefficient... */ m68k_setpc (m68k_getpc ()); fill_prefetch_0 (); opcode = get_word(m68k_getpc()); if (opcode == 0x4e72 /* RTE */ || opcode == 0x4e74 /* RTD */ || opcode == 0x4e75 /* RTS */ || opcode == 0x4e77 /* RTR */ || opcode == 0x4e76 /* TRAPV */ || (opcode & 0xffc0) == 0x4e80 /* JSR */ || (opcode & 0xffc0) == 0x4ec0 /* JMP */ || (opcode & 0xff00) == 0x6100 /* BSR */ || ((opcode & 0xf000) == 0x6000 /* Bcc */ && cctrue((opcode >> 8) & 0xf)) || ((opcode & 0xf0f0) == 0x5050 /* DBcc */ && !cctrue((opcode >> 8) & 0xf) && (uae_s16)m68k_dreg(regs, opcode & 7) != 0)) { last_trace_ad = m68k_getpc (); SPCFLAGS_CLEAR( SPCFLAG_TRACE ); SPCFLAGS_SET( SPCFLAG_DOTRACE ); } } else if (regs.t1) { last_trace_ad = m68k_getpc (); SPCFLAGS_CLEAR( SPCFLAG_TRACE ); SPCFLAGS_SET( SPCFLAG_DOTRACE ); } } int m68k_do_specialties (void) { #if USE_JIT // Block was compiled SPCFLAGS_CLEAR( SPCFLAG_JIT_END_COMPILE ); // Retain the request to get out of compiled code until // we reached the toplevel execution, i.e. the one that // can compile then run compiled code. This also means // we processed all (nested) EmulOps if ((m68k_execute_depth == 0) && SPCFLAGS_TEST( SPCFLAG_JIT_EXEC_RETURN )) SPCFLAGS_CLEAR( SPCFLAG_JIT_EXEC_RETURN ); #endif if (SPCFLAGS_TEST( SPCFLAG_DOTRACE )) { Exception (9,last_trace_ad); } while (SPCFLAGS_TEST( SPCFLAG_STOP )) { if (SPCFLAGS_TEST( SPCFLAG_INT | SPCFLAG_DOINT )){ SPCFLAGS_CLEAR( SPCFLAG_INT | SPCFLAG_DOINT ); int intr = intlev (); if (intr != -1 && intr > regs.intmask) { Interrupt (intr); regs.stopped = 0; SPCFLAGS_CLEAR( SPCFLAG_STOP ); } } } if (SPCFLAGS_TEST( SPCFLAG_TRACE )) do_trace (); if (SPCFLAGS_TEST( SPCFLAG_DOINT )) { SPCFLAGS_CLEAR( SPCFLAG_DOINT ); int intr = intlev (); if (intr != -1 && intr > regs.intmask) { Interrupt (intr); regs.stopped = 0; } } if (SPCFLAGS_TEST( SPCFLAG_INT )) { SPCFLAGS_CLEAR( SPCFLAG_INT ); SPCFLAGS_SET( SPCFLAG_DOINT ); } if (SPCFLAGS_TEST( SPCFLAG_BRK )) { SPCFLAGS_CLEAR( SPCFLAG_BRK ); return 1; } return 0; } void m68k_do_execute (void) { for (;;) { uae_u32 opcode = GET_OPCODE; #if FLIGHT_RECORDER m68k_record_step(m68k_getpc()); #endif (*cpufunctbl[opcode])(opcode); cpu_check_ticks(); if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) { if (m68k_do_specialties()) return; } } } void m68k_execute (void) { #if USE_JIT ++m68k_execute_depth; #endif for (;;) { if (quit_program) break; m68k_do_execute(); } #if USE_JIT --m68k_execute_depth; #endif } static void m68k_verify (uaecptr addr, uaecptr *nextpc) { uae_u32 opcode, val; struct instr *dp; opcode = get_iword_1(0); last_op_for_exception_3 = opcode; m68kpc_offset = 2; if (cpufunctbl[cft_map (opcode)] == op_illg_1) { opcode = 0x4AFC; } dp = table68k + opcode; if (dp->suse) { if (!verify_ea (dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, &val)) { Exception (3, 0); return; } } if (dp->duse) { if (!verify_ea (dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, &val)) { Exception (3, 0); return; } } } void m68k_disasm (uaecptr addr, uaecptr *nextpc, int cnt) { uaecptr newpc = 0; m68kpc_offset = addr - m68k_getpc (); while (cnt-- > 0) { char instrname[20],*ccpt; int opwords; uae_u32 opcode; struct mnemolookup *lookup; struct instr *dp; printf ("%08lx: ", m68k_getpc () + m68kpc_offset); for (opwords = 0; opwords < 5; opwords++){ printf ("%04x ", get_iword_1 (m68kpc_offset + opwords*2)); } opcode = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; if (cpufunctbl[cft_map (opcode)] == op_illg_1) { opcode = 0x4AFC; } dp = table68k + opcode; for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) ; strcpy (instrname, lookup->name); ccpt = strstr (instrname, "cc"); if (ccpt != 0) { strncpy (ccpt, ccnames[dp->cc], 2); } printf ("%s", instrname); switch (dp->size){ case sz_byte: printf (".B "); break; case sz_word: printf (".W "); break; case sz_long: printf (".L "); break; default: printf (" "); break; } if (dp->suse) { newpc = m68k_getpc () + m68kpc_offset; newpc += ShowEA (dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0); } if (dp->suse && dp->duse) printf (","); if (dp->duse) { newpc = m68k_getpc () + m68kpc_offset; newpc += ShowEA (dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 0); } if (ccpt != 0) { if (cctrue(dp->cc)) printf (" == %08lx (TRUE)", newpc); else printf (" == %08lx (FALSE)", newpc); } else if ((opcode & 0xff00) == 0x6100) /* BSR */ printf (" == %08lx", newpc); printf ("\n"); } if (nextpc) *nextpc = m68k_getpc () + m68kpc_offset; } void m68k_dumpstate (uaecptr *nextpc) { int i; for (i = 0; i < 8; i++){ printf ("D%d: %08lx ", i, m68k_dreg(regs, i)); if ((i & 3) == 3) printf ("\n"); } for (i = 0; i < 8; i++){ printf ("A%d: %08lx ", i, m68k_areg(regs, i)); if ((i & 3) == 3) printf ("\n"); } if (regs.s == 0) regs.usp = m68k_areg(regs, 7); if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7); if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7); printf ("USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n", regs.usp,regs.isp,regs.msp,regs.vbr); printf ("T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n", regs.t1, regs.t0, regs.s, regs.m, GET_XFLG, GET_NFLG, GET_ZFLG, GET_VFLG, GET_CFLG, regs.intmask); fpu_dump_registers(); fpu_dump_flags(); m68k_disasm(m68k_getpc (), nextpc, 1); if (nextpc) printf ("next PC: %08lx\n", *nextpc); } BasiliskII/src/uae_cpu/newcpu.h0000644000175000017500000002005611735673707016646 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * MC68000 emulation * * Copyright 1995 Bernd Schmidt * * 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 */ #ifndef NEWCPU_H #define NEWCPU_H #ifndef FLIGHT_RECORDER #define FLIGHT_RECORDER 0 #endif #include "m68k.h" #include "readcpu.h" #include "spcflags.h" extern int areg_byteinc[]; extern int imm8_table[]; extern int movem_index1[256]; extern int movem_index2[256]; extern int movem_next[256]; extern int broken_in; #ifdef X86_ASSEMBLY /* This hack seems to force all register saves (pushl %reg) to be moved to the begining of the function, thus making it possible to cpuopti to remove them since m68k_run_1 will save those registers before calling the instruction handler */ # define cpuop_tag(tag) __asm__ __volatile__ ( "#cpuop_" tag ) #else # define cpuop_tag(tag) ; #endif #define cpuop_begin() do { cpuop_tag("begin"); } while (0) #define cpuop_end() do { cpuop_tag("end"); } while (0) typedef void REGPARAM2 cpuop_func (uae_u32) REGPARAM; struct cputbl { cpuop_func *handler; uae_u16 specific; uae_u16 opcode; }; extern cpuop_func *cpufunctbl[65536] ASM_SYM_FOR_FUNC ("cpufunctbl"); #if USE_JIT typedef void compop_func (uae_u32) REGPARAM; struct comptbl { compop_func *handler; uae_u32 specific; uae_u32 opcode; }; #endif extern void REGPARAM2 op_illg (uae_u32) REGPARAM; typedef char flagtype; struct regstruct { uae_u32 regs[16]; uae_u32 pc; uae_u8 * pc_p; uae_u8 * pc_oldp; spcflags_t spcflags; int intmask; uae_u32 vbr, sfc, dfc; uaecptr usp, isp, msp; uae_u16 sr; flagtype t1; flagtype t0; flagtype s; flagtype m; flagtype x; flagtype stopped; #if USE_PREFETCH_BUFFER /* Fellow sources say this is 4 longwords. That's impossible. It needs * to be at least a longword. The HRM has some cryptic comment about two * instructions being on the same longword boundary. * The way this is implemented now seems like a good compromise. */ uae_u32 prefetch; #endif }; extern regstruct regs, lastint_regs; #define m68k_dreg(r,num) ((r).regs[(num)]) #define m68k_areg(r,num) (((r).regs + 8)[(num)]) #define get_ibyte(o) do_get_mem_byte((uae_u8 *)(regs.pc_p + (o) + 1)) #define get_iword(o) do_get_mem_word((uae_u16 *)(regs.pc_p + (o))) #define get_ilong(o) do_get_mem_long((uae_u32 *)(regs.pc_p + (o))) #ifdef HAVE_GET_WORD_UNSWAPPED #define GET_OPCODE (do_get_mem_word_unswapped (regs.pc_p)) #else #define GET_OPCODE (get_iword (0)) #endif #if USE_PREFETCH_BUFFER static __inline__ uae_u32 get_ibyte_prefetch (uae_s32 o) { if (o > 3 || o < 0) return do_get_mem_byte((uae_u8 *)(regs.pc_p + o + 1)); return do_get_mem_byte((uae_u8 *)(((uae_u8 *)®s.prefetch) + o + 1)); } static __inline__ uae_u32 get_iword_prefetch (uae_s32 o) { if (o > 3 || o < 0) return do_get_mem_word((uae_u16 *)(regs.pc_p + o)); return do_get_mem_word((uae_u16 *)(((uae_u8 *)®s.prefetch) + o)); } static __inline__ uae_u32 get_ilong_prefetch (uae_s32 o) { if (o > 3 || o < 0) return do_get_mem_long((uae_u32 *)(regs.pc_p + o)); if (o == 0) return do_get_mem_long(®s.prefetch); return (do_get_mem_word (((uae_u16 *)®s.prefetch) + 1) << 16) | do_get_mem_word ((uae_u16 *)(regs.pc_p + 4)); } #endif #define m68k_incpc(o) (regs.pc_p += (o)) static __inline__ void fill_prefetch_0 (void) { #if USE_PREFETCH_BUFFER uae_u32 r; #ifdef UNALIGNED_PROFITABLE r = *(uae_u32 *)regs.pc_p; regs.prefetch = r; #else r = do_get_mem_long ((uae_u32 *)regs.pc_p); do_put_mem_long (®s.prefetch, r); #endif #endif } #if 0 static __inline__ void fill_prefetch_2 (void) { uae_u32 r = do_get_mem_long (®s.prefetch) << 16; uae_u32 r2 = do_get_mem_word (((uae_u16 *)regs.pc_p) + 1); r |= r2; do_put_mem_long (®s.prefetch, r); } #else #define fill_prefetch_2 fill_prefetch_0 #endif /* These are only used by the 68020/68881 code, and therefore don't * need to handle prefetch. */ static __inline__ uae_u32 next_ibyte (void) { uae_u32 r = get_ibyte (0); m68k_incpc (2); return r; } static __inline__ uae_u32 next_iword (void) { uae_u32 r = get_iword (0); m68k_incpc (2); return r; } static __inline__ uae_u32 next_ilong (void) { uae_u32 r = get_ilong (0); m68k_incpc (4); return r; } static __inline__ void m68k_setpc (uaecptr newpc) { #if REAL_ADDRESSING || DIRECT_ADDRESSING regs.pc_p = get_real_address(newpc); #else regs.pc_p = regs.pc_oldp = get_real_address(newpc); regs.pc = newpc; #endif } static __inline__ uaecptr m68k_getpc (void) { #if REAL_ADDRESSING || DIRECT_ADDRESSING return get_virtual_address(regs.pc_p); #else return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp); #endif } #define m68k_setpc_fast m68k_setpc #define m68k_setpc_bcc m68k_setpc #define m68k_setpc_rte m68k_setpc static __inline__ void m68k_do_rts(void) { m68k_setpc(get_long(m68k_areg(regs, 7))); m68k_areg(regs, 7) += 4; } static __inline__ void m68k_do_bsr(uaecptr oldpc, uae_s32 offset) { m68k_areg(regs, 7) -= 4; put_long(m68k_areg(regs, 7), oldpc); m68k_incpc(offset); } static __inline__ void m68k_do_jsr(uaecptr oldpc, uaecptr dest) { m68k_areg(regs, 7) -= 4; put_long(m68k_areg(regs, 7), oldpc); m68k_setpc(dest); } static __inline__ void m68k_setstopped (int stop) { regs.stopped = stop; /* A traced STOP instruction drops through immediately without actually stopping. */ if (stop && (regs.spcflags & SPCFLAG_DOTRACE) == 0) SPCFLAGS_SET( SPCFLAG_STOP ); } extern uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp); extern uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp); extern uae_s32 ShowEA (int reg, amodes mode, wordsizes size, char *buf); extern void MakeSR (void); extern void MakeFromSR (void); extern void Exception (int, uaecptr); extern void dump_counts (void); extern int m68k_move2c (int, uae_u32 *); extern int m68k_movec2 (int, uae_u32 *); extern void m68k_divl (uae_u32, uae_u32, uae_u16, uaecptr); extern void m68k_mull (uae_u32, uae_u32, uae_u16); extern void m68k_emulop (uae_u32); extern void m68k_emulop_return (void); extern void init_m68k (void); extern void exit_m68k (void); extern void m68k_dumpstate (uaecptr *); extern void m68k_disasm (uaecptr, uaecptr *, int); extern void m68k_reset (void); extern void m68k_enter_debugger(void); extern int m68k_do_specialties(void); extern void mmu_op (uae_u32, uae_u16); /* Opcode of faulting instruction */ extern uae_u16 last_op_for_exception_3; /* PC at fault time */ extern uaecptr last_addr_for_exception_3; /* Address that generated the exception */ extern uaecptr last_fault_for_exception_3; #define CPU_OP_NAME(a) op ## a /* 68020 + 68881 */ extern struct cputbl op_smalltbl_0_ff[]; /* 68020 */ extern struct cputbl op_smalltbl_1_ff[]; /* 68010 */ extern struct cputbl op_smalltbl_2_ff[]; /* 68000 */ extern struct cputbl op_smalltbl_3_ff[]; /* 68000 slow but compatible. */ extern struct cputbl op_smalltbl_4_ff[]; #if FLIGHT_RECORDER extern void m68k_record_step(uaecptr) REGPARAM; #endif extern void m68k_do_execute(void); extern void m68k_execute(void); #if USE_JIT extern void m68k_compile_execute(void); #endif #ifdef USE_CPU_EMUL_SERVICES extern int32 emulated_ticks; extern void cpu_do_check_ticks(void); static inline void cpu_check_ticks(void) { if (--emulated_ticks <= 0) cpu_do_check_ticks(); } #else #define cpu_check_ticks() #define cpu_do_check_ticks() #endif #endif /* NEWCPU_H */ BasiliskII/src/uae_cpu/cpu_emulation.h0000644000175000017500000001022010736405223020163 0ustar centriscentris/* * cpu_emulation.h - Definitions for Basilisk II CPU emulation module (UAE 0.8.10 version) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef CPU_EMULATION_H #define CPU_EMULATION_H #include /* * Memory system */ // RAM and ROM pointers (allocated and set by main_*.cpp) extern uint32 RAMBaseMac; // RAM base (Mac address space), does not include Low Mem when != 0 extern uint8 *RAMBaseHost; // RAM base (host address space) extern uint32 RAMSize; // Size of RAM extern uint32 ROMBaseMac; // ROM base (Mac address space) extern uint8 *ROMBaseHost; // ROM base (host address space) extern uint32 ROMSize; // Size of ROM #if !REAL_ADDRESSING && !DIRECT_ADDRESSING // If we are not using real or direct addressing, the Mac frame buffer gets // mapped to this location. The memory must be allocated by VideoInit(). // If multiple monitors are used, they must share the frame buffer const uint32 MacFrameBaseMac = 0xa0000000; extern uint8 *MacFrameBaseHost; // Frame buffer base (host address space) extern uint32 MacFrameSize; // Size of frame buffer #endif extern int MacFrameLayout; // Frame buffer layout (see defines below) // Possible frame buffer layouts enum { FLAYOUT_NONE, // No frame buffer FLAYOUT_DIRECT, // Frame buffer is in MacOS layout, no conversion needed FLAYOUT_HOST_555, // 16 bit, RGB 555, host byte order FLAYOUT_HOST_565, // 16 bit, RGB 565, host byte order FLAYOUT_HOST_888 // 32 bit, RGB 888, host byte order }; // Mac memory access functions #include "memory.h" static inline uint32 ReadMacInt32(uint32 addr) {return get_long(addr);} static inline uint32 ReadMacInt16(uint32 addr) {return get_word(addr);} static inline uint32 ReadMacInt8(uint32 addr) {return get_byte(addr);} static inline void WriteMacInt32(uint32 addr, uint32 l) {put_long(addr, l);} static inline void WriteMacInt16(uint32 addr, uint32 w) {put_word(addr, w);} static inline void WriteMacInt8(uint32 addr, uint32 b) {put_byte(addr, b);} static inline uint8 *Mac2HostAddr(uint32 addr) {return get_real_address(addr);} static inline uint32 Host2MacAddr(uint8 *addr) {return get_virtual_address(addr);} static inline void *Mac_memset(uint32 addr, int c, size_t n) {return memset(Mac2HostAddr(addr), c, n);} static inline void *Mac2Host_memcpy(void *dest, uint32 src, size_t n) {return memcpy(dest, Mac2HostAddr(src), n);} static inline void *Host2Mac_memcpy(uint32 dest, const void *src, size_t n) {return memcpy(Mac2HostAddr(dest), src, n);} static inline void *Mac2Mac_memcpy(uint32 dest, uint32 src, size_t n) {return memcpy(Mac2HostAddr(dest), Mac2HostAddr(src), n);} /* * 680x0 emulation */ // Initialization extern bool Init680x0(void); // This routine may want to look at CPUType/FPUType to set up the apropriate emulation extern void Exit680x0(void); extern void InitFrameBufferMapping(void); // 680x0 dynamic recompilation activation flag #if USE_JIT extern bool UseJIT; #else const bool UseJIT = false; #endif // 680x0 emulation functions struct M68kRegisters; extern void Start680x0(void); // Reset and start 680x0 extern "C" void Execute68k(uint32 addr, M68kRegisters *r); // Execute 68k code from EMUL_OP routine extern "C" void Execute68kTrap(uint16 trap, M68kRegisters *r); // Execute MacOS 68k trap from EMUL_OP routine // Interrupt functions extern void TriggerInterrupt(void); // Trigger interrupt level 1 (InterruptFlag must be set first) extern void TriggerNMI(void); // Trigger interrupt level 7 #endif BasiliskII/src/uae_cpu/readcpu.cpp0000644000175000017500000006134311735673707017327 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * Read 68000 CPU specs from file "table68k" * * Copyright 1995,1996 Bernd Schmidt * * 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 */ #include #include #include #include #include "sysdeps.h" #include "readcpu.h" int nr_cpuop_funcs; struct mnemolookup lookuptab[] = { { i_ILLG, "ILLEGAL" }, { i_OR, "OR" }, { i_CHK, "CHK" }, { i_CHK2, "CHK2" }, { i_AND, "AND" }, { i_EOR, "EOR" }, { i_ORSR, "ORSR" }, { i_ANDSR, "ANDSR" }, { i_EORSR, "EORSR" }, { i_SUB, "SUB" }, { i_SUBA, "SUBA" }, { i_SUBX, "SUBX" }, { i_SBCD, "SBCD" }, { i_ADD, "ADD" }, { i_ADDA, "ADDA" }, { i_ADDX, "ADDX" }, { i_ABCD, "ABCD" }, { i_NEG, "NEG" }, { i_NEGX, "NEGX" }, { i_NBCD, "NBCD" }, { i_CLR, "CLR" }, { i_NOT, "NOT" }, { i_TST, "TST" }, { i_BTST, "BTST" }, { i_BCHG, "BCHG" }, { i_BCLR, "BCLR" }, { i_BSET, "BSET" }, { i_CMP, "CMP" }, { i_CMPM, "CMPM" }, { i_CMPA, "CMPA" }, { i_MVPRM, "MVPRM" }, { i_MVPMR, "MVPMR" }, { i_MOVE, "MOVE" }, { i_MOVEA, "MOVEA" }, { i_MVSR2, "MVSR2" }, { i_MV2SR, "MV2SR" }, { i_SWAP, "SWAP" }, { i_EXG, "EXG" }, { i_EXT, "EXT" }, { i_MVMEL, "MVMEL" }, { i_MVMLE, "MVMLE" }, { i_TRAP, "TRAP" }, { i_MVR2USP, "MVR2USP" }, { i_MVUSP2R, "MVUSP2R" }, { i_NOP, "NOP" }, { i_RESET, "RESET" }, { i_RTE, "RTE" }, { i_RTD, "RTD" }, { i_LINK, "LINK" }, { i_UNLK, "UNLK" }, { i_RTS, "RTS" }, { i_STOP, "STOP" }, { i_TRAPV, "TRAPV" }, { i_RTR, "RTR" }, { i_JSR, "JSR" }, { i_JMP, "JMP" }, { i_BSR, "BSR" }, { i_Bcc, "Bcc" }, { i_LEA, "LEA" }, { i_PEA, "PEA" }, { i_DBcc, "DBcc" }, { i_Scc, "Scc" }, { i_DIVU, "DIVU" }, { i_DIVS, "DIVS" }, { i_MULU, "MULU" }, { i_MULS, "MULS" }, { i_ASR, "ASR" }, { i_ASL, "ASL" }, { i_LSR, "LSR" }, { i_LSL, "LSL" }, { i_ROL, "ROL" }, { i_ROR, "ROR" }, { i_ROXL, "ROXL" }, { i_ROXR, "ROXR" }, { i_ASRW, "ASRW" }, { i_ASLW, "ASLW" }, { i_LSRW, "LSRW" }, { i_LSLW, "LSLW" }, { i_ROLW, "ROLW" }, { i_RORW, "RORW" }, { i_ROXLW, "ROXLW" }, { i_ROXRW, "ROXRW" }, { i_MOVE2C, "MOVE2C" }, { i_MOVEC2, "MOVEC2" }, { i_CAS, "CAS" }, { i_CAS2, "CAS2" }, { i_MULL, "MULL" }, { i_DIVL, "DIVL" }, { i_BFTST, "BFTST" }, { i_BFEXTU, "BFEXTU" }, { i_BFCHG, "BFCHG" }, { i_BFEXTS, "BFEXTS" }, { i_BFCLR, "BFCLR" }, { i_BFFFO, "BFFFO" }, { i_BFSET, "BFSET" }, { i_BFINS, "BFINS" }, { i_PACK, "PACK" }, { i_UNPK, "UNPK" }, { i_TAS, "TAS" }, { i_BKPT, "BKPT" }, { i_CALLM, "CALLM" }, { i_RTM, "RTM" }, { i_TRAPcc, "TRAPcc" }, { i_MOVES, "MOVES" }, { i_FPP, "FPP" }, { i_FDBcc, "FDBcc" }, { i_FScc, "FScc" }, { i_FTRAPcc, "FTRAPcc" }, { i_FBcc, "FBcc" }, { i_FBcc, "FBcc" }, { i_FSAVE, "FSAVE" }, { i_FRESTORE, "FRESTORE" }, { i_CINVL, "CINVL" }, { i_CINVP, "CINVP" }, { i_CINVA, "CINVA" }, { i_CPUSHL, "CPUSHL" }, { i_CPUSHP, "CPUSHP" }, { i_CPUSHA, "CPUSHA" }, { i_MOVE16, "MOVE16" }, { i_EMULOP_RETURN, "EMULOP_RETURN" }, { i_EMULOP, "EMULOP" }, { i_MMUOP, "MMUOP" }, { i_ILLG, "" }, }; struct instr *table68k; static __inline__ amodes mode_from_str (const char *str) { if (strncmp (str, "Dreg", 4) == 0) return Dreg; if (strncmp (str, "Areg", 4) == 0) return Areg; if (strncmp (str, "Aind", 4) == 0) return Aind; if (strncmp (str, "Apdi", 4) == 0) return Apdi; if (strncmp (str, "Aipi", 4) == 0) return Aipi; if (strncmp (str, "Ad16", 4) == 0) return Ad16; if (strncmp (str, "Ad8r", 4) == 0) return Ad8r; if (strncmp (str, "absw", 4) == 0) return absw; if (strncmp (str, "absl", 4) == 0) return absl; if (strncmp (str, "PC16", 4) == 0) return PC16; if (strncmp (str, "PC8r", 4) == 0) return PC8r; if (strncmp (str, "Immd", 4) == 0) return imm; abort (); return (amodes)0; } static __inline__ amodes mode_from_mr (int mode, int reg) { switch (mode) { case 0: return Dreg; case 1: return Areg; case 2: return Aind; case 3: return Aipi; case 4: return Apdi; case 5: return Ad16; case 6: return Ad8r; case 7: switch (reg) { case 0: return absw; case 1: return absl; case 2: return PC16; case 3: return PC8r; case 4: return imm; case 5: case 6: case 7: return am_illg; } } abort (); return (amodes)0; } static void build_insn (int insn) { int find = -1; int variants; struct instr_def id; const char *opcstr; int i, n; int flaglive = 0, flagdead = 0; int cflow = 0; id = defs68k[insn]; // Control flow information cflow = id.cflow; // Mask of flags set/used unsigned char flags_set(0), flags_used(0); for (i = 0, n = 4; i < 5; i++, n--) { switch (id.flaginfo[i].flagset) { case fa_unset: case fa_isjmp: break; default: flags_set |= (1 << n); } switch (id.flaginfo[i].flaguse) { case fu_unused: case fu_isjmp: break; default: flags_used |= (1 << n); } } for (i = 0; i < 5; i++) { switch (id.flaginfo[i].flagset){ case fa_unset: break; case fa_zero: flagdead |= 1 << i; break; case fa_one: flagdead |= 1 << i; break; case fa_dontcare: flagdead |= 1 << i; break; case fa_unknown: flagdead = -1; goto out1; case fa_set: flagdead |= 1 << i; break; } } out1: for (i = 0; i < 5; i++) { switch (id.flaginfo[i].flaguse) { case fu_unused: break; case fu_unknown: flaglive = -1; goto out2; case fu_used: flaglive |= 1 << i; break; } } out2: opcstr = id.opcstr; for (variants = 0; variants < (1 << id.n_variable); variants++) { int bitcnt[lastbit]; int bitval[lastbit]; int bitpos[lastbit]; int i; uae_u16 opc = id.bits; uae_u16 msk, vmsk; int pos = 0; int mnp = 0; int bitno = 0; char mnemonic[64]; wordsizes sz = sz_long; int srcgather = 0, dstgather = 0; int usesrc = 0, usedst = 0; int srctype = 0; int srcpos = -1, dstpos = -1; amodes srcmode = am_unknown, destmode = am_unknown; int srcreg = -1, destreg = -1; for (i = 0; i < lastbit; i++) bitcnt[i] = bitval[i] = 0; vmsk = 1 << id.n_variable; for (i = 0, msk = 0x8000; i < 16; i++, msk >>= 1) { if (!(msk & id.mask)) { int currbit = id.bitpos[bitno++]; int bit_set; vmsk >>= 1; bit_set = variants & vmsk ? 1 : 0; if (bit_set) opc |= msk; bitpos[currbit] = 15 - i; bitcnt[currbit]++; bitval[currbit] <<= 1; bitval[currbit] |= bit_set; } } if (bitval[bitj] == 0) bitval[bitj] = 8; /* first check whether this one does not match after all */ if (bitval[bitz] == 3 || bitval[bitC] == 1) continue; if (bitcnt[bitI] && (bitval[bitI] == 0x00 || bitval[bitI] == 0xff)) continue; if (bitcnt[bitE] && (bitval[bitE] == 0x00)) continue; /* bitI and bitC get copied to biti and bitc */ if (bitcnt[bitI]) { bitval[biti] = bitval[bitI]; bitpos[biti] = bitpos[bitI]; } if (bitcnt[bitC]) bitval[bitc] = bitval[bitC]; pos = 0; while (opcstr[pos] && !isspace(opcstr[pos])) { if (opcstr[pos] == '.') { pos++; switch (opcstr[pos]) { case 'B': sz = sz_byte; break; case 'W': sz = sz_word; break; case 'L': sz = sz_long; break; case 'z': switch (bitval[bitz]) { case 0: sz = sz_byte; break; case 1: sz = sz_word; break; case 2: sz = sz_long; break; default: abort(); } break; default: abort(); } } else { mnemonic[mnp] = opcstr[pos]; if (mnemonic[mnp] == 'f') { find = -1; switch (bitval[bitf]) { case 0: mnemonic[mnp] = 'R'; break; case 1: mnemonic[mnp] = 'L'; break; default: abort(); } } mnp++; if ((unsigned)mnp >= sizeof(mnemonic) - 1) { mnemonic[sizeof(mnemonic) - 1] = 0; fprintf(stderr, "Instruction %s overflow\n", mnemonic); abort(); } } pos++; } mnemonic[mnp] = 0; /* now, we have read the mnemonic and the size */ while (opcstr[pos] && isspace(opcstr[pos])) pos++; /* A goto a day keeps the D******a away. */ if (opcstr[pos] == 0) goto endofline; /* parse the source address */ usesrc = 1; switch (opcstr[pos++]) { case 'D': srcmode = Dreg; switch (opcstr[pos++]) { case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break; case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break; default: abort(); } break; case 'A': srcmode = Areg; switch (opcstr[pos++]) { case 'r': srcreg = bitval[bitr]; srcgather = 1; srcpos = bitpos[bitr]; break; case 'R': srcreg = bitval[bitR]; srcgather = 1; srcpos = bitpos[bitR]; break; default: abort(); } switch (opcstr[pos]) { case 'p': srcmode = Apdi; pos++; break; case 'P': srcmode = Aipi; pos++; break; } break; case 'L': srcmode = absl; break; case '#': switch (opcstr[pos++]) { case 'z': srcmode = imm; break; case '0': srcmode = imm0; break; case '1': srcmode = imm1; break; case '2': srcmode = imm2; break; case 'i': srcmode = immi; srcreg = (uae_s32)(uae_s8)bitval[biti]; if (CPU_EMU_SIZE < 4) { /* Used for branch instructions */ srctype = 1; srcgather = 1; srcpos = bitpos[biti]; } break; case 'j': srcmode = immi; srcreg = bitval[bitj]; if (CPU_EMU_SIZE < 3) { /* 1..8 for ADDQ/SUBQ and rotshi insns */ srcgather = 1; srctype = 3; srcpos = bitpos[bitj]; } break; case 'J': srcmode = immi; srcreg = bitval[bitJ]; if (CPU_EMU_SIZE < 5) { /* 0..15 */ srcgather = 1; srctype = 2; srcpos = bitpos[bitJ]; } break; case 'k': srcmode = immi; srcreg = bitval[bitk]; if (CPU_EMU_SIZE < 3) { srcgather = 1; srctype = 4; srcpos = bitpos[bitk]; } break; case 'K': srcmode = immi; srcreg = bitval[bitK]; if (CPU_EMU_SIZE < 5) { /* 0..15 */ srcgather = 1; srctype = 5; srcpos = bitpos[bitK]; } break; case 'E': srcmode = immi; srcreg = bitval[bitE]; if (CPU_EMU_SIZE < 5) { // gb-- what is CPU_EMU_SIZE used for ?? /* 1..255 */ srcgather = 1; srctype = 6; srcpos = bitpos[bitE]; } break; case 'p': srcmode = immi; srcreg = bitval[bitp]; if (CPU_EMU_SIZE < 5) { /* 0..3 */ srcgather = 1; srctype = 7; srcpos = bitpos[bitp]; } break; default: abort(); } break; case 'd': srcreg = bitval[bitD]; srcmode = mode_from_mr(bitval[bitd],bitval[bitD]); if (srcmode == am_illg) continue; if (CPU_EMU_SIZE < 2 && (srcmode == Areg || srcmode == Dreg || srcmode == Aind || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi || srcmode == Apdi)) { srcgather = 1; srcpos = bitpos[bitD]; } if (opcstr[pos] == '[') { pos++; if (opcstr[pos] == '!') { /* exclusion */ do { pos++; if (mode_from_str(opcstr+pos) == srcmode) goto nomatch; pos += 4; } while (opcstr[pos] == ','); pos++; } else { if (opcstr[pos+4] == '-') { /* replacement */ if (mode_from_str(opcstr+pos) == srcmode) srcmode = mode_from_str(opcstr+pos+5); else goto nomatch; pos += 10; } else { /* normal */ while(mode_from_str(opcstr+pos) != srcmode) { pos += 4; if (opcstr[pos] == ']') goto nomatch; pos++; } while(opcstr[pos] != ']') pos++; pos++; break; } } } /* Some addressing modes are invalid as destination */ if (srcmode == imm || srcmode == PC16 || srcmode == PC8r) goto nomatch; break; case 's': srcreg = bitval[bitS]; srcmode = mode_from_mr(bitval[bits],bitval[bitS]); if (srcmode == am_illg) continue; if (CPU_EMU_SIZE < 2 && (srcmode == Areg || srcmode == Dreg || srcmode == Aind || srcmode == Ad16 || srcmode == Ad8r || srcmode == Aipi || srcmode == Apdi)) { srcgather = 1; srcpos = bitpos[bitS]; } if (opcstr[pos] == '[') { pos++; if (opcstr[pos] == '!') { /* exclusion */ do { pos++; if (mode_from_str(opcstr+pos) == srcmode) goto nomatch; pos += 4; } while (opcstr[pos] == ','); pos++; } else { if (opcstr[pos+4] == '-') { /* replacement */ if (mode_from_str(opcstr+pos) == srcmode) srcmode = mode_from_str(opcstr+pos+5); else goto nomatch; pos += 10; } else { /* normal */ while(mode_from_str(opcstr+pos) != srcmode) { pos += 4; if (opcstr[pos] == ']') goto nomatch; pos++; } while(opcstr[pos] != ']') pos++; pos++; } } } break; default: abort(); } /* safety check - might have changed */ if (srcmode != Areg && srcmode != Dreg && srcmode != Aind && srcmode != Ad16 && srcmode != Ad8r && srcmode != Aipi && srcmode != Apdi && srcmode != immi) { srcgather = 0; } if (srcmode == Areg && sz == sz_byte) goto nomatch; if (opcstr[pos] != ',') goto endofline; pos++; /* parse the destination address */ usedst = 1; switch (opcstr[pos++]) { case 'D': destmode = Dreg; switch (opcstr[pos++]) { case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break; case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break; default: abort(); } if (dstpos < 0 || dstpos >= 32) abort(); break; case 'A': destmode = Areg; switch (opcstr[pos++]) { case 'r': destreg = bitval[bitr]; dstgather = 1; dstpos = bitpos[bitr]; break; case 'R': destreg = bitval[bitR]; dstgather = 1; dstpos = bitpos[bitR]; break; case 'x': destreg = 0; dstgather = 0; dstpos = 0; break; default: abort(); } if (dstpos < 0 || dstpos >= 32) abort(); switch (opcstr[pos]) { case 'p': destmode = Apdi; pos++; break; case 'P': destmode = Aipi; pos++; break; } break; case 'L': destmode = absl; break; case '#': switch (opcstr[pos++]) { case 'z': destmode = imm; break; case '0': destmode = imm0; break; case '1': destmode = imm1; break; case '2': destmode = imm2; break; case 'i': destmode = immi; destreg = (uae_s32)(uae_s8)bitval[biti]; break; case 'j': destmode = immi; destreg = bitval[bitj]; break; case 'J': destmode = immi; destreg = bitval[bitJ]; break; case 'k': destmode = immi; destreg = bitval[bitk]; break; case 'K': destmode = immi; destreg = bitval[bitK]; break; default: abort(); } break; case 'd': destreg = bitval[bitD]; destmode = mode_from_mr(bitval[bitd],bitval[bitD]); if (destmode == am_illg) continue; if (CPU_EMU_SIZE < 1 && (destmode == Areg || destmode == Dreg || destmode == Aind || destmode == Ad16 || destmode == Ad8r || destmode == Aipi || destmode == Apdi)) { dstgather = 1; dstpos = bitpos[bitD]; } if (opcstr[pos] == '[') { pos++; if (opcstr[pos] == '!') { /* exclusion */ do { pos++; if (mode_from_str(opcstr+pos) == destmode) goto nomatch; pos += 4; } while (opcstr[pos] == ','); pos++; } else { if (opcstr[pos+4] == '-') { /* replacement */ if (mode_from_str(opcstr+pos) == destmode) destmode = mode_from_str(opcstr+pos+5); else goto nomatch; pos += 10; } else { /* normal */ while(mode_from_str(opcstr+pos) != destmode) { pos += 4; if (opcstr[pos] == ']') goto nomatch; pos++; } while(opcstr[pos] != ']') pos++; pos++; break; } } } /* Some addressing modes are invalid as destination */ if (destmode == imm || destmode == PC16 || destmode == PC8r) goto nomatch; break; case 's': destreg = bitval[bitS]; destmode = mode_from_mr(bitval[bits],bitval[bitS]); if (destmode == am_illg) continue; if (CPU_EMU_SIZE < 1 && (destmode == Areg || destmode == Dreg || destmode == Aind || destmode == Ad16 || destmode == Ad8r || destmode == Aipi || destmode == Apdi)) { dstgather = 1; dstpos = bitpos[bitS]; } if (opcstr[pos] == '[') { pos++; if (opcstr[pos] == '!') { /* exclusion */ do { pos++; if (mode_from_str(opcstr+pos) == destmode) goto nomatch; pos += 4; } while (opcstr[pos] == ','); pos++; } else { if (opcstr[pos+4] == '-') { /* replacement */ if (mode_from_str(opcstr+pos) == destmode) destmode = mode_from_str(opcstr+pos+5); else goto nomatch; pos += 10; } else { /* normal */ while(mode_from_str(opcstr+pos) != destmode) { pos += 4; if (opcstr[pos] == ']') goto nomatch; pos++; } while(opcstr[pos] != ']') pos++; pos++; } } } break; default: abort(); } /* safety check - might have changed */ if (destmode != Areg && destmode != Dreg && destmode != Aind && destmode != Ad16 && destmode != Ad8r && destmode != Aipi && destmode != Apdi) { dstgather = 0; } if (destmode == Areg && sz == sz_byte) goto nomatch; #if 0 if (sz == sz_byte && (destmode == Aipi || destmode == Apdi)) { dstgather = 0; } #endif endofline: /* now, we have a match */ if (table68k[opc].mnemo != i_ILLG) fprintf(stderr, "Double match: %x: %s\n", opc, opcstr); if (find == -1) { for (find = 0;; find++) { if (strcmp(mnemonic, lookuptab[find].name) == 0) { table68k[opc].mnemo = lookuptab[find].mnemo; break; } if (strlen(lookuptab[find].name) == 0) abort(); } } else { table68k[opc].mnemo = lookuptab[find].mnemo; } table68k[opc].cc = bitval[bitc]; if (table68k[opc].mnemo == i_BTST || table68k[opc].mnemo == i_BSET || table68k[opc].mnemo == i_BCLR || table68k[opc].mnemo == i_BCHG) { sz = destmode == Dreg ? sz_long : sz_byte; } table68k[opc].size = sz; table68k[opc].sreg = srcreg; table68k[opc].dreg = destreg; table68k[opc].smode = srcmode; table68k[opc].dmode = destmode; table68k[opc].spos = srcgather ? srcpos : -1; table68k[opc].dpos = dstgather ? dstpos : -1; table68k[opc].suse = usesrc; table68k[opc].duse = usedst; table68k[opc].stype = srctype; table68k[opc].plev = id.plevel; table68k[opc].clev = id.cpulevel; #if 0 for (i = 0; i < 5; i++) { table68k[opc].flaginfo[i].flagset = id.flaginfo[i].flagset; table68k[opc].flaginfo[i].flaguse = id.flaginfo[i].flaguse; } #endif // Fix flags used information for Scc, Bcc, TRAPcc, DBcc instructions if ( table68k[opc].mnemo == i_Scc || table68k[opc].mnemo == i_Bcc || table68k[opc].mnemo == i_DBcc || table68k[opc].mnemo == i_TRAPcc ) { switch (table68k[opc].cc) { // CC mask: XNZVC // 8421 case 0: flags_used = 0x00; break; /* T */ case 1: flags_used = 0x00; break; /* F */ case 2: flags_used = 0x05; break; /* HI */ case 3: flags_used = 0x05; break; /* LS */ case 4: flags_used = 0x01; break; /* CC */ case 5: flags_used = 0x01; break; /* CS */ case 6: flags_used = 0x04; break; /* NE */ case 7: flags_used = 0x04; break; /* EQ */ case 8: flags_used = 0x02; break; /* VC */ case 9: flags_used = 0x02; break; /* VS */ case 10:flags_used = 0x08; break; /* PL */ case 11:flags_used = 0x08; break; /* MI */ case 12:flags_used = 0x0A; break; /* GE */ case 13:flags_used = 0x0A; break; /* LT */ case 14:flags_used = 0x0E; break; /* GT */ case 15:flags_used = 0x0E; break; /* LE */ } } #if 1 /* gb-- flagdead and flaglive would not have correct information */ table68k[opc].flagdead = flags_set; table68k[opc].flaglive = flags_used; #else table68k[opc].flagdead = flagdead; table68k[opc].flaglive = flaglive; #endif table68k[opc].cflow = cflow; nomatch: /* FOO! */; } } void read_table68k (void) { int i; table68k = (struct instr *)malloc (65536 * sizeof (struct instr)); for (i = 0; i < 65536; i++) { table68k[i].mnemo = i_ILLG; table68k[i].handler = -1; } for (i = 0; i < n_defs68k; i++) { build_insn (i); } } static int mismatch; static void handle_merges (long int opcode) { uae_u16 smsk; uae_u16 dmsk; int sbitdst, dstend; int srcreg, dstreg; if (table68k[opcode].spos == -1) { sbitdst = 1; smsk = 0; } else { switch (table68k[opcode].stype) { case 0: smsk = 7; sbitdst = 8; break; case 1: smsk = 255; sbitdst = 256; break; case 2: smsk = 15; sbitdst = 16; break; case 3: smsk = 7; sbitdst = 8; break; case 4: smsk = 7; sbitdst = 8; break; case 5: smsk = 63; sbitdst = 64; break; case 6: smsk = 255; sbitdst = 256; break; case 7: smsk = 3; sbitdst = 4; break; default: smsk = 0; sbitdst = 0; abort(); break; } smsk <<= table68k[opcode].spos; } if (table68k[opcode].dpos == -1) { dstend = 1; dmsk = 0; } else { dmsk = 7 << table68k[opcode].dpos; dstend = 8; } for (srcreg=0; srcreg < sbitdst; srcreg++) { for (dstreg=0; dstreg < dstend; dstreg++) { uae_u16 code = opcode; code = (code & ~smsk) | (srcreg << table68k[opcode].spos); code = (code & ~dmsk) | (dstreg << table68k[opcode].dpos); /* Check whether this is in fact the same instruction. * The instructions should never differ, except for the * Bcc.(BW) case. */ if (table68k[code].mnemo != table68k[opcode].mnemo || table68k[code].size != table68k[opcode].size || table68k[code].suse != table68k[opcode].suse || table68k[code].duse != table68k[opcode].duse) { mismatch++; continue; } if (table68k[opcode].suse && (table68k[opcode].spos != table68k[code].spos || table68k[opcode].smode != table68k[code].smode || table68k[opcode].stype != table68k[code].stype)) { mismatch++; continue; } if (table68k[opcode].duse && (table68k[opcode].dpos != table68k[code].dpos || table68k[opcode].dmode != table68k[code].dmode)) { mismatch++; continue; } if (code != opcode) table68k[code].handler = opcode; } } } void do_merges (void) { long int opcode; int nr = 0; mismatch = 0; for (opcode = 0; opcode < 65536; opcode++) { if (table68k[opcode].handler != -1 || table68k[opcode].mnemo == i_ILLG) continue; nr++; handle_merges (opcode); } nr_cpuop_funcs = nr; } int get_no_mismatches (void) { return mismatch; } const char *get_instruction_name (unsigned int opcode) { struct instr *ins = &table68k[opcode]; for (int i = 0; lookuptab[i].name[0]; i++) { if (ins->mnemo == lookuptab[i].mnemo) return lookuptab[i].name; } abort(); return NULL; } static char *get_ea_string (amodes mode, wordsizes size) { static char buffer[80]; buffer[0] = 0; switch (mode){ case Dreg: strcpy (buffer,"Dn"); break; case Areg: strcpy (buffer,"An"); break; case Aind: strcpy (buffer,"(An)"); break; case Aipi: strcpy (buffer,"(An)+"); break; case Apdi: strcpy (buffer,"-(An)"); break; case Ad16: strcpy (buffer,"(d16,An)"); break; case Ad8r: strcpy (buffer,"(d8,An,Xn)"); break; case PC16: strcpy (buffer,"(d16,PC)"); break; case PC8r: strcpy (buffer,"(d8,PC,Xn)"); break; case absw: strcpy (buffer,"(xxx).W"); break; case absl: strcpy (buffer,"(xxx).L"); break; case imm: switch (size){ case sz_byte: strcpy (buffer,"#.B"); break; case sz_word: strcpy (buffer,"#.W"); break; case sz_long: strcpy (buffer,"#.L"); break; default: break; } break; case imm0: strcpy (buffer,"#.B"); break; case imm1: strcpy (buffer,"#.W"); break; case imm2: strcpy (buffer,"#.L"); break; case immi: strcpy (buffer,"#"); break; default: break; } return buffer; } const char *get_instruction_string (unsigned int opcode) { static char out[100]; struct instr *ins; strcpy (out, get_instruction_name (opcode)); ins = &table68k[opcode]; if (ins->size == sz_byte) strcat (out,".B"); if (ins->size == sz_word) strcat (out,".W"); if (ins->size == sz_long) strcat (out,".L"); strcat (out," "); if (ins->suse) strcat (out, get_ea_string (ins->smode, ins->size)); if (ins->duse) { if (ins->suse) strcat (out,","); strcat (out, get_ea_string (ins->dmode, ins->size)); } return out; } BasiliskII/src/uae_cpu/readcpu.h0000644000175000017500000000633310641232005016743 0ustar centriscentris#ifndef READCPU_H #define READCPU_H #ifdef __cplusplus extern "C" { #endif ENUMDECL { Dreg, Areg, Aind, Aipi, Apdi, Ad16, Ad8r, absw, absl, PC16, PC8r, imm, imm0, imm1, imm2, immi, am_unknown, am_illg } ENUMNAME (amodes); ENUMDECL { i_ILLG, i_OR, i_AND, i_EOR, i_ORSR, i_ANDSR, i_EORSR, i_SUB, i_SUBA, i_SUBX, i_SBCD, i_ADD, i_ADDA, i_ADDX, i_ABCD, i_NEG, i_NEGX, i_NBCD, i_CLR, i_NOT, i_TST, i_BTST, i_BCHG, i_BCLR, i_BSET, i_CMP, i_CMPM, i_CMPA, i_MVPRM, i_MVPMR, i_MOVE, i_MOVEA, i_MVSR2, i_MV2SR, i_SWAP, i_EXG, i_EXT, i_MVMEL, i_MVMLE, i_TRAP, i_MVR2USP, i_MVUSP2R, i_RESET, i_NOP, i_STOP, i_RTE, i_RTD, i_LINK, i_UNLK, i_RTS, i_TRAPV, i_RTR, i_JSR, i_JMP, i_BSR, i_Bcc, i_LEA, i_PEA, i_DBcc, i_Scc, i_DIVU, i_DIVS, i_MULU, i_MULS, i_ASR, i_ASL, i_LSR, i_LSL, i_ROL, i_ROR, i_ROXL, i_ROXR, i_ASRW, i_ASLW, i_LSRW, i_LSLW, i_ROLW, i_RORW, i_ROXLW, i_ROXRW, i_CHK,i_CHK2, i_MOVEC2, i_MOVE2C, i_CAS, i_CAS2, i_DIVL, i_MULL, i_BFTST,i_BFEXTU,i_BFCHG,i_BFEXTS,i_BFCLR,i_BFFFO,i_BFSET,i_BFINS, i_PACK, i_UNPK, i_TAS, i_BKPT, i_CALLM, i_RTM, i_TRAPcc, i_MOVES, i_FPP, i_FDBcc, i_FScc, i_FTRAPcc, i_FBcc, i_FSAVE, i_FRESTORE, i_CINVL, i_CINVP, i_CINVA, i_CPUSHL, i_CPUSHP, i_CPUSHA, i_MOVE16, i_MMUOP, i_EMULOP_RETURN, i_EMULOP } ENUMNAME (instrmnem); extern struct mnemolookup { instrmnem mnemo; const char *name; } lookuptab[]; ENUMDECL { sz_byte, sz_word, sz_long } ENUMNAME (wordsizes); ENUMDECL { fa_set, fa_unset, fa_zero, fa_one, fa_dontcare, fa_unknown, fa_isjmp } ENUMNAME (flagaffect); ENUMDECL { fu_used, fu_unused, fu_maybecc, fu_unknown, fu_isjmp } ENUMNAME (flaguse); ENUMDECL { fl_normal = 0, fl_branch = 1, fl_jump = 2, fl_return = 3, fl_trap = 4, fl_const_jump = 8, /* Instructions that can trap don't mark the end of a block */ fl_end_block = 3 } ENUMNAME (cflow_t); ENUMDECL { bit0, bit1, bitc, bitC, bitf, biti, bitI, bitj, bitJ, bitk, bitK, bits, bitS, bitd, bitD, bitr, bitR, bitz, bitE, bitp, lastbit } ENUMNAME (bitvals); struct instr_def { unsigned int bits; int n_variable; char bitpos[16]; unsigned int mask; int cpulevel; int plevel; struct { unsigned int flaguse:3; unsigned int flagset:3; } flaginfo[5]; unsigned char cflow; unsigned char sduse; const char *opcstr; }; extern struct instr_def defs68k[]; extern int n_defs68k; extern struct instr { long int handler; unsigned char dreg; unsigned char sreg; signed char dpos; signed char spos; unsigned char sduse; int flagdead:8, flaglive:8; unsigned int mnemo:8; unsigned int cc:4; unsigned int plev:2; wordsizes size:2; amodes smode:5; unsigned int stype:3; amodes dmode:5; unsigned int suse:1; unsigned int duse:1; unsigned int unused1:1; unsigned int clev:3; unsigned int cflow:3; unsigned int unused2:2; } *table68k; extern void read_table68k (void); extern void do_merges (void); extern int get_no_mismatches (void); extern int nr_cpuop_funcs; extern const char *get_instruction_name (unsigned int opcode); extern const char *get_instruction_string (unsigned int opcode); #ifdef __cplusplus } #endif #endif /* READCPU_H */ BasiliskII/src/uae_cpu/memory.h0000644000175000017500000001357011735673707016660 0ustar centriscentris/* * UAE - The Un*x Amiga Emulator * * memory management * * Copyright 1995 Bernd Schmidt * * 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 */ #ifndef UAE_MEMORY_H #define UAE_MEMORY_H #if !DIRECT_ADDRESSING && !REAL_ADDRESSING /* Enabling this adds one additional native memory reference per 68k memory * access, but saves one shift (on the x86). Enabling this is probably * better for the cache. My favourite benchmark (PP2) doesn't show a * difference, so I leave this enabled. */ #if 1 || defined SAVE_MEMORY #define SAVE_MEMORY_BANKS #endif typedef uae_u32 (REGPARAM2 *mem_get_func)(uaecptr) REGPARAM; typedef void (REGPARAM2 *mem_put_func)(uaecptr, uae_u32) REGPARAM; typedef uae_u8 *(REGPARAM2 *xlate_func)(uaecptr) REGPARAM; #undef DIRECT_MEMFUNCS_SUCCESSFUL #ifndef CAN_MAP_MEMORY #undef USE_COMPILER #endif #if defined(USE_COMPILER) && !defined(USE_MAPPED_MEMORY) #define USE_MAPPED_MEMORY #endif typedef struct { /* These ones should be self-explanatory... */ mem_get_func lget, wget, bget; mem_put_func lput, wput, bput; /* Use xlateaddr to translate an Amiga address to a uae_u8 * that can * be used to address memory without calling the wget/wput functions. * This doesn't work for all memory banks, so this function may call * abort(). */ xlate_func xlateaddr; } addrbank; extern uae_u8 filesysory[65536]; extern addrbank ram_bank; // Mac RAM extern addrbank rom_bank; // Mac ROM extern addrbank frame_bank; // Frame buffer /* Default memory access functions */ extern uae_u8 *REGPARAM2 default_xlate(uaecptr addr) REGPARAM; #define bankindex(addr) (((uaecptr)(addr)) >> 16) #ifdef SAVE_MEMORY_BANKS extern addrbank *mem_banks[65536]; #define get_mem_bank(addr) (*mem_banks[bankindex(addr)]) #define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = (b)) #else extern addrbank mem_banks[65536]; #define get_mem_bank(addr) (mem_banks[bankindex(addr)]) #define put_mem_bank(addr, b) (mem_banks[bankindex(addr)] = *(b)) #endif extern void memory_init(void); extern void map_banks(addrbank *bank, int first, int count); #ifndef NO_INLINE_MEMORY_ACCESS #define longget(addr) (call_mem_get_func(get_mem_bank(addr).lget, addr)) #define wordget(addr) (call_mem_get_func(get_mem_bank(addr).wget, addr)) #define byteget(addr) (call_mem_get_func(get_mem_bank(addr).bget, addr)) #define longput(addr,l) (call_mem_put_func(get_mem_bank(addr).lput, addr, l)) #define wordput(addr,w) (call_mem_put_func(get_mem_bank(addr).wput, addr, w)) #define byteput(addr,b) (call_mem_put_func(get_mem_bank(addr).bput, addr, b)) #else extern uae_u32 longget(uaecptr addr); extern uae_u32 wordget(uaecptr addr); extern uae_u32 byteget(uaecptr addr); extern void longput(uaecptr addr, uae_u32 l); extern void wordput(uaecptr addr, uae_u32 w); extern void byteput(uaecptr addr, uae_u32 b); #endif #ifndef MD_HAVE_MEM_1_FUNCS #define longget_1 longget #define wordget_1 wordget #define byteget_1 byteget #define longput_1 longput #define wordput_1 wordput #define byteput_1 byteput #endif #endif /* !DIRECT_ADDRESSING && !REAL_ADDRESSING */ #if REAL_ADDRESSING const uintptr MEMBaseDiff = 0; #elif DIRECT_ADDRESSING extern uintptr MEMBaseDiff; #endif #if REAL_ADDRESSING || DIRECT_ADDRESSING static __inline__ uae_u8 *do_get_real_address(uaecptr addr) { return (uae_u8 *)MEMBaseDiff + addr; } static __inline__ uae_u32 do_get_virtual_address(uae_u8 *addr) { return (uintptr)addr - MEMBaseDiff; } static __inline__ uae_u32 get_long(uaecptr addr) { uae_u32 * const m = (uae_u32 *)do_get_real_address(addr); return do_get_mem_long(m); } static __inline__ uae_u32 get_word(uaecptr addr) { uae_u16 * const m = (uae_u16 *)do_get_real_address(addr); return do_get_mem_word(m); } static __inline__ uae_u32 get_byte(uaecptr addr) { uae_u8 * const m = (uae_u8 *)do_get_real_address(addr); return do_get_mem_byte(m); } static __inline__ void put_long(uaecptr addr, uae_u32 l) { uae_u32 * const m = (uae_u32 *)do_get_real_address(addr); do_put_mem_long(m, l); } static __inline__ void put_word(uaecptr addr, uae_u32 w) { uae_u16 * const m = (uae_u16 *)do_get_real_address(addr); do_put_mem_word(m, w); } static __inline__ void put_byte(uaecptr addr, uae_u32 b) { uae_u8 * const m = (uae_u8 *)do_get_real_address(addr); do_put_mem_byte(m, b); } static __inline__ uae_u8 *get_real_address(uaecptr addr) { return do_get_real_address(addr); } static __inline__ uae_u32 get_virtual_address(uae_u8 *addr) { return do_get_virtual_address(addr); } #else static __inline__ uae_u32 get_long(uaecptr addr) { return longget_1(addr); } static __inline__ uae_u32 get_word(uaecptr addr) { return wordget_1(addr); } static __inline__ uae_u32 get_byte(uaecptr addr) { return byteget_1(addr); } static __inline__ void put_long(uaecptr addr, uae_u32 l) { longput_1(addr, l); } static __inline__ void put_word(uaecptr addr, uae_u32 w) { wordput_1(addr, w); } static __inline__ void put_byte(uaecptr addr, uae_u32 b) { byteput_1(addr, b); } static __inline__ uae_u8 *get_real_address(uaecptr addr) { return get_mem_bank(addr).xlateaddr(addr); } /* gb-- deliberately not implemented since it shall not be used... */ extern uae_u32 get_virtual_address(uae_u8 *addr); #endif /* DIRECT_ADDRESSING || REAL_ADDRESSING */ #endif /* MEMORY_H */ BasiliskII/src/prefs_items.cpp0000644000175000017500000001116510736405217016565 0ustar centriscentris/* * prefs_items.cpp - Common preferences items * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "sys.h" #include "prefs.h" // Common preferences items (those which exist on all platforms) // Except for "disk", "floppy", "cdrom", "scsiX", "screen", "rom" and "ether", // these are guaranteed to be in the prefs. prefs_desc common_prefs_items[] = { {"disk", TYPE_STRING, true, "device/file name of Mac volume"}, {"floppy", TYPE_STRING, true, "device/file name of Mac floppy drive"}, {"cdrom", TYPE_STRING, true, "device/file names of Mac CD-ROM drive"}, {"extfs", TYPE_STRING, false, "root path of ExtFS"}, {"scsi0", TYPE_STRING, false, "SCSI target for Mac SCSI ID 0"}, {"scsi1", TYPE_STRING, false, "SCSI target for Mac SCSI ID 1"}, {"scsi2", TYPE_STRING, false, "SCSI target for Mac SCSI ID 2"}, {"scsi3", TYPE_STRING, false, "SCSI target for Mac SCSI ID 3"}, {"scsi4", TYPE_STRING, false, "SCSI target for Mac SCSI ID 4"}, {"scsi5", TYPE_STRING, false, "SCSI target for Mac SCSI ID 5"}, {"scsi6", TYPE_STRING, false, "SCSI target for Mac SCSI ID 6"}, {"screen", TYPE_STRING, false, "video mode"}, {"seriala", TYPE_STRING, false, "device name of Mac serial port A"}, {"serialb", TYPE_STRING, false, "device name of Mac serial port B"}, {"ether", TYPE_STRING, false, "device name of Mac ethernet adapter"}, {"etherconfig", TYPE_STRING, false,"path of network config script"}, {"udptunnel", TYPE_BOOLEAN, false, "tunnel all network packets over UDP"}, {"udpport", TYPE_INT32, false, "IP port number for tunneling"}, {"rom", TYPE_STRING, false, "path of ROM file"}, {"bootdrive", TYPE_INT32, false, "boot drive number"}, {"bootdriver", TYPE_INT32, false, "boot driver number"}, {"ramsize", TYPE_INT32, false, "size of Mac RAM in bytes"}, {"frameskip", TYPE_INT32, false, "number of frames to skip in refreshed video modes"}, {"modelid", TYPE_INT32, false, "Mac Model ID (Gestalt Model ID minus 6)"}, {"cpu", TYPE_INT32, false, "CPU type (0 = 68000, 1 = 68010 etc.)"}, {"fpu", TYPE_BOOLEAN, false, "enable FPU emulation"}, {"nocdrom", TYPE_BOOLEAN, false, "don't install CD-ROM driver"}, {"nosound", TYPE_BOOLEAN, false, "don't enable sound output"}, {"noclipconversion", TYPE_BOOLEAN, false, "don't convert clipboard contents"}, {"nogui", TYPE_BOOLEAN, false, "disable GUI"}, {"jit", TYPE_BOOLEAN, false, "enable JIT compiler"}, {"jitfpu", TYPE_BOOLEAN, false, "enable JIT compilation of FPU instructions"}, {"jitdebug", TYPE_BOOLEAN, false, "enable JIT debugger (requires mon builtin)"}, {"jitcachesize", TYPE_INT32, false, "translation cache size in KB"}, {"jitlazyflush", TYPE_BOOLEAN, false, "enable lazy invalidation of translation cache"}, {"jitinline", TYPE_BOOLEAN, false, "enable translation through constant jumps"}, {"jitblacklist", TYPE_STRING, false, "blacklist opcodes from translation"}, {"keyboardtype", TYPE_INT32, false, "hardware keyboard type"}, {NULL, TYPE_END, false, NULL} // End of list }; /* * Set default values for preferences items */ void AddPrefsDefaults(void) { SysAddSerialPrefs(); PrefsAddBool("udptunnel", false); PrefsAddInt32("udpport", 6066); PrefsAddInt32("bootdriver", 0); PrefsAddInt32("bootdrive", 0); PrefsAddInt32("ramsize", 8 * 1024 * 1024); PrefsAddInt32("frameskip", 6); PrefsAddInt32("modelid", 5); // Mac IIci PrefsAddInt32("cpu", 3); // 68030 PrefsAddBool("fpu", false); PrefsAddBool("nocdrom", false); PrefsAddBool("nosound", false); PrefsAddBool("noclipconversion", false); PrefsAddBool("nogui", false); #if USE_JIT // JIT compiler specific options PrefsAddBool("jit", true); PrefsAddBool("jitfpu", true); PrefsAddBool("jitdebug", false); PrefsAddInt32("jitcachesize", 8192); PrefsAddBool("jitlazyflush", true); PrefsAddBool("jitinline", true); #else PrefsAddBool("jit", false); #endif PrefsAddInt32("keyboardtype", 5); } BasiliskII/src/native_cpu/0000755000175000017500000000000011735674751015705 5ustar centriscentrisBasiliskII/src/native_cpu/cpu_emulation.h0000644000175000017500000000570510736405223020713 0ustar centriscentris/* * cpu_emulation.h - Definitions for Basilisk II CPU emulation module (native 68k version) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef CPU_EMULATION_H #define CPU_EMULATION_H /* * Memory system */ // RAM and ROM pointers (allocated and set by main_*.cpp) extern uint32 RAMBaseMac; // RAM base (Mac address space), does not include Low Mem when != 0 extern uint8 *RAMBaseHost; // RAM base (host address space) extern uint32 RAMSize; // Size of RAM extern uint32 ROMBaseMac; // ROM base (Mac address space) extern uint8 *ROMBaseHost; // ROM base (host address space) extern uint32 ROMSize; // Size of ROM // Mac memory access functions static inline uint32 ReadMacInt32(uint32 addr) {return *(uint32 *)addr;} static inline uint32 ReadMacInt16(uint32 addr) {return *(uint16 *)addr;} static inline uint32 ReadMacInt8(uint32 addr) {return *(uint8 *)addr;} static inline void WriteMacInt32(uint32 addr, uint32 l) {*(uint32 *)addr = l;} static inline void WriteMacInt16(uint32 addr, uint32 w) {*(uint16 *)addr = w;} static inline void WriteMacInt8(uint32 addr, uint32 b) {*(uint8 *)addr = b;} static inline uint8 *Mac2HostAddr(uint32 addr) {return (uint8 *)addr;} static inline uint32 Host2MacAddr(uint8 *addr) {return (uint32)addr;} static inline void *Mac_memset(uint32 addr, int c, size_t n) {return memset(Mac2HostAddr(addr), c, n);} static inline void *Mac2Host_memcpy(void *dest, uint32 src, size_t n) {return memcpy(dest, Mac2HostAddr(src), n);} static inline void *Host2Mac_memcpy(uint32 dest, const void *src, size_t n) {return memcpy(Mac2HostAddr(dest), src, n);} static inline void *Mac2Mac_memcpy(uint32 dest, uint32 src, size_t n) {return memcpy(Mac2HostAddr(dest), Mac2HostAddr(src), n);} /* * 680x0 emulation */ // 680x0 emulation functions struct M68kRegisters; extern void Start680x0(void); // Reset and start 680x0 extern "C" void Execute68k(uint32 addr, M68kRegisters *r); // Execute 68k code from EMUL_OP routine extern "C" void Execute68kTrap(uint16 trap, M68kRegisters *r); // Execute MacOS 68k trap from EMUL_OP routine // Interrupt functions extern void TriggerInterrupt(void); // Trigger interrupt (InterruptFlag must be set first) extern void TriggerNMI(void); // Trigger interrupt level 7 #endif BasiliskII/src/ether.cpp0000644000175000017500000003212110736405217015347 0ustar centriscentris/* * ether.cpp - Ethernet device driver * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 1 "Device Manager" * Inside Macintosh: Networking, chapter 11 "Ethernet, Token Ring, and FDDI" * Inside AppleTalk, chapter 3 "Ethernet and TokenTalk Link Access Protocols" */ #include "sysdeps.h" #include #include #if SUPPORTS_UDP_TUNNEL #include #include #include #include #include #include #endif #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "emul_op.h" #include "prefs.h" #include "ether.h" #include "ether_defs.h" #ifndef NO_STD_NAMESPACE using std::map; #endif #define DEBUG 0 #include "debug.h" #define MONITOR 0 #ifdef __BEOS__ #define CLOSESOCKET closesocket #else #define CLOSESOCKET close #endif // Global variables uint8 ether_addr[6]; // Ethernet address (set by ether_init()) static bool net_open = false; // Flag: initialization succeeded, network device open (set by EtherInit()) static bool udp_tunnel = false; // Flag: tunnelling AppleTalk over UDP using BSD socket API static uint16 udp_port; static int udp_socket = -1; // Mac address of driver data in MacOS RAM uint32 ether_data = 0; // Attached network protocols for UDP tunneling, maps protocol type to MacOS handler address static map udp_protocols; /* * Initialization */ void EtherInit(void) { net_open = false; udp_tunnel = false; #if SUPPORTS_UDP_TUNNEL // UDP tunnelling requested? if (PrefsFindBool("udptunnel")) { udp_tunnel = true; udp_port = PrefsFindInt32("udpport"); // Open UDP socket udp_socket = socket(PF_INET, SOCK_DGRAM, 0); if (udp_socket < 0) { perror("socket"); return; } // Bind to specified address and port struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = INADDR_ANY; sa.sin_port = htons(udp_port); if (bind(udp_socket, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("bind"); CLOSESOCKET(udp_socket); udp_socket = -1; return; } // Retrieve local IP address (or at least one of them) socklen_t sa_length = sizeof(sa); getsockname(udp_socket, (struct sockaddr *)&sa, &sa_length); uint32 udp_ip = sa.sin_addr.s_addr; if (udp_ip == INADDR_ANY || udp_ip == INADDR_LOOPBACK) { char name[256]; gethostname(name, sizeof(name)); struct hostent *local = gethostbyname(name); if (local) udp_ip = *(uint32 *)local->h_addr_list[0]; } udp_ip = ntohl(udp_ip); // Construct dummy Ethernet address from local IP address ether_addr[0] = 'B'; ether_addr[1] = '2'; ether_addr[2] = udp_ip >> 24; ether_addr[3] = udp_ip >> 16; ether_addr[4] = udp_ip >> 8; ether_addr[5] = udp_ip; D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5])); // Set socket options int on = 1; #ifdef __BEOS__ setsockopt(udp_socket, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(on)); #else setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); ioctl(udp_socket, FIONBIO, &on); #endif // Start thread for packet reception if (!ether_start_udp_thread(udp_socket)) { CLOSESOCKET(udp_socket); udp_socket = -1; return; } net_open = true; } else #endif if (ether_init()) net_open = true; } /* * Deinitialization */ void EtherExit(void) { if (net_open) { #if SUPPORTS_UDP_TUNNEL if (udp_tunnel) { if (udp_socket >= 0) { ether_stop_udp_thread(); CLOSESOCKET(udp_socket); udp_socket = -1; } } else #endif ether_exit(); net_open = false; } } /* * Reset */ void EtherReset(void) { udp_protocols.clear(); ether_reset(); } /* * Check whether Ethernet address is AppleTalk or Ethernet broadcast address */ static inline bool is_apple_talk_broadcast(uint8 *p) { return p[0] == 0x09 && p[1] == 0x00 && p[2] == 0x07 && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff; } static inline bool is_ethernet_broadcast(uint8 *p) { return p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff && p[4] == 0xff && p[5] == 0xff; } /* * Driver Open() routine */ int16 EtherOpen(uint32 pb, uint32 dce) { D(bug("EtherOpen\n")); // Allocate driver data M68kRegisters r; r.d[0] = SIZEOF_etherdata; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) return openErr; ether_data = r.a[0]; D(bug(" data %08x\n", ether_data)); WriteMacInt16(ether_data + ed_DeferredTask + qType, dtQType); WriteMacInt32(ether_data + ed_DeferredTask + dtAddr, ether_data + ed_Code); WriteMacInt32(ether_data + ed_DeferredTask + dtParam, ether_data + ed_Result); // Deferred function for signalling that packet write is complete (pointer to mydtResult in a1) WriteMacInt16(ether_data + ed_Code, 0x2019); // move.l (a1)+,d0 (result) WriteMacInt16(ether_data + ed_Code + 2, 0x2251); // move.l (a1),a1 (dce) WriteMacInt32(ether_data + ed_Code + 4, 0x207808fc); // move.l JIODone,a0 WriteMacInt16(ether_data + ed_Code + 8, 0x4ed0); // jmp (a0) WriteMacInt32(ether_data + ed_DCE, dce); // ReadPacket/ReadRest routines WriteMacInt16(ether_data + ed_ReadPacket, 0x6010); // bra 2 WriteMacInt16(ether_data + ed_ReadPacket + 2, 0x3003); // move.w d3,d0 WriteMacInt16(ether_data + ed_ReadPacket + 4, 0x9041); // sub.w d1,d0 WriteMacInt16(ether_data + ed_ReadPacket + 6, 0x4a43); // tst.w d3 WriteMacInt16(ether_data + ed_ReadPacket + 8, 0x6702); // beq 1 WriteMacInt16(ether_data + ed_ReadPacket + 10, M68K_EMUL_OP_ETHER_READ_PACKET); WriteMacInt16(ether_data + ed_ReadPacket + 12, 0x3600); //1 move.w d0,d3 WriteMacInt16(ether_data + ed_ReadPacket + 14, 0x7000); // moveq #0,d0 WriteMacInt16(ether_data + ed_ReadPacket + 16, 0x4e75); // rts WriteMacInt16(ether_data + ed_ReadPacket + 18, M68K_EMUL_OP_ETHER_READ_PACKET); //2 WriteMacInt16(ether_data + ed_ReadPacket + 20, 0x4a43); // tst.w d3 WriteMacInt16(ether_data + ed_ReadPacket + 22, 0x4e75); // rts return 0; } /* * Driver Control() routine */ int16 EtherControl(uint32 pb, uint32 dce) { uint16 code = ReadMacInt16(pb + csCode); D(bug("EtherControl %d\n", code)); switch (code) { case 1: // KillIO return -1; case kENetAddMulti: // Add multicast address D(bug(" AddMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); if (net_open && !udp_tunnel) return ether_add_multicast(pb); return noErr; case kENetDelMulti: // Delete multicast address D(bug(" DelMulti %08x%04x\n", ReadMacInt32(pb + eMultiAddr), ReadMacInt16(pb + eMultiAddr + 4))); if (net_open && !udp_tunnel) return ether_del_multicast(pb); return noErr; case kENetAttachPH: { // Attach protocol handler uint16 type = ReadMacInt16(pb + eProtType); uint32 handler = ReadMacInt32(pb + ePointer); D(bug(" AttachPH prot %04x, handler %08x\n", type, handler)); if (net_open) { if (udp_tunnel) { if (udp_protocols.find(type) != udp_protocols.end()) return lapProtErr; udp_protocols[type] = handler; } else return ether_attach_ph(type, handler); } return noErr; } case kENetDetachPH: { // Detach protocol handler uint16 type = ReadMacInt16(pb + eProtType); D(bug(" DetachPH prot %04x\n", type)); if (net_open) { if (udp_tunnel) { if (udp_protocols.erase(type) == 0) return lapProtErr; } else return ether_detach_ph(type); } return noErr; } case kENetWrite: { // Transmit raw Ethernet packet uint32 wds = ReadMacInt32(pb + ePointer); D(bug(" EtherWrite ")); if (ReadMacInt16(wds) < 14) return eLenErr; // Header incomplete // Set source address uint32 hdr = ReadMacInt32(wds + 2); Host2Mac_memcpy(hdr + 6, ether_addr, 6); D(bug("to %08x%04x, type %04x\n", ReadMacInt32(hdr), ReadMacInt16(hdr + 4), ReadMacInt16(hdr + 12))); if (net_open) { #if SUPPORTS_UDP_TUNNEL if (udp_tunnel) { // Copy packet to buffer uint8 packet[1514]; int len = ether_wds_to_buffer(wds, packet); // Extract destination address uint32 dest_ip; if (packet[0] == 'B' && packet[1] == '2') dest_ip = (packet[2] << 24) | (packet[3] << 16) | (packet[4] << 8) | packet[5]; else if (is_apple_talk_broadcast(packet) || is_ethernet_broadcast(packet)) dest_ip = INADDR_BROADCAST; else return eMultiErr; #if MONITOR bug("Sending Ethernet packet:\n"); for (int i=0; i 18) size = 18; WriteMacInt16(pb + eDataSize, size); // Number of bytes actually written Host2Mac_memcpy(ReadMacInt32(pb + ePointer), buf, size); return noErr; } case kENetSetGeneral: // Set general mode (always in general mode) D(bug(" SetGeneral\n")); return noErr; default: printf("WARNING: Unknown EtherControl(%d)\n", code); return controlErr; } } /* * Ethernet ReadPacket routine */ void EtherReadPacket(uint32 &src, uint32 &dest, uint32 &len, uint32 &remaining) { D(bug("EtherReadPacket src %08x, dest %08x, len %08x, remaining %08x\n", src, dest, len, remaining)); uint32 todo = len > remaining ? remaining : len; Mac2Mac_memcpy(dest, src, todo); src += todo; dest += todo; len -= todo; remaining -= todo; } #if SUPPORTS_UDP_TUNNEL /* * Read packet from UDP socket */ void ether_udp_read(uint32 packet, int length, struct sockaddr_in *from) { // Drop packets sent by us if (memcmp(Mac2HostAddr(packet) + 6, ether_addr, 6) == 0) return; #if MONITOR bug("Receiving Ethernet packet:\n"); for (int i=0; i 0) { bug("WARNING: Nested allocation of ethernet packets!\n"); } } #endif BasiliskII/src/adb.cpp0000644000175000017500000002611511340201430014753 0ustar centriscentris/* * adb.cpp - ADB emulation (mouse/keyboard) * * Basilisk II (C) Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 5 "ADB Manager" * Technote HW 01: "ADB - The Untold Story: Space Aliens Ate My Mouse" */ #include #include "sysdeps.h" #include "cpu_emulation.h" #include "emul_op.h" #include "main.h" #include "prefs.h" #include "video.h" #include "adb.h" #ifdef POWERPC_ROM #include "thunks.h" #endif #define DEBUG 0 #include "debug.h" // Global variables static int mouse_x = 0, mouse_y = 0; // Mouse position static int old_mouse_x = 0, old_mouse_y = 0; static bool mouse_button[3] = {false, false, false}; // Mouse button states static bool old_mouse_button[3] = {false, false, false}; static bool relative_mouse = false; static uint8 key_states[16]; // Key states (Mac keycodes) #define MATRIX(code) (key_states[code >> 3] & (1 << (~code & 7))) // Keyboard event buffer (Mac keycodes with up/down flag) const int KEY_BUFFER_SIZE = 16; static uint8 key_buffer[KEY_BUFFER_SIZE]; static unsigned int key_read_ptr = 0, key_write_ptr = 0; static uint8 mouse_reg_3[2] = {0x63, 0x01}; // Mouse ADB register 3 static uint8 key_reg_2[2] = {0xff, 0xff}; // Keyboard ADB register 2 static uint8 key_reg_3[2] = {0x62, 0x05}; // Keyboard ADB register 3 static uint8 m_keyboard_type = 0x05; // ADB mouse motion lock (for platforms that use separate input thread) static B2_mutex *mouse_lock; /* * Initialize ADB emulation */ void ADBInit(void) { mouse_lock = B2_create_mutex(); m_keyboard_type = (uint8)PrefsFindInt32("keyboardtype"); key_reg_3[1] = m_keyboard_type; } /* * Exit ADB emulation */ void ADBExit(void) { if (mouse_lock) { B2_delete_mutex(mouse_lock); mouse_lock = NULL; } } /* * ADBOp() replacement */ void ADBOp(uint8 op, uint8 *data) { D(bug("ADBOp op %02x, data %02x %02x %02x\n", op, data[0], data[1], data[2])); // ADB reset? if ((op & 0x0f) == 0) { mouse_reg_3[0] = 0x63; mouse_reg_3[1] = 0x01; key_reg_2[0] = 0xff; key_reg_2[1] = 0xff; key_reg_3[0] = 0x62; key_reg_3[1] = m_keyboard_type; return; } // Cut op into fields uint8 adr = op >> 4; uint8 cmd = (op >> 2) & 3; uint8 reg = op & 3; // Check which device was addressed and act accordingly if (adr == (mouse_reg_3[0] & 0x0f)) { // Mouse if (cmd == 2) { // Listen switch (reg) { case 3: // Address/HandlerID if (data[2] == 0xfe) // Change address mouse_reg_3[0] = (mouse_reg_3[0] & 0xf0) | (data[1] & 0x0f); else if (data[2] == 1 || data[2] == 2 || data[2] == 4) // Change device handler ID mouse_reg_3[1] = data[2]; else if (data[2] == 0x00) // Change address and enable bit mouse_reg_3[0] = (mouse_reg_3[0] & 0xd0) | (data[1] & 0x2f); break; } } else if (cmd == 3) { // Talk switch (reg) { case 1: // Extended mouse protocol data[0] = 8; data[1] = 'a'; // Identifier data[2] = 'p'; data[3] = 'p'; data[4] = 'l'; data[5] = 300 >> 8; // Resolution (dpi) data[6] = 300 & 0xff; data[7] = 1; // Class (mouse) data[8] = 3; // Number of buttons break; case 3: // Address/HandlerID data[0] = 2; data[1] = mouse_reg_3[0] & 0xf0 | (rand() & 0x0f); data[2] = mouse_reg_3[1]; break; default: data[0] = 0; break; } } D(bug(" mouse reg 3 %02x%02x\n", mouse_reg_3[0], mouse_reg_3[1])); } else if (adr == (key_reg_3[0] & 0x0f)) { // Keyboard if (cmd == 2) { // Listen switch (reg) { case 2: // LEDs/Modifiers key_reg_2[0] = data[1]; key_reg_2[1] = data[2]; break; case 3: // Address/HandlerID if (data[2] == 0xfe) // Change address key_reg_3[0] = (key_reg_3[0] & 0xf0) | (data[1] & 0x0f); else if (data[2] == 0x00) // Change address and enable bit key_reg_3[0] = (key_reg_3[0] & 0xd0) | (data[1] & 0x2f); break; } } else if (cmd == 3) { // Talk switch (reg) { case 2: { // LEDs/Modifiers uint8 reg2hi = 0xff; uint8 reg2lo = key_reg_2[1] | 0xf8; if (MATRIX(0x6b)) // Scroll Lock reg2lo &= ~0x40; if (MATRIX(0x47)) // Num Lock reg2lo &= ~0x80; if (MATRIX(0x37)) // Command reg2hi &= ~0x01; if (MATRIX(0x3a)) // Option reg2hi &= ~0x02; if (MATRIX(0x38)) // Shift reg2hi &= ~0x04; if (MATRIX(0x36)) // Control reg2hi &= ~0x08; if (MATRIX(0x39)) // Caps Lock reg2hi &= ~0x20; if (MATRIX(0x75)) // Delete reg2hi &= ~0x40; data[0] = 2; data[1] = reg2hi; data[2] = reg2lo; break; } case 3: // Address/HandlerID data[0] = 2; data[1] = key_reg_3[0] & 0xf0 | (rand() & 0x0f); data[2] = key_reg_3[1]; break; default: data[0] = 0; break; } } D(bug(" keyboard reg 3 %02x%02x\n", key_reg_3[0], key_reg_3[1])); } else // Unknown address if (cmd == 3) data[0] = 0; // Talk: 0 bytes of data } /* * Mouse was moved (x/y are absolute or relative, depending on ADBSetRelMouseMode()) */ void ADBMouseMoved(int x, int y) { B2_lock_mutex(mouse_lock); if (relative_mouse) { mouse_x += x; mouse_y += y; } else { mouse_x = x; mouse_y = y; } B2_unlock_mutex(mouse_lock); SetInterruptFlag(INTFLAG_ADB); TriggerInterrupt(); } /* * Mouse button pressed */ void ADBMouseDown(int button) { mouse_button[button] = true; SetInterruptFlag(INTFLAG_ADB); TriggerInterrupt(); } /* * Mouse button released */ void ADBMouseUp(int button) { mouse_button[button] = false; SetInterruptFlag(INTFLAG_ADB); TriggerInterrupt(); } /* * Set mouse mode (absolute or relative) */ void ADBSetRelMouseMode(bool relative) { if (relative_mouse != relative) { relative_mouse = relative; mouse_x = mouse_y = 0; } } /* * Key pressed ("code" is the Mac key code) */ void ADBKeyDown(int code) { // Add keycode to buffer key_buffer[key_write_ptr] = code; key_write_ptr = (key_write_ptr + 1) % KEY_BUFFER_SIZE; // Set key in matrix key_states[code >> 3] |= (1 << (~code & 7)); // Trigger interrupt SetInterruptFlag(INTFLAG_ADB); TriggerInterrupt(); } /* * Key released ("code" is the Mac key code) */ void ADBKeyUp(int code) { // Add keycode to buffer key_buffer[key_write_ptr] = code | 0x80; // Key-up flag key_write_ptr = (key_write_ptr + 1) % KEY_BUFFER_SIZE; // Clear key in matrix key_states[code >> 3] &= ~(1 << (~code & 7)); // Trigger interrupt SetInterruptFlag(INTFLAG_ADB); TriggerInterrupt(); } /* * ADB interrupt function (executed as part of 60Hz interrupt) */ void ADBInterrupt(void) { M68kRegisters r; // Return if ADB is not initialized uint32 adb_base = ReadMacInt32(0xcf8); if (!adb_base || adb_base == 0xffffffff) return; uint32 tmp_data = adb_base + 0x163; // Temporary storage for faked ADB data // Get mouse state B2_lock_mutex(mouse_lock); int mx = mouse_x; int my = mouse_y; if (relative_mouse) mouse_x = mouse_y = 0; int mb[3] = {mouse_button[0], mouse_button[1], mouse_button[2]}; B2_unlock_mutex(mouse_lock); uint32 key_base = adb_base + 4; uint32 mouse_base = adb_base + 16; if (relative_mouse) { // Mouse movement (relative) and buttons if (mx != 0 || my != 0 || mb[0] != old_mouse_button[0] || mb[1] != old_mouse_button[1] || mb[2] != old_mouse_button[2]) { // Call mouse ADB handler if (mouse_reg_3[1] == 4) { // Extended mouse protocol WriteMacInt8(tmp_data, 3); WriteMacInt8(tmp_data + 1, (my & 0x7f) | (mb[0] ? 0 : 0x80)); WriteMacInt8(tmp_data + 2, (mx & 0x7f) | (mb[1] ? 0 : 0x80)); WriteMacInt8(tmp_data + 3, ((my >> 3) & 0x70) | ((mx >> 7) & 0x07) | (mb[2] ? 0x08 : 0x88)); } else { // 100/200 dpi mode WriteMacInt8(tmp_data, 2); WriteMacInt8(tmp_data + 1, (my & 0x7f) | (mb[0] ? 0 : 0x80)); WriteMacInt8(tmp_data + 2, (mx & 0x7f) | (mb[1] ? 0 : 0x80)); } r.a[0] = tmp_data; r.a[1] = ReadMacInt32(mouse_base); r.a[2] = ReadMacInt32(mouse_base + 4); r.a[3] = adb_base; r.d[0] = (mouse_reg_3[0] << 4) | 0x0c; // Talk 0 Execute68k(r.a[1], &r); old_mouse_button[0] = mb[0]; old_mouse_button[1] = mb[1]; old_mouse_button[2] = mb[2]; } } else { // Update mouse position (absolute) if (mx != old_mouse_x || my != old_mouse_y) { #ifdef POWERPC_ROM static const uint8 proc_template[] = { 0x2f, 0x08, // move.l a0,-(sp) 0x2f, 0x00, // move.l d0,-(sp) 0x2f, 0x01, // move.l d1,-(sp) 0x70, 0x01, // moveq #1,d0 (MoveTo) 0xaa, 0xdb, // CursorDeviceDispatch M68K_RTS >> 8, M68K_RTS & 0xff }; BUILD_SHEEPSHAVER_PROCEDURE(proc); r.a[0] = ReadMacInt32(mouse_base + 4); r.d[0] = mx; r.d[1] = my; Execute68k(proc, &r); #else WriteMacInt16(0x82a, mx); WriteMacInt16(0x828, my); WriteMacInt16(0x82e, mx); WriteMacInt16(0x82c, my); WriteMacInt8(0x8ce, ReadMacInt8(0x8cf)); // CrsrCouple -> CrsrNew #endif old_mouse_x = mx; old_mouse_y = my; } // Send mouse button events if (mb[0] != old_mouse_button[0] || mb[1] != old_mouse_button[1] || mb[2] != old_mouse_button[2]) { uint32 mouse_base = adb_base + 16; // Call mouse ADB handler if (mouse_reg_3[1] == 4) { // Extended mouse protocol WriteMacInt8(tmp_data, 3); WriteMacInt8(tmp_data + 1, mb[0] ? 0 : 0x80); WriteMacInt8(tmp_data + 2, mb[1] ? 0 : 0x80); WriteMacInt8(tmp_data + 3, mb[2] ? 0x08 : 0x88); } else { // 100/200 dpi mode WriteMacInt8(tmp_data, 2); WriteMacInt8(tmp_data + 1, mb[0] ? 0 : 0x80); WriteMacInt8(tmp_data + 2, mb[1] ? 0 : 0x80); } r.a[0] = tmp_data; r.a[1] = ReadMacInt32(mouse_base); r.a[2] = ReadMacInt32(mouse_base + 4); r.a[3] = adb_base; r.d[0] = (mouse_reg_3[0] << 4) | 0x0c; // Talk 0 Execute68k(r.a[1], &r); old_mouse_button[0] = mb[0]; old_mouse_button[1] = mb[1]; old_mouse_button[2] = mb[2]; } } // Process accumulated keyboard events while (key_read_ptr != key_write_ptr) { // Read keyboard event uint8 mac_code = key_buffer[key_read_ptr]; key_read_ptr = (key_read_ptr + 1) % KEY_BUFFER_SIZE; // Call keyboard ADB handler WriteMacInt8(tmp_data, 2); WriteMacInt8(tmp_data + 1, mac_code); WriteMacInt8(tmp_data + 2, mac_code == 0x7f ? 0x7f : 0xff); // Power key is special r.a[0] = tmp_data; r.a[1] = ReadMacInt32(key_base); r.a[2] = ReadMacInt32(key_base + 4); r.a[3] = adb_base; r.d[0] = (key_reg_3[0] << 4) | 0x0c; // Talk 0 Execute68k(r.a[1], &r); } // Clear temporary data WriteMacInt32(tmp_data, 0); WriteMacInt32(tmp_data + 4, 0); } BasiliskII/src/serial.cpp0000644000175000017500000001457510736405217015534 0ustar centriscentris/* * serial.cpp - Serial device driver * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Inside Macintosh: Devices, chapter 7 "Serial Driver" * Technote HW 04: "Break/CTS Device Driver Event Structure" * Technote 1018: "Understanding the SerialDMA Driver" */ #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "serial.h" #include "serial_defs.h" #include "emul_op.h" #define DEBUG 0 #include "debug.h" // Global variables SERDPort *the_serd_port[2]; /* * Driver Open() routine */ int16 SerialOpen(uint32 pb, uint32 dce, int port) { D(bug("SerialOpen port %d, pb %08lx, dce %08lx\n", port, pb, dce)); if (port == 0 || port == 2) { // Do nothing for input side return noErr; } else { // Do nothing if port is already open SERDPort *the_port = the_serd_port[port >> 1]; if (the_port->is_open) return noErr; // Init variables the_port->read_pending = the_port->write_pending = false; the_port->read_done = the_port->write_done = false; the_port->cum_errors = 0; // Open port int16 res = the_port->open(ReadMacInt16(0x1fc + (port & 2))); if (res) return res; // Allocate Deferred Task structures M68kRegisters r; r.d[0] = SIZEOF_serdt * 2; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) { the_port->close(); return openErr; } uint32 input_dt = the_port->input_dt = r.a[0]; uint32 output_dt = the_port->output_dt = r.a[0] + SIZEOF_serdt; D(bug(" input_dt %08lx, output_dt %08lx\n", input_dt, output_dt)); WriteMacInt16(input_dt + qType, dtQType); WriteMacInt32(input_dt + dtAddr, input_dt + serdtCode); WriteMacInt32(input_dt + dtParam, input_dt + serdtResult); // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1) WriteMacInt16(input_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result) WriteMacInt16(input_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce) WriteMacInt32(input_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0 WriteMacInt16(input_dt + serdtCode + 8, 0x4ed0); // jmp (a0) WriteMacInt16(output_dt + qType, dtQType); WriteMacInt32(output_dt + dtAddr, output_dt + serdtCode); WriteMacInt32(output_dt + dtParam, output_dt + serdtResult); // Deferred function for signalling that Prime is complete (pointer to mydtResult in a1) WriteMacInt16(output_dt + serdtCode, 0x2019); // move.l (a1)+,d0 (result) WriteMacInt16(output_dt + serdtCode + 2, 0x2251); // move.l (a1),a1 (dce) WriteMacInt32(output_dt + serdtCode + 4, 0x207808fc); // move.l JIODone,a0 WriteMacInt16(output_dt + serdtCode + 8, 0x4ed0); // jmp (a0) the_port->is_open = true; return noErr; } } /* * Driver Prime() routine */ int16 SerialPrime(uint32 pb, uint32 dce, int port) { D(bug("SerialPrime port %d, pb %08lx, dce %08lx\n", port, pb, dce)); // Error if port is not open SERDPort *the_port = the_serd_port[port >> 1]; if (!the_port->is_open) return notOpenErr; if (port == 0 || port == 2) { if (the_port->read_pending) { printf("FATAL: SerialPrimeIn() called while request is pending\n"); return readErr; } else return the_port->prime_in(pb, dce); } else { if (the_port->write_pending) { printf("FATAL: SerialPrimeOut() called while request is pending\n"); return readErr; } else return the_port->prime_out(pb, dce); } } /* * Driver Control() routine */ int16 SerialControl(uint32 pb, uint32 dce, int port) { uint16 code = ReadMacInt16(pb + csCode); D(bug("SerialControl %d, port %d, pb %08lx, dce %08lx\n", code, port, pb, dce)); // Error if port is not open SERDPort *the_port = the_serd_port[port >> 1]; if (!the_port->is_open) return notOpenErr; switch (code) { case kSERDSetPollWrite: return noErr; default: return the_port->control(pb, dce, code); } } /* * Driver Status() routine */ int16 SerialStatus(uint32 pb, uint32 dce, int port) { uint16 code = ReadMacInt16(pb + csCode); D(bug("SerialStatus %d, port %d, pb %08lx, dce %08lx\n", code, port, pb, dce)); // Error if port is not open SERDPort *the_port = the_serd_port[port >> 1]; if (!the_port->is_open) return notOpenErr; switch (code) { case kSERDVersion: WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver return noErr; case 0x8000: WriteMacInt8(pb + csParam, 9); // Second-generation SerialDMA driver WriteMacInt16(pb + csParam + 4, 0x1997); // Date of serial driver WriteMacInt16(pb + csParam + 6, 0x0616); return noErr; default: return the_port->status(pb, dce, code); } } /* * Driver Close() routine */ int16 SerialClose(uint32 pb, uint32 dce, int port) { D(bug("SerialClose port %d, pb %08lx, dce %08lx\n", port, pb, dce)); if (port == 0 || port == 2) { // Do nothing for input side return noErr; } else { // Close port if open SERDPort *the_port = the_serd_port[port >> 1]; if (the_port->is_open) { int16 res = the_port->close(); M68kRegisters r; // Free Deferred Task structures r.a[0] = the_port->input_dt; Execute68kTrap(0xa01f, &r); // DisposePtr() the_port->is_open = false; return res; } else return noErr; } } /* * Serial interrupt - Prime command completed, activate deferred tasks to call IODone */ static void serial_irq(SERDPort *p) { if (p->is_open) { if (p->read_pending && p->read_done) { EnqueueMac(p->input_dt, 0xd92); p->read_pending = p->read_done = false; } if (p->write_pending && p->write_done) { EnqueueMac(p->output_dt, 0xd92); p->write_pending = p->write_done = false; } } } void SerialInterrupt(void) { D(bug("SerialIRQ\n")); serial_irq(the_serd_port[0]); serial_irq(the_serd_port[1]); } BasiliskII/src/rsrc_patches.cpp0000644000175000017500000002654010736405217016730 0ustar centriscentris/* * rsrc_patches.cpp - Resource patches * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include "sysdeps.h" #include "cpu_emulation.h" #include "macos_util.h" #include "main.h" #include "prefs.h" #include "emul_op.h" #include "audio.h" #include "audio_defs.h" #include "rsrc_patches.h" #if ENABLE_MON #include "mon.h" #endif #define DEBUG 0 #include "debug.h" /* * Search resource for byte string, return offset (or 0) */ static uint32 find_rsrc_data(const uint8 *rsrc, uint32 max, const uint8 *search, uint32 search_len, uint32 ofs = 0) { while (ofs < max - search_len) { if (!memcmp(rsrc + ofs, search, search_len)) return ofs; ofs++; } return 0; } /* * Install SynchIdleTime() patch */ static void patch_idle_time(uint8 *p, uint32 size, int n = 1) { if (!PrefsFindBool("idlewait")) return; static const uint8 dat[] = {0x70, 0x03, 0xa0, 0x9f}; uint32 base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { uint8 *pbase = p + base - 0x80; static const uint8 dat2[] = {0x20, 0x78, 0x02, 0xb6, 0x41, 0xe8, 0x00, 0x80}; base = find_rsrc_data(pbase, 0x80, dat2, sizeof(dat2)); if (base) { uint16 *p16 = (uint16 *)(pbase + base); *p16++ = htons(M68K_EMUL_OP_IDLE_TIME); *p16 = htons(M68K_NOP); FlushCodeCache(pbase + base, 4); D(bug(" patch %d applied\n", n)); } } } /* * Resource patches via vCheckLoad */ void CheckLoad(uint32 type, int16 id, uint8 *p, uint32 size) { uint16 *p16; uint32 base; D(bug("vCheckLoad %c%c%c%c (%08x) ID %d, data %p, size %d\n", (char)(type >> 24), (char)((type >> 16) & 0xff), (char )((type >> 8) & 0xff), (char )(type & 0xff), type, id, p, size)); if (type == FOURCC('b','o','o','t') && id == 3) { D(bug(" boot 3 found\n")); // Set boot stack pointer (7.5, 7.6, 7.6.1, 8.0) static const uint8 dat[] = {0x22, 0x00, 0xe4, 0x89, 0x90, 0x81, 0x22, 0x40}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base + 6); *p16 = htons(M68K_EMUL_OP_FIX_BOOTSTACK); FlushCodeCache(p + base + 6, 2); D(bug(" patch 1 applied\n")); } #if !ROM_IS_WRITE_PROTECTED // Set fake handle at 0x0000 to some safe place (so broken Mac programs won't write into Mac ROM) (7.1, 7.5, 8.0) static const uint8 dat2[] = {0x20, 0x78, 0x02, 0xae, 0xd1, 0xfc, 0x00, 0x01, 0x00, 0x00, 0x21, 0xc8, 0x00, 0x00}; base = find_rsrc_data(p, size, dat2, sizeof(dat2)); if (base) { p16 = (uint16 *)(p + base); #if defined(USE_SCRATCHMEM_SUBTERFUGE) // Set 0x0000 to scratch memory area extern uint8 *ScratchMem; const uint32 ScratchMemBase = Host2MacAddr(ScratchMem); *p16++ = htons(0x207c); // move.l #ScratchMem,a0 *p16++ = htons(ScratchMemBase >> 16); *p16++ = htons(ScratchMemBase); *p16++ = htons(M68K_NOP); *p16 = htons(M68K_NOP); #else #error System specific handling for writable ROM is required here #endif FlushCodeCache(p + base, 14); D(bug(" patch 2 applied\n")); } } else if (type == FOURCC('b','o','o','t') && id == 2) { D(bug(" boot 2 found\n")); // Set fake handle at 0x0000 to some safe place (so broken Mac programs won't write into Mac ROM) (7.1, 7.5, 8.0) static const uint8 dat[] = {0x20, 0x78, 0x02, 0xae, 0xd1, 0xfc, 0x00, 0x01, 0x00, 0x00, 0x21, 0xc8, 0x00, 0x00}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base); #if defined(USE_SCRATCHMEM_SUBTERFUGE) // Set 0x0000 to scratch memory area extern uint8 *ScratchMem; const uint32 ScratchMemBase = Host2MacAddr(ScratchMem); *p16++ = htons(0x207c); // move.l #ScratchMem,a0 *p16++ = htons(ScratchMemBase >> 16); *p16++ = htons(ScratchMemBase); *p16++ = htons(M68K_NOP); *p16 = htons(M68K_NOP); #else #error System specific handling for writable ROM is required here #endif FlushCodeCache(p + base, 14); D(bug(" patch 1 applied\n")); } #endif } else if (type == FOURCC('P','T','C','H') && id == 630) { D(bug("PTCH 630 found\n")); // Don't replace Time Manager (Classic ROM, 6.0.3) static const uint8 dat[] = {0x30, 0x3c, 0x00, 0x58, 0xa2, 0x47}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base); p16[2] = htons(M68K_NOP); p16[7] = htons(M68K_NOP); p16[12] = htons(M68K_NOP); FlushCodeCache(p + base, 26); D(bug(" patch 1 applied\n")); } // Don't replace Time Manager (Classic ROM, 6.0.8) static const uint8 dat2[] = {0x70, 0x58, 0xa2, 0x47}; base = find_rsrc_data(p, size, dat2, sizeof(dat2)); if (base) { p16 = (uint16 *)(p + base); p16[1] = htons(M68K_NOP); p16[5] = htons(M68K_NOP); p16[9] = htons(M68K_NOP); FlushCodeCache(p + base, 20); D(bug(" patch 1 applied\n")); } } else if (type == FOURCC('p','t','c','h') && id == 26) { D(bug(" ptch 26 found\n")); // Trap ABC4 is initialized with absolute ROM address (7.1, 7.5, 7.6, 7.6.1, 8.0) static const uint8 dat[] = {0x40, 0x83, 0x36, 0x10}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base); *p16++ = htons((ROMBaseMac + 0x33610) >> 16); *p16 = htons((ROMBaseMac + 0x33610) & 0xffff); FlushCodeCache(p + base, 4); D(bug(" patch 1 applied\n")); } } else if (type == FOURCC('p','t','c','h') && id == 34) { D(bug(" ptch 34 found\n")); // Don't wait for VIA (Classic ROM, 6.0.8) static const uint8 dat[] = {0x22, 0x78, 0x01, 0xd4, 0x10, 0x11, 0x02, 0x00, 0x00, 0x30}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base + 14); *p16 = htons(M68K_NOP); FlushCodeCache(p + base + 14, 2); D(bug(" patch 1 applied\n")); } // Don't replace ADBOp() (Classic ROM, 6.0.8) static const uint8 dat2[] = {0x21, 0xc0, 0x05, 0xf0}; base = find_rsrc_data(p, size, dat2, sizeof(dat2)); if (base) { p16 = (uint16 *)(p + base); *p16++ = htons(M68K_NOP); *p16 = htons(M68K_NOP); FlushCodeCache(p + base, 4); D(bug(" patch 2 applied\n")); } } else if (type == FOURCC('g','p','c','h') && id == 750) { D(bug(" gpch 750 found\n")); // Don't use PTEST instruction in BlockMove() (7.5, 7.6, 7.6.1, 8.0) static const uint8 dat[] = {0x20, 0x5f, 0x22, 0x5f, 0x0c, 0x38, 0x00, 0x04, 0x01, 0x2f}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base + 4); *p16++ = htons(M68K_EMUL_OP_BLOCK_MOVE); *p16++ = htons(0x7000); *p16 = htons(M68K_RTS); FlushCodeCache(p + base + 4, 6); D(bug(" patch 1 applied\n")); } // Patch SynchIdleTime() patch_idle_time(p, size, 2); } else if (type == FOURCC('l','p','c','h') && id == 24) { D(bug(" lpch 24 found\n")); // Don't replace Time Manager (7.0.1, 7.1, 7.5, 7.6, 7.6.1, 8.0) static const uint8 dat[] = {0x70, 0x59, 0xa2, 0x47}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base + 2); *p16++ = htons(M68K_NOP); p16 += 3; *p16++ = htons(M68K_NOP); p16 += 7; *p16 = htons(M68K_NOP); FlushCodeCache(p + base + 2, 28); D(bug(" patch 1 applied\n")); } } else if (type == FOURCC('l','p','c','h') && id == 31) { D(bug(" lpch 31 found\n")); // Don't write to VIA in vSoundDead() (7.0.1, 7.1, 7.5, 7.6, 7.6.1, 8.0) static const uint8 dat[] = {0x20, 0x78, 0x01, 0xd4, 0x08, 0xd0, 0x00, 0x07, 0x4e, 0x75}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base); *p16 = htons(M68K_RTS); FlushCodeCache(p + base, 2); D(bug(" patch 1 applied\n")); } // Don't replace SCSI manager (7.1, 7.5, 7.6.1, 8.0) static const uint8 dat2[] = {0x0c, 0x6f, 0x00, 0x0e, 0x00, 0x04, 0x66, 0x0c}; base = find_rsrc_data(p, size, dat2, sizeof(dat2)); if (base) { p16 = (uint16 *)(p + base); *p16++ = htons(M68K_EMUL_OP_SCSI_DISPATCH); *p16++ = htons(0x2e49); // move.l a1,a7 *p16 = htons(M68K_JMP_A0); FlushCodeCache(p + base, 6); D(bug(" patch 2 applied\n")); } // Patch SynchIdleTime() patch_idle_time(p, size, 3); } else if (type == FOURCC('t','h','n','g') && id == -16563) { D(bug(" thng -16563 found\n")); // Set audio component flags (7.5, 7.6, 7.6.1, 8.0) *(uint32 *)(p + componentFlags) = htonl(audio_component_flags); D(bug(" patch 1 applied\n")); } else if (type == FOURCC('s','i','f','t') && id == -16563) { D(bug(" sift -16563 found\n")); // Replace audio component (7.5, 7.6, 7.6.1, 8.0) p16 = (uint16 *)p; *p16++ = htons(0x4e56); *p16++ = htons(0x0000); // link a6,#0 *p16++ = htons(0x48e7); *p16++ = htons(0x8018); // movem.l d0/a3-a4,-(sp) *p16++ = htons(0x266e); *p16++ = htons(0x000c); // movea.l 12(a6),a3 *p16++ = htons(0x286e); *p16++ = htons(0x0008); // movea.l 8(a6),a4 *p16++ = htons(M68K_EMUL_OP_AUDIO); *p16++ = htons(0x2d40); *p16++ = htons(0x0010); // move.l d0,16(a6) *p16++ = htons(0x4cdf); *p16++ = htons(0x1801); // movem.l (sp)+,d0/a3-a4 *p16++ = htons(0x4e5e); // unlk a6 *p16++ = htons(0x4e74); *p16++ = htons(0x0008); // rtd #8 FlushCodeCache(p, 32); D(bug(" patch 1 applied\n")); } else if (type == FOURCC('i','n','s','t') && id == -19069) { D(bug(" inst -19069 found\n")); // Don't replace Microseconds (QuickTime 2.0) static const uint8 dat[] = {0x30, 0x3c, 0xa1, 0x93, 0xa2, 0x47}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base + 4); *p16 = htons(M68K_NOP); FlushCodeCache(p + base + 4, 2); D(bug(" patch 1 applied\n")); } } else if (type == FOURCC('D','R','V','R') && id == -20066) { D(bug("DRVR -20066 found\n")); // Don't access SCC in .Infra driver static const uint8 dat[] = {0x28, 0x78, 0x01, 0xd8, 0x48, 0xc7, 0x20, 0x0c, 0xd0, 0x87, 0x20, 0x40, 0x1c, 0x10}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base + 12); *p16 = htons(0x7a00); // moveq #0,d6 FlushCodeCache(p + base + 12, 2); D(bug(" patch 1 applied\n")); } } else if (type == FOURCC('l','t','l','k') && id == 0) { D(bug(" ltlk 0 found\n")); // Disable LocalTalk (7.0.1, 7.5, 7.6, 7.6.1, 8.0) p16 = (uint16 *)p; *p16++ = htons(M68K_JMP_A0); *p16++ = htons(0x7000); *p16 = htons(M68K_RTS); FlushCodeCache(p, 6); D(bug(" patch 1 applied\n")); } else if (type == FOURCC('D','R','V','R') && id == 41) { D(bug(" DRVR 41 found\n")); // Don't access ROM85 as it it was a pointer to a ROM version number (8.0, 8.1) static const uint8 dat[] = {0x3a, 0x2e, 0x00, 0x0a, 0x55, 0x4f, 0x3e, 0xb8, 0x02, 0x8e, 0x30, 0x1f, 0x48, 0xc0, 0x24, 0x40, 0x20, 0x40}; base = find_rsrc_data(p, size, dat, sizeof(dat)); if (base) { p16 = (uint16 *)(p + base + 4); *p16++ = htons(0x303c); // move.l #ROM85,%d0 *p16++ = htons(0x028e); *p16++ = htons(M68K_NOP); *p16++ = htons(M68K_NOP); FlushCodeCache(p + base + 4, 8); D(bug(" patch 1 applied\n")); } } } BasiliskII/src/macos_util.cpp0000644000175000017500000000721410736405217016404 0ustar centriscentris/* * macos_util.cpp - MacOS definitions/utility functions * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include "sysdeps.h" #include "cpu_emulation.h" #include "adb.h" #include "main.h" #include "sony.h" #include "disk.h" #include "cdrom.h" #include "macos_util.h" #define DEBUG 0 #include "debug.h" /* * Enqueue QElem to list */ void EnqueueMac(uint32 elem, uint32 list) { WriteMacInt32(elem + qLink, 0); if (!ReadMacInt32(list + qTail)) { WriteMacInt32(list + qHead, elem); WriteMacInt32(list + qTail, elem); } else { WriteMacInt32(ReadMacInt32(list + qTail) + qLink, elem); WriteMacInt32(list + qTail, elem); } } /* * Find first free drive number, starting at num */ static bool is_drive_number_free(int num) { uint32 e = ReadMacInt32(0x308 + qHead); while (e) { uint32 d = e - dsQLink; if ((int)ReadMacInt16(d + dsQDrive) == num) return false; e = ReadMacInt32(e + qLink); } return true; } int FindFreeDriveNumber(int num) { while (!is_drive_number_free(num)) num++; return num; } /* * Mount volume with given file handle (call this function when you are unable to * do automatic media change detection and the user has to press a special key * or something to mount a volume; this function will check if there's really a * volume in the drive with SysIsDiskInserted(); volumes which are present on startup * are automatically mounted) */ void MountVolume(void *fh) { SonyMountVolume(fh) || DiskMountVolume(fh) || CDROMMountVolume(fh); } /* * Calculate disk image file layout given file size and first 256 data bytes */ void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size) { if (size == 419284 || size == 838484) { // 400K/800K DiskCopy image, 84 byte header start_byte = 84; real_size = (size - 84) & ~0x1ff; } else { // 0..511 byte header start_byte = size & 0x1ff; real_size = size - start_byte; } } uint32 DebugUtil(uint32 Selector) { switch (Selector) { case duDebuggerGetMax: return 3; case duDebuggerEnter: return 0; case duDebuggerExit: return 0; case duDebuggerPoll: ADBInterrupt(); return 0; default: return (uint32) paramErr; } } /* * Convert time_t value to MacOS time (seconds since 1.1.1904) */ uint32 TimeToMacTime(time_t t) { // This code is taken from glibc 2.2 // Convert to number of seconds elapsed since 1-Jan-1904 struct tm *local = localtime(&t); const int TM_EPOCH_YEAR = 1900; const int MAC_EPOCH_YEAR = 1904; int a4 = ((local->tm_year + TM_EPOCH_YEAR) >> 2) - !(local->tm_year & 3); int b4 = (MAC_EPOCH_YEAR >> 2) - !(MAC_EPOCH_YEAR & 3); int a100 = a4 / 25 - (a4 % 25 < 0); int b100 = b4 / 25 - (b4 % 25 < 0); int a400 = a100 >> 2; int b400 = b100 >> 2; int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); uint32 days = local->tm_yday + 365 * (local->tm_year - 4) + intervening_leap_days; return local->tm_sec + 60 * (local->tm_min + 60 * (local->tm_hour + 24 * days)); } BasiliskII/src/extfs.cpp0000644000175000017500000020545611026576123015404 0ustar centriscentris/* * extfs.cpp - MacOS file system for native file system access * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ /* * SEE ALSO * Guide to the File System Manager (from FSM 1.2 SDK) * * TODO * LockRng * UnlockRng * (CatSearch) * (MakeFSSpec) * (GetVolMountInfoSize) * (GetVolMountInfo) * (GetForeignPrivs) * (SetForeignPrivs) */ #include "sysdeps.h" #include #include #include #include #include #include #include #ifndef WIN32 #include #include #endif #if defined __APPLE__ && defined __MACH__ #include #endif #include "cpu_emulation.h" #include "emul_op.h" #include "main.h" #include "disk.h" #include "prefs.h" #include "user_strings.h" #include "extfs.h" #include "extfs_defs.h" #ifdef WIN32 # include "posix_emu.h" #endif #define DEBUG 0 #include "debug.h" // File system global data and 68k routines enum { fsCommProcStub = 0, fsHFSProcStub = 6, fsDrvStatus = 12, // Drive Status record fsFSD = 42, // File system descriptor fsPB = 238, // IOParam (for mounting and renaming), also used for temporary storage fsVMI = 288, // VoumeMountInfoHeader (for mounting) fsParseRec = 296, // ParsePathRec struct fsReturn = 306, // Area for return data of 68k routines fsAllocateVCB = 562, // UTAllocateVCB(uint16 *sysVCBLength{a0}, uint32 *vcb{a1}) fsAddNewVCB = 578, // UTAddNewVCB(int drive_number{d0}, int16 *vRefNum{a1}, uint32 vcb{a1}) fsDetermineVol = 594, // UTDetermineVol(uint32 pb{a0}, int16 *status{a1}, int16 *more_matches{a2}, int16 *vRefNum{a3}, uint32 *vcb{a4}) fsResolveWDCB = 614, // UTResolveWDCB(uint32 procID{d0}, int16 index{d1}, int16 vRefNum{d0}, uint32 *wdcb{a0}) fsGetDefaultVol = 632, // UTGetDefaultVol(uint32 wdpb{a0}) fsGetPathComponentName = 644, // UTGetPathComponentName(uint32 rec{a0}) fsParsePathname = 656, // UTParsePathname(uint32 *start{a0}, uint32 name{a1}) fsDisposeVCB = 670, // UTDisposeVCB(uint32 vcb{a0}) fsCheckWDRefNum = 682, // UTCheckWDRefNum(int16 refNum{d0}) fsSetDefaultVol = 694, // UTSetDefaultVol(uint32 dummy{d0}, int32 dirID{d1}, int16 refNum{d2}) fsAllocateFCB = 710, // UTAllocateFCB(int16 *refNum{a0}, uint32 *fcb{a1}) fsReleaseFCB = 724, // UTReleaseFCB(int16 refNum{d0}) fsIndexFCB = 736, // UTIndexFCB(uint32 vcb{a0}, int16 *refNum{a1}, uint32 *fcb{a2}) fsResolveFCB = 752, // UTResolveFCB(int16 refNum{d0}, uint32 *fcb{a0}) fsAdjustEOF = 766, // UTAdjustEOF(int16 refNum{d0}) fsAllocateWDCB = 778, // UTAllocateWDCB(uint32 pb{a0}) fsReleaseWDCB = 790, // UTReleaseWDCB(int16 vRefNum{d0}) SIZEOF_fsdat = 802 }; static uint32 fs_data = 0; // Mac address of global data // File system and volume name static char FS_NAME[32], VOLUME_NAME[32]; // This directory is our root (read from prefs) static const char *RootPath; static bool ready = false; static struct stat root_stat; // File system ID/media type const int16 MY_FSID = EMULATOR_ID_2; const uint32 MY_MEDIA_TYPE = EMULATOR_ID_4; // CNID of root and root's parent const uint32 ROOT_ID = 2; const uint32 ROOT_PARENT_ID = 1; // File system stack size const int STACK_SIZE = 0x10000; // Allocation block and clump size as reported to MacOS (these are of course // not the real values and have no meaning on the host OS) const int AL_BLK_SIZE = 0x4000; const int CLUMP_SIZE = 0x4000; // Drive number of our pseudo-drive static int drive_number; // Disk/drive icon const uint8 ExtFSIcon[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x91, 0x80, 0x00, 0x00, 0x91, 0x80, 0x00, 0x01, 0x21, 0x80, 0x00, 0x01, 0x21, 0x80, 0x00, 0x02, 0x41, 0x8c, 0x00, 0x02, 0x41, 0x80, 0x00, 0x04, 0x81, 0x80, 0x00, 0x04, 0x81, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 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, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // These objects are used to map CNIDs to path names struct FSItem { FSItem *next; // Pointer to next FSItem in list uint32 id; // CNID of this file/dir uint32 parent_id; // CNID of parent file/dir FSItem *parent; // Pointer to parent char *name; // Object name (C string) - Host OS char guest_name[32]; // Object name (C string) - Guest OS time_t mtime; // Modification time for get_cat_info caching int cache_dircount; // Cached number of files in directory }; static FSItem *first_fs_item, *last_fs_item; static uint32 next_cnid = fsUsrCNID; // Next available CNID /* * Get object creation time */ #if defined __APPLE__ && defined __MACH__ struct crtimebuf { unsigned long length; struct timespec crtime; }; static uint32 do_get_creation_time(const char *path) { struct attrlist attr; memset(&attr, 0, sizeof(attr)); attr.bitmapcount = ATTR_BIT_MAP_COUNT; attr.commonattr = ATTR_CMN_CRTIME; crtimebuf buf; if (getattrlist(path, &attr, &buf, sizeof(buf), FSOPT_NOFOLLOW) < 0) return 0; return TimeToMacTime(buf.crtime.tv_sec); } static uint32 get_creation_time(const char *path) { if (path == NULL) return 0; if (path == RootPath) { static uint32 root_crtime = UINT_MAX; if (root_crtime == UINT_MAX) root_crtime = do_get_creation_time(path); return root_crtime; } return do_get_creation_time(path); } #endif /* * Find FSItem for given CNID */ static FSItem *find_fsitem_by_id(uint32 cnid) { FSItem *p = first_fs_item; while (p) { if (p->id == cnid) return p; p = p->next; } return NULL; } /* * Create FSItem with the given parameters */ static FSItem *create_fsitem(const char *name, const char *guest_name, FSItem *parent) { FSItem *p = new FSItem; last_fs_item->next = p; p->next = NULL; last_fs_item = p; p->id = next_cnid++; p->parent_id = parent->id; p->parent = parent; p->name = new char[strlen(name) + 1]; strcpy(p->name, name); strncpy(p->guest_name, guest_name, 31); p->guest_name[31] = 0; p->mtime = 0; return p; } /* * Find FSItem for given name and parent, construct new FSItem if not found */ static FSItem *find_fsitem(const char *name, FSItem *parent) { FSItem *p = first_fs_item; while (p) { if (p->parent == parent && !strcmp(p->name, name)) return p; p = p->next; } // Not found, construct new FSItem return create_fsitem(name, host_encoding_to_macroman(name), parent); } /* * Find FSItem for given guest_name and parent, construct new FSItem if not found */ static FSItem *find_fsitem_guest(const char *guest_name, FSItem *parent) { FSItem *p = first_fs_item; while (p) { if (p->parent == parent && !strcmp(p->guest_name, guest_name)) return p; p = p->next; } // Not found, construct new FSItem return create_fsitem(macroman_to_host_encoding(guest_name), guest_name, parent); } /* * Get full path (->full_path) for given FSItem */ static char full_path[MAX_PATH_LENGTH]; static void add_path_comp(const char *s) { add_path_component(full_path, s); } static void get_path_for_fsitem(FSItem *p) { if (p->id == ROOT_PARENT_ID) { full_path[0] = 0; } else if (p->id == ROOT_ID) { strncpy(full_path, RootPath, MAX_PATH_LENGTH-1); full_path[MAX_PATH_LENGTH-1] = 0; } else { get_path_for_fsitem(p->parent); add_path_comp(p->name); } } /* * Exchange parent CNIDs in all FSItems */ static void swap_parent_ids(uint32 parent1, uint32 parent2) { FSItem *p = first_fs_item; while (p) { if (p->parent_id == parent1) p->parent_id = parent2; else if (p->parent_id == parent2) p->parent_id = parent1; p = p->next; } } /* * String handling functions */ // Copy pascal string static void pstrcpy(char *dst, const char *src) { int size = *dst++ = *src++; while (size--) *dst++ = *src++; } // Convert C string to pascal string static void cstr2pstr(char *dst, const char *src) { *dst++ = strlen(src); char c; while ((c = *src++) != 0) { // Note: we are converting host ':' characters to Mac '/' characters here // '/' is not a path separator as this function is only used on object names if (c == ':') c = '/'; *dst++ = c; } } // Convert string (no length byte) to C string, length given separately static void strn2cstr(char *dst, const char *src, int size) { while (size--) { char c = *src++; // Note: we are converting Mac '/' characters to host ':' characters here // '/' is not a path separator as this function is only used on object names if (c == '/') c = ':'; *dst++ = c; } *dst = 0; } /* * Convert errno to MacOS error code */ static int16 errno2oserr(void) { D(bug(" errno %08x\n", errno)); switch (errno) { case 0: return noErr; case ENOENT: case EISDIR: return fnfErr; case EACCES: case EPERM: return permErr; case EEXIST: return dupFNErr; case EBUSY: case ENOTEMPTY: return fBsyErr; case ENOSPC: return dskFulErr; case EROFS: return wPrErr; case EMFILE: return tmfoErr; case ENOMEM: return -108; case EIO: default: return ioErr; } } /* * Initialization */ void ExtFSInit(void) { // System specific initialization extfs_init(); // Get file system and volume name cstr2pstr(FS_NAME, GetString(STR_EXTFS_NAME)); cstr2pstr(VOLUME_NAME, GetString(STR_EXTFS_VOLUME_NAME)); // Create root's parent FSItem FSItem *p = new FSItem; first_fs_item = last_fs_item = p; p->next = NULL; p->id = ROOT_PARENT_ID; p->parent_id = 0; p->parent = NULL; p->name = new char[1]; p->name[0] = 0; p->guest_name[0] = 0; // Create root FSItem p = new FSItem; last_fs_item->next = p; p->next = NULL; last_fs_item = p; p->id = ROOT_ID; p->parent_id = ROOT_PARENT_ID; p->parent = first_fs_item; const char *volume_name = GetString(STR_EXTFS_VOLUME_NAME); p->name = new char[strlen(volume_name) + 1]; strcpy(p->name, volume_name); strncpy(p->guest_name, host_encoding_to_macroman(p->name), 32); p->guest_name[31] = 0; // Find path for root if ((RootPath = PrefsFindString("extfs")) != NULL) { if (stat(RootPath, &root_stat)) return; if (!S_ISDIR(root_stat.st_mode)) return; ready = true; } } /* * Deinitialization */ void ExtFSExit(void) { // Delete all FSItems FSItem *p = first_fs_item, *next; while (p) { next = p->next; delete[] p->name; delete p; p = next; } first_fs_item = last_fs_item = NULL; // System specific deinitialization extfs_exit(); } /* * Install file system */ void InstallExtFS(void) { int num_blocks = 0xffff; // Fake number of blocks of our drive M68kRegisters r; D(bug("InstallExtFS\n")); if (!ready) return; // FSM present? r.d[0] = gestaltFSAttr; Execute68kTrap(0xa1ad, &r); // Gestalt() D(bug("FSAttr %d, %08x\n", r.d[0], r.a[0])); if ((r.d[0] & 0xffff) || !(r.a[0] & (1 << gestaltHasFileSystemManager))) { printf("WARNING: No FSM present, disabling ExtFS\n"); return; } // Yes, version >=1.2? r.d[0] = gestaltFSMVersion; Execute68kTrap(0xa1ad, &r); // Gestalt() D(bug("FSMVersion %d, %08x\n", r.d[0], r.a[0])); if ((r.d[0] & 0xffff) || (r.a[0] < 0x0120)) { printf("WARNING: FSM <1.2 found, disabling ExtFS\n"); return; } D(bug("FSM present\n")); // Yes, allocate file system stack r.d[0] = STACK_SIZE; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) return; uint32 fs_stack = r.a[0]; // Allocate memory for our data structures and 68k code r.d[0] = SIZEOF_fsdat; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() if (r.a[0] == 0) return; fs_data = r.a[0]; // Set up 68k code fragments int p = fs_data + fsCommProcStub; WriteMacInt16(p, M68K_EMUL_OP_EXTFS_COMM); p += 2; WriteMacInt16(p, M68K_RTD); p += 2; WriteMacInt16(p, 10); p += 2; if (p - fs_data != fsHFSProcStub) goto fsdat_error; WriteMacInt16(p, M68K_EMUL_OP_EXTFS_HFS); p += 2; WriteMacInt16(p, M68K_RTD); p += 2; WriteMacInt16(p, 16); p = fs_data + fsAllocateVCB; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp) WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x7006); p+= 2; // UTAllocateVCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsAddNewVCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(a7) WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(a7) WriteMacInt16(p, 0x7007); p+= 2; // UTAddNewVCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsDetermineVol) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp) WriteMacInt16(p, 0x2f0a); p+= 2; // move.l a2,-(sp) WriteMacInt16(p, 0x2f0b); p+= 2; // move.l a3,-(sp) WriteMacInt16(p, 0x2f0c); p+= 2; // move.l a4,-(sp) WriteMacInt16(p, 0x701d); p+= 2; // UTDetermineVol WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsResolveWDCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f00); p+= 2; // move.l d0,-(sp) WriteMacInt16(p, 0x3f01); p+= 2; // move.w d1,-(sp) WriteMacInt16(p, 0x3f02); p+= 2; // move.w d2,-(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x700e); p+= 2; // UTResolveWDCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsGetDefaultVol) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x7012); p+= 2; // UTGetDefaultVol WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsGetPathComponentName) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x701c); p+= 2; // UTGetPathComponentName WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsParsePathname) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp) WriteMacInt16(p, 0x701b); p+= 2; // UTParsePathname WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsDisposeVCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x7008); p+= 2; // UTDisposeVCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsCheckWDRefNum) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp) WriteMacInt16(p, 0x7013); p+= 2; // UTCheckWDRefNum WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsSetDefaultVol) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f00); p+= 2; // move.l d0,-(sp) WriteMacInt16(p, 0x2f01); p+= 2; // move.l d1,-(sp) WriteMacInt16(p, 0x3f02); p+= 2; // move.w d2,-(sp) WriteMacInt16(p, 0x7011); p+= 2; // UTSetDefaultVol WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsAllocateFCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp) WriteMacInt16(p, 0x7000); p+= 2; // UTAllocateFCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsReleaseFCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp) WriteMacInt16(p, 0x7001); p+= 2; // UTReleaseFCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsIndexFCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp) WriteMacInt16(p, 0x2f0a); p+= 2; // move.l a2,-(sp) WriteMacInt16(p, 0x7004); p+= 2; // UTIndexFCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsResolveFCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x7005); p+= 2; // UTResolveFCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsAdjustEOF) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp) WriteMacInt16(p, 0x7010); p+= 2; // UTAdjustEOF WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsAllocateWDCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp) WriteMacInt16(p, 0x700c); p+= 2; // UTAllocateWDCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != fsReleaseWDCB) goto fsdat_error; WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp) WriteMacInt16(p, 0x700d); p+= 2; // UTReleaseWDCB WriteMacInt16(p, 0xa824); p+= 2; // FSMgr WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 WriteMacInt16(p, M68K_RTS); p+= 2; if (p - fs_data != SIZEOF_fsdat) goto fsdat_error; // Set up drive status WriteMacInt8(fs_data + fsDrvStatus + dsDiskInPlace, 8); // Fixed disk WriteMacInt8(fs_data + fsDrvStatus + dsInstalled, 1); WriteMacInt16(fs_data + fsDrvStatus + dsQType, hard20); WriteMacInt16(fs_data + fsDrvStatus + dsDriveSize, num_blocks & 0xffff); WriteMacInt16(fs_data + fsDrvStatus + dsDriveS1, num_blocks >> 16); WriteMacInt16(fs_data + fsDrvStatus + dsQFSID, MY_FSID); // Add drive to drive queue drive_number = FindFreeDriveNumber(1); D(bug(" adding drive %d\n", drive_number)); r.d[0] = (drive_number << 16) | (DiskRefNum & 0xffff); r.a[0] = fs_data + fsDrvStatus + dsQLink; Execute68kTrap(0xa04e, &r); // AddDrive() // Init FSDRec and install file system D(bug(" installing file system\n")); WriteMacInt16(fs_data + fsFSD + fsdLength, SIZEOF_FSDRec); WriteMacInt16(fs_data + fsFSD + fsdVersion, fsdVersion1); WriteMacInt16(fs_data + fsFSD + fileSystemFSID, MY_FSID); Host2Mac_memcpy(fs_data + fsFSD + fileSystemName, FS_NAME, 32); WriteMacInt32(fs_data + fsFSD + fileSystemCommProc, fs_data + fsCommProcStub); WriteMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfProc, fs_data + fsHFSProcStub); WriteMacInt32(fs_data + fsFSD + fsdHFSCI + stackTop, fs_stack + STACK_SIZE); WriteMacInt32(fs_data + fsFSD + fsdHFSCI + stackSize, STACK_SIZE); WriteMacInt32(fs_data + fsFSD + fsdHFSCI + idSector, (uint32)-1); r.a[0] = fs_data + fsFSD; r.d[0] = 0; // InstallFS Execute68kTrap(0xa0ac, &r); // FSMDispatch() D(bug(" InstallFS() returned %d\n", r.d[0])); // Enable HFS component D(bug(" enabling HFS component\n")); WriteMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfMask, ReadMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfMask) | (fsmComponentEnableMask | hfsCIResourceLoadedMask | hfsCIDoesHFSMask)); r.a[0] = fs_data + fsFSD; r.d[3] = SIZEOF_FSDRec; r.d[4] = MY_FSID; r.d[0] = 5; // SetFSInfo Execute68kTrap(0xa0ac, &r); // FSMDispatch() D(bug(" SetFSInfo() returned %d\n", r.d[0])); // Mount volume D(bug(" mounting volume\n")); WriteMacInt32(fs_data + fsPB + ioBuffer, fs_data + fsVMI); WriteMacInt16(fs_data + fsVMI + vmiLength, SIZEOF_VolumeMountInfoHeader); WriteMacInt32(fs_data + fsVMI + vmiMedia, MY_MEDIA_TYPE); r.a[0] = fs_data + fsPB; r.d[0] = 0x41; // PBVolumeMount Execute68kTrap(0xa260, &r); // HFSDispatch() D(bug(" PBVolumeMount() returned %d\n", r.d[0])); return; fsdat_error: printf("FATAL: ExtFS data block initialization error\n"); QuitEmulator(); } /* * FS communications function */ int16 ExtFSComm(uint16 message, uint32 paramBlock, uint32 globalsPtr) { D(bug("ExtFSComm(%d, %08lx, %08lx)\n", message, paramBlock, globalsPtr)); switch (message) { case ffsNopMessage: case ffsLoadMessage: case ffsUnloadMessage: return noErr; case ffsGetIconMessage: { // Get disk/drive icon if (ReadMacInt8(paramBlock + iconType) == kLargeIcon && ReadMacInt32(paramBlock + requestSize) >= sizeof(ExtFSIcon)) { Host2Mac_memcpy(ReadMacInt32(paramBlock + iconBufferPtr), ExtFSIcon, sizeof(ExtFSIcon)); WriteMacInt32(paramBlock + actualSize, sizeof(ExtFSIcon)); return noErr; } else return -5012; // afpItemNotFound } case ffsIDDiskMessage: { // Check if volume is handled by our FS if ((int16)ReadMacInt16(paramBlock + ioVRefNum) == drive_number) return noErr; else return extFSErr; } case ffsIDVolMountMessage: { // Check if volume can be mounted by our FS if (ReadMacInt32(ReadMacInt32(paramBlock + ioBuffer) + vmiMedia) == MY_MEDIA_TYPE) return noErr; else return extFSErr; } default: return fsmUnknownFSMMessageErr; } } /* * Get current directory specified by given ParamBlock/dirID */ static int16 get_current_dir(uint32 pb, uint32 dirID, uint32 ¤t_dir, bool no_vol_name = false) { M68kRegisters r; int16 result; // Determine volume D(bug(" determining volume, dirID %d\n", dirID)); r.a[0] = pb; r.a[1] = fs_data + fsReturn; r.a[2] = fs_data + fsReturn + 2; r.a[3] = fs_data + fsReturn + 4; r.a[4] = fs_data + fsReturn + 6; uint32 name_ptr = 0; if (no_vol_name) { name_ptr = ReadMacInt32(pb + ioNamePtr); WriteMacInt32(pb + ioNamePtr, 0); } Execute68k(fs_data + fsDetermineVol, &r); if (no_vol_name) WriteMacInt32(pb + ioNamePtr, name_ptr); int16 status = ReadMacInt16(fs_data + fsReturn); D(bug(" UTDetermineVol() returned %d, status %d\n", r.d[0], status)); result = (int16)(r.d[0] & 0xffff); if (result == noErr) { switch (status) { case dtmvFullPathname: // Determined by full pathname current_dir = ROOT_ID; break; case dtmvVRefNum: // Determined by refNum or by drive number case dtmvDriveNum: current_dir = dirID ? dirID : ROOT_ID; break; case dtmvWDRefNum: // Determined by working directory refNum if (dirID) current_dir = dirID; else { D(bug(" resolving WDCB\n")); r.d[0] = 0; r.d[1] = 0; r.d[2] = ReadMacInt16(pb + ioVRefNum); r.a[0] = fs_data + fsReturn; Execute68k(fs_data + fsResolveWDCB, &r); uint32 wdcb = ReadMacInt32(fs_data + fsReturn); D(bug(" UTResolveWDCB() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdcb + wdDirID))); result = (int16)(r.d[0] & 0xffff); if (result == noErr) current_dir = ReadMacInt32(wdcb + wdDirID); } break; case dtmvDefault: // Determined by default volume if (dirID) current_dir = dirID; else { uint32 wdpb = fs_data + fsReturn; WriteMacInt32(wdpb + ioNamePtr, 0); D(bug(" getting default volume\n")); r.a[0] = wdpb; Execute68k(fs_data + fsGetDefaultVol, &r); D(bug(" UTGetDefaultVol() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdpb + ioWDDirID))); result = (int16)(r.d[0] & 0xffff); if (result == noErr) current_dir = ReadMacInt32(wdpb + ioWDDirID); } break; default: result = paramErr; break; } } return result; } /* * Get path component name */ static int16 get_path_component_name(uint32 rec) { // D(bug(" getting path component\n")); M68kRegisters r; r.a[0] = rec; Execute68k(fs_data + fsGetPathComponentName, &r); // D(bug(" UTGetPathComponentName returned %d\n", r.d[0])); return (int16)(r.d[0] & 0xffff); } /* * Get FSItem and full path (->full_path) for file/dir specified in ParamBlock */ static int16 get_item_and_path(uint32 pb, uint32 dirID, FSItem *&item, bool no_vol_name = false) { M68kRegisters r; // Find FSItem for parent directory int16 result; uint32 current_dir; if ((result = get_current_dir(pb, dirID, current_dir, no_vol_name)) != noErr) return result; D(bug(" current dir %08x\n", current_dir)); FSItem *p = find_fsitem_by_id(current_dir); if (p == NULL) return dirNFErr; // Start parsing uint32 parseRec = fs_data + fsParseRec; WriteMacInt32(parseRec + ppNamePtr, ReadMacInt32(pb + ioNamePtr)); WriteMacInt16(parseRec + ppStartOffset, 0); WriteMacInt16(parseRec + ppComponentLength, 0); WriteMacInt8(parseRec + ppMoreName, false); WriteMacInt8(parseRec + ppFoundDelimiter, false); // Get length of volume name D(bug(" parsing pathname\n")); r.a[0] = parseRec + ppStartOffset; r.a[1] = ReadMacInt32(parseRec + ppNamePtr); Execute68k(fs_data + fsParsePathname, &r); D(bug(" UTParsePathname() returned %d, startOffset %d\n", r.d[0], ReadMacInt16(parseRec + ppStartOffset))); result = (int16)(r.d[0] & 0xffff); if (result == noErr) { // Check for leading delimiter of the partial pathname result = get_path_component_name(parseRec); if (result == noErr) { if (ReadMacInt16(parseRec + ppComponentLength) == 0 && ReadMacInt8(parseRec + ppFoundDelimiter)) { // Get past initial delimiter WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + 1); } // Parse until there is no more pathname to parse while ((result == noErr) && ReadMacInt8(parseRec + ppMoreName)) { // Search for the next delimiter from startOffset result = get_path_component_name(parseRec); if (result == noErr) { if (ReadMacInt16(parseRec + ppComponentLength) == 0) { // Delimiter immediately following another delimiter, get parent if (current_dir != ROOT_ID) { p = p->parent; current_dir = p->id; } else result = bdNamErr; // startOffset = start of next component WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + 1); } else if (ReadMacInt8(parseRec + ppMoreName)) { // Component found and isn't the last, so it must be a directory, enter it char name[32]; strn2cstr(name, (char *)Mac2HostAddr(ReadMacInt32(parseRec + ppNamePtr)) + ReadMacInt16(parseRec + ppStartOffset) + 1, ReadMacInt16(parseRec + ppComponentLength)); D(bug(" entering %s\n", name)); p = find_fsitem_guest(name, p); current_dir = p->id; // startOffset = start of next component WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + ReadMacInt16(parseRec + ppComponentLength) + 1); } } } if (result == noErr) { // There is no more pathname to parse if (ReadMacInt16(parseRec + ppComponentLength) == 0) { // Pathname ended with '::' or was simply a volume name, so current directory is the object item = p; } else { // Pathname ended with 'name:' or 'name', so name is the object char name[32]; strn2cstr(name, (char *)Mac2HostAddr(ReadMacInt32(parseRec + ppNamePtr)) + ReadMacInt16(parseRec + ppStartOffset) + 1, ReadMacInt16(parseRec + ppComponentLength)); D(bug(" object is %s\n", name)); item = find_fsitem_guest(name, p); } } } } else { // Default to bad name result = bdNamErr; if (ReadMacInt32(pb + ioNamePtr) == 0 || ReadMacInt8(ReadMacInt32(pb + ioNamePtr)) == 0) { // Pathname was NULL or a zero length string, so we found a directory at the end of the string item = p; result = noErr; } } // Eat the path if (result == noErr) { get_path_for_fsitem(item); D(bug(" path %s\n", full_path)); } return result; } /* * Find FCB for given file RefNum */ static uint32 find_fcb(int16 refNum) { D(bug(" finding FCB\n")); M68kRegisters r; r.d[0] = refNum; r.a[0] = fs_data + fsReturn; Execute68k(fs_data + fsResolveFCB, &r); uint32 fcb = ReadMacInt32(fs_data + fsReturn); D(bug(" UTResolveFCB() returned %d, fcb %08lx\n", r.d[0], fcb)); if (r.d[0] & 0xffff) return 0; else return fcb; } /* * HFS interface functions */ // Check if volume belongs to our FS static int16 fs_mount_vol(uint32 pb) { D(bug(" fs_mount_vol(%08lx), vRefNum %d\n", pb, ReadMacInt16(pb + ioVRefNum))); if ((int16)ReadMacInt16(pb + ioVRefNum) == drive_number) return noErr; else return extFSErr; } // Mount volume static int16 fs_volume_mount(uint32 pb) { D(bug(" fs_volume_mount(%08lx)\n", pb)); M68kRegisters r; // Create new VCB D(bug(" creating VCB\n")); r.a[0] = fs_data + fsReturn; r.a[1] = fs_data + fsReturn + 2; Execute68k(fs_data + fsAllocateVCB, &r); #if DEBUG uint16 sysVCBLength = ReadMacInt16(fs_data + fsReturn); #endif uint32 vcb = ReadMacInt32(fs_data + fsReturn + 2); D(bug(" UTAllocateVCB() returned %d, vcb %08lx, size %d\n", r.d[0], vcb, sysVCBLength)); if (r.d[0] & 0xffff) return (int16)r.d[0]; // Init VCB WriteMacInt16(vcb + vcbSigWord, 0x4244); #if defined(__BEOS__) || defined(WIN32) WriteMacInt32(vcb + vcbCrDate, TimeToMacTime(root_stat.st_crtime)); #elif defined __APPLE__ && defined __MACH__ WriteMacInt32(vcb + vcbCrDate, get_creation_time(RootPath)); #else WriteMacInt32(vcb + vcbCrDate, 0); #endif WriteMacInt32(vcb + vcbLsMod, TimeToMacTime(root_stat.st_mtime)); WriteMacInt32(vcb + vcbVolBkUp, 0); WriteMacInt16(vcb + vcbNmFls, 1); //!! WriteMacInt16(vcb + vcbNmRtDirs, 1); //!! WriteMacInt16(vcb + vcbNmAlBlks, 0xffff); //!! WriteMacInt32(vcb + vcbAlBlkSiz, AL_BLK_SIZE); WriteMacInt32(vcb + vcbClpSiz, CLUMP_SIZE); WriteMacInt32(vcb + vcbNxtCNID, next_cnid); WriteMacInt16(vcb + vcbFreeBks, 0xffff); //!! Host2Mac_memcpy(vcb + vcbVN, VOLUME_NAME, 28); WriteMacInt16(vcb + vcbFSID, MY_FSID); WriteMacInt32(vcb + vcbFilCnt, 1); //!! WriteMacInt32(vcb + vcbDirCnt, 1); //!! // Add VCB to VCB queue D(bug(" adding VCB to queue\n")); r.d[0] = drive_number; r.a[0] = fs_data + fsReturn; r.a[1] = vcb; Execute68k(fs_data + fsAddNewVCB, &r); int16 vRefNum = (int16)ReadMacInt32(fs_data + fsReturn); D(bug(" UTAddNewVCB() returned %d, vRefNum %d\n", r.d[0], vRefNum)); if (r.d[0] & 0xffff) return (int16)r.d[0]; // Post diskInsertEvent D(bug(" posting diskInsertEvent\n")); r.d[0] = drive_number; r.a[0] = 7; // diskEvent Execute68kTrap(0xa02f, &r); // PostEvent() // Return volume RefNum WriteMacInt16(pb + ioVRefNum, vRefNum); return noErr; } // Unmount volume static int16 fs_unmount_vol(uint32 vcb) { D(bug(" fs_unmount_vol(%08lx), vRefNum %d\n", vcb, ReadMacInt16(vcb + vcbVRefNum))); M68kRegisters r; // Remove and free VCB D(bug(" freeing VCB\n")); r.a[0] = vcb; Execute68k(fs_data + fsDisposeVCB, &r); D(bug(" UTDisposeVCB() returned %d\n", r.d[0])); return (int16)r.d[0]; } // Get information about a volume (HVolumeParam) static int16 fs_get_vol_info(uint32 pb, bool hfs) { // D(bug(" fs_get_vol_info(%08lx)\n", pb)); // Fill in struct if (ReadMacInt32(pb + ioNamePtr)) pstrcpy((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), VOLUME_NAME); #if defined(__BEOS__) || defined(WIN32) WriteMacInt32(pb + ioVCrDate, TimeToMacTime(root_stat.st_crtime)); #elif defined __APPLE__ && defined __MACH__ WriteMacInt32(pb + ioVCrDate, get_creation_time(RootPath)); #else WriteMacInt32(pb + ioVCrDate, 0); #endif WriteMacInt32(pb + ioVLsMod, TimeToMacTime(root_stat.st_mtime)); WriteMacInt16(pb + ioVAtrb, 0); WriteMacInt16(pb + ioVNmFls, 1); //!! WriteMacInt16(pb + ioVBitMap, 0); WriteMacInt16(pb + ioAllocPtr, 0); WriteMacInt16(pb + ioVNmAlBlks, 0xffff); //!! WriteMacInt32(pb + ioVAlBlkSiz, AL_BLK_SIZE); WriteMacInt32(pb + ioVClpSiz, CLUMP_SIZE); WriteMacInt16(pb + ioAlBlSt, 0); WriteMacInt32(pb + ioVNxtCNID, next_cnid); WriteMacInt16(pb + ioVFrBlk, 0xffff); //!! if (hfs) { WriteMacInt16(pb + ioVDrvInfo, drive_number); WriteMacInt16(pb + ioVDRefNum, ReadMacInt16(fs_data + fsDrvStatus + dsQRefNum)); WriteMacInt16(pb + ioVFSID, MY_FSID); WriteMacInt32(pb + ioVBkUp, 0); WriteMacInt16(pb + ioVSeqNum, 0); WriteMacInt32(pb + ioVWrCnt, 0); WriteMacInt32(pb + ioVFilCnt, 1); //!! WriteMacInt32(pb + ioVDirCnt, 1); //!! Mac_memset(pb + ioVFndrInfo, 0, 32); } return noErr; } // Change volume information (HVolumeParam) static int16 fs_set_vol_info(uint32 pb) { D(bug(" fs_set_vol_info(%08lx)\n", pb)); //!! times return noErr; } // Get volume parameter block static int16 fs_get_vol_parms(uint32 pb) { // D(bug(" fs_get_vol_parms(%08lx)\n", pb)); // Return parameter block uint32 actual = ReadMacInt32(pb + ioReqCount); if (actual > SIZEOF_GetVolParmsInfoBuffer) actual = SIZEOF_GetVolParmsInfoBuffer; WriteMacInt32(pb + ioActCount, actual); uint32 p = ReadMacInt32(pb + ioBuffer); if (actual > vMVersion) WriteMacInt16(p + vMVersion, 2); if (actual > vMAttrib) WriteMacInt32(p + vMAttrib, kNoMiniFndr | kNoVNEdit | kNoLclSync | kTrshOffLine | kNoSwitchTo | kNoBootBlks | kNoSysDir | kHasExtFSVol); if (actual > vMLocalHand) WriteMacInt32(p + vMLocalHand, 0); if (actual > vMServerAdr) WriteMacInt32(p + vMServerAdr, 0); if (actual > vMVolumeGrade) WriteMacInt32(p + vMVolumeGrade, 0); if (actual > vMForeignPrivID) WriteMacInt16(p + vMForeignPrivID, 0); return noErr; } // Get default volume (WDParam) static int16 fs_get_vol(uint32 pb) { D(bug(" fs_get_vol(%08lx)\n", pb)); M68kRegisters r; // Getting default volume D(bug(" getting default volume\n")); r.a[0] = pb; Execute68k(fs_data + fsGetDefaultVol, &r); D(bug(" UTGetDefaultVol() returned %d\n", r.d[0])); return (int16)r.d[0]; } // Set default volume (WDParam) static int16 fs_set_vol(uint32 pb, bool hfs, uint32 vcb) { D(bug(" fs_set_vol(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioWDDirID))); M68kRegisters r; // Determine parameters uint32 dirID; int16 refNum; if (hfs) { // Find FSItem for given dir FSItem *fs_item; int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioWDDirID), fs_item); if (result != noErr) return result; // Is it a directory? struct stat st; if (stat(full_path, &st)) return dirNFErr; if (!S_ISDIR(st.st_mode)) return dirNFErr; // Get dirID and refNum dirID = fs_item->id; refNum = ReadMacInt16(vcb + vcbVRefNum); } else { // Is the given vRefNum a working directory number? D(bug(" checking for WDRefNum\n")); r.d[0] = ReadMacInt16(pb + ioVRefNum); Execute68k(fs_data + fsCheckWDRefNum, &r); D(bug(" UTCheckWDRefNum() returned %d\n", r.d[0])); if (r.d[0] & 0xffff) { // Volume refNum dirID = ROOT_ID; refNum = ReadMacInt16(vcb + vcbVRefNum); } else { // WD refNum dirID = 0; refNum = ReadMacInt16(pb + ioVRefNum); } } // Setting default volume D(bug(" setting default volume\n")); r.d[0] = 0; r.d[1] = dirID; r.d[2] = refNum; Execute68k(fs_data + fsSetDefaultVol, &r); D(bug(" UTSetDefaultVol() returned %d\n", r.d[0])); return (int16)r.d[0]; } // Query file attributes (HFileParam) static int16 fs_get_file_info(uint32 pb, bool hfs, uint32 dirID) { D(bug(" fs_get_file_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), dirID)); FSItem *fs_item; int16 dir_index = ReadMacInt16(pb + ioFDirIndex); if (dir_index <= 0) { // Query item specified by ioDirID and ioNamePtr // Find FSItem for given file int16 result = get_item_and_path(pb, dirID, fs_item); if (result != noErr) return result; } else { // Query item in directory specified by ioDirID by index // Find FSItem for parent directory int16 result; uint32 current_dir; if ((result = get_current_dir(pb, dirID, current_dir, true)) != noErr) return result; FSItem *p = find_fsitem_by_id(current_dir); if (p == NULL) return dirNFErr; get_path_for_fsitem(p); // Look for nth item in directory and add name to path DIR *d = opendir(full_path); if (d == NULL) return dirNFErr; struct dirent *de = NULL; for (int i=0; id_name[0] == '.') goto read_next_de; // Suppress names beginning with '.' (MacOS could interpret these as driver names) //!! suppress directories } add_path_comp(de->d_name); // Get FSItem for queried item fs_item = find_fsitem(de->d_name, p); closedir(d); } // Get stats struct stat st; if (stat(full_path, &st)) return fnfErr; if (S_ISDIR(st.st_mode)) return fnfErr; // Fill in struct from fs_item and stats if (ReadMacInt32(pb + ioNamePtr)) cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->guest_name); WriteMacInt16(pb + ioFRefNum, 0); WriteMacInt8(pb + ioFlAttrib, access(full_path, W_OK) == 0 ? 0 : faLocked); WriteMacInt32(pb + ioDirID, fs_item->id); #if defined(__BEOS__) || defined(WIN32) WriteMacInt32(pb + ioFlCrDat, TimeToMacTime(st.st_crtime)); #elif defined __APPLE__ && defined __MACH__ WriteMacInt32(pb + ioFlCrDat, get_creation_time(full_path)); #else WriteMacInt32(pb + ioFlCrDat, 0); #endif WriteMacInt32(pb + ioFlMdDat, TimeToMacTime(st.st_mtime)); get_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false); WriteMacInt16(pb + ioFlStBlk, 0); WriteMacInt32(pb + ioFlLgLen, st.st_size); WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1); WriteMacInt16(pb + ioFlRStBlk, 0); uint32 rf_size = get_rfork_size(full_path); WriteMacInt32(pb + ioFlRLgLen, rf_size); WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1); if (hfs) { WriteMacInt32(pb + ioFlBkDat, 0); WriteMacInt32(pb + ioFlParID, fs_item->parent_id); WriteMacInt32(pb + ioFlClpSiz, 0); } return noErr; } // Set file attributes (HFileParam) static int16 fs_set_file_info(uint32 pb, bool hfs, uint32 dirID) { D(bug(" fs_set_file_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), dirID)); // Find FSItem for given file/dir FSItem *fs_item; int16 result = get_item_and_path(pb, dirID, fs_item); if (result != noErr) return result; // Get stats struct stat st; if (stat(full_path, &st) < 0) return errno2oserr(); if (S_ISDIR(st.st_mode)) return fnfErr; // Set Finder info set_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false); //!! times return noErr; } // Query file/directory attributes static int16 fs_get_cat_info(uint32 pb) { D(bug(" fs_get_cat_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), ReadMacInt32(pb + ioDirID))); FSItem *fs_item; int16 dir_index = ReadMacInt16(pb + ioFDirIndex); if (dir_index < 0) { // Query directory specified by ioDirID // Find FSItem for directory fs_item = find_fsitem_by_id(ReadMacInt32(pb + ioDrDirID)); if (fs_item == NULL) return dirNFErr; get_path_for_fsitem(fs_item); } else if (dir_index == 0) { // Query item specified by ioDirID and ioNamePtr // Find FSItem for given file/dir int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item); if (result != noErr) return result; } else { // Query item in directory specified by ioDirID by index // Find FSItem for parent directory int16 result; uint32 current_dir; if ((result = get_current_dir(pb, ReadMacInt32(pb + ioDirID), current_dir, true)) != noErr) return result; FSItem *p = find_fsitem_by_id(current_dir); if (p == NULL) return dirNFErr; get_path_for_fsitem(p); // Look for nth item in directory and add name to path DIR *d = opendir(full_path); if (d == NULL) return dirNFErr; struct dirent *de = NULL; for (int i=0; id_name[0] == '.') goto read_next_de; // Suppress names beginning with '.' (MacOS could interpret these as driver names) } add_path_comp(de->d_name); // Get FSItem for queried item fs_item = find_fsitem(de->d_name, p); closedir(d); } D(bug(" path %s\n", full_path)); // Get stats struct stat st; if (stat(full_path, &st) < 0) return errno2oserr(); if (dir_index == -1 && !S_ISDIR(st.st_mode)) return dirNFErr; // Fill in struct from fs_item and stats if (ReadMacInt32(pb + ioNamePtr)) cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->guest_name); WriteMacInt16(pb + ioFRefNum, 0); WriteMacInt8(pb + ioFlAttrib, (S_ISDIR(st.st_mode) ? faIsDir : 0) | (access(full_path, W_OK) == 0 ? 0 : faLocked)); WriteMacInt8(pb + ioACUser, 0); WriteMacInt32(pb + ioDirID, fs_item->id); WriteMacInt32(pb + ioFlParID, fs_item->parent_id); #if defined(__BEOS__) || defined(WIN32) WriteMacInt32(pb + ioFlCrDat, TimeToMacTime(st.st_crtime)); #elif defined __APPLE__ && defined __MACH__ WriteMacInt32(pb + ioFlCrDat, get_creation_time(full_path)); #else WriteMacInt32(pb + ioFlCrDat, 0); #endif time_t mtime = st.st_mtime; bool cached = true; if (mtime > fs_item->mtime) { fs_item->mtime = mtime; cached = false; } WriteMacInt32(pb + ioFlMdDat, TimeToMacTime(mtime)); WriteMacInt32(pb + ioFlBkDat, 0); get_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode)); if (S_ISDIR(st.st_mode)) { // Determine number of files in directory (cached) int count; if (cached) count = fs_item->cache_dircount; else { count = 0; DIR *d = opendir(full_path); if (d) { struct dirent *de; for (;;) { de = readdir(d); if (de == NULL) break; if (de->d_name[0] == '.') continue; // Suppress names beginning with '.' count++; } closedir(d); } fs_item->cache_dircount = count; } WriteMacInt16(pb + ioDrNmFls, count); } else { WriteMacInt16(pb + ioFlStBlk, 0); WriteMacInt32(pb + ioFlLgLen, st.st_size); WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1); WriteMacInt16(pb + ioFlRStBlk, 0); uint32 rf_size = get_rfork_size(full_path); WriteMacInt32(pb + ioFlRLgLen, rf_size); WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1); WriteMacInt32(pb + ioFlClpSiz, 0); } return noErr; } // Set file/directory attributes static int16 fs_set_cat_info(uint32 pb) { D(bug(" fs_set_cat_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), ReadMacInt32(pb + ioDirID))); // Find FSItem for given file/dir FSItem *fs_item; int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item); if (result != noErr) return result; // Get stats struct stat st; if (stat(full_path, &st) < 0) return errno2oserr(); // Set Finder info set_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode)); //!! times return noErr; } // Open file static int16 fs_open(uint32 pb, uint32 dirID, uint32 vcb, bool resource_fork) { D(bug(" fs_open(%08lx), %s, vRefNum %d, name %.31s, dirID %d, perm %d\n", pb, resource_fork ? "rsrc" : "data", ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID, ReadMacInt8(pb + ioPermssn))); M68kRegisters r; // Find FSItem for given file FSItem *fs_item; int16 result = get_item_and_path(pb, dirID, fs_item); if (result != noErr) return result; // Convert ioPermssn to open() flag int flag = 0; bool write_ok = (access(full_path, W_OK) == 0); switch (ReadMacInt8(pb + ioPermssn)) { case fsCurPerm: // Whatever is currently allowed if (write_ok) flag = O_RDWR; else flag = O_RDONLY; break; case fsRdPerm: // Exclusive read flag = O_RDONLY; break; case fsWrPerm: // Exclusive write flag = O_WRONLY; break; case fsRdWrPerm: // Exclusive read/write case fsRdWrShPerm: // Shared read/write default: flag = O_RDWR; break; } // Try to open and stat the file int fd = -1; struct stat st; if (resource_fork) { if (access(full_path, F_OK)) return fnfErr; fd = open_rfork(full_path, flag); if (fd >= 0) { if (fstat(fd, &st) < 0) { close(fd); return errno2oserr(); } } else { // Resource fork not supported, silently ignore it ("pseudo" resource fork) st.st_size = 0; st.st_mode = 0; } } else { fd = open(full_path, flag); if (fd < 0) return errno2oserr(); if (fstat(fd, &st) < 0) { close(fd); return errno2oserr(); } } // File open, allocate FCB D(bug(" allocating FCB\n")); r.a[0] = pb + ioRefNum; r.a[1] = fs_data + fsReturn; Execute68k(fs_data + fsAllocateFCB, &r); uint32 fcb = ReadMacInt32(fs_data + fsReturn); D(bug(" UTAllocateFCB() returned %d, fRefNum %d, fcb %08lx\n", r.d[0], ReadMacInt16(pb + ioRefNum), fcb)); if (r.d[0] & 0xffff) { close(fd); return (int16)r.d[0]; } // Initialize FCB, fd is stored in fcbCatPos WriteMacInt32(fcb + fcbFlNm, fs_item->id); WriteMacInt8(fcb + fcbFlags, ((flag == O_WRONLY || flag == O_RDWR) ? fcbWriteMask : 0) | (resource_fork ? fcbResourceMask : 0) | (write_ok ? 0 : fcbFileLockedMask)); WriteMacInt32(fcb + fcbEOF, st.st_size); WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1); WriteMacInt32(fcb + fcbCrPs, 0); WriteMacInt32(fcb + fcbVPtr, vcb); WriteMacInt32(fcb + fcbClmpSize, CLUMP_SIZE); get_finfo(full_path, fs_data + fsPB, 0, false); WriteMacInt32(fcb + fcbFType, ReadMacInt32(fs_data + fsPB + fdType)); WriteMacInt32(fcb + fcbCatPos, fd); WriteMacInt32(fcb + fcbDirID, fs_item->parent_id); cstr2pstr((char *)Mac2HostAddr(fcb + fcbCName), fs_item->guest_name); return noErr; } // Close file static int16 fs_close(uint32 pb) { D(bug(" fs_close(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum))); M68kRegisters r; // Find FCB and fd for file uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); if (fcb == 0) return rfNumErr; if (ReadMacInt32(fcb + fcbFlNm) == 0) return fnOpnErr; int fd = ReadMacInt32(fcb + fcbCatPos); // Close file if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { FSItem *item = find_fsitem_by_id(ReadMacInt32(fcb + fcbFlNm)); if (item) { get_path_for_fsitem(item); close_rfork(full_path, fd); } } else close(fd); WriteMacInt32(fcb + fcbCatPos, (uint32)-1); // Release FCB D(bug(" releasing FCB\n")); r.d[0] = ReadMacInt16(pb + ioRefNum); Execute68k(fs_data + fsReleaseFCB, &r); D(bug(" UTReleaseFCB() returned %d\n", r.d[0])); return (int16)r.d[0]; } // Query information about FCB (FCBPBRec) static int16 fs_get_fcb_info(uint32 pb, uint32 vcb) { D(bug(" fs_get_fcb_info(%08lx), vRefNum %d, refNum %d, idx %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioFCBIndx))); M68kRegisters r; uint32 fcb = 0; if (ReadMacInt16(pb + ioFCBIndx) == 0) { // Get information about single file // Find FCB for file fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); } else { // Get information about file specified by index // Find FCB by index WriteMacInt16(pb + ioRefNum, 0); for (int i=0; i<(int)ReadMacInt16(pb + ioFCBIndx); i++) { D(bug(" indexing FCBs\n")); r.a[0] = vcb; r.a[1] = pb + ioRefNum; r.a[2] = fs_data + fsReturn; Execute68k(fs_data + fsIndexFCB, &r); fcb = ReadMacInt32(fs_data + fsReturn); D(bug(" UTIndexFCB() returned %d, fcb %p\n", r.d[0], fcb)); if (r.d[0] & 0xffff) return (int16)r.d[0]; } } if (fcb == 0) return rfNumErr; // Copy information from FCB if (ReadMacInt32(pb + ioNamePtr)) pstrcpy((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), (char *)Mac2HostAddr(fcb + fcbCName)); WriteMacInt32(pb + ioFCBFlNm, ReadMacInt32(fcb + fcbFlNm)); WriteMacInt8(pb + ioFCBFlags, ReadMacInt8(fcb + fcbFlags)); WriteMacInt16(pb + ioFCBStBlk, ReadMacInt16(fcb + fcbSBlk)); WriteMacInt32(pb + ioFCBEOF, ReadMacInt32(fcb + fcbEOF)); WriteMacInt32(pb + ioFCBPLen, ReadMacInt32(fcb + fcbPLen)); WriteMacInt32(pb + ioFCBCrPs, ReadMacInt32(fcb + fcbCrPs)); WriteMacInt16(pb + ioFCBVRefNum, ReadMacInt16(ReadMacInt32(fcb + fcbVPtr) + vcbVRefNum)); WriteMacInt32(pb + ioFCBClpSiz, ReadMacInt32(fcb + fcbClmpSize)); WriteMacInt32(pb + ioFCBParID, ReadMacInt32(fcb + fcbDirID)); return noErr; } // Obtain logical size of an open file static int16 fs_get_eof(uint32 pb) { D(bug(" fs_get_eof(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum))); M68kRegisters r; // Find FCB and fd for file uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); if (fcb == 0) return rfNumErr; if (ReadMacInt32(fcb + fcbFlNm) == 0) return fnOpnErr; int fd = ReadMacInt32(fcb + fcbCatPos); if (fd < 0) if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork WriteMacInt32(pb + ioMisc, 0); return noErr; } else return fnOpnErr; // Get file size struct stat st; if (fstat(fd, &st) < 0) return errno2oserr(); // Adjust FCBs WriteMacInt32(fcb + fcbEOF, st.st_size); WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1); WriteMacInt32(pb + ioMisc, st.st_size); D(bug(" adjusting FCBs\n")); r.d[0] = ReadMacInt16(pb + ioRefNum); Execute68k(fs_data + fsAdjustEOF, &r); D(bug(" UTAdjustEOF() returned %d\n", r.d[0])); return noErr; } // Truncate file static int16 fs_set_eof(uint32 pb) { D(bug(" fs_set_eof(%08lx), refNum %d, size %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioMisc))); M68kRegisters r; // Find FCB and fd for file uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); if (fcb == 0) return rfNumErr; if (ReadMacInt32(fcb + fcbFlNm) == 0) return fnOpnErr; int fd = ReadMacInt32(fcb + fcbCatPos); if (fd < 0) if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) // "pseudo" resource fork return noErr; else return fnOpnErr; // Truncate file uint32 size = ReadMacInt32(pb + ioMisc); if (ftruncate(fd, size) < 0) return errno2oserr(); // Adjust FCBs WriteMacInt32(fcb + fcbEOF, size); WriteMacInt32(fcb + fcbPLen, (size | (AL_BLK_SIZE - 1)) + 1); D(bug(" adjusting FCBs\n")); r.d[0] = ReadMacInt16(pb + ioRefNum); Execute68k(fs_data + fsAdjustEOF, &r); D(bug(" UTAdjustEOF() returned %d\n", r.d[0])); return noErr; } // Query current file position static int16 fs_get_fpos(uint32 pb) { D(bug(" fs_get_fpos(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum))); WriteMacInt32(pb + ioReqCount, 0); WriteMacInt32(pb + ioActCount, 0); WriteMacInt16(pb + ioPosMode, 0); // Find FCB and fd for file uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); if (fcb == 0) return rfNumErr; if (ReadMacInt32(fcb + fcbFlNm) == 0) return fnOpnErr; int fd = ReadMacInt32(fcb + fcbCatPos); if (fd < 0) if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork WriteMacInt32(pb + ioPosOffset, 0); return noErr; } else return fnOpnErr; // Get file position uint32 pos = lseek(fd, 0, SEEK_CUR); WriteMacInt32(fcb + fcbCrPs, pos); WriteMacInt32(pb + ioPosOffset, pos); return noErr; } // Set current file position static int16 fs_set_fpos(uint32 pb) { D(bug(" fs_set_fpos(%08lx), refNum %d, posMode %d, offset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset))); // Find FCB and fd for file uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); if (fcb == 0) return rfNumErr; if (ReadMacInt32(fcb + fcbFlNm) == 0) return fnOpnErr; int fd = ReadMacInt32(fcb + fcbCatPos); if (fd < 0) if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork WriteMacInt32(pb + ioPosOffset, 0); return noErr; } else return fnOpnErr; // Set file position switch (ReadMacInt16(pb + ioPosMode) & 3) { case fsFromStart: if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0) return posErr; break; case fsFromLEOF: if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0) return posErr; break; case fsFromMark: if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0) return posErr; break; default: break; } uint32 pos = lseek(fd, 0, SEEK_CUR); WriteMacInt32(fcb + fcbCrPs, pos); WriteMacInt32(pb + ioPosOffset, pos); return noErr; } // Read from file static int16 fs_read(uint32 pb) { D(bug(" fs_read(%08lx), refNum %d, buffer %p, count %d, posMode %d, posOffset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioBuffer), ReadMacInt32(pb + ioReqCount), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset))); // Check parameters if ((int32)ReadMacInt32(pb + ioReqCount) < 0) return paramErr; // Find FCB and fd for file uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); if (fcb == 0) return rfNumErr; if (ReadMacInt32(fcb + fcbFlNm) == 0) return fnOpnErr; int fd = ReadMacInt32(fcb + fcbCatPos); if (fd < 0) if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork WriteMacInt32(pb + ioActCount, 0); return eofErr; } else return fnOpnErr; // Seek switch (ReadMacInt16(pb + ioPosMode) & 3) { case fsFromStart: if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0) return posErr; break; case fsFromLEOF: if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0) return posErr; break; case fsFromMark: if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0) return posErr; break; } // Read ssize_t actual = extfs_read(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount)); int16 read_err = errno2oserr(); D(bug(" actual %d\n", actual)); WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0); uint32 pos = lseek(fd, 0, SEEK_CUR); WriteMacInt32(fcb + fcbCrPs, pos); WriteMacInt32(pb + ioPosOffset, pos); if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount)) return actual < 0 ? read_err : eofErr; else return noErr; } // Write to file static int16 fs_write(uint32 pb) { D(bug(" fs_write(%08lx), refNum %d, buffer %p, count %d, posMode %d, posOffset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioBuffer), ReadMacInt32(pb + ioReqCount), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset))); // Check parameters if ((int32)ReadMacInt32(pb + ioReqCount) < 0) return paramErr; // Find FCB and fd for file uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum)); if (fcb == 0) return rfNumErr; if (ReadMacInt32(fcb + fcbFlNm) == 0) return fnOpnErr; int fd = ReadMacInt32(fcb + fcbCatPos); if (fd < 0) if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork WriteMacInt32(pb + ioActCount, ReadMacInt32(pb + ioReqCount)); return noErr; } else return fnOpnErr; // Seek switch (ReadMacInt16(pb + ioPosMode) & 3) { case fsFromStart: if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0) return posErr; break; case fsFromLEOF: if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0) return posErr; break; case fsFromMark: if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0) return posErr; break; } // Write ssize_t actual = extfs_write(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount)); int16 write_err = errno2oserr(); D(bug(" actual %d\n", actual)); WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0); uint32 pos = lseek(fd, 0, SEEK_CUR); WriteMacInt32(fcb + fcbCrPs, pos); WriteMacInt32(pb + ioPosOffset, pos); if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount)) return write_err; else return noErr; } // Create file static int16 fs_create(uint32 pb, uint32 dirID) { D(bug(" fs_create(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID)); // Find FSItem for given file FSItem *fs_item; int16 result = get_item_and_path(pb, dirID, fs_item); if (result != noErr) return result; // Does the file already exist? if (access(full_path, F_OK) == 0) return dupFNErr; // Create file int fd = creat(full_path, 0666); if (fd < 0) return errno2oserr(); else { close(fd); return noErr; } } // Create directory static int16 fs_dir_create(uint32 pb) { D(bug(" fs_dir_create(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioDirID))); // Find FSItem for given directory FSItem *fs_item; int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item); if (result != noErr) return result; // Does the directory already exist? if (access(full_path, F_OK) == 0) return dupFNErr; // Create directory if (mkdir(full_path, 0777) < 0) return errno2oserr(); else { WriteMacInt32(pb + ioDirID, fs_item->id); return noErr; } } // Delete file/directory static int16 fs_delete(uint32 pb, uint32 dirID) { D(bug(" fs_delete(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID)); // Find FSItem for given file/dir FSItem *fs_item; int16 result = get_item_and_path(pb, dirID, fs_item); if (result != noErr) return result; // Delete file if (!extfs_remove(full_path)) return errno2oserr(); else return noErr; } // Rename file/directory static int16 fs_rename(uint32 pb, uint32 dirID) { D(bug(" fs_rename(%08lx), vRefNum %d, name %.31s, dirID %d, new name %.31s\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID, Mac2HostAddr(ReadMacInt32(pb + ioMisc) + 1))); // Find path of given file/dir FSItem *fs_item; int16 result = get_item_and_path(pb, dirID, fs_item); if (result != noErr) return result; // Save path of existing item char old_path[MAX_PATH_LENGTH]; strcpy(old_path, full_path); // Find path for new name Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam); WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioMisc)); FSItem *new_item; result = get_item_and_path(fs_data + fsPB, dirID, new_item); if (result != noErr) return result; // Does the new name already exist? if (access(full_path, F_OK) == 0) return dupFNErr; // Rename item D(bug(" renaming %s -> %s\n", old_path, full_path)); if (!extfs_rename(old_path, full_path)) return errno2oserr(); else { // The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems swap_parent_ids(fs_item->id, new_item->id); uint32 t = fs_item->id; fs_item->id = new_item->id; new_item->id = t; return noErr; } } // Move file/directory (CMovePBRec) static int16 fs_cat_move(uint32 pb) { D(bug(" fs_cat_move(%08lx), vRefNum %d, name %.31s, dirID %d, new name %.31s, new dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioDirID), Mac2HostAddr(ReadMacInt32(pb + ioNewName) + 1), ReadMacInt32(pb + ioNewDirID))); // Find path of given file/dir FSItem *fs_item; int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item); if (result != noErr) return result; // Save path of existing item char old_path[MAX_PATH_LENGTH]; strcpy(old_path, full_path); // Find path for new directory Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam); WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioNewName)); FSItem *new_dir_item; result = get_item_and_path(fs_data + fsPB, ReadMacInt32(pb + ioNewDirID), new_dir_item); if (result != noErr) return result; // Append old file/dir name add_path_comp(fs_item->name); // Does the new name already exist? if (access(full_path, F_OK) == 0) return dupFNErr; // Move item D(bug(" moving %s -> %s\n", old_path, full_path)); if (!extfs_rename(old_path, full_path)) return errno2oserr(); else { // The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems FSItem *new_item = find_fsitem(fs_item->name, new_dir_item); if (new_item) { swap_parent_ids(fs_item->id, new_item->id); uint32 t = fs_item->id; fs_item->id = new_item->id; new_item->id = t; } return noErr; } } // Open working directory (WDParam) static int16 fs_open_wd(uint32 pb) { D(bug(" fs_open_wd(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioWDDirID))); M68kRegisters r; // Allocate WDCB D(bug(" allocating WDCB\n")); r.a[0] = pb; Execute68k(fs_data + fsAllocateWDCB, &r); D(bug(" UTAllocateWDCB returned %d, refNum is %d\n", r.d[0], ReadMacInt16(pb + ioVRefNum))); return (int16)r.d[0]; } // Close working directory (WDParam) static int16 fs_close_wd(uint32 pb) { D(bug(" fs_close_wd(%08lx), vRefNum %d\n", pb, ReadMacInt16(pb + ioVRefNum))); M68kRegisters r; // Release WDCB D(bug(" releasing WDCB\n")); r.d[0] = ReadMacInt16(pb + ioVRefNum); Execute68k(fs_data + fsReleaseWDCB, &r); D(bug(" UTReleaseWDCB returned %d\n", r.d[0])); return (int16)r.d[0]; } // Query information about working directory (WDParam) static int16 fs_get_wd_info(uint32 pb, uint32 vcb) { D(bug(" fs_get_wd_info(%08lx), vRefNum %d, idx %d, procID %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioWDIndex), ReadMacInt32(pb + ioWDProcID))); M68kRegisters r; // Querying volume? if (ReadMacInt16(pb + ioWDIndex) == 0 && ReadMacInt16(pb + ioVRefNum) == ReadMacInt16(vcb + vcbVRefNum)) { WriteMacInt32(pb + ioWDProcID, 0); WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(vcb + vcbVRefNum)); if (ReadMacInt32(pb + ioNamePtr)) Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), vcb + vcbVN, 28); WriteMacInt32(pb + ioWDDirID, ROOT_ID); return noErr; } // Resolve WDCB D(bug(" resolving WDCB\n")); r.d[0] = ReadMacInt32(pb + ioWDProcID); r.d[1] = ReadMacInt16(pb + ioWDIndex); r.d[2] = ReadMacInt16(pb + ioVRefNum); r.a[0] = fs_data + fsReturn; Execute68k(fs_data + fsResolveWDCB, &r); uint32 wdcb = ReadMacInt32(fs_data + fsReturn); D(bug(" UTResolveWDCB() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdcb + wdDirID))); if (r.d[0] & 0xffff) return (int16)r.d[0]; // Return information WriteMacInt32(pb + ioWDProcID, ReadMacInt32(wdcb + wdProcID)); WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(ReadMacInt32(wdcb + wdVCBPtr) + vcbVRefNum)); if (ReadMacInt32(pb + ioNamePtr)) Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), ReadMacInt32(wdcb + wdVCBPtr) + vcbVN, 28); WriteMacInt32(pb + ioWDDirID, ReadMacInt32(wdcb + wdDirID)); return noErr; } // Main dispatch routine int16 ExtFSHFS(uint32 vcb, uint16 selectCode, uint32 paramBlock, uint32 globalsPtr, int16 fsid) { uint16 trapWord = selectCode & 0xf0ff; bool hfs = selectCode & kHFSMask; switch (trapWord) { case kFSMOpen: return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, false); case kFSMClose: return fs_close(paramBlock); case kFSMRead: return fs_read(paramBlock); case kFSMWrite: return fs_write(paramBlock); case kFSMGetVolInfo: return fs_get_vol_info(paramBlock, hfs); case kFSMCreate: return fs_create(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0); case kFSMDelete: return fs_delete(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0); case kFSMOpenRF: return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, true); case kFSMRename: return fs_rename(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0); case kFSMGetFileInfo: return fs_get_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0); case kFSMSetFileInfo: return fs_set_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0); case kFSMUnmountVol: return fs_unmount_vol(vcb); case kFSMMountVol: return fs_mount_vol(paramBlock); case kFSMAllocate: D(bug(" allocate\n")); WriteMacInt32(paramBlock + ioActCount, ReadMacInt32(paramBlock + ioReqCount)); return noErr; case kFSMGetEOF: return fs_get_eof(paramBlock); case kFSMSetEOF: return fs_set_eof(paramBlock); case kFSMGetVol: return fs_get_vol(paramBlock); case kFSMSetVol: return fs_set_vol(paramBlock, hfs, vcb); case kFSMEject: D(bug(" eject\n")); return noErr; case kFSMGetFPos: return fs_get_fpos(paramBlock); case kFSMOffline: D(bug(" offline\n")); return noErr; case kFSMSetFilLock: return noErr; //!! case kFSMRstFilLock: return noErr; //!! case kFSMSetFPos: return fs_set_fpos(paramBlock); case kFSMOpenWD: return fs_open_wd(paramBlock); case kFSMCloseWD: return fs_close_wd(paramBlock); case kFSMCatMove: return fs_cat_move(paramBlock); case kFSMDirCreate: return fs_dir_create(paramBlock); case kFSMGetWDInfo: return fs_get_wd_info(paramBlock, vcb); case kFSMGetFCBInfo: return fs_get_fcb_info(paramBlock, vcb); case kFSMGetCatInfo: return fs_get_cat_info(paramBlock); case kFSMSetCatInfo: return fs_set_cat_info(paramBlock); case kFSMSetVolInfo: return fs_set_vol_info(paramBlock); case kFSMGetVolParms: return fs_get_vol_parms(paramBlock); case kFSMVolumeMount: return fs_volume_mount(paramBlock); case kFSMFlushVol: case kFSMFlushFile: D(bug(" flush_vol/flush_file\n")); return noErr; default: D(bug("ExtFSHFS(%08lx, %04x, %08lx, %08lx, %d)\n", vcb, selectCode, paramBlock, globalsPtr, fsid)); return paramErr; } } BasiliskII/src/include/0000755000175000017500000000000011735674751015173 5ustar centriscentrisBasiliskII/src/include/debug.h0000644000175000017500000000341310736405223016415 0ustar centriscentris/* * debug.h - Debugging utilities * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef DEBUG_H #define DEBUG_H #if defined(WIN32) && !defined(__CYGWIN__) // Windows debugging goes where it's supposed to go #include #include #include #include #include static void _cdecl inline winbug( char *s, ...) { va_list vargs; char msg[1024], date[50], hours[50]; struct _timeb tstruct; _ftime( &tstruct ); _strtime( hours ); _strdate( date ); sprintf( msg, "B2: %s %s:%03u ", date, hours, tstruct.millitm ); va_start( vargs, s ); vsprintf( &msg[strlen(msg)], s, vargs ); va_end( vargs ); OutputDebugString(msg); } #define bug winbug #elif defined(AMIGA) // Amiga debugging info goes to serial port (or sushi) #ifdef __cplusplus extern "C" { #endif extern void kprintf(const char *, ...); #ifdef __cplusplus } #endif #define bug kprintf #else // Other systems just print it to stdout #include #define bug printf #endif #if DEBUG #define D(x) (x); #else #define D(x) ; #endif #endif BasiliskII/src/include/ether_defs.h0000644000175000017500000000246610736405223017446 0ustar centriscentris/* * ether_defs.h - Definitions for MacOS Ethernet drivers * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef ETHER_DEFS_H #define ETHER_DEFS_H // Error codes enum { eMultiErr = -91, eLenErr = -92, lapProtErr = -94, excessCollsns = -95 }; // Control codes enum { kENetSetGeneral = 253, kENetGetInfo = 252, kENetRdCancel = 251, kENetRead = 250, kENetWrite = 249, kENetDetachPH = 248, kENetAttachPH = 247, kENetAddMulti = 246, kENetDelMulti = 245 }; enum { // EParamBlock struct eProtType = 28, ePointer = 30, eBuffSize = 34, eDataSize = 36, eMultiAddr = 28 }; #endif BasiliskII/src/include/xpram.h0000644000175000017500000000224711232133661016456 0ustar centriscentris/* * xpram.h - XPRAM handling * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef XPRAM_H #define XPRAM_H #if POWERPC_ROM const int XPRAM_SIZE = 8192; #else const int XPRAM_SIZE = 256; #endif extern uint8 XPRAM[XPRAM_SIZE]; extern void XPRAMInit(const char *vmdir); extern void XPRAMExit(void); // System specific and internal functions/data extern void LoadXPRAM(const char *vmdir); extern void SaveXPRAM(void); extern void ZapPRAM(void); #endif BasiliskII/src/include/adb.h0000644000175000017500000000231110736405223016051 0ustar centriscentris/* * adb.h - ADB emulation (mouse/keyboard) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef ADB_H #define ADB_H extern void ADBInit(void); extern void ADBExit(void); extern void ADBOp(uint8 op, uint8 *data); extern void ADBMouseMoved(int x, int y); extern void ADBMouseDown(int button); extern void ADBMouseUp(int button); extern void ADBKeyDown(int code); extern void ADBKeyUp(int code); extern void ADBInterrupt(void); extern void ADBSetRelMouseMode(bool relative); #endif BasiliskII/src/include/sys.h0000644000175000017500000000564310736405223016154 0ustar centriscentris/* * sys.h - System dependent routines (mostly I/O) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SYS_H #define SYS_H // Supported media types enum { MEDIA_FLOPPY = 1, MEDIA_CD = 2, MEDIA_HD = 4, MEDIA_REMOVABLE = MEDIA_FLOPPY | MEDIA_CD }; extern void SysInit(void); extern void SysExit(void); extern void SysAddFloppyPrefs(void); extern void SysAddDiskPrefs(void); extern void SysAddCDROMPrefs(void); extern void SysAddSerialPrefs(void); /* * These routines are used for reading from and writing to disk files * or devices in sony.cpp, disk.cpp and cdrom.cpp. Their purpose is to * hide all OS-specific details of file and device access. The routines * must also hide all restrictions on the location or alignment of the * data buffer or on the transfer length that may be imposed by the * underlying OS. * A file/device is identified by a "filename" (character string) that * may (but need not) map to a valid file path. After Sys_open(), the * file/device is identified by an abstract "file handle" (void *), * that is freed by Sys_close(). */ extern void *Sys_open(const char *name, bool read_only); extern void Sys_close(void *fh); extern size_t Sys_read(void *fh, void *buffer, loff_t offset, size_t length); extern size_t Sys_write(void *fh, void *buffer, loff_t offset, size_t length); extern loff_t SysGetFileSize(void *fh); extern void SysEject(void *fh); extern bool SysFormat(void *fh); extern bool SysIsReadOnly(void *fh); extern bool SysIsFixedDisk(void *fh); extern bool SysIsDiskInserted(void *fh); extern void SysPreventRemoval(void *fh); extern void SysAllowRemoval(void *fh); extern bool SysCDReadTOC(void *fh, uint8 *toc); extern bool SysCDGetPosition(void *fh, uint8 *pos); extern bool SysCDPlay(void *fh, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f); extern bool SysCDPause(void *fh); extern bool SysCDResume(void *fh); extern bool SysCDStop(void *fh, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f); extern bool SysCDScan(void *fh, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse); extern void SysCDSetVolume(void *fh, uint8 left, uint8 right); extern void SysCDGetVolume(void *fh, uint8 &left, uint8 &right); #endif BasiliskII/src/include/emul_op.h0000644000175000017500000000566110736405223016776 0ustar centriscentris/* * emul_op.h - 68k opcodes for ROM patches * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef EMUL_OP_H #define EMUL_OP_H // 68k opcodes const uint16 M68K_ILLEGAL = 0x4afc; const uint16 M68K_NOP = 0x4e71; const uint16 M68K_RTS = 0x4e75; const uint16 M68K_RTD = 0x4e74; const uint16 M68K_RTR = 0x4e77; const uint16 M68K_JMP = 0x4ef9; const uint16 M68K_JMP_A0 = 0x4ed0; const uint16 M68K_JSR = 0x4eb9; const uint16 M68K_JSR_A0 = 0x4e90; // Extended opcodes enum { M68K_EXEC_RETURN = 0x7100, // Extended opcodes (illegal moveq form) M68K_EMUL_BREAK, M68K_EMUL_OP_SHUTDOWN, M68K_EMUL_OP_RESET, M68K_EMUL_OP_CLKNOMEM, M68K_EMUL_OP_READ_XPRAM, M68K_EMUL_OP_READ_XPRAM2, M68K_EMUL_OP_PATCH_BOOT_GLOBS, M68K_EMUL_OP_FIX_BOOTSTACK, // 0x7108 M68K_EMUL_OP_FIX_MEMSIZE, M68K_EMUL_OP_INSTALL_DRIVERS, M68K_EMUL_OP_SERD, M68K_EMUL_OP_SONY_OPEN, M68K_EMUL_OP_SONY_PRIME, M68K_EMUL_OP_SONY_CONTROL, M68K_EMUL_OP_SONY_STATUS, M68K_EMUL_OP_DISK_OPEN, // 0x7110 M68K_EMUL_OP_DISK_PRIME, M68K_EMUL_OP_DISK_CONTROL, M68K_EMUL_OP_DISK_STATUS, M68K_EMUL_OP_CDROM_OPEN, M68K_EMUL_OP_CDROM_PRIME, M68K_EMUL_OP_CDROM_CONTROL, M68K_EMUL_OP_CDROM_STATUS, M68K_EMUL_OP_VIDEO_OPEN, // 0x7118 M68K_EMUL_OP_VIDEO_CONTROL, M68K_EMUL_OP_VIDEO_STATUS, M68K_EMUL_OP_SERIAL_OPEN, M68K_EMUL_OP_SERIAL_PRIME, M68K_EMUL_OP_SERIAL_CONTROL, M68K_EMUL_OP_SERIAL_STATUS, M68K_EMUL_OP_SERIAL_CLOSE, M68K_EMUL_OP_ETHER_OPEN, // 0x7120 M68K_EMUL_OP_ETHER_CONTROL, M68K_EMUL_OP_ETHER_READ_PACKET, M68K_EMUL_OP_ADBOP, M68K_EMUL_OP_INSTIME, M68K_EMUL_OP_RMVTIME, M68K_EMUL_OP_PRIMETIME, M68K_EMUL_OP_MICROSECONDS, M68K_EMUL_OP_SCSI_DISPATCH, // 0x7128 M68K_EMUL_OP_IRQ, M68K_EMUL_OP_PUT_SCRAP, M68K_EMUL_OP_GET_SCRAP, M68K_EMUL_OP_CHECKLOAD, M68K_EMUL_OP_AUDIO, M68K_EMUL_OP_EXTFS_COMM, M68K_EMUL_OP_EXTFS_HFS, M68K_EMUL_OP_BLOCK_MOVE, // 0x7130 M68K_EMUL_OP_SOUNDIN_OPEN, M68K_EMUL_OP_SOUNDIN_PRIME, M68K_EMUL_OP_SOUNDIN_CONTROL, M68K_EMUL_OP_SOUNDIN_STATUS, M68K_EMUL_OP_SOUNDIN_CLOSE, M68K_EMUL_OP_DEBUGUTIL, M68K_EMUL_OP_IDLE_TIME, M68K_EMUL_OP_MAX // highest number }; // Functions extern void EmulOp(uint16 opcode, struct M68kRegisters *r); // Execute EMUL_OP opcode (called by 68k emulator or Line-F trap handler) #endif BasiliskII/src/include/extfs_defs.h0000644000175000017500000002647210736405223017473 0ustar centriscentris/* * extfs_defs.h - MacOS types and structures for external file system * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef EXTFS_DEFS_H #define EXTFS_DEFS_H #include "macos_util.h" // Gestalt selectors enum { gestaltFSAttr = FOURCC('f','s',' ',' '), gestaltFullExtFSDispatching = 0, gestaltHasFSSpecCalls = 1, gestaltHasFileSystemManager = 2, gestaltFSMDoesDynamicLoad = 3, gestaltFSSupports4GBVols = 4, gestaltFSSupports2TBVols = 5, gestaltHasExtendedDiskInit = 6, gestaltDTMgrSupportsFSM = 7 }; enum { gestaltFSMVersion = FOURCC('f','s','m',' ') }; // File attributes enum { faLocked = 0x01, faRFOpen = 0x04, faDFOpen = 0x08, faIsDir = 0x10, faOpen = 0x80 }; // Volume attributes enum { vaBusy = 0x40, vaHardLock = 0x80, vaSoftLock = 0x8000 }; // vMAttrib (GetVolParms) constants enum { kLimitFCBs = 1 << 31, kLocalWList = 1 << 30, kNoMiniFndr = 1 << 29, kNoVNEdit = 1 << 28, kNoLclSync = 1 << 27, kTrshOffLine = 1 << 26, kNoSwitchTo = 1 << 25, kNoDeskItems = 1 << 20, kNoBootBlks = 1 << 19, kAccessCntl = 1 << 18, kNoSysDir = 1 << 17, kHasExtFSVol = 1 << 16, kHasOpenDeny = 1 << 15, kHasCopyFile = 1 << 14, kHasMoveRename = 1 << 13, kHasDesktopMgr = 1 << 12, kHasShortName = 1 << 11, kHasFolderLock = 1 << 10, kHasPersonalAccessPrivileges = 1 << 9, kHasUserGroupList = 1 << 8, kHasCatSearch = 1 << 7, kHasFileIDs = 1 << 6, kHasBTreeMgr = 1 << 5, kHasBlankAccessPrivileges = 1 << 4, kSupportsAsyncRequests = 1 << 3 }; enum { fsUsrCNID = 16, kHFSBit = 9, kHFSMask = 0x0200, kAsyncBit = 10, kAsyncMask = 0x0400 }; // HFSCIProc selectCode values enum { kFSMOpen = 0xA000, kFSMClose = 0xA001, kFSMRead = 0xA002, kFSMWrite = 0xA003, kFSMGetVolInfo = 0xA007, kFSMCreate = 0xA008, kFSMDelete = 0xA009, kFSMOpenRF = 0xA00A, kFSMRename = 0xA00B, kFSMGetFileInfo = 0xA00C, kFSMSetFileInfo = 0xA00D, kFSMUnmountVol = 0xA00E, kFSMMountVol = 0xA00F, kFSMAllocate = 0xA010, kFSMGetEOF = 0xA011, kFSMSetEOF = 0xA012, kFSMFlushVol = 0xA013, kFSMGetVol = 0xA014, kFSMSetVol = 0xA015, kFSMEject = 0xA017, kFSMGetFPos = 0xA018, kFSMOffline = 0xA035, kFSMSetFilLock = 0xA041, kFSMRstFilLock = 0xA042, kFSMSetFilType = 0xA043, kFSMSetFPos = 0xA044, kFSMFlushFile = 0xA045, kFSMOpenWD = 0x0001, kFSMCloseWD = 0x0002, kFSMCatMove = 0x0005, kFSMDirCreate = 0x0006, kFSMGetWDInfo = 0x0007, kFSMGetFCBInfo = 0x0008, kFSMGetCatInfo = 0x0009, kFSMSetCatInfo = 0x000A, kFSMSetVolInfo = 0x000B, kFSMLockRng = 0x0010, kFSMUnlockRng = 0x0011, kFSMXGetVolInfo = 0x0012, kFSMCreateFileIDRef = 0x0014, kFSMDeleteFileIDRef = 0x0015, kFSMResolveFileIDRef = 0x0016, kFSMExchangeFiles = 0x0017, kFSMCatSearch = 0x0018, kFSMOpenDF = 0x001A, kFSMMakeFSSpec = 0x001B, kFSMDTGetPath = 0x0020, kFSMDTCloseDown = 0x0021, kFSMDTAddIcon = 0x0022, kFSMDTGetIcon = 0x0023, kFSMDTGetIconInfo = 0x0024, kFSMDTAddAPPL = 0x0025, kFSMDTRemoveAPPL = 0x0026, kFSMDTGetAPPL = 0x0027, kFSMDTSetComment = 0x0028, kFSMDTRemoveComment = 0x0029, kFSMDTGetComment = 0x002A, kFSMDTFlush = 0x002B, kFSMDTReset = 0x002C, kFSMDTGetInfo = 0x002D, kFSMDTOpenInform = 0x002E, kFSMDTDelete = 0x002F, kFSMGetVolParms = 0x0030, kFSMGetLogInInfo = 0x0031, kFSMGetDirAccess = 0x0032, kFSMSetDirAccess = 0x0033, kFSMMapID = 0x0034, kFSMMapName = 0x0035, kFSMCopyFile = 0x0036, kFSMMoveRename = 0x0037, kFSMOpenDeny = 0x0038, kFSMOpenRFDeny = 0x0039, kFSMGetXCatInfo = 0x003A, kFSMGetVolMountInfoSize = 0x003F, kFSMGetVolMountInfo = 0x0040, kFSMVolumeMount = 0x0041, kFSMShare = 0x0042, kFSMUnShare = 0x0043, kFSMGetUGEntry = 0x0044, kFSMGetForeignPrivs = 0x0060, kFSMSetForeignPrivs = 0x0061 }; // UTDetermineVol status values enum { dtmvError = 0, dtmvFullPathname = 1, dtmvVRefNum = 2, dtmvWDRefNum = 3, dtmvDriveNum = 4, dtmvDefault = 5 }; // Miscellaneous constants used by FSM enum { fsdVersion1 = 1, fsmIgnoreFSID = 0xFFFE, fsmGenericFSID = 0xFFFF }; // compInterfMask bits common to all FSM components enum { fsmComponentEnableBit = 31, fsmComponentEnableMask = (long)0x80000000, fsmComponentBusyBit = 30, fsmComponentBusyMask = 0x40000000 }; // compInterfMask bits specific to HFS component enum { hfsCIDoesHFSBit = 23, hfsCIDoesHFSMask = 0x00800000, hfsCIDoesAppleShareBit = 22, hfsCIDoesAppleShareMask = 0x00400000, hfsCIDoesDeskTopBit = 21, hfsCIDoesDeskTopMask = 0x00200000, hfsCIDoesDynamicLoadBit = 20, hfsCIDoesDynamicLoadMask = 0x00100000, hfsCIResourceLoadedBit = 19, hfsCIResourceLoadedMask = 0x00080000, hfsCIHasHLL2PProcBit = 18, hfsCIHasHLL2PProcMask = 0x00040000, hfsCIWantsDTSupportBit = 17, hfsCIWantsDTSupportMask = 0x00020000 }; // FCBRec.fcbFlags bits enum { fcbWriteBit = 0, fcbWriteMask = 0x01, fcbResourceBit = 1, fcbResourceMask = 0x02, fcbWriteLockedBit = 2, fcbWriteLockedMask = 0x04, fcbSharedWriteBit = 4, fcbSharedWriteMask = 0x10, fcbFileLockedBit = 5, fcbFileLockedMask = 0x20, fcbOwnClumpBit = 6, fcbOwnClumpMask = 0x40, fcbModifiedBit = 7, fcbModifiedMask = 0x80 }; // InformFSM messages enum { fsmNopMessage = 0, fsmDrvQElChangedMessage = 1, fsmGetFSIconMessage = 2 }; // Messages passed to the fileSystemCommProc enum { ffsNopMessage = 0, ffsGetIconMessage = 1, ffsIDDiskMessage = 2, ffsLoadMessage = 3, ffsUnloadMessage = 4, ffsIDVolMountMessage = 5, ffsInformMessage = 6, ffsGetIconInfoMessage = 7 }; // Error codes from FSM functions enum { fsmFFSNotFoundErr = -431, fsmBusyFFSErr = -432, fsmBadFFSNameErr = -433, fsmBadFSDLenErr = -434, fsmDuplicateFSIDErr = -435, fsmBadFSDVersionErr = -436, fsmNoAlternateStackErr = -437, fsmUnknownFSMMessageErr = -438 }; // paramBlock for ffsGetIconMessage and fsmGetFSIconMessage enum { kLargeIcon = 1 }; enum { // FSMGetIconRec struct iconBufferPtr = 2, requestSize = 6, actualSize = 10, iconType = 14, isEjectable = 15, driveQElemPtr = 16, fileSystemSpecPtr = 20 }; enum { // VolumeMountInfoHeader struct vmiLength = 0, vmiMedia = 2, vmiFlags = 6, SIZEOF_VolumeMountInfoHeader = 8 }; enum { // GetVolParmsInfoBuffer struct vMVersion = 0, vMAttrib = 2, vMLocalHand = 6, vMServerAdr = 10, vMVolumeGrade = 14, vMForeignPrivID = 18, SIZEOF_GetVolParmsInfoBuffer = 20 }; // Finder Flags enum { kIsOnDesk = 0x0001, kColor = 0x000E, kIsShared = 0x0040, kHasBeenInited = 0x0100, kHasCustomIcon = 0x0400, kIsStationery = 0x0800, kNameLocked = 0x1000, kHasBundle = 0x2000, kIsInvisible = 0x4000, kIsAlias = 0x8000 }; enum { // FInfo struct fdType = 0, fdCreator = 4, fdFlags = 8, fdLocation = 10, fdFldr = 14, SIZEOF_FInfo = 16 }; enum { // FXInfo struct fdIconID = 0, fdUnused = 2, fdScript = 8, fdXFlags = 9, fdComment = 10, fdPutAway = 12, SIZEOF_FXInfo = 16 }; enum { // HFileParam/HFileInfo struct ioFRefNum = 24, ioFVersNum = 26, ioFDirIndex = 28, ioFlAttrib = 30, ioACUser = 31, ioFlFndrInfo = 32, ioDirID = 48, ioFlStBlk = 52, ioFlLgLen = 54, ioFlPyLen = 58, ioFlRStBlk = 62, ioFlRLgLen = 64, ioFlRPyLen = 68, ioFlCrDat = 72, ioFlMdDat = 76, ioFlBkDat = 80, ioFlXFndrInfo = 84, ioFlParID = 100, ioFlClpSiz = 104 }; enum { // DInfo struct frRect = 0, frFlags = 8, frLocation = 10, frView = 14, SIZEOF_DInfo = 16 }; enum { // DXInfo struct frScroll = 0, frOpenChain = 4, frScript = 8, frXFlags = 9, frComment = 10, frPutAway = 12, SIZEOF_DXInfo = 16 }; enum { // HDirParam/DirInfo struct ioDrUsrWds = 32, ioDrDirID = 48, ioDrNmFls = 52, ioDrCrDat = 72, ioDrMdDat = 76, ioDrBkDat = 80, ioDrFndrInfo = 84, ioDrParID = 100 }; enum { // WDParam struct ioWDIndex = 26, ioWDProcID = 28, ioWDVRefNum = 32, ioWDDirID = 48, SIZEOF_WDParam = 52 }; enum { // HVolumeParam struct ioVolIndex = 28, ioVCrDate = 30, ioVLsMod = 34, ioVAtrb = 38, ioVNmFls = 40, ioVBitMap = 42, ioAllocPtr = 44, ioVNmAlBlks = 46, ioVAlBlkSiz = 48, ioVClpSiz = 52, ioAlBlSt = 56, ioVNxtCNID = 58, ioVFrBlk = 62, ioVSigWord = 64, ioVDrvInfo = 66, ioVDRefNum = 68, ioVFSID = 70, ioVBkUp = 72, ioVSeqNum = 76, ioVWrCnt = 78, ioVFilCnt = 82, ioVDirCnt = 86, ioVFndrInfo = 90 }; enum { // CMovePBRec struct ioNewName = 28, ioNewDirID = 36 }; enum { // FCBPBRec struct ioFCBIndx = 28, ioFCBFlNm = 32, ioFCBFlags = 36, ioFCBStBlk = 38, ioFCBEOF = 40, ioFCBPLen = 44, ioFCBCrPs = 48, ioFCBVRefNum = 52, ioFCBClpSiz = 54, ioFCBParID = 58 }; // Volume control block enum { // VCB struct vcbFlags = 6, vcbSigWord = 8, vcbCrDate = 10, vcbLsMod = 14, vcbAtrb = 18, vcbNmFls = 20, vcbVBMSt = 22, vcbAllocPtr = 24, vcbNmAlBlks = 26, vcbAlBlkSiz = 28, vcbClpSiz = 32, vcbAlBlSt = 36, vcbNxtCNID = 38, vcbFreeBks = 42, vcbVN = 44, vcbDrvNum = 72, vcbDRefNum = 74, vcbFSID = 76, vcbVRefNum = 78, vcbMAdr = 80, vcbBufAdr = 84, vcbMLen = 88, vcbDirIndex = 90, vcbDirBlk = 92, vcbVolBkUp = 94, vcbVSeqNum = 98, vcbWrCnt = 100, vcbXTClpSiz = 104, vcbCTClpSiz = 108, vcbNmRtDirs = 112, vcbFilCnt = 114, vcbDirCnt = 118, vcbFndrInfo = 122, vcbVCSize = 154, vcbVBMCSiz = 156, vcbCtlCSiz = 158, vcbXTAlBlks = 160, vcbCTAlBlks = 162, vcbXTRef = 164, vcbCTRef = 166, vcbCtlBuf = 168, vcbDirIDM = 172, vcbOffsM = 176, SIZEOF_VCB = 178 }; // Working directory control block enum { // WDCBRec struct wdVCBPtr = 0, wdDirID = 4, wdCatHint = 8, wdProcID = 12, SIZEOF_WDCBRec = 16 }; // File control block enum { // FCBRec struct fcbFlNm = 0, fcbFlags = 4, fcbTypByt = 5, fcbSBlk = 6, fcbEOF = 8, fcbPLen = 12, fcbCrPs = 16, fcbVPtr = 20, fcbBfAdr = 24, fcbFlPos = 28, fcbClmpSize = 30, fcbBTCBPtr = 34, fcbExtRec = 38, fcbFType = 50, fcbCatPos = 54, fcbDirID = 58, fcbCName = 62 }; enum { // ParsePathRec struct ppNamePtr = 0, ppStartOffset = 4, ppComponentLength = 6, ppMoreName = 8, ppFoundDelimiter = 9, SIZEOF_ParsePathRec = 10 }; enum { // HFSCIRec struct compInterfMask = 0, compInterfProc = 4, log2PhyProc = 8, stackTop = 12, stackSize = 16, stackPtr = 20, idSector = 28, SIZEOF_HFSCIRec = 40 }; enum { // DICIRec struct maxVolNameLength = 8, blockSize = 10, SIZEOF_DICIRec = 24 }; enum { // FSDRec struct fsdLink = 0, fsdLength = 4, fsdVersion = 6, fileSystemFSID = 8, fileSystemName = 10, fileSystemSpec = 42, fileSystemGlobalsPtr = 112, fileSystemCommProc = 116, fsdHFSCI = 132, fsdDICI = 172, SIZEOF_FSDRec = 196 }; #endif BasiliskII/src/include/slot_rom.h0000644000175000017500000000165210736405223017170 0ustar centriscentris/* * slot_rom.h - Slot declaration ROM * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SLOT_ROM_H #define SLOT_ROM_H extern bool InstallSlotROM(void); extern void ChecksumSlotROM(void); #endif BasiliskII/src/include/ether.h0000644000175000017500000000557710736405223016453 0ustar centriscentris/* * ether.h - Ethernet device driver * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef ETHER_H #define ETHER_H struct sockaddr_in; extern void EtherInit(void); extern void EtherExit(void); extern int16 EtherOpen(uint32 pb, uint32 dce); extern int16 EtherControl(uint32 pb, uint32 dce); extern void EtherReadPacket(uint32 &src, uint32 &dest, uint32 &len, uint32 &remaining); // System specific and internal functions/data extern void EtherReset(void); extern void EtherInterrupt(void); extern bool ether_init(void); extern void ether_exit(void); extern void ether_reset(void); extern int16 ether_add_multicast(uint32 pb); extern int16 ether_del_multicast(uint32 pb); extern int16 ether_attach_ph(uint16 type, uint32 handler); extern int16 ether_detach_ph(uint16 type); extern int16 ether_write(uint32 wds); extern bool ether_start_udp_thread(int socket_fd); extern void ether_stop_udp_thread(void); extern void ether_udp_read(uint32 packet, int length, struct sockaddr_in *from); extern uint8 ether_addr[6]; // Ethernet address (set by ether_init()) // Ethernet driver data in MacOS RAM enum { ed_DeferredTask = 0, // Deferred Task struct ed_Code = 20, // DT code is stored here ed_Result = 30, // Result for DT ed_DCE = 34, // DCE for DT (must come directly behind ed_Result) ed_RHA = 38, // Read header area ed_ReadPacket = 52, // ReadPacket/ReadRest routines SIZEOF_etherdata = 76 }; extern uint32 ether_data; // Mac address of driver data in MacOS RAM // Ethernet packet allocator (optimized for 32-bit platforms in real addressing mode) class EthernetPacket { #if SIZEOF_VOID_P == 4 && REAL_ADDRESSING uint8 packet[1516]; public: uint32 addr(void) const { return (uint32)packet; } #else uint32 packet; public: EthernetPacket(); ~EthernetPacket(); uint32 addr(void) const { return packet; } #endif }; // Copy packet data from WDS to linear buffer (must hold at least 1514 bytes), // returns packet length static inline int ether_wds_to_buffer(uint32 wds, uint8 *p) { int len = 0; while (len < 1514) { int w = ReadMacInt16(wds); if (w == 0) break; Mac2Host_memcpy(p, ReadMacInt32(wds + 2), w); len += w; p += w; wds += 6; } return len; } #endif BasiliskII/src/include/macos_util.h0000644000175000017500000001274610736405223017477 0ustar centriscentris/* * macos_util.h - MacOS definitions/utility functions * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef MACOS_UTIL_H #define MACOS_UTIL_H #include "cpu_emulation.h" /* * Queues */ enum { // Queue types dummyType = 0, vType = 1, ioQType = 2, drvQType = 3, evType = 4, fsQType = 5, sIQType = 6, dtQType = 7, nmType = 8 }; enum { // QElem struct qLink = 0, qType = 4, qData = 6 }; enum { // QHdr struct qFlags = 0, qHead = 2, qTail = 6 }; /* * Definitions for Device Manager */ // Error codes enum { noErr = 0, controlErr = -17, statusErr = -18, readErr = -19, writErr = -20, badUnitErr = -21, unitEmptyErr = -22, openErr = -23, closErr = -24, abortErr = -27, notOpenErr = -28, dskFulErr = -34, nsvErr = -35, ioErr = -36, bdNamErr = -37, fnOpnErr = -38, eofErr = -39, posErr = -40, tmfoErr = -42, fnfErr = -43, wPrErr = -44, fLckdErr = -45, fBsyErr = -47, dupFNErr = -48, paramErr = -50, rfNumErr = -51, permErr = -54, nsDrvErr = -56, extFSErr = -58, noDriveErr = -64, offLinErr = -65, noNybErr = -66, noAdrMkErr = -67, dataVerErr = -68, badCksmErr = -69, badBtSlpErr = -70, noDtaMkErr = -71, badDCksum = -72, badDBtSlp = -73, wrUnderrun = -74, cantStepErr = -75, tk0BadErr = -76, initIWMErr = -77, twoSideErr = -78, spdAdjErr = -79, seekErr = -80, sectNFErr = -81, fmt1Err = -82, fmt2Err = -83, verErr = -84, memFullErr = -108, dirNFErr = -120 }; // Misc constants enum { goodbye = -1, ioInProgress = 1, aRdCmd = 2, aWrCmd = 3, asyncTrpBit = 10, noQueueBit = 9, dReadEnable = 0, dWritEnable = 1, dCtlEnable = 2, dStatEnable = 3, dNeedGoodBye = 4, dNeedTime = 5, dNeedLock = 6, dOpened = 5, dRAMBased = 6, drvrActive = 7, rdVerify = 64, fsCurPerm = 0, fsRdPerm = 1, fsWrPerm = 2, fsRdWrPerm = 3, fsRdWrShPerm = 4, fsAtMark = 0, fsFromStart = 1, fsFromLEOF = 2, fsFromMark = 3, sony = 0, hard20 = 1 }; enum { // Large volume constants kWidePosOffsetBit = 8, kMaximumBlocksIn4GB = 0x007fffff }; enum { // IOParam struct ioTrap = 6, ioCmdAddr = 8, ioCompletion = 12, ioResult = 16, ioNamePtr = 18, ioVRefNum = 22, ioRefNum = 24, ioVersNum = 26, ioPermssn = 27, ioMisc = 28, ioBuffer = 32, ioReqCount = 36, ioActCount = 40, ioPosMode = 44, ioPosOffset = 46, ioWPosOffset = 46, // Wide positioning offset when ioPosMode has kWidePosOffsetBit set SIZEOF_IOParam = 50 }; enum { // CntrlParam struct csCode = 26, csParam = 28 }; enum { // DrvSts struct dsTrack = 0, dsWriteProt = 2, dsDiskInPlace = 3, dsInstalled = 4, dsSides = 5, dsQLink = 6, dsQType = 10, dsQDrive = 12, dsQRefNum = 14, dsQFSID = 16, dsTwoSideFmt = 18, dsNewIntf = 19, dsDiskErrs = 20, dsMFMDrive = 22, dsMFMDisk = 23, dsTwoMegFmt = 24 }; enum { // DrvSts2 struct dsDriveSize = 18, dsDriveS1 = 20, dsDriveType = 22, dsDriveManf = 24, dsDriveChar = 26, dsDriveMisc = 28, SIZEOF_DrvSts = 30 }; enum { // DCtlEntry struct dCtlDriver = 0, dCtlFlags = 4, dCtlQHdr = 6, dCtlPosition = 16, dCtlStorage = 20, dCtlRefNum = 24, dCtlCurTicks = 26, dCtlWindow = 30, dCtlDelay = 34, dCtlEMask = 36, dCtlMenu = 38, dCtlSlot = 40, dCtlSlotId = 41, dCtlDevBase = 42, dCtlOwner = 46, dCtlExtDev = 50, dCtlFillByte = 51, dCtlNodeID = 52 }; /* * Definitions for Deferred Task Manager */ enum { // DeferredTask struct dtFlags = 6, dtAddr = 8, dtParam = 12, dtReserved = 16 }; // Definitions for DebugUtil() Selector enum { duDebuggerGetMax = 0, duDebuggerEnter = 1, duDebuggerExit = 2, duDebuggerPoll = 3, duGetPageState = 4, duPageFaultFatal = 5, duDebuggerLockMemory = 6, duDebuggerUnlockMemory = 7, duEnterSupervisorMode = 8 }; // Functions extern void EnqueueMac(uint32 elem, uint32 list); // Enqueue QElem in list extern int FindFreeDriveNumber(int num); // Find first free drive number, starting at "num" extern void MountVolume(void *fh); // Mount volume with given file handle (see sys.h) extern void FileDiskLayout(loff_t size, uint8 *data, loff_t &start_byte, loff_t &real_size); // Calculate disk image file layout given file size and first 256 data bytes extern uint32 DebugUtil(uint32 Selector); // DebugUtil() Replacement extern uint32 TimeToMacTime(time_t t); // Convert time_t value to MacOS time // Construct four-character-code #define FOURCC(a,b,c,d) (((uint32)(a) << 24) | ((uint32)(b) << 16) | ((uint32)(c) << 8) | (uint32)(d)) // Emulator identification codes (4 and 2 characters) const uint32 EMULATOR_ID_4 = 0x62617369; // 'basi' const uint16 EMULATOR_ID_2 = 0x6261; // 'ba' // Test if basic MacOS initializations (of the ROM) are done static inline bool HasMacStarted(void) { return ReadMacInt32(0xcfc) == FOURCC('W','L','S','C'); // Mac warm start flag } #endif BasiliskII/src/include/timer.h0000644000175000017500000000330010736405223016442 0ustar centriscentris/* * timer.h - Time Manager emulation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef TIMER_H #define TIMER_H extern void TimerInit(void); extern void TimerExit(void); extern void TimerReset(void); extern void TimerInterrupt(void); extern int16 InsTime(uint32 tm, uint16 trap); extern int16 RmvTime(uint32 tm); extern int16 PrimeTime(uint32 tm, int32 time); extern void Microseconds(uint32 &hi, uint32 &lo); extern uint32 TimerDateTime(void); // System specific and internal functions/data extern void timer_current_time(tm_time_t &t); extern void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b); extern void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b); extern int timer_cmp_time(tm_time_t a, tm_time_t b); extern void timer_mac2host_time(tm_time_t &res, int32 mactime); extern int32 timer_host2mac_time(tm_time_t hosttime); // Suspend execution of emulator thread and resume it on events extern void idle_wait(void); extern void idle_resume(void); #endif BasiliskII/src/include/clip.h0000644000175000017500000000201610736405223016254 0ustar centriscentris/* * clip.h - Clipboard handling * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef CLIP_H #define CLIP_H extern void ClipInit(void); extern void ClipExit(void); extern void PutScrap(uint32 type, void *scrap, int32 length); extern void GetScrap(void **handle, uint32 type, int32 offset); #endif BasiliskII/src/include/extfs.h0000644000175000017500000000431110736405223016456 0ustar centriscentris/* * extfs.h - MacOS file system for access native file system access * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef EXTFS_H #define EXTFS_H extern void ExtFSInit(void); extern void ExtFSExit(void); extern void InstallExtFS(void); extern int16 ExtFSComm(uint16 message, uint32 paramBlock, uint32 globalsPtr); extern int16 ExtFSHFS(uint32 vcb, uint16 selectCode, uint32 paramBlock, uint32 globalsPtr, int16 fsid); // System specific and internal functions/data extern void extfs_init(void); extern void extfs_exit(void); extern void add_path_component(char *path, const char *component); extern void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir); extern void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir); extern uint32 get_rfork_size(const char *path); extern int open_rfork(const char *path, int flag); extern void close_rfork(const char *path, int fd); extern ssize_t extfs_read(int fd, void *buffer, size_t length); extern ssize_t extfs_write(int fd, void *buffer, size_t length); extern bool extfs_remove(const char *path); extern bool extfs_rename(const char *old_path, const char *new_path); extern const char *host_encoding_to_macroman(const char *filename); // What if the guest OS is using MacJapanese or MacArabic? Oh well... extern const char *macroman_to_host_encoding(const char *filename); // What if the guest OS is using MacJapanese or MacArabic? Oh well... // Maximum length of full path name const int MAX_PATH_LENGTH = 1024; #endif BasiliskII/src/include/disk.h0000644000175000017500000000265210736405223016265 0ustar centriscentris/* * disk.h - Generic disk driver * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef DISK_H #define DISK_H const int DiskRefNum = -63; // RefNum of driver const uint16 DiskDriverFlags = 0x6f04; // Driver flags extern const uint8 DiskIcon[258]; // Icon data (copied to ROM by PatchROM()) extern uint32 DiskIconAddr; // Icon address (Mac address space, set by PatchROM()) extern void DiskInit(void); extern void DiskExit(void); extern void DiskInterrupt(void); extern bool DiskMountVolume(void *fh); extern int16 DiskOpen(uint32 pb, uint32 dce); extern int16 DiskPrime(uint32 pb, uint32 dce); extern int16 DiskControl(uint32 pb, uint32 dce); extern int16 DiskStatus(uint32 pb, uint32 dce); #endif BasiliskII/src/include/prefs_editor.h0000644000175000017500000000161610736405223020017 0ustar centriscentris/* * prefs_editor.h - Preferences editor * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef PREFS_EDITOR_H #define PREFS_EDITOR_H extern bool PrefsEditor(void); #endif BasiliskII/src/include/rsrc_patches.h0000644000175000017500000000166210736405223020013 0ustar centriscentris/* * rsrc_patches.h - Resource patches * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef RSRC_PATCHES_H #define RSRC_PATCHES_H extern void CheckLoad(uint32 type, int16 id, uint8 *p, uint32 size); #endif BasiliskII/src/include/main.h0000644000175000017500000000502211232133661016245 0ustar centriscentris/* * main.h - General definitions * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef MAIN_H #define MAIN_H // CPU type (0 = 68000, 1 = 68010, 2 = 68020, 3 = 68030, 4 = 68040/060) extern int CPUType; extern bool CPUIs68060; // Flag to distinguish 68040 and 68060 // FPU type (0 = no FPU, 1 = 68881, 2 = 68882) extern int FPUType; // Flag: 24-bit-addressing? extern bool TwentyFourBitAddressing; // 68k register structure (for Execute68k()) struct M68kRegisters { uint32 d[8]; uint32 a[8]; uint16 sr; }; // General functions extern bool InitAll(const char *vmdir); extern void ExitAll(void); // Platform-specific functions extern void FlushCodeCache(void *start, uint32 size); // Code was patched, flush caches if neccessary extern void QuitEmulator(void); // Quit emulator extern void ErrorAlert(const char *text); // Display error alert extern void ErrorAlert(int string_id); extern void WarningAlert(const char *text); // Display warning alert extern void WarningAlert(int string_id); extern bool ChoiceAlert(const char *text, const char *pos, const char *neg); // Display choice alert // Mutexes (non-recursive) struct B2_mutex; extern B2_mutex *B2_create_mutex(void); extern void B2_lock_mutex(B2_mutex *mutex); extern void B2_unlock_mutex(B2_mutex *mutex); extern void B2_delete_mutex(B2_mutex *mutex); // Interrupt flags enum { INTFLAG_60HZ = 1, // 60.15Hz VBL INTFLAG_1HZ = 2, // ~1Hz interrupt INTFLAG_SERIAL = 4, // Serial driver INTFLAG_ETHER = 8, // Ethernet driver INTFLAG_AUDIO = 16, // Audio block read INTFLAG_TIMER = 32, // Time Manager INTFLAG_ADB = 64, // ADB INTFLAG_NMI = 128 // NMI }; extern uint32 InterruptFlags; // Currently pending interrupts extern void SetInterruptFlag(uint32 flag); // Set/clear interrupt flags extern void ClearInterruptFlag(uint32 flag); #endif BasiliskII/src/include/video_defs.h0000644000175000017500000000771710736405223017451 0ustar centriscentris/* * video_defs.h - Definitions for MacOS video drivers * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef VIDEO_DEFS_H #define VIDEO_DEFS_H // Video driver control codes enum { cscSetMode = 2, cscSetEntries = 3, cscSetGamma = 4, cscGrayPage = 5, cscSetGray = 6, cscSetInterrupt = 7, cscDirectSetEntries = 8, cscSetDefaultMode = 9, cscSwitchMode = 10, cscSetSync = 11, cscSavePreferredConfiguration = 16, cscSetHardwareCursor = 22, cscDrawHardwareCursor = 23, cscSetConvolution = 24, cscSetPowerState = 25, cscPrivateControlCall = 26, cscSetMultiConnect = 27, cscSetClutBehavior = 28 }; // Video driver status codes enum { cscGetMode = 2, cscGetEntries = 3, cscGetPages = 4, cscGetBaseAddress = 5, cscGetGray = 6, cscGetInterrupt = 7, cscGetGamma = 8, cscGetDefaultMode = 9, cscGetCurrentMode = 10, cscGetSync = 11, cscGetConnection = 12, cscGetModeTiming = 13, cscGetModeBaseAddress = 14, cscGetScanProc = 15, cscGetPreferredConfiguration = 16, cscGetNextResolution = 17, cscGetVideoParameters = 18, cscGetGammaInfoList = 20, cscRetrieveGammaTable = 21, cscSupportsHardwareCursor = 22, cscGetHardwareCursorDrawState = 23, cscGetConvolution = 24, cscGetPowerState = 25, cscPrivateStatusCall = 26, cscGetDDCBlock = 27, cscGetMultiConnect = 28, cscGetClutBehavior = 29 }; enum { // VDSwitchInfo struct csMode = 0, csData = 2, csPage = 6, csBaseAddr = 8, csReserved = 12 }; enum { // VDSetEntry struct csTable = 0, csStart = 4, csCount = 6 }; enum { // VDGammaRecord csGTable = 0 }; enum { // VDDisplayConnectInfo struct csDisplayType = 0, csConnectTaggedType = 2, csConnectTaggedData = 3, csConnectFlags = 4, csDisplayComponent = 8, csConnectReserved = 12 }; enum { // VDTimingInfo struct csTimingMode = 0, csTimingReserved = 4, csTimingFormat = 8, csTimingData = 12, csTimingFlags = 16 }; enum { // VDResolutionInfo struct csPreviousDisplayModeID = 0, csRIDisplayModeID = 4, csHorizontalPixels = 8, csVerticalLines = 12, csRefreshRate = 16, csMaxDepthMode = 20, csResolutionFlags = 22 }; enum { // VDVideoParametersInfo struct csDisplayModeID = 0, csDepthMode = 4, csVPBlockPtr = 6, csPageCount = 10, csDeviceType = 14 }; enum { // VPBlock struct vpBaseOffset = 0, vpRowBytes = 4, vpBounds = 6, vpVersion = 14, vpPackType = 16, vpPackSize = 18, vpHRes = 22, vpVRes = 26, vpPixelType = 30, vpPixelSize = 32, vpCmpCount = 34, vpCmpSize = 36, vpPlaneBytes = 38 }; enum { // SPBlock struct spResult = 0, spPointer = 4, spSize = 8, spOffsetData = 12, spIOFileName = 16, spExecPBlk = 20, spParamData = 24, spMisc = 28, spReserved = 32, spIOReserved = 36, spRefNum = 38, spCategory = 40, spCType = 42, spDrvrSW = 44, spDrvrHW = 46, spTBMask = 48, spSlot = 49, spID = 50, spExtDev = 51, spHwDev = 52, spByteLanes = 53, spFlags = 54, spKey = 55, SIZEOF_SPBlock = 56 }; enum { // struct GammaTbl gVersion = 0, gType = 2, gFormulaSize = 4, gChanCnt = 6, gDataCnt = 8, gDataWidth = 10, gFormulaData = 12, // variable size SIZEOF_GammaTbl = 12 }; enum { // struct VDMultiConnectInfo csDisplayCountOrNumber = 0, csConnectInfo = 4 }; #endif BasiliskII/src/include/scsi.h0000644000175000017500000000305510736405223016272 0ustar centriscentris/* * scsi.h - SCSI Manager * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SCSI_H #define SCSI_H extern int16 SCSIReset(void); extern int16 SCSIGet(void); extern int16 SCSISelect(int id); extern int16 SCSICmd(int cmd_length, uint8 *cmd); extern int16 SCSIRead(uint32 tib); extern int16 SCSIWrite(uint32 tib); extern int16 SCSIComplete(uint32 timeout, uint32 message, uint32 stat); extern uint16 SCSIStat(void); extern int16 SCSIMgrBusy(void); // System specific and internal functions/data extern void SCSIInit(void); extern void SCSIExit(void); extern void scsi_set_cmd(int cmd_length, uint8 *cmd); extern bool scsi_is_target_present(int id); extern bool scsi_set_target(int id, int lun); extern bool scsi_send_cmd(size_t data_length, bool reading, int sg_index, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout); #endif BasiliskII/src/include/user_strings.h0000644000175000017500000001271610736405223020064 0ustar centriscentris/* * user_strings.h - Localizable strings * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef USER_STRINGS_H #define USER_STRINGS_H // Common string numbers enum { // General messages STR_ABOUT_TEXT1 = 0, STR_ABOUT_TEXT2, STR_READING_ROM_FILE, STR_SHELL_ERROR_PREFIX, STR_GUI_ERROR_PREFIX, STR_ERROR_ALERT_TITLE, STR_SHELL_WARNING_PREFIX, STR_GUI_WARNING_PREFIX, STR_WARNING_ALERT_TITLE, STR_NOTICE_ALERT_TITLE, STR_ABOUT_TITLE, STR_OK_BUTTON, STR_START_BUTTON, STR_QUIT_BUTTON, STR_CANCEL_BUTTON, // Error messages STR_NO_MEM_ERR = 1000, STR_NOT_ENOUGH_MEMORY_ERR, STR_NO_RAM_AREA_ERR, STR_NO_ROM_AREA_ERR, STR_NO_ROM_FILE_ERR, STR_ROM_FILE_READ_ERR, STR_ROM_SIZE_ERR, STR_UNSUPPORTED_ROM_TYPE_ERR, STR_OPEN_WINDOW_ERR, STR_OPEN_SCREEN_ERR, STR_SCSI_BUFFER_ERR, STR_SCSI_SG_FULL_ERR, // Warning messages STR_SMALL_RAM_WARN = 2000, STR_CREATE_VOLUME_WARN, STR_VOLUME_IS_MOUNTED_WARN, STR_CANNOT_UNMOUNT_WARN, // Preferences window STR_PREFS_TITLE = 3000, STR_PREFS_MENU = 3020, STR_PREFS_ITEM_ABOUT, STR_PREFS_ITEM_START, STR_PREFS_ITEM_ZAP_PRAM, STR_PREFS_ITEM_QUIT, STR_NONE_LAB = 3100, STR_VOLUMES_PANE_TITLE = 3200, // Volumes pane STR_VOLUMES_CTRL, STR_ADD_VOLUME_BUTTON, STR_CREATE_VOLUME_BUTTON, STR_EDIT_VOLUME_BUTTON, STR_REMOVE_VOLUME_BUTTON, STR_ADD_VOLUME_PANEL_BUTTON, STR_CREATE_VOLUME_PANEL_BUTTON, STR_CDROM_DRIVE_CTRL, STR_BOOTDRIVER_CTRL, STR_BOOT_ANY_LAB, STR_BOOT_CDROM_LAB, STR_NOCDROM_CTRL, STR_EXTFS_CTRL, STR_DEVICE_CTRL, STR_UNIT_CTRL, STR_ADD_VOLUME_TITLE, STR_CREATE_VOLUME_TITLE, STR_EDIT_VOLUME_TITLE, STR_HARDFILE_SIZE_CTRL, STR_VOL_READONLY_CTRL, STR_VOL_TYPE_CTRL, STR_VOL_FILE_LAB, STR_VOL_DEVICE_LAB, STR_VOL_OPENFLAGS_CTRL, STR_VOL_STARTBLOCK_CTRL, STR_VOL_SIZE_CTRL, STR_VOL_BLOCKSIZE_CTRL, STR_VOL_FILE_CTRL, STR_SCSI_PANE_TITLE = 3300, // SCSI pane STR_SCSI_ID_0 = 3301, STR_SCSI_ID_1 = 3302, STR_SCSI_ID_2 = 3303, STR_SCSI_ID_3 = 3304, STR_SCSI_ID_4 = 3305, STR_SCSI_ID_5 = 3306, STR_SCSI_ID_6 = 3307, STR_GRAPHICS_SOUND_PANE_TITLE = 3400, // Graphics/Sound pane STR_GRAPHICS_CTRL, STR_VIDEO_TYPE_CTRL, STR_WINDOW_LAB, STR_FULLSCREEN_LAB, STR_PIP_LAB, STR_FRAMESKIP_CTRL, STR_REF_5HZ_LAB, STR_REF_7_5HZ_LAB, STR_REF_10HZ_LAB, STR_REF_15HZ_LAB, STR_REF_30HZ_LAB, STR_REF_60HZ_LAB, STR_REF_DYNAMIC_LAB, STR_DISPLAY_X_CTRL, STR_DISPLAY_Y_CTRL, STR_SIZE_384_LAB, STR_SIZE_480_LAB, STR_SIZE_512_LAB, STR_SIZE_600_LAB, STR_SIZE_640_LAB, STR_SIZE_768_LAB, STR_SIZE_800_LAB, STR_SIZE_1024_LAB, STR_SIZE_MAX_LAB, STR_COLOR_DEPTH_CTRL, STR_1_BIT_LAB, STR_2_BIT_LAB, STR_4_BIT_LAB, STR_8_BIT_LAB, STR_15_BIT_LAB, STR_24_BIT_LAB, STR_SCREEN_MODE_CTRL, STR_8_BIT_640x480_LAB, STR_8_BIT_800x600_LAB, STR_8_BIT_1024x768_LAB, STR_8_BIT_1152x900_LAB, STR_8_BIT_1280x1024_LAB, STR_8_BIT_1600x1200_LAB, STR_15_BIT_640x480_LAB, STR_15_BIT_800x600_LAB, STR_15_BIT_1024x768_LAB, STR_15_BIT_1152x900_LAB, STR_15_BIT_1280x1024_LAB, STR_15_BIT_1600x1200_LAB, STR_24_BIT_640x480_LAB, STR_24_BIT_800x600_LAB, STR_24_BIT_1024x768_LAB, STR_24_BIT_1152x900_LAB, STR_24_BIT_1280x1024_LAB, STR_24_BIT_1600x1200_LAB, STR_SOUND_CTRL, STR_NOSOUND_CTRL, STR_SERIAL_NETWORK_PANE_TITLE = 3500, // Serial/Networking pane STR_SERIALA_CTRL, STR_SERIALB_CTRL, STR_ISPAR_CTRL, STR_ETHER_ENABLE_CTRL, STR_ETHERNET_IF_CTRL, STR_UDPTUNNEL_CTRL, STR_UDPPORT_CTRL, STR_MEMORY_MISC_PANE_TITLE = 3600, // Memory/Misc pane STR_RAMSIZE_CTRL, STR_RAMSIZE_2MB_LAB, STR_RAMSIZE_4MB_LAB, STR_RAMSIZE_8MB_LAB, STR_RAMSIZE_16MB_LAB, STR_RAMSIZE_32MB_LAB, STR_RAMSIZE_64MB_LAB, STR_RAMSIZE_128MB_LAB, STR_RAMSIZE_256MB_LAB, STR_RAMSIZE_512MB_LAB, STR_RAMSIZE_1024MB_LAB, STR_RAMSIZE_SLIDER, STR_RAMSIZE_FMT, STR_MODELID_CTRL, STR_MODELID_5_LAB, STR_MODELID_14_LAB, STR_CPU_CTRL, STR_CPU_68020_LAB, STR_CPU_68020_FPU_LAB, STR_CPU_68030_LAB, STR_CPU_68030_FPU_LAB, STR_CPU_68040_LAB, STR_ROM_FILE_CTRL, STR_IDLEWAIT_CTRL, STR_JIT_PANE_TITLE = 3700, // JIT Compiler pane STR_JIT_CTRL, STR_JIT_FPU_CTRL, STR_JIT_ATRAPS_CTRL, STR_JIT_CACHE_SIZE_CTRL, STR_JIT_CACHE_SIZE_2MB_LAB, STR_JIT_CACHE_SIZE_4MB_LAB, STR_JIT_CACHE_SIZE_8MB_LAB, STR_JIT_CACHE_SIZE_16MB_LAB, STR_JIT_LAZY_CINV_CTRL, STR_JIT_FOLLOW_CONST_JUMPS, // Mac window STR_WINDOW_TITLE = 4000, STR_WINDOW_TITLE_FROZEN, STR_WINDOW_MENU = 4050, STR_WINDOW_ITEM_ABOUT, STR_WINDOW_ITEM_REFRESH, STR_WINDOW_ITEM_MOUNT, STR_SUSPEND_WINDOW_TITLE, // External file system STR_EXTFS_NAME = 5000, STR_EXTFS_VOLUME_NAME }; // Common and platform-specific string definitions struct user_string_def { int num; const char *str; }; extern user_string_def common_strings[]; extern user_string_def platform_strings[]; // Fetch pointer to string, given the string number extern const char *GetString(int num); #endif BasiliskII/src/include/sony.h0000644000175000017500000000301610736405223016316 0ustar centriscentris/* * sony.h - Replacement .Sony driver (floppy drives) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SONY_H #define SONY_H const int SonyRefNum = -5; // RefNum of driver const uint16 SonyDriverFlags = 0x6f00; // Driver flags extern const uint8 SonyDiskIcon[258]; // Icon data (copied to ROM by PatchROM()) extern const uint8 SonyDriveIcon[258]; extern uint32 SonyDiskIconAddr; // Icon addresses (Mac address space, set by PatchROM()) extern uint32 SonyDriveIconAddr; extern void SonyInit(void); extern void SonyExit(void); extern void SonyInterrupt(void); extern bool SonyMountVolume(void *fh); extern int16 SonyOpen(uint32 pb, uint32 dce); extern int16 SonyPrime(uint32 pb, uint32 dce); extern int16 SonyControl(uint32 pb, uint32 dce); extern int16 SonyStatus(uint32 pb, uint32 dce); #endif BasiliskII/src/include/rom_patches.h0000644000175000017500000000336210736405223017636 0ustar centriscentris/* * rom_patches.h - ROM patches * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef ROM_PATCHES_H #define ROM_PATCHES_H // ROM version number, set by CheckROM() enum { ROM_VERSION_64K = 0x0000, // Original Macintosh (64KB) ROM_VERSION_PLUS = 0x0075, // Mac Plus ROMs (128KB) ROM_VERSION_CLASSIC = 0x0276, // SE/Classic ROMs (256/512KB) ROM_VERSION_II = 0x0178, // Not 32-bit clean Mac II ROMs (256KB) ROM_VERSION_32 = 0x067c // 32-bit clean Mac II ROMs (512KB/1MB) }; extern uint16 ROMVersion; // ROM offset of breakpoint, used by PatchROM() extern uint32 ROMBreakpoint; // ROM offset of UniversalInfo, set by PatchROM() extern uint32 UniversalInfo; // Mac address of PutScrap() patch extern uint32 PutScrapPatch; // Mac address of GetScrap() patch extern uint32 GetScrapPatch; // Flag: print ROM information in PatchROM() extern bool PrintROMInfo; extern bool CheckROM(void); extern bool PatchROM(void); extern void InstallDrivers(uint32 pb); extern void InstallSERD(void); extern void PatchAfterStartup(void); #endif BasiliskII/src/include/video.h0000644000175000017500000002223410736405223016437 0ustar centriscentris/* * video.h - Video/graphics emulation * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef VIDEO_H #define VIDEO_H #include #ifndef NO_STD_NAMESPACE using std::vector; #endif /* Some of the terminology here is completely frelled. In Basilisk II, a "video mode" refers to a combination of resolution and color depth, and this information is stored in a video_mode structure. In Apple documentation, a "mode" historically refers to the color depth only (because old Macs had fixed-frequency monitors and could not change the resolution). These "modes" are assigned a number (0x80, 0x81, etc.), which we here call "Apple mode". When Macs learned how to deal with multiscan monitors, Apple introduced another type of "mode", also having numbers starting from 0x80 but refrerring to the resolution and/or video timing of the display (it's possible to have two modes with the same dimension but different refresh rates). We call this a "resolution ID". The combination of "Apple mode" and "ID" corresponds to a Basilisk II "video mode". To make the confusion worse, the video driver control call that sets the color depth is called "SetMode" while the one that sets both depth and resolution is "SwitchMode"... */ // Color depth codes enum video_depth { VDEPTH_1BIT, // 2 colors VDEPTH_2BIT, // 4 colors VDEPTH_4BIT, // 16 colors VDEPTH_8BIT, // 256 colors VDEPTH_16BIT, // "Thousands" VDEPTH_32BIT // "Millions" }; // 1, 2, 4 and 8 bit depths use a color palette inline bool IsDirectMode(video_depth depth) { return depth == VDEPTH_16BIT || depth == VDEPTH_32BIT; } // Return the depth code that corresponds to the specified bits-per-pixel value inline video_depth DepthModeForPixelDepth(int depth) { switch (depth) { case 1: return VDEPTH_1BIT; case 2: return VDEPTH_2BIT; case 4: return VDEPTH_4BIT; case 8: return VDEPTH_8BIT; case 15: case 16: return VDEPTH_16BIT; case 24: case 32: return VDEPTH_32BIT; default: return VDEPTH_1BIT; } } // Return a bytes-per-row value (assuming no padding) for the specified depth and pixel width inline uint32 TrivialBytesPerRow(uint32 width, video_depth depth) { switch (depth) { case VDEPTH_1BIT: return width / 8; case VDEPTH_2BIT: return width / 4; case VDEPTH_4BIT: return width / 2; case VDEPTH_8BIT: return width; case VDEPTH_16BIT: return width * 2; case VDEPTH_32BIT: return width * 4; default: return width; } } /* You are not completely free in your selection of depth/resolution combinations: 1) the lowest supported color depth must be available in all resolutions 2) if one resolution provides a certain color depth, it must also provide all lower supported depths For example, it is possible to have this set of modes: 640x480 @ 8 bit 640x480 @ 32 bit 800x600 @ 8 bit 800x600 @ 32 bit 1024x768 @ 8 bit But this is not possible (violates rule 1): 640x480 @ 8 bit 800x600 @ 8 bit 1024x768 @ 1 bit And neither is this (violates rule 2, 640x480 @ 16 bit is missing): 640x480 @ 8 bit 640x480 @ 32 bit 800x600 @ 8 bit 800x600 @ 16 bit 1024x768 @ 8 bit */ // Description of a video mode struct video_mode { uint32 x; // X size of screen (pixels) uint32 y; // Y size of screen (pixels) uint32 resolution_id; // Resolution ID (should be >= 0x80 and uniquely identify the sets of modes with the same X/Y size) video_depth depth; // Color depth (see definitions above) uint32 bytes_per_row; // Bytes per row of frame buffer uint32 user_data; // Free for use by platform-specific code }; inline bool IsDirectMode(const video_mode &mode) { return IsDirectMode(mode.depth); } // Mac video driver per-display private variables (opaque) struct video_locals; // Abstract base class representing one (possibly virtual) monitor // ("monitor" = rectangular display with a contiguous frame buffer) class monitor_desc { public: monitor_desc(const vector &available_modes, video_depth default_depth, uint32 default_id); virtual ~monitor_desc() {} // Get Mac slot ID number uint8 get_slot_id(void) const {return slot_id;} // Get current Mac frame buffer base address uint32 get_mac_frame_base(void) const {return mac_frame_base;} // Set Mac frame buffer base address (called from switch_to_mode()) void set_mac_frame_base(uint32 base) {mac_frame_base = base;} // Get current video mode const video_mode &get_current_mode(void) const {return *current_mode;} // Get Apple mode id for given depth uint16 depth_to_apple_mode(video_depth depth) const {return apple_mode_for_depth[depth];} // Get current color depth uint16 get_apple_mode(void) const {return depth_to_apple_mode(current_mode->depth);} // Get bytes-per-row value for specified resolution/depth // (if the mode isn't supported, make a good guess) uint32 get_bytes_per_row(video_depth depth, uint32 id) const; // Check whether a mode with the specified depth exists on this display bool has_depth(video_depth depth) const; // Mac video driver functions int16 driver_open(void); int16 driver_control(uint16 code, uint32 param, uint32 dce); int16 driver_status(uint16 code, uint32 param); protected: vector modes; // List of supported video modes vector::const_iterator current_mode; // Currently selected video mode uint32 mac_frame_base; // Mac frame buffer address for current mode // Mac video driver per-display private variables/functions private: // Check whether the specified resolution ID is one of the supported resolutions bool has_resolution(uint32 id) const; // Return iterator signifying "invalid mode" vector::const_iterator invalid_mode(void) const {return modes.end();} // Find specified mode (depth/resolution) (or invalid_mode() if not found) vector::const_iterator find_mode(uint16 apple_mode, uint32 id) const; // Find maximum supported depth for given resolution ID video_depth max_depth_of_resolution(uint32 id) const; // Get X/Y size of specified resolution void get_size_of_resolution(uint32 id, uint32 &x, uint32 &y) const; // Set palette to 50% gray void set_gray_palette(void); // Load gamma-corrected black-to-white ramp to palette for direct-color mode void load_ramp_palette(void); // Allocate gamma table of specified size bool allocate_gamma_table(int size); // Set gamma table (0 = build linear ramp) bool set_gamma_table(uint32 user_table); // Switch video mode void switch_mode(vector::const_iterator it, uint32 param, uint32 dce); uint8 slot_id; // NuBus slot ID number static uint8 next_slot_id; // Next available slot ID uint8 palette[256 * 3]; // Color palette, 256 entries, RGB bool luminance_mapping; // Luminance mapping on/off bool interrupts_enabled; // VBL interrupts on/off bool dm_present; // We received a GetVideoParameters call, so the Display Manager seems to be present uint32 gamma_table; // Mac address of gamma table int alloc_gamma_table_size; // Allocated size of gamma table uint16 current_apple_mode; // Currently selected depth/resolution uint32 current_id; uint16 preferred_apple_mode; // Preferred depth/resolution uint32 preferred_id; uint32 slot_param; // Mac address of Slot Manager parameter block // For compatibility reasons with older (pre-Display Manager) versions of // MacOS, the Apple modes must start at 0x80 and be contiguous. Therefore // we maintain an array to map the depth codes to the corresponding Apple // mode. uint16 apple_mode_for_depth[6]; // The following functions are implemented by platform-specific code public: // Called by the video driver to switch the video mode on this display // (must call set_mac_frame_base()) virtual void switch_to_current_mode(void) = 0; // Called by the video driver to set the color palette (in indexed modes) // or the gamma table (in direct modes) virtual void set_palette(uint8 *pal, int num) = 0; }; // Vector of pointers to available monitor descriptions, filled by VideoInit() extern vector VideoMonitors; extern int16 VideoDriverOpen(uint32 pb, uint32 dce); extern int16 VideoDriverControl(uint32 pb, uint32 dce); extern int16 VideoDriverStatus(uint32 pb, uint32 dce); // System specific and internal functions/data extern bool VideoInit(bool classic); extern void VideoExit(void); extern void VideoQuitFullScreen(void); extern void VideoInterrupt(void); extern void VideoRefresh(void); #endif BasiliskII/src/include/serial.h0000644000175000017500000000556610736405223016621 0ustar centriscentris/* * serial.h - Serial device driver * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SERIAL_H #define SERIAL_H /* * port: * 0 - .AIn * 1 - .AOut * 2 - .BIn * 3 - .BOut */ #ifdef POWERPC_ROM extern int16 SerialOpen(uint32 pb, uint32 dce); extern int16 SerialPrimeIn(uint32 pb, uint32 dce); extern int16 SerialPrimeOut(uint32 pb, uint32 dce); extern int16 SerialControl(uint32 pb, uint32 dce); extern int16 SerialStatus(uint32 pb, uint32 dce); extern int16 SerialClose(uint32 pb, uint32 dce); extern int16 SerialNothing(uint32 pb, uint32 dce); #else extern int16 SerialOpen(uint32 pb, uint32 dce, int port); extern int16 SerialPrime(uint32 pb, uint32 dce, int port); extern int16 SerialControl(uint32 pb, uint32 dce, int port); extern int16 SerialStatus(uint32 pb, uint32 dce, int port); extern int16 SerialClose(uint32 pb, uint32 dce, int port); #endif extern void SerialInterrupt(void); // System specific and internal functions/data extern void SerialInit(void); extern void SerialExit(void); // Serial driver Deferred Task structure enum { serdtCode = 20, // DT code is stored here serdtResult = 30, serdtDCE = 34, SIZEOF_serdt = 38 }; // Variables for one (In/Out combined) serial port // To implement a serial driver, you create a subclass of SERDPort class SERDPort { public: SERDPort() { is_open = false; input_dt = output_dt = 0; } virtual ~SERDPort() {} virtual int16 open(uint16 config) = 0; virtual int16 prime_in(uint32 pb, uint32 dce) = 0; virtual int16 prime_out(uint32 pb, uint32 dce) = 0; virtual int16 control(uint32 pb, uint32 dce, uint16 code) = 0; virtual int16 status(uint32 pb, uint32 dce, uint16 code) = 0; virtual int16 close(void) = 0; bool is_open; // Port has been opened uint8 cum_errors; // Cumulative errors bool read_pending; // Read operation pending bool read_done; // Read operation complete uint32 input_dt; // Mac address of Deferred Task for reading bool write_pending; // Write operation pending bool write_done; // Write operation complete uint32 output_dt; // Mac address of Deferred Task for writing #ifdef POWERPC_ROM uint32 dt_store; #endif }; extern SERDPort *the_serd_port[2]; #endif BasiliskII/src/include/audio_defs.h0000644000175000017500000001235210736405223017433 0ustar centriscentris/* * audio_defs.h - Definitions for MacOS audio components * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef AUDIO_DEFS_H #define AUDIO_DEFS_H #include "macos_util.h" // Error codes enum { badComponentSelector = (int32)0x80008002, noHardwareErr = -200, badChannel = -205, siInvalidSampleRate = -225, siInvalidSampleSize = -226, siDeviceBusyErr = -227 }; // General component dispatch selector codes enum { kComponentOpenSelect = -1, kComponentCloseSelect = -2, kComponentCanDoSelect = -3, kComponentVersionSelect = -4, kComponentRegisterSelect = -5 }; // Sound component dispatch selector codes enum { kSoundComponentInitOutputDeviceSelect = 1, kSoundComponentSetSourceSelect = 2, kSoundComponentGetSourceSelect = 3, kSoundComponentGetSourceDataSelect = 4, kSoundComponentSetOutputSelect = 5, kDelegatedSoundComponentSelectors = 0x0100, kSoundComponentAddSourceSelect = kDelegatedSoundComponentSelectors + 1, kSoundComponentRemoveSourceSelect = kDelegatedSoundComponentSelectors + 2, kSoundComponentGetInfoSelect = kDelegatedSoundComponentSelectors + 3, kSoundComponentSetInfoSelect = kDelegatedSoundComponentSelectors + 4, kSoundComponentStartSourceSelect = kDelegatedSoundComponentSelectors + 5, kSoundComponentStopSourceSelect = kDelegatedSoundComponentSelectors + 6, kSoundComponentPauseSourceSelect = kDelegatedSoundComponentSelectors + 7, kSoundComponentPlaySourceBufferSelect = kDelegatedSoundComponentSelectors + 8 }; // Sound information selectors const uint32 siNumberChannels = FOURCC('c','h','a','n'); // current number of channels const uint32 siChannelAvailable = FOURCC('c','h','a','v'); // number of channels available const uint32 siSampleRate = FOURCC('s','r','a','t'); // current sample rate const uint32 siSampleRateAvailable = FOURCC('s','r','a','v'); // sample rates available const uint32 siSampleSize = FOURCC('s','s','i','z'); // current sample size const uint32 siSampleSizeAvailable = FOURCC('s','s','a','v'); // sample sizes available const uint32 siHardwareMute = FOURCC('h','m','u','t'); // mute state of all hardware const uint32 siHardwareVolume = FOURCC('h','v','o','l'); // volume level of all hardware const uint32 siHardwareVolumeSteps = FOURCC('h','s','t','p'); // number of volume steps for hardware const uint32 siHardwareBusy = FOURCC('h','w','b','s'); // sound hardware is in use const uint32 siHeadphoneMute = FOURCC('p','m','u','t'); // mute state of headphone const uint32 siHeadphoneVolume = FOURCC('p','v','o','l'); // volume level of headphone const uint32 siHeadphoneVolumeSteps = FOURCC('h','d','s','t'); // number of volume steps for headphone const uint32 siSpeakerMute = FOURCC('s','m','u','t'); // mute state of all built-in speakers const uint32 siSpeakerVolume = FOURCC('s','v','o','l'); // volume level of built-in speaker const uint32 siDeviceName = FOURCC('n','a','m','e'); const uint32 siDeviceIcon = FOURCC('i','c','o','n'); const uint32 siHardwareFormat = FOURCC('h','w','f','m'); enum { // ComponentResource struct componentType = 0, componentSubType = 4, componentManufacturer = 8, componentFlags = 12, componentFlagsMask = 16, componentResType = 20, componentResID = 24, componentNameType = 26, componentNameID = 30, componentInfoType = 32, componentInfoID = 36, componentIconType = 38, componentIconID = 42, componentVersion = 44, componentRegisterFlags = 48, componentIconFamily = 52, componentPFCount = 54, componentPFFlags = 58, componentPFResType = 62, componentPFResID = 66, componentPFPlatform = 68 }; // Component feature flags enum { k8BitRawIn = (1 << 0), k8BitTwosIn = (1 << 1), k16BitIn = (1 << 2), kStereoIn = (1 << 3), k8BitRawOut = (1 << 8), k8BitTwosOut = (1 << 9), k16BitOut = (1 << 10), kStereoOut = (1 << 11), kReverse = (1L << 16), kRateConvert = (1L << 17), kCreateSoundSource = (1L << 18), kHighQuality = (1L << 22), kNonRealTime = (1L << 23), cmpWantsRegisterMessage = (1L << 31) }; enum { // ComponentParameters struct cp_flags = 0, // call modifiers: sync/async, deferred, immed, etc cp_paramSize = 1, // size in bytes of actual parameters passed to this call cp_what = 2, // routine selector, negative for Component management calls cp_params = 4 // actual parameters for the indicated routine }; enum { // SoundComponentData struct scd_flags = 0, scd_format = 4, scd_numChannels = 8, scd_sampleSize = 10, scd_sampleRate = 12, scd_sampleCount = 16, scd_buffer = 20, scd_reserved = 24, SIZEOF_scd = 28 }; enum { // SoundInfoList struct sil_count = 0, sil_infoHandle = 2 }; #endif BasiliskII/src/include/serial_defs.h0000644000175000017500000000617310736405223017615 0ustar centriscentris/* * serial_defs.h - Definitions for MacOS serial drivers * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef SERIAL_DEFS_H #define SERIAL_DEFS_H // Error codes enum { rcvrErr = -89, breakRecd = -90 }; // Serial port configuration enum { baud150 = 763, baud300 = 380, baud600 = 189, baud1200 = 94, baud1800 = 62, baud2400 = 46, baud3600 = 30, baud4800 = 22, baud7200 = 14, baud9600 = 10, baud14400 = 6, baud19200 = 4, baud28800 = 2, baud38400 = 1, baud57600 = 0 }; enum { stop10 = 0x4000, stop15 = 0x8000, stop20 = 0xc000 }; enum { noParity = 0, oddParity = 0x1000, evenParity = 0x3000 }; enum { data5 = 0, data6 = 0x0800, data7 = 0x0400, data8 = 0x0c00 }; // Serial events enum { dsrEvent = 2, riEvent = 4, dcdEvent = 8, ctsEvent = 32, breakEvent = 128 }; // Flags for SerStaRec.xOffSent enum { xOffWasSent = 128, dtrNegated = 64, rtsNegated = 32 }; // Serial driver error masks enum { swOverrunErr = 1, breakErr = 8, parityErr = 16, hwOverrunErr = 32, framingErr = 64 }; // Option for kSERDMiscOptions enum { kOptionPreserveDTR = 128, kOptionClockX1CTS = 64 }; // Flags for SerShk.fCTS enum { kUseCTSOutputFlowControl = 128, kUseDSROutputFlowControl = 64, kUseRTSInputFlowControl = 128, kUseDTRInputFlowControl = 64 }; // Control codes enum { kSERDConfiguration = 8, kSERDInputBuffer = 9, kSERDSerHShake = 10, kSERDClearBreak = 11, kSERDSetBreak = 12, kSERDBaudRate = 13, kSERDHandshake = 14, kSERDClockMIDI = 15, kSERDMiscOptions = 16, kSERDAssertDTR = 17, kSERDNegateDTR = 18, kSERDSetPEChar = 19, kSERDSetPEAltChar = 20, kSERDSetXOffFlag = 21, kSERDClearXOffFlag = 22, kSERDSendXOn = 23, kSERDSendXOnOut = 24, kSERDSendXOff = 25, kSERDSendXOffOut = 26, kSERDResetChannel = 27, kSERDHandshakeRS232 = 28, kSERDStickParity = 29, kSERDAssertRTS = 30, kSERDNegateRTS = 31, kSERD115KBaud = 115, kSERD230KBaud = 230, kSERDSetHighSpeed = 0x4a46, // 'JF' kSERDSetPollWrite = 0x6a66 // 'jf' }; // Status codes enum { kSERDInputCount = 2, kSERDStatus = 8, kSERDVersion = 9, kSERDGetDCD = 256 }; enum { // SerShk struct shkFXOn = 0, shkFCTS = 1, shkXOn = 2, shkXOff = 3, shkErrs = 4, shkEvts = 5, shkFInX = 6, shkFDTR = 7 }; enum { // SerSta struct staCumErrs = 0, staXOffSent = 1, staRdPend = 2, staWrPend = 3, staCtsHold = 4, staXOffHold = 5, staDsrHold = 6, staModemStatus = 7 }; #endif BasiliskII/src/include/audio.h0000644000175000017500000000712210736405223016431 0ustar centriscentris/* * audio.h - Audio support * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef AUDIO_H #define AUDIO_H #include #ifndef NO_STD_NAMESPACE using std::vector; #endif extern int32 AudioDispatch(uint32 params, uint32 ti); extern bool AudioAvailable; // Flag: audio output available (from the software point of view) extern int16 SoundInOpen(uint32 pb, uint32 dce); extern int16 SoundInPrime(uint32 pb, uint32 dce); extern int16 SoundInControl(uint32 pb, uint32 dce); extern int16 SoundInStatus(uint32 pb, uint32 dce); extern int16 SoundInClose(uint32 pb, uint32 dce); // System specific and internal functions/data extern void AudioInit(void); extern void AudioExit(void); extern void AudioReset(void); extern void AudioInterrupt(void); extern void audio_enter_stream(void); extern void audio_exit_stream(void); extern bool audio_set_sample_rate(int index); extern bool audio_set_sample_size(int index); extern bool audio_set_channels(int index); extern bool audio_get_main_mute(void); extern uint32 audio_get_main_volume(void); extern bool audio_get_speaker_mute(void); extern uint32 audio_get_speaker_volume(void); extern void audio_set_main_mute(bool mute); extern void audio_set_main_volume(uint32 vol); extern void audio_set_speaker_mute(bool mute); extern void audio_set_speaker_volume(uint32 vol); // Current audio status struct audio_status { uint32 sample_rate; // 16.16 fixed point uint32 sample_size; // 8 or 16 uint32 channels; // 1 (mono) or 2 (stereo) uint32 mixer; // Mac address of Apple Mixer int num_sources; // Number of active sources }; extern struct audio_status AudioStatus; extern bool audio_open; // Flag: audio is open and ready extern int audio_frames_per_block; // Number of audio frames per block extern uint32 audio_component_flags; // Component feature flags extern vector audio_sample_rates; // Vector of supported sample rates (16.16 fixed point) extern vector audio_sample_sizes; // Vector of supported sample sizes extern vector audio_channel_counts; // Array of supported channels counts // Audio component global data and 68k routines enum { adatDelegateCall = 0, // 68k code to call DelegateCall() adatOpenMixer = 14, // 68k code to call OpenMixerSoundComponent() adatCloseMixer = 36, // 68k code to call CloseMixerSoundComponent() adatGetInfo = 54, // 68k code to call GetInfo() adatSetInfo = 78, // 68k code to call SetInfo() adatPlaySourceBuffer = 102, // 68k code to call PlaySourceBuffer() adatGetSourceData = 126, // 68k code to call GetSourceData() adatStartSource = 146, // 68k code to call StartSource() adatData = 168, // SoundComponentData struct adatMixer = 196, // Mac address of mixer, returned by adatOpenMixer adatStreamInfo = 200, // Mac address of stream info, returned by adatGetSourceData SIZEOF_adat = 204 }; extern uint32 audio_data; // Mac address of global data area #endif BasiliskII/src/include/cdrom.h0000644000175000017500000000266110736405223016437 0ustar centriscentris/* * cdrom.h - CD-ROM driver * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef CDROM_H #define CDROM_H const int CDROMRefNum = -62; // RefNum of driver const uint16 CDROMDriverFlags = 0x6d04; // Driver flags extern const uint8 CDROMIcon[258]; // Icon data (copied to ROM by PatchROM()) extern uint32 CDROMIconAddr; // Icon address (Mac address space, set by PatchROM()) extern void CDROMInit(void); extern void CDROMExit(void); extern void CDROMInterrupt(void); extern bool CDROMMountVolume(void *fh); extern int16 CDROMOpen(uint32 pb, uint32 dce); extern int16 CDROMPrime(uint32 pb, uint32 dce); extern int16 CDROMControl(uint32 pb, uint32 dce); extern int16 CDROMStatus(uint32 pb, uint32 dce); #endif BasiliskII/src/include/version.h0000644000175000017500000000170610736405223017017 0ustar centriscentris/* * version.h - Version information * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef VERSION_H #define VERSION_H const int VERSION_MAJOR = 1; const int VERSION_MINOR = 0; #define VERSION_STRING "Basilisk II V1.0" #endif BasiliskII/src/include/prefs.h0000644000175000017500000000525111232133661016444 0ustar centriscentris/* * prefs.h - Preferences handling * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef PREFS_H #define PREFS_H #include extern void PrefsInit(const char *vmdir, int &argc, char **&argv); extern void PrefsExit(void); extern void PrefsPrintUsage(void); extern void AddPrefsDefaults(void); extern void AddPlatformPrefsDefaults(void); // Preferences loading/saving extern void LoadPrefs(const char *vmdir); extern void SavePrefs(void); extern void LoadPrefsFromStream(FILE *f); extern void SavePrefsToStream(FILE *f); // Public preferences access functions extern void PrefsAddString(const char *name, const char *s); extern void PrefsAddBool(const char *name, bool b); extern void PrefsAddInt32(const char *name, int32 val); extern void PrefsReplaceString(const char *name, const char *s, int index = 0); extern void PrefsReplaceBool(const char *name, bool b); extern void PrefsReplaceInt32(const char *name, int32 val); extern const char *PrefsFindString(const char *name, int index = 0); extern bool PrefsFindBool(const char *name); extern int32 PrefsFindInt32(const char *name); extern void PrefsRemoveItem(const char *name, int index = 0); #ifdef SHEEPSHAVER // Platform specific functions: extern void prefs_init(); extern void prefs_exit(); #endif /* * Definition of preferences items */ // Item types enum prefs_type { TYPE_STRING, // char[] TYPE_BOOLEAN, // bool TYPE_INT32, // int32 TYPE_ANY, // Wildcard for find_node TYPE_END = TYPE_ANY // Terminator for prefs_desc list }; // Item descriptor struct prefs_desc { const char *name; // Name of keyword prefs_type type; // Type (see above) bool multiple; // Can this item occur multiple times (only for TYPE_STRING)? const char *help; // Help/descriptive text about this item }; // List of common preferences items (those which exist on all platforms) extern prefs_desc common_prefs_items[]; // List of platform-specific preferences items extern prefs_desc platform_prefs_items[]; #endif BasiliskII/src/emul_op.cpp0000644000175000017500000004022111340220101015653 0ustar centriscentris/* * emul_op.cpp - 68k opcodes for ROM patches * * Basilisk II (C) Christian Bauer * * 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 */ #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "macos_util.h" #include "rom_patches.h" #include "rsrc_patches.h" #include "xpram.h" #include "adb.h" #include "timer.h" #include "clip.h" #include "serial.h" #include "sony.h" #include "disk.h" #include "cdrom.h" #include "scsi.h" #include "video.h" #include "audio.h" #include "ether.h" #include "extfs.h" #include "emul_op.h" #ifdef ENABLE_MON #include "mon.h" #endif #define DEBUG 0 #include "debug.h" /* * Execute EMUL_OP opcode (called by 68k emulator or Illegal Instruction trap handler) */ void EmulOp(uint16 opcode, M68kRegisters *r) { D(bug("EmulOp %04x\n", opcode)); switch (opcode) { case M68K_EMUL_BREAK: { // Breakpoint printf("*** Breakpoint\n"); printf("d0 %08x d1 %08x d2 %08x d3 %08x\n" "d4 %08x d5 %08x d6 %08x d7 %08x\n" "a0 %08x a1 %08x a2 %08x a3 %08x\n" "a4 %08x a5 %08x a6 %08x a7 %08x\n" "sr %04x\n", r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7], r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7], r->sr); VideoQuitFullScreen(); #ifdef ENABLE_MON const char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); #endif QuitEmulator(); break; } case M68K_EMUL_OP_SHUTDOWN: // Quit emulator QuitEmulator(); break; case M68K_EMUL_OP_RESET: { // MacOS reset D(bug("*** RESET ***\n")); TimerReset(); EtherReset(); AudioReset(); // Create BootGlobs at top of memory Mac_memset(RAMBaseMac + RAMSize - 4096, 0, 4096); uint32 boot_globs = RAMBaseMac + RAMSize - 0x1c; WriteMacInt32(boot_globs + 0x00, RAMBaseMac); // First RAM bank WriteMacInt32(boot_globs + 0x04, RAMSize); WriteMacInt32(boot_globs + 0x08, 0xffffffff); // End of bank table WriteMacInt32(boot_globs + 0x0c, 0); // Setup registers for boot routine r->d[0] = ReadMacInt32(ROMBaseMac + UniversalInfo + 0x18); // AddrMapFlags r->d[1] = ReadMacInt32(ROMBaseMac + UniversalInfo + 0x1c); // UnivROMFlags r->d[2] = ReadMacInt32(ROMBaseMac + UniversalInfo + 0x10); // HWCfgFlags/IDs if (FPUType) r->d[2] |= 0x10000000; // Set FPU flag if FPU present else r->d[2] &= 0xefffffff; // Clear FPU flag if no FPU present r->a[0] = ROMBaseMac + UniversalInfo + ReadMacInt32(ROMBaseMac + UniversalInfo);// AddrMap r->a[1] = ROMBaseMac + UniversalInfo; // UniversalInfo r->a[6] = boot_globs; // BootGlobs r->a[7] = RAMBaseMac + 0x10000; // Boot stack break; } case M68K_EMUL_OP_CLKNOMEM: { // Clock/PRAM operations bool is_read = r->d[1] & 0x80; if ((r->d[1] & 0x78) == 0x38) { // XPRAM uint8 reg = (r->d[1] << 5) & 0xe0 | (r->d[1] >> 10) & 0x1f; if (is_read) { r->d[2] = XPRAM[reg]; bool localtalk = !(XPRAM[0xe0] || XPRAM[0xe1]); // LocalTalk enabled? switch (reg) { case 0x08: if (ROMVersion != ROM_VERSION_32) r->d[2] &= 0xf8; break; case 0x8a: r->d[2] |= 0x05; // 32bit mode is always enabled break; case 0xe0: // Disable LocalTalk (use EtherTalk instead) if (localtalk) r->d[2] = 0x00; break; case 0xe1: if (localtalk) r->d[2] = 0xf1; break; case 0xe2: if (localtalk) r->d[2] = 0x00; break; case 0xe3: if (localtalk) r->d[2] = 0x0a; break; } D(bug("Read XPRAM %02x->%02lx\n", reg, r->d[2])); } else { D(bug("Write XPRAM %02x<-%02lx\n", reg, r->d[2] & 0xff)); if (reg == 0x8a && !TwentyFourBitAddressing) r->d[2] |= 0x05; // 32bit mode is always enabled if possible XPRAM[reg] = r->d[2]; } } else { // PRAM, RTC and other clock registers uint8 reg = (r->d[1] >> 2) & 0x1f; if (reg >= 0x10 || (reg >= 0x08 && reg < 0x0c)) { if (is_read) { r->d[2] = XPRAM[reg]; D(bug("Read XPRAM %02x->%02x\n", reg, XPRAM[reg])); } else { D(bug("Write PRAM %02x<-%02lx\n", reg, r->d[2])); XPRAM[reg] = r->d[2]; } } else if (reg < 0x08 && is_read) { uint32 t = TimerDateTime(); uint8 b = t; switch (reg & 3) { case 1: b = t >> 8; break; case 2: b = t >> 16; break; case 3: b = t >> 24; break; } r->d[2] = b; } else D(bug("RTC %s op %d, d1 %08lx d2 %08lx\n", is_read ? "read" : "write", reg, r->d[1], r->d[2])); } r->d[0] = 0; r->d[1] = r->d[2]; break; } case M68K_EMUL_OP_READ_XPRAM: // Read from XPRAM (ROM10/11) D(bug("Read XPRAM %02lx\n", r->d[1])); r->d[1] = XPRAM[r->d[1] & 0xff]; break; case M68K_EMUL_OP_READ_XPRAM2: // Read from XPRAM (ROM15) D(bug("Read XPRAM %02lx\n", r->d[0])); r->d[0] = XPRAM[r->d[0] & 0xff]; break; case M68K_EMUL_OP_PATCH_BOOT_GLOBS: // Patch BootGlobs at startup D(bug("Patch BootGlobs\n")); WriteMacInt32(r->a[4] - 20, RAMBaseMac + RAMSize); // MemTop WriteMacInt8(r->a[4] - 26, 0); // No MMU WriteMacInt8(r->a[4] - 25, ReadMacInt8(r->a[4] - 25) | 1); // No MMU r->a[6] = RAMBaseMac + RAMSize; break; case M68K_EMUL_OP_FIX_BOOTSTACK: // Set boot stack to 3/4 of RAM (7.5) r->a[1] = RAMBaseMac + RAMSize * 3 / 4; D(bug("Fix boot stack %08x\n", r->a[1])); break; case M68K_EMUL_OP_FIX_MEMSIZE: { // Set correct logical and physical memory size D(bug("Fix MemSize\n")); uint32 diff = ReadMacInt32(0x1ef8) - ReadMacInt32(0x1ef4); // Difference between logical and physical size WriteMacInt32(0x1ef8, RAMSize); // Physical RAM size WriteMacInt32(0x1ef4, RAMSize - diff); // Logical RAM size break; } case M68K_EMUL_OP_ADBOP: // ADBOp() replacement ADBOp(r->d[0], Mac2HostAddr(ReadMacInt32(r->a[0]))); break; case M68K_EMUL_OP_INSTIME: // InsTime() replacement r->d[0] = InsTime(r->a[0], r->d[1]); break; case M68K_EMUL_OP_RMVTIME: // RmvTime() replacement r->d[0] = RmvTime(r->a[0]); break; case M68K_EMUL_OP_PRIMETIME: // PrimeTime() replacement r->d[0] = PrimeTime(r->a[0], r->d[0]); break; case M68K_EMUL_OP_MICROSECONDS: // Microseconds() replacement Microseconds(r->a[0], r->d[0]); break; case M68K_EMUL_OP_INSTALL_DRIVERS: {// Patch to install our own drivers during startup // Install drivers D(bug("InstallDrivers\n")); InstallDrivers(r->a[0]); // Install PutScrap() patch M68kRegisters r; if (PutScrapPatch) { r.d[0] = 0xa9fe; r.a[0] = PutScrapPatch; Execute68kTrap(0xa647, &r); // SetToolTrap() } // Install GetScrap() patch if (GetScrapPatch) { r.d[0] = 0xa9fd; r.a[0] = GetScrapPatch; Execute68kTrap(0xa647, &r); // SetToolTrap() } // Setup fake ASC registers if (ROMVersion == ROM_VERSION_32) { r.d[0] = 0x1000; Execute68kTrap(0xa71e, &r); // NewPtrSysClear() uint32 asc_regs = r.a[0]; D(bug("ASC registers at %08lx\n", asc_regs)); WriteMacInt8(asc_regs + 0x800, 0x0f); // Set ASC version number WriteMacInt32(0xcc0, asc_regs); // Set ASCBase } break; } case M68K_EMUL_OP_SERD: // Install serial drivers D(bug("InstallSERD\n")); InstallSERD(); break; case M68K_EMUL_OP_SONY_OPEN: // Floppy driver functions r->d[0] = SonyOpen(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SONY_PRIME: r->d[0] = SonyPrime(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SONY_CONTROL: r->d[0] = SonyControl(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SONY_STATUS: r->d[0] = SonyStatus(r->a[0], r->a[1]); break; case M68K_EMUL_OP_DISK_OPEN: // Disk driver functions r->d[0] = DiskOpen(r->a[0], r->a[1]); break; case M68K_EMUL_OP_DISK_PRIME: r->d[0] = DiskPrime(r->a[0], r->a[1]); break; case M68K_EMUL_OP_DISK_CONTROL: r->d[0] = DiskControl(r->a[0], r->a[1]); break; case M68K_EMUL_OP_DISK_STATUS: r->d[0] = DiskStatus(r->a[0], r->a[1]); break; case M68K_EMUL_OP_CDROM_OPEN: // CD-ROM driver functions r->d[0] = CDROMOpen(r->a[0], r->a[1]); break; case M68K_EMUL_OP_CDROM_PRIME: r->d[0] = CDROMPrime(r->a[0], r->a[1]); break; case M68K_EMUL_OP_CDROM_CONTROL: r->d[0] = CDROMControl(r->a[0], r->a[1]); break; case M68K_EMUL_OP_CDROM_STATUS: r->d[0] = CDROMStatus(r->a[0], r->a[1]); break; case M68K_EMUL_OP_VIDEO_OPEN: // Video driver functions r->d[0] = VideoDriverOpen(r->a[0], r->a[1]); break; case M68K_EMUL_OP_VIDEO_CONTROL: r->d[0] = VideoDriverControl(r->a[0], r->a[1]); break; case M68K_EMUL_OP_VIDEO_STATUS: r->d[0] = VideoDriverStatus(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SERIAL_OPEN: // Serial driver functions r->d[0] = SerialOpen(r->a[0], r->a[1], r->d[0]); break; case M68K_EMUL_OP_SERIAL_PRIME: r->d[0] = SerialPrime(r->a[0], r->a[1], r->d[0]); break; case M68K_EMUL_OP_SERIAL_CONTROL: r->d[0] = SerialControl(r->a[0], r->a[1], r->d[0]); break; case M68K_EMUL_OP_SERIAL_STATUS: r->d[0] = SerialStatus(r->a[0], r->a[1], r->d[0]); break; case M68K_EMUL_OP_SERIAL_CLOSE: r->d[0] = SerialClose(r->a[0], r->a[1], r->d[0]); break; case M68K_EMUL_OP_ETHER_OPEN: // Ethernet driver functions r->d[0] = EtherOpen(r->a[0], r->a[1]); break; case M68K_EMUL_OP_ETHER_CONTROL: r->d[0] = EtherControl(r->a[0], r->a[1]); break; case M68K_EMUL_OP_ETHER_READ_PACKET: EtherReadPacket(r->a[0], r->a[3], r->d[3], r->d[1]); break; case M68K_EMUL_OP_SOUNDIN_OPEN: // Sound input driver functions r->d[0] = SoundInOpen(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SOUNDIN_PRIME: r->d[0] = SoundInPrime(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SOUNDIN_CONTROL: r->d[0] = SoundInControl(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SOUNDIN_STATUS: r->d[0] = SoundInStatus(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SOUNDIN_CLOSE: r->d[0] = SoundInClose(r->a[0], r->a[1]); break; case M68K_EMUL_OP_SCSI_DISPATCH: { // SCSIDispatch() replacement uint32 ret = ReadMacInt32(r->a[7]); // Get return address uint16 sel = ReadMacInt16(r->a[7] + 4); // Get selector r->a[7] += 6; int stack = 0; switch (sel) { case 0: // SCSIReset WriteMacInt16(r->a[7], SCSIReset()); stack = 0; break; case 1: // SCSIGet WriteMacInt16(r->a[7], SCSIGet()); stack = 0; break; case 2: // SCSISelect case 11: // SCSISelAtn WriteMacInt16(r->a[7] + 2, SCSISelect(ReadMacInt16(r->a[7]) & 0xff)); stack = 2; break; case 3: // SCSICmd WriteMacInt16(r->a[7] + 6, SCSICmd(ReadMacInt16(r->a[7]), Mac2HostAddr(ReadMacInt32(r->a[7] + 2)))); stack = 6; break; case 4: // SCSIComplete WriteMacInt16(r->a[7] + 12, SCSIComplete(ReadMacInt32(r->a[7]), ReadMacInt32(r->a[7] + 4), ReadMacInt32(r->a[7] + 8))); stack = 12; break; case 5: // SCSIRead case 8: // SCSIRBlind WriteMacInt16(r->a[7] + 4, SCSIRead(ReadMacInt32(r->a[7]))); stack = 4; break; case 6: // SCSIWrite case 9: // SCSIWBlind WriteMacInt16(r->a[7] + 4, SCSIWrite(ReadMacInt32(r->a[7]))); stack = 4; break; case 10: // SCSIStat WriteMacInt16(r->a[7], SCSIStat()); stack = 0; break; case 12: // SCSIMsgIn WriteMacInt16(r->a[7] + 4, 0); stack = 4; break; case 13: // SCSIMsgOut WriteMacInt16(r->a[7] + 2, 0); stack = 2; break; case 14: // SCSIMgrBusy WriteMacInt16(r->a[7], SCSIMgrBusy()); stack = 0; break; default: printf("FATAL: SCSIDispatch(%d): illegal selector\n", sel); QuitEmulator(); break; } r->a[0] = ret; // "rtd" emulation, a0 = return address, a1 = new stack pointer r->a[1] = r->a[7] + stack; break; } case M68K_EMUL_OP_IRQ: // Level 1 interrupt r->d[0] = 0; if (InterruptFlags & INTFLAG_60HZ) { ClearInterruptFlag(INTFLAG_60HZ); // Increment Ticks variable WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); if (HasMacStarted()) { // Mac has started, execute all 60Hz interrupt functions TimerInterrupt(); VideoInterrupt(); // Call DoVBLTask(0) if (ROMVersion == ROM_VERSION_32) { M68kRegisters r2; r2.d[0] = 0; Execute68kTrap(0xa072, &r2); } r->d[0] = 1; // Flag: 68k interrupt routine executes VBLTasks etc. } } if (InterruptFlags & INTFLAG_1HZ) { ClearInterruptFlag(INTFLAG_1HZ); if (HasMacStarted()) { SonyInterrupt(); DiskInterrupt(); CDROMInterrupt(); } } if (InterruptFlags & INTFLAG_SERIAL) { ClearInterruptFlag(INTFLAG_SERIAL); SerialInterrupt(); } if (InterruptFlags & INTFLAG_ETHER) { ClearInterruptFlag(INTFLAG_ETHER); EtherInterrupt(); } if (InterruptFlags & INTFLAG_AUDIO) { ClearInterruptFlag(INTFLAG_AUDIO); AudioInterrupt(); } if (InterruptFlags & INTFLAG_ADB) { ClearInterruptFlag(INTFLAG_ADB); if (HasMacStarted()) ADBInterrupt(); } if (InterruptFlags & INTFLAG_NMI) { ClearInterruptFlag(INTFLAG_NMI); if (HasMacStarted()) TriggerNMI(); } break; case M68K_EMUL_OP_PUT_SCRAP: { // PutScrap() patch void *scrap = Mac2HostAddr(ReadMacInt32(r->a[7] + 4)); uint32 type = ReadMacInt32(r->a[7] + 8); int32 length = ReadMacInt32(r->a[7] + 12); PutScrap(type, scrap, length); break; } case M68K_EMUL_OP_GET_SCRAP: { // GetScrap() patch void **scrap_handle = (void **)Mac2HostAddr(ReadMacInt32(r->a[7] + 4)); uint32 type = ReadMacInt32(r->a[7] + 8); int32 length = ReadMacInt32(r->a[7] + 12); GetScrap(scrap_handle, type, length); break; } case M68K_EMUL_OP_CHECKLOAD: { // vCheckLoad() patch (resource loader) uint32 type = r->d[1]; int16 id = ReadMacInt16(r->a[2]); if (r->a[0] == 0) break; uint32 adr = ReadMacInt32(r->a[0]); if (adr == 0) break; uint8 *p = Mac2HostAddr(adr); uint32 size = ReadMacInt32(adr - 8) & 0xffffff; CheckLoad(type, id, p, size); break; } case M68K_EMUL_OP_AUDIO: // Audio component dispatch function r->d[0] = AudioDispatch(r->a[3], r->a[4]); break; #if SUPPORTS_EXTFS case M68K_EMUL_OP_EXTFS_COMM: // External file system routines WriteMacInt16(r->a[7] + 14, ExtFSComm(ReadMacInt16(r->a[7] + 12), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 4))); break; case M68K_EMUL_OP_EXTFS_HFS: WriteMacInt16(r->a[7] + 20, ExtFSHFS(ReadMacInt32(r->a[7] + 16), ReadMacInt16(r->a[7] + 14), ReadMacInt32(r->a[7] + 10), ReadMacInt32(r->a[7] + 6), ReadMacInt16(r->a[7] + 4))); break; #endif case M68K_EMUL_OP_BLOCK_MOVE: // BlockMove() cache flushing FlushCodeCache(Mac2HostAddr(r->a[0]), r->a[1]); break; case M68K_EMUL_OP_DEBUGUTIL: // printf("DebugUtil d0=%08lx a5=%08lx\n", r->d[0], r->a[5]); r->d[0] = DebugUtil(r->d[0]); break; case M68K_EMUL_OP_IDLE_TIME: // SynchIdleTime() patch // Sleep if no events pending if (ReadMacInt32(0x14c) == 0) idle_wait(); r->a[0] = ReadMacInt32(0x2b6); break; default: printf("FATAL: EMUL_OP called with bogus opcode %08x\n", opcode); printf("d0 %08x d1 %08x d2 %08x d3 %08x\n" "d4 %08x d5 %08x d6 %08x d7 %08x\n" "a0 %08x a1 %08x a2 %08x a3 %08x\n" "a4 %08x a5 %08x a6 %08x a7 %08x\n" "sr %04x\n", r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7], r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7], r->sr); #ifdef ENABLE_MON const char *arg[4] = {"mon", "-m", "-r", NULL}; mon(3, arg); #endif QuitEmulator(); break; } } BasiliskII/src/powerrom_cpu/0000755000175000017500000000000011735674751016271 5ustar centriscentrisBasiliskII/src/powerrom_cpu/cpu_emulation.h0000644000175000017500000000521710736405223021275 0ustar centriscentris/* * cpu_emulation.h - Definitions for Basilisk II CPU emulation module (Apple PowerMac ROM 680x0 emulator version (BeOS/PPC)) * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #ifndef CPU_EMULATION_H #define CPU_EMULATION_H /* * Memory system */ // RAM and ROM pointers (allocated and set by main_*.cpp) extern uint32 RAMBaseMac; // RAM base (Mac address space), does not include Low Mem when != 0 extern uint8 *RAMBaseHost; // RAM base (host address space) extern uint32 RAMSize; // Size of RAM extern uint32 ROMBaseMac; // ROM base (Mac address space) extern uint8 *ROMBaseHost; // ROM base (host address space) extern uint32 ROMSize; // Size of ROM // Mac memory access functions static inline uint32 ReadMacInt32(uint32 addr) {return ntohl(*(uint32 *)addr);} static inline uint32 ReadMacInt16(uint32 addr) {return ntohs(*(uint16 *)addr);} static inline uint32 ReadMacInt8(uint32 addr) {return *(uint8 *)addr;} static inline void WriteMacInt32(uint32 addr, uint32 l) {*(uint32 *)addr = htonl(l);} static inline void WriteMacInt16(uint32 addr, uint32 w) {*(uint16 *)addr = htons(w);} static inline void WriteMacInt8(uint32 addr, uint32 b) {*(uint8 *)addr = b;} static inline uint8 *Mac2HostAddr(uint32 addr) {return (uint8 *)addr;} static inline uint32 Host2MacAddr(uint8 *addr) {return (uint32)addr;} /* * 680x0 emulation */ // Initialization extern bool Init680x0(void); // This routine may want to look at CPUType/FPUType to set up the apropriate emulation extern void Exit680x0(void); // 680x0 emulation functions struct M68kRegisters; extern void Start680x0(void); // Reset and start 680x0 extern "C" void Execute68k(uint32 addr, M68kRegisters *r); // Execute 68k code from EMUL_OP routine extern "C" void Execute68kTrap(uint16 trap, M68kRegisters *r); // Execute MacOS 68k trap from EMUL_OP routine // Interrupt functions extern void TriggerInterrupt(void); // Trigger interrupt (InterruptFlag must be set first) #endif BasiliskII/src/powerrom_cpu/powerrom_cpu.cpp0000644000175000017500000011666110736405223021513 0ustar centriscentris/* * powerrom_cpu.cpp - Using the 680x0 emulator in PowerMac ROMs for Basilisk II * * Basilisk II (C) 1997-2008 Christian Bauer * * 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 */ #include #include #include #include #include #include #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" #include "emul_op.h" #include "prefs.h" #include "timer.h" #include "user_strings.h" #include "sheep_driver.h" #define DEBUG 0 #include "debug.h" // Save FP regs in Execute68k()? #define SAVE_FP_EXEC_68K 0 // Constants const char ROM_FILE_NAME[] = "PowerROM"; const char KERNEL_AREA_NAME[] = "Macintosh Kernel Data"; const char DR_CACHE_AREA_NAME[] = "Macintosh DR Cache"; const uint32 ROM_BASE = 0x40800000; // Base address of ROM const uint32 ROM_SIZE = 0x00400000; // Size of ROM file const uint32 ROM_AREA_SIZE = 0x00500000; // Size of ROM area const uint32 DR_CACHE_BASE = 0x69000000; // Address of DR cache const uint32 DR_CACHE_SIZE = 0x80000; // Size of DR Cache const uint32 SIG_STACK_SIZE = 8192; // Size of signal stack // PowerPC opcodes const uint32 POWERPC_NOP = 0x60000000; const uint32 POWERPC_ILLEGAL = 0x00000000; const uint32 POWERPC_BLR = 0x4e800020; const uint32 POWERPC_BCTR = 0x4e800420; // Extra Low Memory Globals #define MODE_68K 0 // 68k emulator active #define MODE_EMUL_OP 1 // Within EMUL_OP routine #define XLM_RESET_STACK 0x2800 // Reset stack pointer #define XLM_KERNEL_DATA 0x2804 // Pointer to Kernel Data #define XLM_TOC 0x2808 // TOC pointer of emulator #define XLM_RUN_MODE 0x2810 // Current run mode, see enum above #define XLM_68K_R25 0x2814 // Contents of the 68k emulator's r25 (which contains the interrupt level), saved upon entering EMUL_OP mode, used by Execute68k() and the USR1 signal handler #define XLM_IRQ_NEST 0x2818 // Interrupt disable nesting counter (>0: disabled) #define XLM_PVR 0x281c // Theoretical PVR #define XLM_EMUL_RETURN_PROC 0x2824 // Pointer to EMUL_RETURN routine #define XLM_EXEC_RETURN_PROC 0x2828 // Pointer to EXEC_RETURN routine #define XLM_EMUL_OP_PROC 0x282c // Pointer to EMUL_OP routine #define XLM_EMUL_RETURN_STACK 0x2830 // Stack pointer for EMUL_RETURN // RAM and ROM pointers uint32 RAMBaseMac; // RAM base (Mac address space) uint8 *RAMBaseHost; // RAM base (host address space) uint32 RAMSize; // Size of RAM uint32 ROMBaseMac; // ROM base (Mac address space) uint8 *ROMBaseHost; // ROM base (host address space) uint32 ROMSize; // Size of ROM // Emulator Data struct EmulatorData { uint32 v[0x400]; }; // Kernel Data struct KernelData { uint32 v[0x400]; EmulatorData ed; }; // Exceptions class file_open_error {}; class file_read_error {}; class rom_size_error {}; // Global variables static void *TOC; // TOC pointer static uint32 PVR; // Theoretical PVR static int64 CPUClockSpeed; // Processor clock speed (Hz) static int64 BusClockSpeed; // Bus clock speed (Hz) static system_info SysInfo; // System information static area_id kernel_area = -1; // Kernel Data area ID static KernelData *kernel_data = NULL; // Pointer to Kernel Data static uint32 KernelDataAddr; // Address of Kernel Data static EmulatorData *emulator_data = NULL; static area_id dr_cache_area; // DR Cache area ID static uint32 DRCacheAddr; // Address of DR Cache static struct sigaction sigusr1_action; // Interrupt signal (of emulator thread) static bool ReadyForSignals = false; // Flag: emul_thread ready to receive signals // Prototypes static void sigusr1_handler(int sig, void *arg, vregs *r); // From main_beos.cpp extern int sheep_fd; // fd of sheep driver extern thread_id emul_thread; // Emulator thread /* * Load ROM file (upper 3MB) * * file_open_error: Cannot open ROM file (nor use built-in ROM) * file_read_error: Cannot read ROM file */ // Decode LZSS data static void decode_lzss(const uint8 *src, uint8 *dest, int size) { char dict[0x1000]; int run_mask = 0, dict_idx = 0xfee; for (;;) { if (run_mask < 0x100) { // Start new run if (--size < 0) break; run_mask = *src++ | 0xff00; } bool bit = run_mask & 1; run_mask >>= 1; if (bit) { // Verbatim copy if (--size < 0) break; int c = *src++; dict[dict_idx++] = c; *dest++ = c; dict_idx &= 0xfff; } else { // Copy from dictionary if (--size < 0) break; int idx = *src++; if (--size < 0) break; int cnt = *src++; idx |= (cnt << 4) & 0xf00; cnt = (cnt & 0x0f) + 3; while (cnt--) { char c = dict[idx++]; dict[dict_idx++] = c; *dest++ = c; idx &= 0xfff; dict_idx &= 0xfff; } } } } static void load_rom(void) { // Get rom file path from preferences const char *rom_path = PrefsFindString("powerrom"); // Try to open ROM file BFile file(rom_path ? rom_path : ROM_FILE_NAME, B_READ_ONLY); if (file.InitCheck() != B_NO_ERROR) { // Failed, then ask sheep driver for ROM uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work ssize_t actual = read(sheep_fd, (void *)rom, ROM_SIZE); if (actual == ROM_SIZE) { // Copy upper 3MB memcpy((void *)(ROM_BASE + 0x100000), rom + 0x100000, ROM_SIZE - 0x100000); delete[] rom; return; } else throw file_open_error(); } printf(GetString(STR_READING_ROM_FILE)); // Get file size off_t rom_size = 0; file.GetSize(&rom_size); uint8 *rom = new uint8[ROM_SIZE]; // Reading directly into the area doesn't work ssize_t actual = file.Read((void *)rom, ROM_SIZE); if (actual == ROM_SIZE) { // Plain ROM image, copy upper 3MB memcpy((void *)(ROM_BASE + 0x100000), rom + 0x100000, ROM_SIZE - 0x100000); delete[] rom; } else { if (strncmp((char *)rom, "", 11) == 0) { // CHRP compressed ROM image D(bug("CHRP ROM image\n")); uint32 lzss_offset, lzss_size; char *s = strstr((char *)rom, "constant lzss-offset"); if (s == NULL) throw rom_size_error(); s -= 7; if (sscanf(s, "%06lx", &lzss_offset) != 1) throw rom_size_error(); s = strstr((char *)rom, "constant lzss-size"); if (s == NULL) throw rom_size_error(); s -= 7; if (sscanf(s, "%06lx", &lzss_size) != 1) throw rom_size_error(); D(bug("Offset of compressed data: %08lx\n", lzss_offset)); D(bug("Size of compressed data: %08lx\n", lzss_size)); D(bug("Uncompressing ROM...\n")); uint8 *decoded = new uint8[ROM_SIZE]; decode_lzss(rom + lzss_offset, decoded, lzss_size); memcpy((void *)(ROM_BASE + 0x100000), decoded + 0x100000, ROM_SIZE - 0x100000); delete[] decoded; delete[] rom; } else if (rom_size != 4*1024*1024) throw rom_size_error(); else throw file_read_error(); } } /* * Patch PowerMac ROM */ // ROM type enum { ROMTYPE_TNT, ROMTYPE_ALCHEMY, ROMTYPE_ZANZIBAR, ROMTYPE_GAZELLE, ROMTYPE_NEWWORLD }; static int ROMType; // Nanokernel boot routine patches static bool patch_nanokernel_boot(void) { uint32 *lp; int i; // Patch ConfigInfo lp = (uint32 *)(ROM_BASE + 0x30d000); lp[0x9c >> 2] = KernelDataAddr; // LA_InfoRecord lp[0xa0 >> 2] = KernelDataAddr; // LA_KernelData lp[0xa4 >> 2] = KernelDataAddr + 0x1000;// LA_EmulatorData lp[0xa8 >> 2] = ROM_BASE + 0x480000; // LA_DispatchTable lp[0xac >> 2] = ROM_BASE + 0x460000; // LA_EmulatorCode lp[0x360 >> 2] = 0; // Physical RAM base (? on NewWorld ROM, this contains -1) lp[0xfd8 >> 2] = ROM_BASE + 0x2a; // 68k reset vector // Skip SR/BAT/SDR init if (ROMType == ROMTYPE_GAZELLE || ROMType == ROMTYPE_NEWWORLD) { lp = (uint32 *)(ROM_BASE + 0x310000); *lp++ = POWERPC_NOP; *lp = 0x38000000; } static const uint32 sr_init_loc[] = {0x3101b0, 0x3101b0, 0x3101b0, 0x3101ec, 0x310200}; lp = (uint32 *)(ROM_BASE + 0x310008); *lp = 0x48000000 | (sr_init_loc[ROMType] - 8) & 0xffff; // b ROM_BASE+0x3101b0 lp = (uint32 *)(ROM_BASE + sr_init_loc[ROMType]); *lp++ = 0x80200000 + XLM_KERNEL_DATA; // lwz r1,(pointer to Kernel Data) *lp++ = 0x3da0dead; // lis r13,0xdead (start of kernel memory) *lp++ = 0x3dc00010; // lis r14,0x0010 (size of page table) *lp = 0x3de00010; // lis r15,0x0010 (size of kernel memory) // Don't read PVR static const uint32 pvr_loc[] = {0x3103b0, 0x3103b4, 0x3103b4, 0x310400, 0x310438}; lp = (uint32 *)(ROM_BASE + pvr_loc[ROMType]); *lp = 0x81800000 + XLM_PVR; // lwz r12,(theoretical PVR) // Set CPU specific data (even if ROM doesn't have support for that CPU) lp = (uint32 *)(ROM_BASE + pvr_loc[ROMType]); if (ntohl(lp[6]) != 0x2c0c0001) return false; uint32 ofs = lp[7] & 0xffff; lp[8] = (lp[8] & 0xffff) | 0x48000000; // beq -> b uint32 loc = (lp[8] & 0xffff) + (uint32)(lp+8) - ROM_BASE; lp = (uint32 *)(ROM_BASE + ofs + 0x310000); switch (PVR >> 16) { case 1: // 601 lp[0] = 0x1000; // Page size lp[1] = 0x8000; // Data cache size lp[2] = 0x8000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00010040; // Unified caches/Inst cache line size lp[5] = 0x00400020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc lp[8] = 0x01000002; // TLB total size/TLB assoc break; case 3: // 603 lp[0] = 0x1000; // Page size lp[1] = 0x2000; // Data cache size lp[2] = 0x2000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00000020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00020002; // Inst cache assoc/Data cache assoc lp[8] = 0x00400002; // TLB total size/TLB assoc break; case 4: // 604 lp[0] = 0x1000; // Page size lp[1] = 0x4000; // Data cache size lp[2] = 0x4000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00000020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00040004; // Inst cache assoc/Data cache assoc lp[8] = 0x00800002; // TLB total size/TLB assoc break; // case 5: // 740? case 6: // 603e case 7: // 603ev lp[0] = 0x1000; // Page size lp[1] = 0x4000; // Data cache size lp[2] = 0x4000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00000020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00040004; // Inst cache assoc/Data cache assoc lp[8] = 0x00400002; // TLB total size/TLB assoc break; case 8: // 750 lp[0] = 0x1000; // Page size lp[1] = 0x8000; // Data cache size lp[2] = 0x8000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00000020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc lp[8] = 0x00800002; // TLB total size/TLB assoc break; case 9: // 604e case 10: // 604ev5 lp[0] = 0x1000; // Page size lp[1] = 0x8000; // Data cache size lp[2] = 0x8000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00000020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00040004; // Inst cache assoc/Data cache assoc lp[8] = 0x00800002; // TLB total size/TLB assoc break; // case 11: // X704? case 12: // ??? lp[0] = 0x1000; // Page size lp[1] = 0x8000; // Data cache size lp[2] = 0x8000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00000020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc lp[8] = 0x00800002; // TLB total size/TLB assoc break; case 13: // ??? lp[0] = 0x1000; // Page size lp[1] = 0x8000; // Data cache size lp[2] = 0x8000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00000020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc lp[8] = 0x01000004; // TLB total size/TLB assoc break; // case 50: // 821 // case 80: // 860 case 96: // ??? lp[0] = 0x1000; // Page size lp[1] = 0x8000; // Data cache size lp[2] = 0x8000; // Inst cache size lp[3] = 0x00200020; // Coherency block size/Reservation granule size lp[4] = 0x00010020; // Unified caches/Inst cache line size lp[5] = 0x00200020; // Data cache line size/Data cache block size touch lp[6] = 0x00200020; // Inst cache block size/Data cache block size lp[7] = 0x00080008; // Inst cache assoc/Data cache assoc lp[8] = 0x00800004; // TLB total size/TLB assoc break; default: printf("WARNING: Unknown CPU type\n"); break; } // Don't set SPRG3, don't test MQ lp = (uint32 *)(ROM_BASE + loc + 0x20); *lp++ = POWERPC_NOP; lp++; *lp++ = POWERPC_NOP; lp++; *lp = POWERPC_NOP; // Don't read MSR lp = (uint32 *)(ROM_BASE + loc + 0x40); *lp = 0x39c00000; // li r14,0 // Don't write to DEC lp = (uint32 *)(ROM_BASE + loc + 0x70); *lp++ = POWERPC_NOP; loc = (lp[0] & 0xffff) + (uint32)lp - ROM_BASE; // Don't set SPRG3 lp = (uint32 *)(ROM_BASE + loc + 0x2c); *lp = POWERPC_NOP; // Don't read PVR static const uint32 pvr_ofs[] = {0x138, 0x138, 0x138, 0x140, 0x148}; lp = (uint32 *)(ROM_BASE + loc + pvr_ofs[ROMType]); *lp = 0x82e00000 + XLM_PVR; // lwz r23,(theoretical PVR) lp = (uint32 *)(ROM_BASE + loc + 0x170); if (*lp == 0x7eff42a6) // NewWorld ROM *lp = 0x82e00000 + XLM_PVR; // lwz r23,(theoretical PVR) lp = (uint32 *)(ROM_BASE + 0x313134); if (*lp == 0x7e5f42a6) *lp = 0x82400000 + XLM_PVR; // lwz r18,(theoretical PVR) lp = (uint32 *)(ROM_BASE + 0x3131f4); if (*lp == 0x7e5f42a6) // NewWorld ROM *lp = 0x82400000 + XLM_PVR; // lwz r18,(theoretical PVR) // Don't read SDR1 static const uint32 sdr1_ofs[] = {0x174, 0x174, 0x174, 0x17c, 0x19c}; lp = (uint32 *)(ROM_BASE + loc + sdr1_ofs[ROMType]); *lp++ = 0x3d00dead; // lis r8,0xdead (pointer to page table) *lp++ = 0x3ec0001f; // lis r22,0x001f (size of page table) *lp = POWERPC_NOP; // Don't clear page table static const uint32 pgtb_ofs[] = {0x198, 0x198, 0x198, 0x1a0, 0x1c4}; lp = (uint32 *)(ROM_BASE + loc + pgtb_ofs[ROMType]); *lp = POWERPC_NOP; // Don't invalidate TLB static const uint32 tlb_ofs[] = {0x1a0, 0x1a0, 0x1a0, 0x1a8, 0x1cc}; lp = (uint32 *)(ROM_BASE + loc + tlb_ofs[ROMType]); *lp = POWERPC_NOP; // Don't create RAM descriptor table static const uint32 desc_ofs[] = {0x350, 0x350, 0x350, 0x358, 0x37c}; lp = (uint32 *)(ROM_BASE + loc + desc_ofs[ROMType]); *lp = POWERPC_NOP; // Don't load SRs and BATs static const uint32 sr_ofs[] = {0x3d8, 0x3d8, 0x3d8, 0x3e0, 0x404}; lp = (uint32 *)(ROM_BASE + loc + sr_ofs[ROMType]); *lp = POWERPC_NOP; // Don't mess with SRs static const uint32 sr2_ofs[] = {0x312118, 0x312118, 0x312118, 0x312118, 0x3121b4}; lp = (uint32 *)(ROM_BASE + sr2_ofs[ROMType]); *lp = POWERPC_BLR; // Don't check performance monitor static const uint32 pm_ofs[] = {0x313148, 0x313148, 0x313148, 0x313148, 0x313218}; lp = (uint32 *)(ROM_BASE + pm_ofs[ROMType]); while (*lp != 0x7e58eba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e78eaa6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e59eba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e79eaa6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e5aeba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e7aeaa6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e5beba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e7beaa6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e5feba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e7feaa6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e5ceba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e7ceaa6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e5deba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e7deaa6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e5eeba6) lp++; *lp++ = POWERPC_NOP; while (*lp != 0x7e7eeaa6) lp++; *lp++ = POWERPC_NOP; // Jump to 68k emulator static const uint32 jump68k_ofs[] = {0x40c, 0x40c, 0x40c, 0x414, 0x438}; lp = (uint32 *)(ROM_BASE + loc + jump68k_ofs[ROMType]); *lp++ = 0x80610634; // lwz r3,0x0634(r1) (pointer to Emulator Data) *lp++ = 0x8081119c; // lwz r4,0x119c(r1) (pointer to opcode table) *lp++ = 0x80011184; // lwz r0,0x1184(r1) (pointer to emulator entry) *lp++ = 0x7c0903a6; // mtctr r0 *lp = POWERPC_BCTR; return true; } // 68k emulator patches static bool patch_68k_emul(void) { uint32 *lp; uint32 base; // Overwrite twi instructions static const uint32 twi_loc[] = {0x36e680, 0x36e6c0, 0x36e6c0, 0x36e6c0, 0x36e740}; base = twi_loc[ROMType]; lp = (uint32 *)(ROM_BASE + base); *lp++ = 0x48000000 + 0x36f900 - base; // b 0x36f900 (Emulator start) *lp++ = POWERPC_ILLEGAL; *lp++ = 0x48000000 + 0x36fb00 - base - 8; // b 0x36fb00 (Reset opcode) *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; *lp++ = POWERPC_ILLEGAL; // Set reset stack pointer lp = (uint32 *)(ROM_BASE + base + 0xf0); *lp++ = 0x80200000 + XLM_RESET_STACK; // lwz r1,XLM_RESET_STACK // Install EXEC_RETURN and EMUL_OP opcodes lp = (uint32 *)(ROM_BASE + 0x380000 + (M68K_EXEC_RETURN << 3)); *lp++ = 0x80000000 + XLM_EXEC_RETURN_PROC; // lwz r0,XLM_EXEC_RETURN_PROC *lp++ = 0x4bfb6ffc; // b 0x36f800 for (int i=0; i> 16); // lis r0,xxx *lp++ = 0x60000000 + ((ROM_BASE + 0x46d0a4) & 0xffff); // ori r0,r0,xxx *lp++ = 0x7c0903a6; // mtctr r0 *lp = POWERPC_BCTR; // bctr return true; } // Nanokernel patches static bool patch_nanokernel(void) { uint32 *lp; // Patch 68k emulator trap routine lp = (uint32 *)(ROM_BASE + 0x312994); // Always restore FPU state while (*lp != 0x39260040) lp++; lp--; *lp = 0x48000441; // bl 0x00312dd4 lp = (uint32 *)(ROM_BASE + 0x312dd8); // Don't modify MSR to turn on FPU while (*lp != 0x810600e4) lp++; lp--; *lp++ = POWERPC_NOP; lp += 2; *lp++ = POWERPC_NOP; lp++; *lp++ = POWERPC_NOP; *lp++ = POWERPC_NOP; *lp = POWERPC_NOP; // Patch trap return routine lp = (uint32 *)(ROM_BASE + 0x312c20); while (*lp != 0x7d5a03a6) lp++; *lp++ = 0x7d4903a6; // mtctr r10 *lp++ = 0x7daff120; // mtcr r13 *lp++ = 0x48000000 + 0x8000 - ((uint32)lp & 0xffff); // b ROM_BASE+0x318000 uint32 xlp = (uint32)lp & 0xffff; lp = (uint32 *)(ROM_BASE + 0x312c50); // Replace rfi while (*lp != 0x4c000064) lp++; *lp = POWERPC_BCTR; lp = (uint32 *)(ROM_BASE + 0x318000); *lp++ = 0x81400000 + XLM_IRQ_NEST; // lwz r10,XLM_IRQ_NEST *lp++ = 0x394affff; // subi r10,r10,1 *lp++ = 0x91400000 + XLM_IRQ_NEST; // stw r10,XLM_IRQ_NEST *lp = 0x48000000 + ((xlp - 0x800c) & 0x03fffffc); // b ROM_BASE+0x312c2c return true; } static bool patch_rom(void) { // Detect ROM type if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot TNT", 8)) ROMType = ROMTYPE_TNT; else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Alchemy", 12)) ROMType = ROMTYPE_ALCHEMY; else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Zanzibar", 13)) ROMType = ROMTYPE_ZANZIBAR; else if (!memcmp((void *)(ROM_BASE + 0x30d064), "Boot Gazelle", 12)) ROMType = ROMTYPE_GAZELLE; else if (!memcmp((void *)(ROM_BASE + 0x30d064), "NewWorld", 8)) ROMType = ROMTYPE_NEWWORLD; else return false; // Apply patches if (!patch_nanokernel_boot()) return false; if (!patch_68k_emul()) return false; if (!patch_nanokernel()) return false; // Copy 68k emulator to 2MB boundary memcpy((void *)(ROM_BASE + ROM_SIZE), (void *)(ROM_BASE + ROM_SIZE - 0x100000), 0x100000); return true; } /* * Initialize 680x0 emulation */ static asm void *get_toc(void) { mr r3,r2 blr } bool Init680x0(void) { char str[256]; // Mac address space = host address space RAMBaseMac = (uint32)RAMBaseHost; ROMBaseMac = (uint32)ROMBaseHost; // Get TOC pointer TOC = get_toc(); // Get system info get_system_info(&SysInfo); switch (SysInfo.cpu_type) { case B_CPU_PPC_601: PVR = 0x00010000; break; case B_CPU_PPC_603: PVR = 0x00030000; break; case B_CPU_PPC_603e: PVR = 0x00060000; break; case B_CPU_PPC_604: PVR = 0x00040000; break; case B_CPU_PPC_604e: PVR = 0x00090000; break; default: PVR = 0x00040000; break; } CPUClockSpeed = SysInfo.cpu_clock_speed; BusClockSpeed = SysInfo.bus_clock_speed; // Delete old areas area_id old_kernel_area = find_area(KERNEL_AREA_NAME); if (old_kernel_area > 0) delete_area(old_kernel_area); area_id old_dr_cache_area = find_area(DR_CACHE_AREA_NAME); if (old_dr_cache_area > 0) delete_area(old_dr_cache_area); // Create area for Kernel Data kernel_data = (KernelData *)0x68ffe000; kernel_area = create_area(KERNEL_AREA_NAME, &kernel_data, B_EXACT_ADDRESS, 0x2000, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); if (kernel_area < 0) { sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(kernel_area), kernel_area); ErrorAlert(str); return false; } emulator_data = &kernel_data->ed; KernelDataAddr = (uint32)kernel_data; D(bug("Kernel Data area %ld at %p, Emulator Data at %p\n", kernel_area, kernel_data, emulator_data)); // Load PowerMac ROM (upper 3MB) try { load_rom(); } catch (file_open_error) { ErrorAlert(STR_NO_ROM_FILE_ERR); return false; } catch (file_read_error) { ErrorAlert(STR_ROM_FILE_READ_ERR); return false; } catch (rom_size_error) { ErrorAlert(STR_ROM_SIZE_ERR); return false; } // Install ROM patches if (!patch_rom()) { ErrorAlert("Unsupported PowerMac ROM version"); return false; } // Create area for DR Cache DRCacheAddr = DR_CACHE_BASE; dr_cache_area = create_area(DR_CACHE_AREA_NAME, (void **)&DRCacheAddr, B_EXACT_ADDRESS, DR_CACHE_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); if (dr_cache_area < 0) { sprintf(str, GetString(STR_NO_KERNEL_DATA_ERR), strerror(dr_cache_area), dr_cache_area); ErrorAlert(str); return false; } D(bug("DR Cache area %ld at %p\n", dr_cache_area, DRCacheAddr)); // Initialize Kernel Data memset(kernel_data, 0, sizeof(KernelData)); if (ROMType == ROMTYPE_NEWWORLD) { kernel_data->v[0xc20 >> 2] = RAMSize; kernel_data->v[0xc24 >> 2] = RAMSize; kernel_data->v[0xc30 >> 2] = RAMSize; kernel_data->v[0xc34 >> 2] = RAMSize; kernel_data->v[0xc38 >> 2] = 0x00010020; kernel_data->v[0xc3c >> 2] = 0x00200001; kernel_data->v[0xc40 >> 2] = 0x00010000; kernel_data->v[0xc50 >> 2] = RAMBaseMac; kernel_data->v[0xc54 >> 2] = RAMSize; kernel_data->v[0xf60 >> 2] = PVR; kernel_data->v[0xf64 >> 2] = CPUClockSpeed; kernel_data->v[0xf68 >> 2] = BusClockSpeed; kernel_data->v[0xf6c >> 2] = CPUClockSpeed; } else { kernel_data->v[0xc80 >> 2] = RAMSize; kernel_data->v[0xc84 >> 2] = RAMSize; kernel_data->v[0xc90 >> 2] = RAMSize; kernel_data->v[0xc94 >> 2] = RAMSize; kernel_data->v[0xc98 >> 2] = 0x00010020; kernel_data->v[0xc9c >> 2] = 0x00200001; kernel_data->v[0xca0 >> 2] = 0x00010000; kernel_data->v[0xcb0 >> 2] = RAMBaseMac; kernel_data->v[0xcb4 >> 2] = RAMSize; kernel_data->v[0xf80 >> 2] = PVR; kernel_data->v[0xf84 >> 2] = CPUClockSpeed; kernel_data->v[0xf88 >> 2] = BusClockSpeed; kernel_data->v[0xf8c >> 2] = CPUClockSpeed; } // Initialize extra low memory memset((void *)0x2000, 0, 0x1000); *(uint32 *)XLM_RESET_STACK = 0x2000; // Reset stack pointer *(KernelData **)XLM_KERNEL_DATA = kernel_data;// For trap replacement routines *(void **)XLM_TOC = TOC; // TOC pointer of emulator *(uint32 *)XLM_PVR = PVR; // Theoretical PVR // Clear caches (as we loaded and patched code) clear_caches((void *)ROM_BASE, ROM_AREA_SIZE, B_INVALIDATE_ICACHE | B_FLUSH_DCACHE); return true; } /* * Deinitialize 680x0 emulation */ void Exit680x0(void) { // Delete DR Cache area if (dr_cache_area >= 0) delete_area(dr_cache_area); // Delete Kernel Data area if (kernel_area >= 0) delete_area(kernel_area); } /* * Quit emulator (must only be called from main thread) */ asm void QuitEmulator(void) { lwz r0,XLM_EMUL_RETURN_PROC mtlr r0 blr } /* * Reset and start 680x0 emulation */ static asm void jump_to_rom(register uint32 entry) { // Create stack frame mflr r0 stw r0,8(r1) mfcr r0 stw r0,4(r1) stwu r1,-(56+19*4+18*8)(r1) // Save PowerPC registers stmw r13,56(r1) stfd f14,56+19*4+0*8(r1) stfd f15,56+19*4+1*8(r1) stfd f16,56+19*4+2*8(r1) stfd f17,56+19*4+3*8(r1) stfd f18,56+19*4+4*8(r1) stfd f19,56+19*4+5*8(r1) stfd f20,56+19*4+6*8(r1) stfd f21,56+19*4+7*8(r1) stfd f22,56+19*4+8*8(r1) stfd f23,56+19*4+9*8(r1) stfd f24,56+19*4+10*8(r1) stfd f25,56+19*4+11*8(r1) stfd f26,56+19*4+12*8(r1) stfd f27,56+19*4+13*8(r1) stfd f28,56+19*4+14*8(r1) stfd f29,56+19*4+15*8(r1) stfd f30,56+19*4+16*8(r1) stfd f31,56+19*4+17*8(r1) // Move entry address to ctr, get pointer to Emulator Data mtctr r3 lwz r3,emulator_data(r2) // Skip over EMUL_RETURN routine and get its address bl @1 /* * EMUL_RETURN: Returned from emulator */ // Restore PowerPC registers lwz r1,XLM_EMUL_RETURN_STACK lwz r2,XLM_TOC lmw r13,56(r1) lfd f14,56+19*4+0*8(r1) lfd f15,56+19*4+1*8(r1) lfd f16,56+19*4+2*8(r1) lfd f17,56+19*4+3*8(r1) lfd f18,56+19*4+4*8(r1) lfd f19,56+19*4+5*8(r1) lfd f20,56+19*4+6*8(r1) lfd f21,56+19*4+7*8(r1) lfd f22,56+19*4+8*8(r1) lfd f23,56+19*4+9*8(r1) lfd f24,56+19*4+10*8(r1) lfd f25,56+19*4+11*8(r1) lfd f26,56+19*4+12*8(r1) lfd f27,56+19*4+13*8(r1) lfd f28,56+19*4+14*8(r1) lfd f29,56+19*4+15*8(r1) lfd f30,56+19*4+16*8(r1) lfd f31,56+19*4+17*8(r1) // Exiting from 68k emulator li r0,1 stw r0,XLM_IRQ_NEST li r0,MODE_EMUL_OP stw r0,XLM_RUN_MODE // Return to caller of jump_to_rom() lwz r0,56+19*4+18*8+8(r1) mtlr r0 lwz r0,56+19*4+18*8+4(r1) mtcrf 0xff,r0 addi r1,r1,56+19*4+18*8 blr // Save address of EMUL_RETURN routine for 68k emulator patch @1 mflr r0 stw r0,XLM_EMUL_RETURN_PROC // Skip over EXEC_RETURN routine and get its address bl @2 /* * EXEC_RETURN: Returned from 68k routine executed with Execute68k() */ // Save r25 (contains current 68k interrupt level) stw r25,XLM_68K_R25 // Reentering EMUL_OP mode li r0,MODE_EMUL_OP stw r0,XLM_RUN_MODE // Save 68k registers lwz r4,56+19*4+18*8+12(r1) stw r8,M68kRegisters.d[0](r4) stw r9,M68kRegisters.d[1](r4) stw r10,M68kRegisters.d[2](r4) stw r11,M68kRegisters.d[3](r4) stw r12,M68kRegisters.d[4](r4) stw r13,M68kRegisters.d[5](r4) stw r14,M68kRegisters.d[6](r4) stw r15,M68kRegisters.d[7](r4) stw r16,M68kRegisters.a[0](r4) stw r17,M68kRegisters.a[1](r4) stw r18,M68kRegisters.a[2](r4) stw r19,M68kRegisters.a[3](r4) stw r20,M68kRegisters.a[4](r4) stw r21,M68kRegisters.a[5](r4) stw r22,M68kRegisters.a[6](r4) // Restore PowerPC registers lmw r13,56(r1) #if SAVE_FP_EXEC_68K lfd f14,56+19*4+0*8(r1) lfd f15,56+19*4+1*8(r1) lfd f16,56+19*4+2*8(r1) lfd f17,56+19*4+3*8(r1) lfd f18,56+19*4+4*8(r1) lfd f19,56+19*4+5*8(r1) lfd f20,56+19*4+6*8(r1) lfd f21,56+19*4+7*8(r1) lfd f22,56+19*4+8*8(r1) lfd f23,56+19*4+9*8(r1) lfd f24,56+19*4+10*8(r1) lfd f25,56+19*4+11*8(r1) lfd f26,56+19*4+12*8(r1) lfd f27,56+19*4+13*8(r1) lfd f28,56+19*4+14*8(r1) lfd f29,56+19*4+15*8(r1) lfd f30,56+19*4+16*8(r1) lfd f31,56+19*4+17*8(r1) #endif // Return to caller lwz r0,56+19*4+18*8+8(r1) mtlr r0 addi r1,r1,56+19*4+18*8 blr // Stave address of EXEC_RETURN routine for 68k emulator patch @2 mflr r0 stw r0,XLM_EXEC_RETURN_PROC // Skip over EMUL_OP routine and get its address bl @3 /* * EMUL_OP: Execute native routine, selector in r5 (my own private mode switch) * * 68k registers are stored in a M68kRegisters struct on the stack * which the native routine may read and modify */ // Save r25 (contains current 68k interrupt level) stw r25,XLM_68K_R25 // Entering EMUL_OP mode within 68k emulator li r0,MODE_EMUL_OP stw r0,XLM_RUN_MODE // Create PowerPC stack frame, reserve space for M68kRegisters mr r3,r1 subi r1,r1,56 // Fake "caller" frame rlwinm r1,r1,0,0,29 // Align stack mfcr r0 rlwinm r0,r0,0,11,8 stw r0,4(r1) mfxer r0 stw r0,16(r1) stw r2,12(r1) stwu r1,-(56+16*4+15*8)(r1) lwz r2,XLM_TOC // Save 68k registers stw r8,56+M68kRegisters.d[0](r1) stw r9,56+M68kRegisters.d[1](r1) stw r10,56+M68kRegisters.d[2](r1) stw r11,56+M68kRegisters.d[3](r1) stw r12,56+M68kRegisters.d[4](r1) stw r13,56+M68kRegisters.d[5](r1) stw r14,56+M68kRegisters.d[6](r1) stw r15,56+M68kRegisters.d[7](r1) stw r16,56+M68kRegisters.a[0](r1) stw r17,56+M68kRegisters.a[1](r1) stw r18,56+M68kRegisters.a[2](r1) stw r19,56+M68kRegisters.a[3](r1) stw r20,56+M68kRegisters.a[4](r1) stw r21,56+M68kRegisters.a[5](r1) stw r22,56+M68kRegisters.a[6](r1) stw r3,56+M68kRegisters.a[7](r1) stfd f0,56+16*4+0*8(r1) stfd f1,56+16*4+1*8(r1) stfd f2,56+16*4+2*8(r1) stfd f3,56+16*4+3*8(r1) stfd f4,56+16*4+4*8(r1) stfd f5,56+16*4+5*8(r1) stfd f6,56+16*4+6*8(r1) stfd f7,56+16*4+7*8(r1) mffs f0 stfd f8,56+16*4+8*8(r1) stfd f9,56+16*4+9*8(r1) stfd f10,56+16*4+10*8(r1) stfd f11,56+16*4+11*8(r1) stfd f12,56+16*4+12*8(r1) stfd f13,56+16*4+13*8(r1) stfd f0,56+16*4+14*8(r1) // Execute native routine mr r3,r5 addi r4,r1,56 bl EmulOp // Restore 68k registers lwz r8,56+M68kRegisters.d[0](r1) lwz r9,56+M68kRegisters.d[1](r1) lwz r10,56+M68kRegisters.d[2](r1) lwz r11,56+M68kRegisters.d[3](r1) lwz r12,56+M68kRegisters.d[4](r1) lwz r13,56+M68kRegisters.d[5](r1) lwz r14,56+M68kRegisters.d[6](r1) lwz r15,56+M68kRegisters.d[7](r1) lwz r16,56+M68kRegisters.a[0](r1) lwz r17,56+M68kRegisters.a[1](r1) lwz r18,56+M68kRegisters.a[2](r1) lwz r19,56+M68kRegisters.a[3](r1) lwz r20,56+M68kRegisters.a[4](r1) lwz r21,56+M68kRegisters.a[5](r1) lwz r22,56+M68kRegisters.a[6](r1) lwz r3,56+M68kRegisters.a[7](r1) lfd f13,56+16*4+14*8(r1) lfd f0,56+16*4+0*8(r1) lfd f1,56+16*4+1*8(r1) lfd f2,56+16*4+2*8(r1) lfd f3,56+16*4+3*8(r1) lfd f4,56+16*4+4*8(r1) lfd f5,56+16*4+5*8(r1) lfd f6,56+16*4+6*8(r1) lfd f7,56+16*4+7*8(r1) mtfsf 0xff,f13 lfd f8,56+16*4+8*8(r1) lfd f9,56+16*4+9*8(r1) lfd f10,56+16*4+10*8(r1) lfd f11,56+16*4+11*8(r1) lfd f12,56+16*4+12*8(r1) lfd f13,56+16*4+13*8(r1) // Delete PowerPC stack frame lwz r2,56+16*4+15*8+12(r1) lwz r0,56+16*4+15*8+16(r1) mtxer r0 lwz r0,56+16*4+15*8+4(r1) mtcrf 0xff,r0 mr r1,r3 // Reeintering 68k emulator li r0,MODE_68K stw r0,XLM_RUN_MODE // Set r0 to 0 for 68k emulator li r0,0 // Execute next 68k opcode rlwimi r29,r27,3,13,28 lhau r27,2(r24) mtlr r29 blr // Save address of EMUL_OP routine for 68k emulator patch @3 mflr r0 stw r0,XLM_EMUL_OP_PROC // Save stack pointer for EMUL_RETURN stw r1,XLM_EMUL_RETURN_STACK // Preset registers for ROM boot routine lis r3,0x40b0 // Pointer to ROM boot structure ori r3,r3,0xd000 // 68k emulator is now active li r0,MODE_68K stw r0,XLM_RUN_MODE // Jump to ROM bctr } void Start680x0(void) { // Install interrupt signal handler sigemptyset(&sigusr1_action.sa_mask); sigusr1_action.sa_handler = (__signal_func_ptr)(sigusr1_handler); sigusr1_action.sa_flags = 0; sigusr1_action.sa_userdata = NULL; sigaction(SIGUSR1, &sigusr1_action, NULL); // Install signal stack set_signal_stack(malloc(SIG_STACK_SIZE), SIG_STACK_SIZE); // We're now ready to receive signals ReadyForSignals = true; D(bug("Jumping to ROM\n")); jump_to_rom(ROM_BASE + 0x310000); D(bug("Returned from ROM\n")); // We're no longer ready to receive signals ReadyForSignals = false; } /* * Trigger interrupt */ void TriggerInterrupt(void) { idle_resume(); if (emul_thread > 0 && ReadyForSignals) send_signal(emul_thread, SIGUSR1); } void TriggerNMI(void) { //!! not implemented yet } /* * Execute 68k subroutine * r->a[7] and r->sr are unused! */ static asm void execute_68k(register uint32 addr, register M68kRegisters *r) { // Create stack frame mflr r0 stw r0,8(r1) stw r4,12(r1) stwu r1,-(56+19*4+18*8)(r1) // Save PowerPC registers stmw r13,56(r1) #if SAVE_FP_EXEC_68K stfd f14,56+19*4+0*8(r1) stfd f15,56+19*4+1*8(r1) stfd f16,56+19*4+2*8(r1) stfd f17,56+19*4+3*8(r1) stfd f18,56+19*4+4*8(r1) stfd f19,56+19*4+5*8(r1) stfd f20,56+19*4+6*8(r1) stfd f21,56+19*4+7*8(r1) stfd f22,56+19*4+8*8(r1) stfd f23,56+19*4+9*8(r1) stfd f24,56+19*4+10*8(r1) stfd f25,56+19*4+11*8(r1) stfd f26,56+19*4+12*8(r1) stfd f27,56+19*4+13*8(r1) stfd f28,56+19*4+14*8(r1) stfd f29,56+19*4+15*8(r1) stfd f30,56+19*4+16*8(r1) stfd f31,56+19*4+17*8(r1) #endif // Set up registers for 68k emulator lwz r31,XLM_KERNEL_DATA // Pointer to Kernel Data addi r31,r31,0x1000 // points to Emulator Data li r0,0 mtcrf 0xff,r0 creqv 11,11,11 // Supervisor mode lwz r8,M68kRegisters.d[0](r4) lwz r9,M68kRegisters.d[1](r4) lwz r10,M68kRegisters.d[2](r4) lwz r11,M68kRegisters.d[3](r4) lwz r12,M68kRegisters.d[4](r4) lwz r13,M68kRegisters.d[5](r4) lwz r14,M68kRegisters.d[6](r4) lwz r15,M68kRegisters.d[7](r4) lwz r16,M68kRegisters.a[0](r4) lwz r17,M68kRegisters.a[1](r4) lwz r18,M68kRegisters.a[2](r4) lwz r19,M68kRegisters.a[3](r4) lwz r20,M68kRegisters.a[4](r4) lwz r21,M68kRegisters.a[5](r4) lwz r22,M68kRegisters.a[6](r4) li r23,0 mr r24,r3 lwz r25,XLM_68K_R25 // MSB of SR li r26,0 li r28,0 // VBR lwz r29,0x74(r31) // Pointer to opcode table lwz r30,0x78(r31) // Address of emulator // Reentering 68k emulator li r0,MODE_68K stw r0,XLM_RUN_MODE // Set r0 to 0 for 68k emulator li r0,0 // Execute 68k opcode lha r27,0(r24) rlwimi r29,r27,3,13,28 lhau r27,2(r24) mtlr r29 blr } void Execute68k(uint32 addr, M68kRegisters *r) { uint16 proc[4] = {M68K_JSR, addr >> 16, addr & 0xffff, M68K_EXEC_RETURN}; execute_68k((uint32)proc, r); } /* * Execute MacOS 68k trap * r->a[7] and r->sr are unused! */ void Execute68kTrap(uint16 trap, struct M68kRegisters *r) { uint16 proc[2] = {trap, M68K_EXEC_RETURN}; execute_68k((uint32)proc, r); } /* * USR1 handler */ static void sigusr1_handler(int sig, void *arg, vregs *r) { // Do nothing if interrupts are disabled if ((*(int32 *)XLM_IRQ_NEST) > 0) return; // 68k emulator active? Then trigger 68k interrupt level 1 if (*(uint32 *)XLM_RUN_MODE == MODE_68K) { *(uint16 *)(kernel_data->v[0x67c >> 2]) = 1; r->cr |= kernel_data->v[0x674 >> 2]; } } BasiliskII/TECH0000644000175000017500000010061307547120430013412 0ustar centriscentrisBASILISK II TECHNICAL MANUAL ============================ 0. Table of Contents -------------------- 1. Introduction 2. Modes of operation 3. Memory access 4. Calling native routines from 68k mode and vice-versa 5. Interrupts 6. Parts of Basilisk II 7. Porting Basilisk II 1. Introduction --------------- Basilisk II can emulate two kind of Macs, depending on the ROM being used: 1. A Mac Classic 2. A Mac II series computer ("Mac II series" here means all 68020/30/40 based Macs with 32-bit clean ROMs (this excludes the original Mac II, the IIx/IIcx and the SE/030), except PowerBooks; in the following, "Mac II" is used as an abbreviation of "Mac II series computer", as defined above) More precisely spoken, MacOS under Basilisk II behaves like on a Mac Classic or Mac II because, apart from the CPU, the RAM and the ROM, absolutely no Mac hardware is emulated. Rather, Basilisk II provides replacements (usually in the form of MacOS drivers) for the parts of MacOS that access hardware. As there are practically no Mac applications that access hardware directly (this is also due to the fact that the hardware of different Mac models is sometimes as different as, say, the hardware of an Atari ST and an Amiga 500), both the compatibility and speed of this approach are very high. 2. Modes of operation --------------------- Basilisk II is designed to run on many different hardware platforms and on many different operating systems. To provide optimal performance under all environments, it can run in four different modes, depending on the features of the underlying environment (the modes are selected with the REAL_ADDRESSING, DIRECT_ADDRESSING and EMULATED_68K defines in "sysdeps.h"): 1. Emulated CPU, "virtual" addressing (EMULATED_68K = 1, REAL_ADDRESSING = 0): This mode is designed for non-68k or little-endian systems or systems that don't allow accessing RAM at 0x0000..0x1fff. This is also the only mode that allows 24-bit addressing, and thus the only mode that allows Mac Classic emulation. The 68k processor is emulated with the UAE CPU engine and two memory areas are allocated for Mac RAM and ROM. The memory map seen by the emulated CPU and the host CPU are different. Mac RAM starts at address 0 for the emulated 68k, but it may start at a different address for the host CPU. In order to handle the particularities of each memory area (RAM, ROM and Frame Buffer), the address space of the emulated 68k is broken down into banks. Each bank is associated with a series of pointers to specific memory access functions that carry out the necessary operations (e.g. byte-swapping, catching illegal writes to memory). A generic memory access function, get_long() for example, goes through the table of memory banks (mem_banks) and fetches the appropriate specific memory access fonction, lget() in our example. This slows down the emulator, of course. 2. Emulated CPU, "direct" addressing (EMULATED_68K = 1, DIRECT_ADDRESSING = 1): As in the virtual addressing mode, the 68k processor is emulated with the UAE CPU engine and two memory areas are set up for RAM and ROM. Mac RAM starts at address 0 for the emulated 68k, but it may start at a different address for the host CPU. Besides, the virtual memory areas seen by the emulated 68k are separated by exactly the same amount of bytes as the corresponding memory areas allocated on the host CPU. This means that address translation simply implies the addition of a constant offset (MEMBaseDiff). Therefore, the memory banks are no longer used and the memory access functions are replaced by inline memory accesses. 3. Emulated CPU, "real" addressing (EMULATED_68K = 1, REAL_ADDRESSING = 1): This mode is intended for non-68k systems that do allow access to RAM at 0x0000..0x1fff. As in the virtual addressing mode, the 68k processor is emulated with the UAE CPU engine and two areas are allocated for RAM and ROM but the emulated CPU lives in the same address space as the host CPU. This means that if something is located at a certain address for the 68k, it is located at the exact same address for the host CPU. Mac addresses and host addresses are the same. The memory accesses of the CPU emulation still go through access functions but the address translation is no longer needed. The memory access functions are replaced by direct, inlined memory accesses, making for the fastest possible speed of the emulator. On little-endian systems, byte-swapping is still required, of course. A usual consequence of the real addressing mode is that the Mac RAM doesn't any longer begin at address 0 for the Mac and that the Mac ROM also is not located where it usually is on a real Mac. But as the Mac ROM is relocatable and the available RAM is defined for MacOS by the start of the system zone (which is relocated to the start of the allocated RAM area) and the MemTop variable (which is also set correctly) this is not a problem. There is, however, one RAM area that must lie in a certain address range. This area contains the Mac "Low Memory Globals" which (on a Mac II) are located at 0x0000..0x1fff and which cannot be moved to a different address range. The Low Memory Globals constitute of many important MacOS and application global variables (e.g. the above mentioned "MemTop" variable which is located at 0x0108). For the real addressing mode to work, the host CPU needs access to 0x0000..0x1fff. Under most operating systems, this is a big problem. On some systems, patches (like PrepareEmul on the Amiga or the sheep_driver under BeOS) can be installed to "open up" this area. On other systems, it might be possible to use access exception handlers to emulate accesses to this area. But if the Low Memory Globals area cannot be made available, using the real addressing mode is not possible. Note: currently, real addressing mode is known to work only on AmigaOS, NetBSD/m68k, FreeBSD/i386, Linux/ppc and Linux/i386. 4. Native CPU (EMULATED_68K = 0, this also requires REAL_ADDRESSING = 1) This mode is designed for systems that use a 68k (68020 or better) processor as host CPU and is the technically most difficult mode to handle. The Mac CPU is no longer emulated (the UAE CPU emulation is not needed) but MacOS and Mac applications run natively on the existing 68k CPU. This means that the emulator has its maximum possible speed (very close to that of a real Mac with the same CPU). As there is no control over the memory accesses of the CPU, real addressing mode is implied, and so the Low Memory area must be accessible (an MMU might be used to set up different address spaces for the Mac and the host, but this is not implemented in Basilisk II). The native CPU mode has some possible pitfalls that might make its implementation difficult on some systems: a) Implied real addressing (this also means that Mac programs that go out of control can crash the emulator or the whole system) b) MacOS and Mac applications assume that they always run in supervisor mode (more precisely, they assume that they can safely use certain priviledged instructions, mostly for interrupt control). So either the whole emulator has to be run in supervisor mode (which usually is not possible on multitasking systems) or priviledged instructions have to be trapped and emulated. The Amiga and NetBSD/m68k versions of Basilisk II use the latter approach (it is possible to run supervisor mode tasks under the AmigaOS multitasking kernel (ShapeShifter does this) but it requires modifying the Exec task switcher and makes the emulator more unstable). c) On multitasking systems, interrupts can usually not be handled as on a real Mac (or with the UAE CPU). The interrupt levels of the host will not be the same as on a Mac, and the operating systems might not allow installing hardware interrupt handlers or the interrupt handlers might have different stack frames and run-time environments than 68k hardware interrupts. The usual solution is to use some sort of software interrupts or signals to interrupt the main emulation process and to manually call the Mac 68k interrupt handler with a faked stack frame. d) 68060 systems are a small problem because there is no Mac that ever used the 68060 and MacOS doesn't know about this processor. Basilisk II reports the 68060 as being a 68040 to the MacOS and patches some places where MacOS makes use of certain 68040-specific features such as the FPU state frame layout or the PTEST instruction. Also, Basilisk II requires that all of the Motorola support software for the 68060 to emulate missing FPU and integer instructions and addressing modes is provided by the host operating system (this also applies to the 68040). e) The "EMUL_OP" mechanism described below requires the interception and handling of certain emulator-defined instructions. 3. Memory access ---------------- There is often a need to access Mac RAM and ROM inside the emulator. As Basilisk II may run in "real" or "virtual" addressing mode on many different architectures, big-endian or little-endian, certain platform-independent data types and functions are provided: a) "sysdeps.h" defines the types int8, uint8, int16, uint16, int32 and uint32 for numeric quantities of a certain signedness and bit length b) "cpu_emulation.h" defines the ReadMacInt*() and WriteMacInt*() functions which should always be used to read from or write to Mac RAM or ROM c) "cpu_emulation.h" also defines the Mac2HostAddr() function that translates a Mac memory address to a (uint8 *) in host address space. This allows you to access larger chunks of Mac memory directly, without going through the read/write functions for every access. But doing so you have to perform any needed endianess conversion of the data yourself by using the ntohs() etc. macros which are available on most systems or defined in "sysdeps.h". 4. Calling native routines from 68k mode and vice-versa ------------------------------------------------------- An emulator like Basilisk II requires two kinds of cross-platform function calls: a) Calling a native routine from the Mac 68k context b) Calling a Mac 68k routine from the native context Situation a) arises in nearly all Basilisk drivers and system patches while case b) is needed for the invocation of Mac call-back or interrupt routines. Basilisk II tries to solve both problems in a way that provides the same interface whether it is running on a 68k or a non-68k system. 4.1. The EMUL_OP mechanism -------------------------- Calling native routines from the Mac 68k context requires breaking out of the 68k emulator or interrupting the current instruction flow and is done via unimplemented 68k opcodes (called "EMUL_OP" opcodes). Basilisk II uses opcodes of the form 0x71xx (these are invalid MOVEQ opcodes) which are defined in "emul_op.h". When such an opcode is encountered, whether by the emulated CPU or a real 68k, the execution is interrupted, all CPU registers saved and the EmulOp() function from "emul_op.cpp" is called. EmulOp() decides which opcode caused the interrupt and performs the required actions (mostly by calling other emulator routines). The EMUL_OP handler routines have access to nearly all of the 68k user mode registers (exceptions being the PC, A7 and SR). So the EMUL_OP opcodes can be thought of as extensions to the 68k instruction set. Some of these opcodes are used to implement ROM or resource patches because they only occupy 2 bytes and there is sometimes not more room for a patch. 4.2. Execute68k() ----------------- "cpu_emulation.h" declares the functions Execute68k() and Execute68kTrap() to call Mac 68k routines or MacOS system traps from inside an EMUL_OP handler routine. They allow setting all 68k user mode registers (except PC and SR) before the call and examining all register contents after the call has returned. EMUL_OP and Execute68k() may be nested, i.e. a routine called with Execute68k() may contain EMUL_OP opcodes and the EMUL_OP handlers may in turn call Execute68k() again. 5. Interrupts ------------- Various parts of Basilisk II (such as the Time Manager and the serial driver) need an interrupt facility to trigger asynchronous events. The MacOS uses different 68k interrupt levels for different events, but for simplicity Basilisk II only uses level 1 and does it's own interrupt dispatching. The "InterruptFlags" contains a bit mask of the pending interrupts. These are the currently defined interrupt sources (see main.h): INTFLAG_60HZ - MacOS 60Hz interrupt (unlike a real Mac, we also handle VBL interrupts and the Time Manager here) INTFLAG_1HZ - MacOS 1Hz interrupt (updates system time) INTFLAG_SERIAL - Interrupt for serial driver I/O completion INTFLAG_ETHER - Interrupt for Ethernet driver I/O completion and packet reception INTFLAG_AUDIO - Interrupt for audio "next block" requests INTFLAG_TIMER - Reserved for a future implementation of a more precise Time Manager (currently not used) INTFLAG_ADB - Interrupt for mouse/keyboard input INTFLAG_NMI - NMI for debugging (not supported on all platforms) An interrupt is triggered by calling SetInterruptFlag() with the desired interrupt flag constant and then TriggerInterrupt(). When the UAE 68k emulator is used, this will signal a hardware interrupt to the emulated 680x0. On a native 68k machine, some other method for interrupting the MacOS thread has to be used (e.g. on AmigaOS, a signal exception is used). Care has to be taken because with the UAE CPU, the interrupt will only occur when Basilisk II is executing MacOS code while on a native 68k machine, the interrupt could occur at any time (e.g. inside an EMUL_OP handler routine). In any case, the MacOS thread will eventually end up in the level 1 interrupt handler which contains an M68K_EMUL_OP_IRQ opcode. The opcode handler in emul_op.cpp will then look at InterruptFlags and decide which routines to call. 6. Parts of Basilisk II ----------------------- The conception of Basilisk II is quite modular and consists of many parts which are relatively independent from each other: - UAE CPU engine ("uae_cpu/*", not needed on all systems) - ROM patches ("rom_patches.cpp", "slot_rom.cpp" and "emul_op.cpp") - resource patches ("rsrc_patches.cpp" and "emul_op.cpp") - PRAM Utilities replacement ("xpram.cpp") - ADB Manager replacement ("adb.cpp") - Time Manager replacement ("timer.cpp") - SCSI Manager replacement ("scsi.cpp") - video driver ("video.cpp") - audio component ("audio.cpp") - floppy driver ("sony.cpp") - disk driver ("disk.cpp") - CD-ROM driver ("cdrom.cpp") - external file system ("extfs.cpp") - serial drivers ("serial.cpp") - Ethernet driver ("ether.cpp") - system-dependant device access ("sys_*.cpp") - user interface strings ("user_strings.cpp") - preferences management ("prefs.cpp" and "prefs_editor_*.cpp") Most modules consist of a platform-independant part (such as video.cpp) and a platform-dependant part (such as video_beos.cpp). The "dummy" directory contains generic "do-nothing" versions of some of the platform-dependant parts to aid in testing and porting. 6.1. UAE CPU engine ------------------- All files relating to the UAE 680x0 emulation are kept in the "uae_cpu" directory. The "cpu_emulation.h" header file defines the link between the UAE CPU and the rest of Basilisk II, and "basilisk_glue.cpp" implements the link. It should be possible to replace the UAE CPU with a different 680x0 emulation by creating a new "xxx_cpu" directory with an appropriate "cpu_emulation.h" header file (for the inlined memory access functions) and writing glue code between the functions declared in "cpu_emulation.h" and those provided by the 680x0 emulator. 6.2. ROM and resource patches ----------------------------- As described above, instead of emulating custom Mac hardware, Basilisk II provides replacements for certain parts of MacOS to redirect input, output and system control functions of the Mac hardware to the underlying operating systems. This is done by applying patches to the Mac ROM ("ROM patches") and the MacOS system file ("resource patches", because nearly all system software is contained in MacOS resources). Unless resources are written back to disk, the system file patches are not permanent (it would cause many problems if they were permanent, because some of the patches vary with different versions of Basilisk II or even every time the emulator is launched). ROM patches are contained in "rom_patches.cpp" and resource patches are contained in "rsrc_patches.cpp". The ROM patches are far more numerous because nearly all the software needed to run MacOS is contained in the Mac ROM (the system file itself consists mainly of ROM patches, in addition to pictures and text). One part of the ROM patches involves the construction of a NuBus slot declaration ROM (in "slot_rom.cpp") which is used to add the video and Ethernet drivers. Apart from the CPU emulation, the ROM and resource patches contain most of the "logic" of the emulator. 6.3. PRAM Utilities ------------------- MacOS stores certain nonvolatile system parameters in a 256 byte battery backed-up CMOS RAM area called "Parameter RAM", "PRAM" or "XPRAM" (which refers to "Extended PRAM" because the earliest Mac models only had 20 bytes of PRAM). Basilisk II patches the ClkNoMem() MacOS trap which is used to access the XPRAM (apart from some routines which are only used early during system startup) and the real-time clock. The XPRAM is emulated in a 256 byte array which is saved to disk to preserve the contents for the next time Basilisk is launched. 6.4. ADB Manager ---------------- For emulating a mouse and a keyboard, Basilisk II patches the ADBOp() MacOS trap. Platform-dependant code reports mouse and keyboard events with the ADBMouseDown() etc. functions where they are queued, and the INTFLAG_ADB interrupt is triggered. The ADBInterrupt() handler function sends the input events to MacOS by calling the ADB mouse and keyboard handlers with Execute68k(). 6.5. Time Manager ----------------- Basilisk II completely replaces the Time Manager (InsTime(), RmvTime(), PrimeTime() and Microseconds() traps). A "TMDesc" structure is associated with each Time Manager task, that contains additional data. The tasks are executed in the TimerInterrupt() function which is currently called inside the 60Hz interrupt handler, thus limiting the resolution of the Time Manager to 16.6ms. 6.6. SCSI Manager ----------------- The (old-style) SCSI Manager is also completely replaced and the MacOS SCSIDispatch() trap redirected to the routines in "scsi.cpp". Under the MacOS, programs have to issue multiple calls for all the different phases of a SCSI bus interaction (arbitration, selection, command transfer etc.). Basilisk II maps this API to an atomic API which is used by most modern operating systems. All action is deferred until the call to SCSIComplete(). The TIB (Transfer Instruction Block) mini-programs used by the MacOS are translated into a scatter/gather list of data blocks. Operating systems that don't support scatter/gather SCSI I/O will have to use buffering if more than one data block is being transmitted. Some more advanced (but rarely used) aspects of the SCSI Manager (like messaging and compare operations) are not emulated. 6.7. Video driver ----------------- The NuBus slot declaration ROM constructed in "slot_rom.cpp" contains a driver definition for a video driver. The Control and Status calls of this driver are implemented in "video.cpp". The host-side initialization of the video system is done in VideoInit(). This function must fill the VideoModes vector with a list of supported video modes (combinations of color depth and resolution). It must then call video_init_depth_list() and setup the VideoMonitor structure with the default mode information and the address of a frame buffer for MacOS. In real addressing mode, this frame buffer must be in a MacOS compatible layout (big-endian and 1, 2, 4 or 8 bits paletted chunky pixels, RGB 5:5:5 or xRGB 8:8:8:8). In virtual addressing mode, the frame buffer is located at address 0xa0000000 on the Mac side and you have to supply the host address, size and layout (BasiliskII will do an automatic pixel format conversion in virtual addressing mode) in the variables MacFrameBaseHost, MacFrameSize and MacFrameLayout. There are two functions of the platform-dependant video driver code that get called during runtime: video_set_palette() to update the CLUT (for indexed modes) or gamma table (for direct color modes), and video_switch_to_mode() to switch to a different color depth and/or resolution (in this case the frame buffer base in VideoMonitor must be updated). 6.8. Audio component -------------------- Basilisk II provides a Sound Manager 3.x audio component for sound output. Earlier Sound Manager versions that don't use components but 'snth' resources are not supported. Nearly all component functions are implemented in "audio.cpp". The system-dependant modules ("audio_*.cpp") handle the initialization of the audio hardware/driver, volume controls, and the actual sound output. The mechanism of sound output varies depending on the platform but usually there will be one "streaming thread" (either a thread that continuously writes data buffers to the audio device or a callback function that provides the next data buffer) that reads blocks of sound data from the MacOS Sound Manager and writes them to the audio device. To request the next data buffer, the streaming thread triggers the INTFLAG_AUDIO interrupt which will cause the MacOS thread to eventually call AudioInterrupt(). Inside AudioInterrupt(), the next data block will be read and the streaming thread is signalled that new audio data is available. 6.9. Floppy, disk and CD-ROM drivers ------------------------------------ Basilisk II contains three MacOS drivers that implement floppy, disk and CD-ROM access ("sony.cpp", "disk.cpp" and "cdrom.cpp"). They rely heavily on the functionality provided by the "sys_*.cpp" module. BTW, the name ".Sony" of the MacOS floppy driver comes from the fact that the 3.5" floppy drive in the first Mac models was custom-built for Apple by Sony (this was one of the first applications of the 3.5" floppy format which was also invented by Sony). 6.10. External file system -------------------------- Basilisk II also provides a method for accessing files and direcories on the host OS from the MacOS side by means of an "external" file system (henceforth called "ExtFS"). The ExtFS is built upon the File System Manager 1.2 interface that is built into MacOS 7.6 (and later) and available as a system extension for earlier MacOS versions. Unlike other parts of Basilisk II, extfs.cpp requires POSIX file I/O and this is not going to change any time soon, so if you are porting Basilisk II to a system without POSIX file functions, you should emulate them. 6.11. Serial drivers -------------------- Similar to the disk drivers, Basilisk II contains replacement serial drivers for the emulation of Mac modem and printer ports. To avoid duplicating code, both ports are handled by the same set of routines. The SerialPrime() etc. functions are mostly wrappers that determine which port is being accessed. All the real work is done by the "SERDPort" class which is subclassed by the platform-dependant code. There are two instances (for port A and B) of the subclasses. Unlike the disk drivers, the serial driver must be able to handle asynchronous operations. Calls to SerialPrime() will usually not actually transmit or receive data but delegate the action to an independant thread. SerialPrime() then returns "1" to indicate that the I/O operation is not yet completed. The completion of the I/O request is signalled by calling the MacOS trap "IODone". However, this can't be done by the I/O thread because it's not in the right run-time environment to call MacOS functions. Therefore it will trigger the INTFLAG_SERIAL interrupt which causes the MacOS thread to eventually call SerialInterrupt(). SerialInterrupt(), in turn, will not call IODone either but install a Deferred Task to do the job. The Deferred Task will be called by MacOS when it returns to interrupt level 0. This mechanism sounds complicated but is necessary to ensure stable operation of the serial driver. 6.12. Ethernet driver --------------------- A driver for Ethernet networking is also contained in the NuBus slot ROM. Only one ethernet card can be handled by Basilisk II. For Ethernet to work, Basilisk II must be able to send and receive raw Ethernet packets, including the 14-byte header (destination and source address and type/length field), but not including the 4-byte CRC. This may not be possible on all platforms or it may require writing special net drivers or add-ons or running with superuser priviledges to get access to the raw packets. For situations in which access to raw Ethernet packets is not possible, Basilisk II implements a special "tunneling" mode in which it sends and receives packets via UDP, using BSD socket functions. It simply wraps the Ethernet packets into UDP packets, using dummy Ethernet addresses that are made up of the IP address of the host. Ethernet broadcast and AppleTalk multicast packets are sent to the IP broadcast address. Because of this non-standard way of tunneling, it is only possible to set up a "virtual" network amongst machines running Basilisk II in this way. Writing packets works as in the serial drivers. The ether_write() routine may choose to send the packet immediately (e.g. under BeOS) and return noErr or to delegate the sending to a separate thread (e.g. under AmigaOS) and return "1" to indicate that the operation is still in progress. For the latter case, a Deferred Task structure is provided in the ether_data area to call IODone from EtherInterrupt() when the packet write is complete (see above for a description of the mechanism). Packet reception is a different story. First of all, there are two methods provided by the MacOS Ethernet driver API to read packets, one of which (ERead/ ERdCancel) is not supported by Basilisk II. Basilisk II only supports reading packets by attaching protocol handlers. This shouldn't be a problem because the only network code I've seen so far that uses ERead is some Apple sample code. AppleTalk, MacTCP, MacIPX, OpenTransport etc. all use protocol handlers. By attaching a protocol handler, the user of the Ethernet driver supplies a handler routine that should be called by the driver upon reception of Ethernet packets of a certain type. 802.2 packets (type/length field of 0..1500 in the packet header) are a bit special: there can be only one protocol handler attached for 802.2 packets (by specifying a packet type of "0"). The MacOS LAP Manager will attach a 802.2 handler upon startup and handle the distribution of 802.2 packets to sub-protocol handlers, but the Basilisk II Ethernet driver is not concerned with this. When the driver receives a packet, it has to look up the protocol handler installed for the respective packet type (if any has been installed at all) and call the packet handler routine. This must be done with Execute68k() from the MacOS thread, so an interrupt (INTFLAG_ETHER) is triggered upon reception of a packet so the EtherInterrupt() routine can call the protocol handler. Before calling the handler, the Ethernet packet header has to be copied to MacOS RAM (the "ed_RHA" field of the ether_data structure is provided for this). The protocol handler will read the packet data by means of the ReadPacket/ReadRest routines supplied by the Ethernet driver. Both routines will eventually end up in EtherReadPacket() which copies the data to Mac address space. EtherReadPacket() requires the host address and length of the packet to be loaded to a0 and d1 before calling the protocol handler. Does this sound complicated? You are probably right. Here is another description of what happens upon reception of a packet: 1. Ethernet card receives packet and notifies some platform-dependant entity inside Basilisk II 2. This entity will store the packet in some safe place and trigger the INTFLAG_ETHER interrupt 3. The MacOS thread will execute the EtherInterrupt() routine and look for received packets 4. If a packet was received of a type to which a protocol handler had been attached, the packet header is copied to ed_RHA, a0/d1 are loaded with the host address and length of the packet data, a3 is loaded with the Mac address of the first byte behing ed_RHA and a4 is loaded with the Mac address of the ed_ReadPacket code inside ether_data, and the protocol handler is called with Execute68k() 5. The protocol handler will eventually try to read the packet data with a "jsr (a4)" or "jsr 2(a4)" 6. This will execute an M68K_EMUL_OP_ETHER_READ_PACKET opcode 7. The EtherReadPacket() opcode handling routine will copy the requested part of the packet data to Mac RAM using the pointer and length which are still in a0/d1 For a more detailed description of the Ethernet driver, see the book "Inside AppleTalk". 6.13. System-dependant device access ------------------------------------ The method for accessing floppy drives, hard disks, CD-ROM drives and files vary greatly between different operating systems. To make Basilisk II easily portable, all device I/O is made via the functions declared in "sys.h" and implemented by the (system-dependant) "sys_*.cpp" modules which provides a standard, Unix-like interface to all kinds of devices. 6.14. User interface strings ---------------------------- To aid in localization, all user interface strings of Basilisk II are collected in "user_strings.cpp" (for common strings) and "user_strings_*.cpp" (for platform-specific strings), and accessed via the GetString() function. This way, Basilisk II may be easily translated to different languages. 6.15. Preferences management ---------------------------- The module "prefs.cpp" handles user preferences in a system-independant way. Preferences items are accessed with the PrefsAdd*(), PrefsReplace*() and PrefsFind*() functions and stored in human-readable and editable text files on disk. There are two lists of available preferences items. The first one, common_prefs_items, is defined in "prefs_items.cpp" and lists items which are available on all systems. The second one, platform_prefs_items, is defined in "prefs_*.cpp" and lists the prefs items which are specific to a certain platform. The "prefs_editor_*.cpp" module provides a graphical user interface for setting the preferences so users won't have to edit the preferences file manually. 7. Porting Basilisk II ---------------------- Porting Basilisk II to a new platform should not be hard. These are the steps involved in the process: 1. Create a new directory inside the "src" directory for your platform. If your platform comes in several "flavours" that require adapted files, you should consider creating subdirectories inside the platform directory. All files needed for your port must be placed inside the new directory. Don't scatter platform-dependant files across the "src" hierarchy. 2. Decide in which mode (virtual addressing, real addressing or native CPU) Basilisk II will run. 3. Create a "sysdeps.h" file which defines the mode and system-dependant data types and memory access functions. Things which are used in Basilisk but missing on your platform (such as endianess macros) should also be defined here. 4. Implement the system-specific parts of Basilisk: main_*.cpp, sys_*.cpp, prefs_*.cpp, prefs_editor_*.cpp, xpram_*.cpp, timer_*.cpp, audio_*.cpp, video_*.cpp, serial_*.cpp, ether_*.cpp, scsi_*.cpp and clip_*.cpp You may want to take the skeleton implementations in the "dummy" directory as a starting point and look at the implementation for other platforms before writing your own. 5. Important things to remember: - Use the ReadMacInt*() and WriteMacInt*() functions from "cpu_emulation.h" to access Mac memory - Use the ntohs() etc. macros to convert endianess when accessing Mac memory directly - Don't modify any source files outside of your platform directory unless you really, really have to. Instead of adding "#ifdef PLATFORM" blocks to one of the platform-independant source files, you should contact me so that we may find a more elegant and more portable solution. 6. Coding style: indent -kr -ts4 Christian Bauer BasiliskII/TODO0000644000175000017500000000341010634252242013427 0ustar centriscentrisBugs: - System 7.1 with Quadra900 ModelID (1MB ROM): 0x108 gets strange value - Apple Personal Diagnostics doesn't work with more than 1023 MB General: - Add support for 2MB ROMs (Quadra 840AV) - Add support for System 6.0.x - Sony: rdVerify, Tag Buffer - Disk: rdVerify - CD-ROM: track lists, positioning type 3, TOC type 4/5, ReadHeader/ReadMCN/ ReadISRC/ReadAudio/ReadAllSubcodes - Sound in - Video: multiple monitor support - More accurate Time Manager - Serial driver: XOn/XOff handshaking - Classic ROM: mouse button/movement is broken with ROM mouse handler - Classic ROM: sound output - Write a nice User's Manual with linuxdoc or something similar - Fix video mode switch to cope with different mac_frame_base (CrsrBase is overriden with the previous base after the mode switch) AmigaOS: - "Create Hardfile..." button - Support for ShapeShifter External Video Drivers - clip_amiga.cpp: clip AmigaOS->Basilisk - sys_amiga.cpp: MaxTransfer/BufMemType/TransferMask, SysAddCDROMPrefs(), SysFormat() - Patch 512K ROM for 68040/060 caches - Input handler instead of IDCMP? - Last sound buffer is not played - Sound output rate/bits/channels switching BeOS: - clip_beos.cpp: clip BeOS->Basilisk - Last sound buffer is not played - Sound output rate/bits/channels switching - Video depth/resolution switching Unix: - sys_unix.cpp: SysFormat(), SysIsFixedDisk(), SysIsDiskInserted(), prevent/allow for non-floppy/CDROM devices - ESD is also available on Solaris - display progress bar during disk file creation in prefs editor Mac OS X: - Sound - Cut and paste - Lots of other stuff. See src/MacOSX/ToDo.html Windows - main_windows.cpp: undo the SDL/DIB driver trick - video_windows.cpp: implement with DirectX - audio_windows.cpp, scsi_windows.cpp: merge from original Windows version BasiliskII/Makefile0000644000175000017500000000705710261061676014417 0ustar centriscentris# Makefile for creating Basilisk II distributions # Written in 2002 by Christian Bauer VERSION := $(shell sed This item describes one MacOS volume to be mounted by Basilisk II. There can be multiple "disk" lines in the preferences file. Basilisk II can handle hardfiles (byte-per-byte images of HFS volumes in a file on the host system), HFS partitions on hard disks etc., and MacOS-partitioned disks (it can only access the first partition, though). The "volume description" is either the pathname of a hardfile or a platform-dependant description of an HFS partition or drive. If the volume description is prefixed by an asterisk ("*"), the volume is write protected for MacOS. Basilisk II can also handle some types of Mac "disk image" files directly, as long as they are uncompressed and unencoded. BeOS: To specify an HFS partition, simply specify its path (e.g. "/dev/disk/scsi/0/1/0/0_3"). If you don't specify any volumes, Basilisk II will search for and use all available HFS partitions. Unix: To specify an HFS partition, simply specify its path (e.g. "/dev/sda5"). If you want to access a MacOS-partitioned hard disk or removable volume (Jaz, Zip etc.) and your operating system doesn't understand MacOS partition tables, you can specify the block device name (e.g. "/dev/sda") to access the first HFS partition on the device. Under Linux, if you don't specify any volumes, Basilisk II will search /etc/fstab for unmounted HFS partitions and use these. AmigaOS: Partitions/drives are specified in the following format: /dev////// "start block" and "size" are given in blocks, "block size" is given in bytes. Windows: To define a logical volume (Windows NT only), specify its path (e.g. "c:\"). To define a physical volume (NT and 9x), additionally give the "physical" keyword (E.g. "physical c:\"). For safety reasons, volumes are mounted as read-only. This is due to the bugs in PC Exchange. If you don't specify any volume, the files *.hfv and *.dsk are searched from the current directory. Note that in this case, Basilisk II tries to boot from the first volume file found, which is random and may not be what you want. floppy This item describes one floppy drive to be used by Basilisk II. There can be multiple "floppy" lines in the preferences file. If no "floppy" line is given, Basilisk II will try to automatically detect and use installed floppy drives. The format of the "floppy drive description" is the same as that of "disk" lines. cdrom This item describes one CD-ROM drive to be used by Basilisk II. There can be multiple "cdrom" lines in the preferences file. If no "cdrom" line is given, Basilisk II will try to automatically detect and use installed CD-ROM drives. The format of the "CD-ROM drive description" is the same as that of "disk" lines. extfs This item specifies the root directory for the "Host Directory Tree" file system (the "Unix/BeOS/Amiga/..." icon on the Finder desktop). All objects contained in that directory are accessible by Mac applications. This feature is only available when File System Manager V1.2 or later is installed on the Mac side. FSM 1.2 is built-in beginning with MacOS 7.6 and can be installed as a system extension (downloadable from Apple, look for the FSM SDK in the developer section) for earlier MacOS versions. scsi0 ... scsi6 These items describe the SCSI target to be used for a given Mac SCSI ID by Basilisk II. Basilisk II emulates the old SCSI Manager and allows to assign a different SCSI target (they don't even have to be on the same SCSI bus) for each SCSI ID (0..6) as seen by the MacOS. "scsi0" describes the target for ID 0, "scsi1" the target for ID 1 etc. The format of the "SCSI target" is platform specific. BeOS: The "SCSI target" has the format "/" (e.g. "0/2"). Due to a bug in BeOS, using SCSI with Basilisk II may cause the SCSI bus to hang. Use with caution. Linux: The "SCSI target" has to be the name of a device that complies to the Generic SCSI driver API. On a standard Linux installation, these devices are "/dev/sg0", "/dev/sg1" etc. Note that you must have appropriate access rights to these devices and that Generic SCSI support has to be compiled into the kernel. FreeBSD: The "SCSI target" has the format "/" (e.g. "2/0"). AmigaOS: The "SCSI target" has the format "/" (e.g. "scsi.device/2"). Windows: The "SCSI target" has the format <"Vendor"> <"Model"> (e.g. scsi0 "HP" "CD-Writer+ 7100"). Note the use of quotes. screen