File:  [UNIX Amiga Emulator] / uae / bebox.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:38:19 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, BSchmidt
CVS tags: uae060, HEAD
uae-0.6.0

/* 
 * UAE - The Un*x Amiga Emulator
 *
 * BeBox port specific stuff
 * 
 * (c) 1996 Christian Bauer
 */

#include <AppKit.h>
#include <InterfaceKit.h>
#include <KernelKit.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __STDC__ 1
#define __GNU_LIBRARY__
#include <getopt.h>
#undef __GNU_LIBRARY__
#undef __STDC__

#ifndef __bebox__
#error Compiling bebox.cpp, but __bebox__ unset.
#endif

extern "C" {
#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "options.h"
#include "memory.h"
#include "custom.h"
#include "newcpu.h"
#include "disk.h"
#include "debug.h"
#include "xwin.h"
#include "os.h"
#include "filesys.h"
#include "keybuf.h"
#include "keyboard.h"
}


class UAEWindow;
class BitmapView;
class Emulator;


/*
 *  The BeOS application object
 */

class UAE : public BApplication {
public:
	UAE();
	virtual void ArgvReceived(int argc, char **argv);
	virtual void ReadyToRun(void);
	virtual bool QuitRequested(void);
	virtual void AboutRequested(void);

private:
	BBitmap *the_bitmap;
	UAEWindow *main_window;
	Emulator *the_emulator;
};


/*
 *  The window in which the Amiga graphics are displayed, handles I/O
 */

class UAEWindow : public BWindow {
public:
	UAEWindow(BRect frame, BBitmap *bitmap);
	virtual bool QuitRequested(void);
	virtual void WindowActivated(bool active);

private:
	BitmapView *main_view;
};


/*
 *  A simple view class for blitting a bitmap on the screen
 */

class BitmapView : public BView {
public:
	BitmapView(BRect frame, BBitmap *bitmap);
	virtual void Draw(BRect update);
	void Draw(BRect from, BRect to);

private:
	BBitmap *the_bitmap;
};


/*
 *  For running the emulation in its own thread
 */

class Emulator {
public:
	Emulator() {thread_running = FALSE;}
	void Run(void);
	void Quit(void);

private:
	static long thread_invoc(Emulator *obj);
	void thread_func(void);

	thread_id the_thread;
	bool thread_running;
};


// Keyboard and mouse
int buttonstate[3];
int newmousecounters;
int lastmx, lastmy;

key_info old_key_info;
bool inwindow;
bool window_open;

// Color map and bitmap
xcolnr xcolors[4096];
struct vidbuf_description gfxvidinfo;

int vsize, hsize, hpixels;

BitmapView *bitmap_view;
UAEWindow *bitmap_window;


// Array for converting Be keycodes to Amiga keycodes
int keycode2amiga[128] = {
	-1, AK_ESC, AK_F1, AK_F2, AK_F3, AK_F4, AK_F5, AK_F6,
	AK_F7, AK_F8, AK_F9, AK_F10, AK_LALT, AK_mousestuff, AK_RALT, -1,

	-1, AK_BACKQUOTE, AK_1, AK_2, AK_3, AK_4, AK_5, AK_6,
	AK_7, AK_8, AK_9, AK_0, AK_MINUS, AK_EQUAL, AK_BS, AK_HELP,

	AK_NPLPAREN, AK_RAMI, AK_NPLPAREN, AK_NPDIV, AK_NPMUL, AK_NPSUB, AK_TAB, AK_Q,
	AK_W, AK_E, AK_R, AK_T, AK_Y, AK_U, AK_I, AK_O,

	AK_P, AK_LBRACKET, AK_RBRACKET, AK_BACKSLASH, AK_DEL, AK_NPRPAREN, AK_LAMI, AK_NP7,
	AK_NP8, AK_NP9, AK_NPADD, AK_CAPSLOCK, AK_A, AK_S, AK_D, AK_F,

	AK_G, AK_H, AK_J, AK_K, AK_L, AK_SEMICOLON, AK_QUOTE, AK_RET,
	AK_NP4, AK_NP5, AK_NP6, AK_LSH, AK_Z, AK_X, AK_C, AK_V,

	AK_B, AK_N, AK_M, AK_COMMA, AK_PERIOD, AK_SLASH, AK_RSH, AK_UP,
	AK_NP1, AK_NP2, AK_NP3, AK_ENT, AK_CTRL, AK_LAMI, AK_SPC, AK_RAMI,

	AK_RALT, AK_LF, AK_DN, AK_RT, AK_NP0, AK_NPDEL, AK_LALT, AK_RALT,
	AK_LTGT, -1, -1, -1, -1, -1, -1, -1,

	-1, -1, -1, -1, -1, -1, -1, -1,
	-1, -1, -1, -1, -1, -1, -1, -1
};


/*
 *  Create application object and start it
 */

main()
{
	UAE *the_app;
	
	the_app = new UAE();
	the_app->Run();
	delete the_app;
	
	return 0;
}


/*
 *  UAE Constructor: Initialize member variables
 */

UAE::UAE() : BApplication('UAEm')
{
	the_bitmap = NULL;
	the_emulator = NULL;
	main_window = NULL;
	window_open = FALSE;
}


/*
 *  Parse command line options
 */

void usage(void)
{
	printf("UAE - The Un*x Amiga emulator\n");
	printf("Summary of command-line options:\n");
	printf("  -h                       : Print help\n");
	printf("  -m VOLNAME:mount_point   : mount file system at <mount point> as AmigaDOS\n"
		   "                             volume VOLNAME:\n");
	printf("  -M VOLNAME:mount_point   : like -m, but mount read-only\n");
	printf("  -a                       : Don't mount the harddisk file automatically.\n"
		   "                             Useful only for testing.\n");
	printf("  -s                       : Emulate 1MB slow memory at 0xC00000\n");
    printf("  -F n                     : Emulate n MB fast memory at 0x200000\n");
	printf("  -f n                     : Set the frame rate to 1/n\n");
	printf("  -d                       : Draw the screen with the right aspect\n");
	printf("  -D                       : Start up the built-in debugger\n");
	printf("  -[0123] file             : Use file instead of df[0123].adf as disk image file\n");
	printf("  -r file                  : Use file as ROM image instead of kick.rom\n");
    printf("  -p filename              : Use filename to save printer output (may be LPT1: ?)\n");
	printf("  -J                       : Fake joystick emulation with the numeric pad.\n");
    printf("  -g                       : Turn on gfx-lib replacement.\n");
    printf("  -d mode                  : Select resolution with the mode parameter.\n");
    printf("  -H mode                  : Set the number of colors with the mode parameter.\n");
    printf("\n");
    printf("Valid resolutions: 0 (320x200); 1 (320x240); 2 (320x400); 3 (800x600);\n"
	   "                   4 (800x600, correct aspect)\n"
	   "Valid color modes: 0 (256 colors); 1 (32768 colors); 2 (65536 colors)\n"
	   "UAE may choose to ignore the color mode/resolution setting.\n");
}

void UAE::ArgvReceived(int argc, char **argv)
{
	int c;

    while(((c = getopt(argc, argv, "Df:gd:hF:asJm:M:0:1:2:3:r:H:p:")) != EOF)) switch(c) {
     case 'h': usage();	exit(0);

     case '0': strncpy(df0, optarg, 255); df0[255] = 0;	break;
     case '1': strncpy(df1, optarg, 255); df1[255] = 0; break;
     case '2': strncpy(df2, optarg, 255); df2[255] = 0; break;
     case '3': strncpy(df3, optarg, 255); df3[255] = 0; break;
     case 'r': strncpy(romfile, optarg, 255); romfile[255] = 0; break;
     case 'p': strncpy(prtname, optarg, 255); prtname[255] = 0; break;		    
     case 'm':
     case 'M':
	{
	    /* mount file system (repeatable)
	     * syntax: [-m | -M] VOLNAME:/mount_point
	     * example: -M CDROM:/cdrom -m UNIXFS:./disk
	     */
	    static int mount_seen = 0;
	    char buf[256];
	    char *s2;
	    int readonly = (c == 'M');
	    
	    if (mount_seen)
		fprintf(stderr, "warning: multiple mounts confuse Kickstart 1.3\n");
	    mount_seen = 1;
	    strncpy(buf, optarg, 255); buf[255] = 0;
	    s2 = strchr(buf, ':');
	    if(s2) {
		*s2++ = '\0';
		add_filesys_unit(buf, s2, readonly);
	    } else {
		fprintf(stderr, "Usage: [-m | -M] VOLNAME:/mount_point\n");
	    }
	}
	break;
	
     case 'f': framerate = atoi(optarg); break;
     case 'D': use_debugger = 1; break;
     case 'J': fake_joystick = 1; break;
     case 'a': automount_uaedev = 0; break;
     case 's': use_slow_mem = 1; break;
     case 'g': use_gfxlib = 1; break;

     case 'F':
	fastmem_size = atoi(optarg) * 0x100000;
	if (fastmem_size != 0x100000 && fastmem_size != 0x200000 
	    && fastmem_size != 0x400000 && fastmem_size != 0x800000) 
	{
	    fastmem_size = 0;
	    fprintf(stderr, "Unsupported fastmem size!\n");
	}
	
	break;
	
     case 'd':
	screen_res = atoi(optarg);
	if (screen_res >= 0 && screen_res <= 4) {
	} else {
	    fprintf(stderr, "Bad video mode selected. Using default.\n");
	    screen_res = 3;
	}
	dont_want_aspect = screen_res != 4;
	use_lores = screen_res < 3;
	break;

     case 'H':
	color_mode = atoi(optarg);
	if (color_mode < 0 || color_mode > 2) {
	    fprintf(stderr, "Bad color mode selected. Using default.\n");
	    color_mode = 0;
	}
	break;
    }
}


/*
 *  Arguments processed, create and start emulation
 */

void UAE::ReadyToRun(void)
{
	vsize = dont_want_aspect ? numscrlines : numscrlines*2;
	hsize = use_lores ? 400 : 800;
	hpixels = use_lores ? 320 : 796;

	// Allocate bitmap
	the_bitmap = new BBitmap(BRect(0, 0, hsize-1, vsize-1), B_COLOR_8_BIT);

	// Set up vidinfo
	gfxvidinfo.bufmem =  (char *)the_bitmap->Bits();
	gfxvidinfo.rowbytes = the_bitmap->BytesPerRow();
	gfxvidinfo.pixbytes = 1;
	gfxvidinfo.maxblocklines = 100;

	// Open window
	main_window = new UAEWindow(BRect(0, 0, hpixels-1, vsize-1), the_bitmap);

	// Initialize mouse and keyboard variables
	buttonstate[0] = buttonstate[1] = buttonstate[2] = FALSE;
	lastmx = lastmy = 0;
	newmousecounters = FALSE;
	inwindow = TRUE;

	// Start emulation
	the_emulator = new Emulator;
	the_emulator->Run();
}


/*
 *  Quit requested (either by menu or by closing the window)
 */

bool UAE::QuitRequested(void)
{
	if (BApplication::QuitRequested()) {

		// Stop emulation
		if (the_emulator) {
			the_emulator->Quit();
			delete the_emulator;
		}

		// Deallocate bitmap
		if (the_bitmap)
			delete the_bitmap;

		return TRUE;
	}
	return FALSE;
}


/*
 *  Display "about" window
 */

void UAE::AboutRequested(void)
{
	char str[256];

	sprintf(str, "UAE V0.5.3 by Bernd Schmidt\nBeBox port by Christian Bauer");
	BAlert *the_alert = new BAlert("", str, "OK");
	the_alert->Go();
}


/*
 *  UAE Window constructor
 */

UAEWindow::UAEWindow(BRect frame, BBitmap *bitmap) : BWindow(frame, "UAE", B_TITLED_WINDOW, B_NOT_RESIZABLE)
{
	int r, g, b, i;

	// Move window to right position
	MoveTo(80, 60);

	// Create bitmap view
	Lock();
	main_view = new BitmapView(frame, bitmap);
	AddChild(main_view);
	main_view->GetKeys(&old_key_info, FALSE);
	Unlock();

	bitmap_view = main_view;
	bitmap_window = this;

	// Initialize xcolors
	i = 0;
	for (r=0; r<16; r++) {
		for (g=0; g<16; g++) {
			for (b=0; b<16; b++)
				xcolors[i++] = index_for_color(r<<4 | r, g<<4 | g, b<<4 | b);
		}
	}

	// Show window
	Show();
	window_open = TRUE;
}


/*
 *  Closing the window quits UAE
 */

bool UAEWindow::QuitRequested(void)
{
	window_open = FALSE;
	be_app->PostMessage(B_QUIT_REQUESTED);
	return TRUE;
}


/*
 *  Window was (de)activated
 */

void UAEWindow::WindowActivated(bool active)
{
	inwindow = active;
}


/*
 *  Bitmap view constructor
 */

BitmapView::BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW)
{
	the_bitmap = bitmap;
}


/*
 *  Blit the bitmap
 */

void BitmapView::Draw(BRect update)
{
	DrawBitmap(the_bitmap, update, update);
}

void BitmapView::Draw(BRect from, BRect to)
{
	DrawBitmap(the_bitmap, from, to);
}


/*
 *  Start main emulation thread
 */

void Emulator::Run(void)
{
	// Initialize everything	
	produce_sound = FALSE;
	init_joystick();
	keybuf_init ();    
	memory_init();
	custom_init();
	DISK_init();
	init_m68k();
	MC68000_reset();

	// Start the emulation thread
	the_thread = spawn_thread(thread_invoc, "UAE 68000", B_NORMAL_PRIORITY, this);
	resume_thread(the_thread);
	thread_running = TRUE;
}


/*
 *  Stop main emulation thread
 */

void Emulator::Quit(void)
{
	// Kill the thread if it is running
	if (thread_running) {
		kill_thread(the_thread);
		thread_running = FALSE;
	}

	close_joystick();
}


/*
 *  The thread's main function
 */

long Emulator::thread_invoc(Emulator *obj)
{
	obj->thread_func();
	return 0;
}

void Emulator::thread_func(void)
{
	// This jumps to MC68000_run() and executes the main loop
	debug();
	thread_running = FALSE;
}


/*
 *  Redraw a line
 */

void flush_line(int y)
{
	if (window_open) {
		bitmap_window->Lock();
		bitmap_view->Draw(BRect(0, y, hpixels-1, y));
		bitmap_window->Unlock();
	}
}


/*
 *  Redraw a block
 */

void flush_block(int ystart, int ystop)
{
	int xs = use_lores ? prev_max_diwstop - 328 : 0;

	if (window_open) {
		bitmap_window->Lock();
		bitmap_view->Draw(BRect(xs, ystart, hpixels+xs-1, ystop), BRect(0, ystart, hpixels-1, ystop));
		bitmap_window->Unlock();
	}
}


/*
 *  Redraw the screen
 */

void flush_screen(int ystart, int ystop)
{
}


/*
 *  Poll mouse and keyboard
 */

void handle_events(void)
{
	key_info the_key_info;
	int be_code, be_byte, be_bit, amiga_code;
	BPoint mouse_point;
	ulong mouse_buttons;

	// Keyboard
	if (window_open && inwindow) {
		bitmap_window->Lock();
		bitmap_view->GetKeys(&the_key_info, FALSE);
		bitmap_window->Unlock();

		for (be_code=0; be_code<0x80; be_code++) {
			be_byte = be_code >> 3;
			be_bit = 1 << (~be_code & 7);

			// Key state changed?
			if ((the_key_info.key_states[be_byte] & be_bit)
			     != (old_key_info.key_states[be_byte] & be_bit)) {

				amiga_code = keycode2amiga[be_code];
				if (the_key_info.key_states[be_byte] & be_bit) {

					// Key pressed
					if (amiga_code == AK_mousestuff)
						togglemouse();
					else
						record_key(amiga_code << 1);
				} else {

					// Key released
					record_key((amiga_code << 1) | 1);
				}
			}
		}		
		old_key_info = the_key_info;

		// "Affengriff"
		if ((the_key_info.key_states[0x5c >> 3] & (1 << (~0x5c & 7)))
		 && (the_key_info.key_states[0x5d >> 3] & (1 << (~0x5d & 7)))
		 && (the_key_info.key_states[0x5f >> 3] & (1 << (~0x5f & 7))))
			MC68000_reset();

		// Scroll lock toggles inhibit_frame
		inhibit_frame = the_key_info.key_states[0x0f >> 3] & (1 << (~0x0f & 7));
	}

	// Mouse
	if (window_open && inwindow) {
		bitmap_window->Lock();
		bitmap_view->GetMouse(&mouse_point, &mouse_buttons, FALSE);
		bitmap_window->Unlock();
		lastmx = mouse_point.x;
		lastmy = mouse_point.y;

		buttonstate[0] = mouse_buttons & B_PRIMARY_MOUSE_BUTTON;
		buttonstate[1] = mouse_buttons & B_TERTIARY_MOUSE_BUTTON;
		buttonstate[2] = mouse_buttons & B_SECONDARY_MOUSE_BUTTON;
	}
}


int debuggable(void)
{
    return TRUE;
}

int needmousehack(void)
{
    return TRUE;
}

void LED(int on)
{
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.