update 0.9.0

This commit is contained in:
Rupert Hausberger 2016-07-30 01:31:36 +02:00
commit ea1d34267e
11 changed files with 1052 additions and 65 deletions

78
example.css Normal file
View file

@ -0,0 +1,78 @@
/*-------------------------------------------------------------------------
| SAE - Scripted Amiga Emulator
| https://github.com/naTmeg/ScriptedAmigaEmulator
|
| Copyright (C) 2012-2016 Rupert Hausberger
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of the GNU General Public License
| as published by the Free Software Foundation; either version 2
| of the License, or (at your option) any later version.
|
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
-------------------------------------------------------------------------*/
a:link { color:#24c; text-decoration:none; }
a:visited { color:#24c; text-decoration:none; }
a:hover { color:#24c; text-decoration:underline; }
body {
top:0;
left:0;
margin:0;
padding:0;
font-family:Verdana;
font-size:13px;
background-color:#f8f8f8;
-webkit-touch-callout:none;
-webkit-user-select:none;
-khtml-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
}
table {
white-space:nowrap;
}
/*---------------------------------*/
.gray { color:gray; }
.green { color:green; }
.orange { color:orange; }
.red { color:red; }
.alt { text-align:left; vertical-align:top; }
.alm { text-align:left; vertical-align:middle; }
.alb { text-align:left; vertical-align:bottom; }
.act { text-align:center; vertical-align:top; }
.acm { text-align:center; vertical-align:middle; }
.acb { text-align:center; vertical-align:bottom; }
.art { text-align:right; vertical-align:top; }
.arm { text-align:right; vertical-align:middle; }
.arb { text-align:right; vertical-align:bottom; }
.info {
font-size:11px;
color:dimgray;
}
.warn {
font-size:11px;
color:red;
}
.noscript {
margin:auto;
padding:4px;
font-size:17px;
font-weight:bold;
text-align:center;
color:red;
}

155
example.htm Normal file
View file

@ -0,0 +1,155 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<title>SAE - Scripted Amiga Emulator</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" type="text/css" href="example.css" />
<!-- Emulator files. When making them into one file, keep the order -->
<script type="text/javascript" src="sae/prototypes.js"></script>
<script type="text/javascript" src="sae/utils.js"></script>
<script type="text/javascript" src="sae/dms.js"></script>
<script type="text/javascript" src="sae/config.js"></script>
<script type="text/javascript" src="sae/roms.js"></script>
<script type="text/javascript" src="sae/memory.js"></script>
<script type="text/javascript" src="sae/autoconf.js"></script>
<script type="text/javascript" src="sae/expansion.js"></script>
<script type="text/javascript" src="sae/events.js"></script>
<script type="text/javascript" src="sae/gayle.js"></script>
<script type="text/javascript" src="sae/ide.js"></script>
<script type="text/javascript" src="sae/filesys.js"></script>
<script type="text/javascript" src="sae/hardfile.js"></script>
<script type="text/javascript" src="sae/input.js"></script>
<script type="text/javascript" src="sae/serial.js"></script>
<script type="text/javascript" src="sae/custom.js"></script>
<script type="text/javascript" src="sae/blitter.js"></script>
<script type="text/javascript" src="sae/copper.js"></script>
<script type="text/javascript" src="sae/playfield.js"></script>
<script type="text/javascript" src="sae/video.js"></script>
<script type="text/javascript" src="sae/audio.js"></script>
<script type="text/javascript" src="sae/cia.js"></script>
<script type="text/javascript" src="sae/disk.js"></script>
<script type="text/javascript" src="sae/rtc.js"></script>
<script type="text/javascript" src="sae/m68k.js"></script>
<script type="text/javascript" src="sae/cpu.js"></script>
<script type="text/javascript" src="sae/amiga.js"></script>
<!-- API-calls and support functions -->
<script type="text/javascript" src="example.js"></script>
</head>
<body onload="init()">
<noscript>
<div style="height:20px"></div>
<div class="noscript">JavaScript is disabled or not supported!</div>
<div style="height:20px"></div>
</noscript>
<div style="text-align:center">
<div style="height:10px"></div>
<table style="margin:auto">
<!-- Status-leds for our hooks later -->
<tr>
<td class="arm">Status</td>
<td class="alm">
<table style="border:1px solid #333">
<tr>
<td class="acm" style="width:32px"><span id="status_led_power">PWR</span></td>
<td class="acm" style="width:16px"><span id="status_led_hd">HD</span></td>
<td class="arm" style="width:16px"><span id="status_led_df0">0</span></td>
<td class="arm" style="width:16px"><span id="status_led_df1">0</span></td>
<td class="arm" style="width:16px"><span id="status_led_df2">0</span></td>
<td class="arm" style="width:16px"><span id="status_led_df3">0</span></td>
<td class="arm" style="width:32px"><span id="status_led_fps">0</span></td>
<td class="arm" style="width:32px"><span id="status_led_cpu">0</span></td>
</tr>
</table>
</td>
</tr>
<!-- Some config-items -->
<tr>
<td class="arm">Config</td>
<td class="alm">
<table style="border:1px solid #333">
<tr>
<td class="arm">Amiga Model</td>
<td>
<select id="cfg_model">
<option value="A500">A500</option>
<option value="A500P">A500 Plus</option>
<option value="A600">A600</option>
<option value="A1000">A1000</option>
<option value="A1200">A1200</option>
<option value="A2000">A2000</option>
<option value="A3000">A3000</option>
<option value="A4000">A4000</option>
<option value="A4000T">A4000 Tower</option>
</select>
</td>
</tr>
<tr>
<td class="arm">Resolution</td>
<td>
<select id="cfg_res">
<option value="1">Lores</option>
<option value="2">Hires</option>
<option value="3">SuperHires</option>
</select>
<select id="cfg_ntsc">
<option value="0">PAL</option>
<option value="1">NTSC</option>
</select>
</td>
</tr>
<tr>
<td class="arm">Kickstart ROM</td>
<td>
<input id="cfg_rom_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="romSelect()" />
<span id="cfg_rom_name" class="red">&lt;unset&gt; (required)</span>
<button class="button" onclick="document.getElementById('cfg_rom_file').click()">Select</button>
<button class="button" id="cfg_rom_remove" onclick="romRemove()">Remove</button>
</td>
</tr>
<tr>
<td class="arm">Floppy (DF0)</td>
<td>
<input id="cfg_df0_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="floppyInsert(0)" />
<span id="cfg_df0_name" class="gray">&lt;empty&gt;</span>
<button class="button" onclick="document.getElementById('cfg_df0_file').click()">Insert</button>
<button class="button" id="cfg_df0_eject" onclick="floppyEject(0)">Eject</button>
</td>
</tr>
</table>
</td>
</tr>
<!-- Control-buttons -->
<tr>
<td class="arm">Controls</td>
<td class="alm">
<table>
<tr>
<td><button onclick="start()">Start</button></td>
<td><button onclick="stop()">Stop</button></td>
<td><button onclick="reset()">Reset</button></td>
<td><button onclick="pause(1)" id="controls_pr">Pause</button></td>
</tr>
</table>
</td>
</tr>
<!-- Output -->
<tr>
<td class="arm">Output</td>
<td class="alm">
<!-- Method 1: SAE will create a canvas and add it into the div-element below -->
<div id="myVideo" style="margin:auto"></div>
<!-- Method 2: The canvas is already defined. SAE will output to the element below.
The size of the canvas is set by SAE according your settings -->
<!--<canvas id="myVideo" style="margin:auto;background-color:#000"></canvas>-->
</td>
</tr>
</table>
</div>
</body>
</html>

548
example.js Normal file
View file

@ -0,0 +1,548 @@
/*-------------------------------------------------------------------------
| SAE - Scripted Amiga Emulator
| https://github.com/naTmeg/ScriptedAmigaEmulator
|
| Copyright (C) 2012-2016 Rupert Hausberger
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of the GNU General Public License
| as published by the Free Software Foundation; either version 2
| of the License, or (at your option) any later version.
|
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| Note: This file does not contain any emulator-code.
-------------------------------------------------------------------------*/
var sae = null; /* SAE instance */
var cfg = null; /* Reference to the config-object */
var inf = null; /* Reference to the info-object */
var running = false; /* Is the emualtion currently running? */
var paused = false; /* Is the emualtion currently paused? */
/*-----------------------------------------------------------------------*/
/* Helpers */
function getSelect(id, asString) {
if (typeof asString == "undefined") asString = false;
var e = document.getElementById(id);
for (var i = 0; i < e.length; i++) {
if (e[i].selected)
return asString ? e[i].value : Number(e[i].value);
}
return false;
}
function setSelect(id, v) {
var e = document.getElementById(id);
var vs = String(v);
for (var i = 0; i < e.length; i++) {
if (e[i].value === vs) {
e[i].selected = true;
return;
}
}
}
function styleDisplayInline(id, show) {
var e = document.getElementById(id);
e.style.display = show ? "inline" : "none";
}
function switchPauseResume(p) {
var e = document.getElementById("controls_pr");
if (p) {
e.innerHTML = "Resume";
e.onclick = function() { pause(false); };
} else {
e.innerHTML = "Pause";
e.onclick = function() { pause(true); };
}
}
function saee2text(err) {
switch (err) {
case SAEE_AlreadyRunning: return "The emulator is already running.";
case SAEE_NotRunning: return "The emulator is not running.";
case SAEE_NoTimer: return "No timing-functions avail. Please upgrade your browser.";
case SAEE_NoMemory: return "Out of memory.";
case SAEE_Internal: return "Internal emulator error.";
case SAEE_Config_Invalid: return "Invalid configuration.";
case SAEE_CPU_Internal: return "Internal CPU-error.";
case SAEE_CPU_Requires68020: return "The selected kickstart-rom does require a 68020 and 32bit address-space";
case SAEE_CPU_Requires680EC20: return "The selected kickstart-rom does require a 68020.";
case SAEE_CPU_Requires68030: return "The selected kickstart-rom does require a 68030.";
case SAEE_CPU_Requires68040: return "The selected kickstart-rom does require a 68040/68060.";
case SAEE_Memory_NoKickstartRom: return "The kickstart-rom is missing.";
case SAEE_Memory_NoExtendedRom: return "An extended-rom is required but missing.\n\nGo to the ROM-page and select a rom from disk...";
case SAEE_Memory_RomSize: return "The kickstart- or extended-rom does have an invalid size.";
case SAEE_Memory_RomKey: return "A ROM-keyfile is required. (Cloanto)";
case SAEE_Memory_RomDecode: return "Invalid ROM-keyfile. (Cloanto)";
case SAEE_Memory_RomChecksum: return "Checksum-error at the kickstart- or extended-rom.";
case SAEE_Memory_RomUnknown: return "Unknown ROM.";
case SAEE_Video_ElementNotFound: return "Video DIV-element not found. Check 'cfg.video.id'";
case SAEE_Video_RequiresCanvas: return "This browser does not support 'Canvas'. Please upgrade to an actual version.";
case SAEE_Video_RequiresWegGl: return "This browser does not support 'WebGL'. Please upgrade to an actual version.";
case SAEE_Video_ComphileShader: return "Can not compile the required shader-program.";
case SAEE_Video_LinkShader: return "Can not link the required shader-program.";
case SAEE_Audio_RequiresWebAudio: return "This browser does not support 'WebAudio'. Please upgrade to an actual version.";
default: return "("+err+")";
}
}
function loadFile(e, callback) {
var reader = new FileReader();
reader.onload = callback;
reader.readAsBinaryString(e);
}
/*---------------------------------*/
/* CRC-32 checksumming */
const crc32Table = (function() {
var table = new Uint32Array(256);
var n, c, k;
for (n = 0; n < 256; n++) {
c = n;
for (k = 0; k < 8; k++)
c = ((c >>> 1) ^ (c & 1 ? 0xedb88320 : 0)) >>> 0;
table[n] = c;
}
return table;
})();
function crc32(data) {
var length = data.length;
var offset = 0;
var crc = 0xffffffff;
while (length-- > 0)
crc = crc32Table[(crc ^ data.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8);
return (crc ^ 0xffffffff) >>> 0;
}
if (crc32("The quick brown fox jumps over the lazy dog") != 0x414fa339)
alert("CRC32-hash testing failed. SAE will not work. This is an internal bug!?");
/*-----------------------------------------------------------------------*/
/* Config */
function fixConfig() {
/* video */
if (cfg.video.enabled) {
if (!inf.video.canvas && !inf.video.webGL)
cfg.video.enabled = false;
else if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL && !inf.video.webGL)
SAEV_config.video.api = SAEC_Config_Video_API_Canvas;
}
/* audio */
if (cfg.audio.mode >= SAEC_Config_Audio_Mode_On) {
if (!inf.audio.webAudio)
cfg.audio.mode = SAEC_Config_Audio_Mode_Off_Emul;
}
}
function setRomName() {
var e = document.getElementById("cfg_rom_name");
if (cfg.memory.rom.size) {
e.className = "";
e.innerHTML = cfg.memory.rom.name;
styleDisplayInline("cfg_rom_remove", 1);
} else {
e.className = "red";
e.innerHTML = "&lt;unset&gt; (required)";
styleDisplayInline("cfg_rom_remove", 0);
document.getElementById("cfg_rom_file").value = "";
}
}
function setFloppyName(n) {
var e = document.getElementById("cfg_df"+n+"_name");
if (cfg.floppy.drive[n].file.size) {
e.className = "";
e.innerHTML = cfg.floppy.drive[n].file.name;
styleDisplayInline("cfg_df"+n+"_eject", 1);
} else {
e.className = "gray";
e.innerHTML = "&lt;unset&gt;";
styleDisplayInline("cfg_df"+n+"_eject", 0);
document.getElementById("cfg_df"+n+"_file").value = "";
}
}
function setConfig() {
fixConfig();
setSelect("cfg_ntsc", cfg.chipset.ntsc ? 1 : 0);
setRomName();
setFloppyName(0);
switch (cfg.video.hresolution) {
case SAEC_Config_Video_HResolution_LoRes:
setSelect("cfg_res", 1);
break;
case SAEC_Config_Video_HResolution_HiRes:
setSelect("cfg_res", 2);
break;
case SAEC_Config_Video_HResolution_SuperHiRes:
setSelect("cfg_res", 3);
break;
}
}
/*---------------------------------*/
function getConfig() {
var model = SAEC_Model_A2000; /* Default model after page-load*/
var modelSubConfig = 0; /* See config.js */
switch (getSelect("cfg_model", true)) {
case "A500": model = SAEC_Model_A500; break;
case "A500P": model = SAEC_Model_A500P; break;
case "A600": model = SAEC_Model_A600; break;
case "A1000": model = SAEC_Model_A1000; break;
case "A1200": model = SAEC_Model_A1200; break;
case "A2000": model = SAEC_Model_A2000; break;
case "A3000": model = SAEC_Model_A3000; break;
case "A4000": model = SAEC_Model_A4000; break;
case "A4000T": model = SAEC_Model_A4000T; break;
/* future. do not use. cd-emulation is not implemented yet.
case "CDTV": model = SAEC_Model_CDTV; break;
case "CD32": model = SAEC_Model_CD32; break; */
}
/* Set the defaults for the selected model.
ROMs and Floppies are not affected. */
sae.setModel(model, modelSubConfig);
/* After here, you may tweak additional settings */
cfg.chipset.ntsc = getSelect("cfg_ntsc") == 1;
cfg.memory.z2FastSize = 2 << 20; /* Give 2mb zorro2 fast-ram */
/* Do we have rom-data? */
if (cfg.memory.rom.size == 0) {
alert(saee2text(SAEE_Memory_NoKickstartRom));
return false;
}
cfg.floppy.speed = SAEC_Config_Floppy_Speed_Turbo; /* Set speed to turbo. This is not always compatible */
cfg.video.id = "myVideo"; /* Set the id-name of the desired output-div or output-canvas */
switch (getSelect("cfg_res")) {
case 1: /* Lores */
cfg.video.hresolution = SAEC_Config_Video_HResolution_LoRes;
cfg.video.vresolution = SAEC_Config_Video_VResolution_NonDouble;
cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH; /* 360 */
cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT; /* 284 */
break;
case 2: /* Hires */
cfg.video.hresolution = SAEC_Config_Video_HResolution_HiRes;
cfg.video.vresolution = SAEC_Config_Video_VResolution_Double;
cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH << 1; /* 720 */
cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT << 1; /* 568 */
break;
case 3: /* SuperHires */
cfg.video.hresolution = SAEC_Config_Video_HResolution_SuperHiRes;
cfg.video.vresolution = SAEC_Config_Video_VResolution_Double;
cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH << 2; /* 1440 */
cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT << 1; /* 568 */
break;
}
/* Set hooks */
cfg.hook.log.error = hook_log_error;
cfg.hook.event.started = hook_event_started;
cfg.hook.event.stopped = hook_event_stopped;
cfg.hook.event.reseted = hook_event_reseted;
cfg.hook.event.paused = hook_event_paused;
cfg.hook.led.power = hook_led_power;
cfg.hook.led.hd = hook_led_hd;
cfg.hook.led.df = hook_led_df;
cfg.hook.led.fps = hook_led_fps;
cfg.hook.led.cpu = hook_led_cpu;
/* Enable debug-log to developer-console */
cfg.debug.level = SAEC_Config_Debug_Level_Log;
/* NOTE:
DO NOT ALTER the config-object while the emulator is running.
I will release a detailed description of the config-object soon.
*/
return true;
}
/*---------------------------------*/
/* Control buttons */
function start() {
if (getConfig()) {
/* Start the emulator. This does take some time.
Once started, the hook SAEV_config.hook.event.started will be called. (new 0.9.1) */
var err = sae.start();
if (err == SAEE_None) {
/* ... */
} else
alert(saee2text(err));
}
}
function stop() {
/* Send stop-request. This does take some time.
Once stopped, the hook SAEV_config.hook.event.stopped will be called. (new 0.9.1) */
var err = sae.stop();
if (err == SAEE_None) {
/* ... */
} else
alert(saee2text(err));
}
function reset() {
/* Send soft-reset request. This does take some time.
Once done, the hook SAEV_config.hook.event.reseted will be called. (new 0.9.1) */
var hard = false, keyboard = false;
var err = sae.reset(hard, keyboard);
if (err == SAEE_None) {
/* ... */
} else
alert(saee2text(err));
}
function pause(p) {
/* Send Pause- or Resume-request. This does take some time.
Once paused or resumed, the hook SAEV_config.hook.event.paused will be called. (new 0.9.1)
true == pause, false == resume */
var err = sae.pause(p);
if (err == SAEE_None) {
/* ... */
} else
alert(saee2text(err));
}
function romSelect() {
var e = document.getElementById("cfg_rom_file").files[0];
if (e) {
loadFile(e, function (event) {
//cfg.memory.rom.path = e.path; currently unused in SAE
cfg.memory.rom.name = e.name; /* filename */
cfg.memory.rom.data = event.target.result; /* typeof 'String' or 'Uint8Array' */
cfg.memory.rom.size = e.size; /* size in bytes */
cfg.memory.rom.crc32 = crc32(event.target.result); /* pre-calculate crc32 for a faster start */
setRomName();
/*ri = new SAEO_RomInfo();
var err = sae.getRomInfo(ri, cfg.memory.rom);
if (err == SAEE_None) {
examine 'ri'...
}*/
});
}
}
function romRemove() {
cfg.memory.rom.clr();
setRomName();
}
function floppyInsert(n) {
var e = document.getElementById("cfg_df"+n+"_file").files[0];
if (e) {
loadFile(e, function(event) {
var file = cfg.floppy.drive[n].file;
//file.path = e.path; currently unused in SAE
file.name = e.name; /* filename */
file.data = event.target.result; /* typeof 'String' or 'Uint8Array' */
file.size = e.size; /* size in bytes */
file.crc32 = crc32(event.target.result); /* pre-calculate crc32 for a faster start */
setFloppyName(n);
/*var di = new SAEO_DiskInfo();
var err = sae.getDiskInfo(di, n);
if (err == SAEE_None) {
examine 'di'...
}*/
/* If the emulator is running, notify about the disk-change */
if (running)
sae.insert(n);
});
}
}
function floppyEject(n) {
cfg.floppy.drive[n].file.clr();
setFloppyName(n);
/* If the emulator is running, notify about the disk-change */
if (running)
sae.eject(n);
}
/*---------------------------------*/
/* Init-routine, called once on page-load */
function init() {
/* Create the emulator */
sae = new ScriptedAmigaEmulator();
/* Get the reference to the info-object.
As alternative, you can use the constant 'SAEC_info' directly,
defined in amiga.js */
inf = sae.getInfo(); /* or */
//inf = SAEC_info;
//console.dir(inf);
/* Get the reference to the config-object.
As alternative, you can use the variable 'SAEV_config' directly,
defined in config.js */
cfg = sae.getConfig(); /* or */
//cfg = SAEV_config;
//console.dir(cfg);
initLEDs();
setConfig();
}
/*-----------------------------------------------------------------------*/
/* Hooks (callbacks) */
/*---------------------------------*/
/* Logging */
/* There is currently only one log-hook, if a fatal error
does occure while the emulator is running. */
function hook_log_error(err, msg) {
/* err is a number type. See SAEE_* for the error code. */
running = false;
if (msg.length)
alert(msg);
}
/*---------------------------------*/
/* Events (new 0.9.1) */
/* Get call after the emulator has finished the starting-process. */
function hook_event_started() {
running = true;
}
/* Get call after the emulator has finished the stopping-process. */
function hook_event_stopped() {
running = false;
if (paused) {
paused = false;
switchPauseResume(paused);
}
resetLEDs();
}
/* Get call after the emulator has finished the reset-routine. */
function hook_event_reseted(hard) {
if (paused) {
paused = false;
switchPauseResume(paused);
}
}
/* Get call after the emulator has finished switching between pause-resume. */
function hook_event_paused(p) {
paused = p;
switchPauseResume(p);
}
/*---------------------------------*/
/* LEDs */
const COL_GRAY = "#000";
const COL_GREEN = "#8C8";
const COL_RED = "#E88";
const COL_ORANGE = "#CC8";
/* cache elements */
var e_led_power = null;
var e_led_hd = null;
var e_led_df = [null,null,null,null];
var e_led_fps = null;
var e_led_cpu = null;
/* Power LED: boolean On/Off */
function hook_led_power(on) {
e_led_power.style.color = on ? COL_GREEN : COL_GRAY;
}
/* Harddisk-LED */
function hook_led_hd(rw) {
/* rw 0=Off, 1=Read, 2=Write */
e_led_hd.style.color = rw == 1 ? COL_GREEN : (rw == 2 ? COL_RED : COL_GRAY);
}
/* Floppy-LED */
function hook_led_df(unit, disabled, cylinder, side, rw) {
/* unit 0-3 */
/* cylinder 0-81 */
/* side 0-1 */
/* rw 0=Off, 1=Read, 2=Write */
if (disabled) {
e_led_df[unit].innerHTML = "-";
e_led_df[unit].style.color = COL_GRAY;
} else {
e_led_df[unit].innerHTML = String(cylinder);
e_led_df[unit].style.color = rw == 1 ? COL_GREEN : (rw == 2 ? COL_RED : COL_GRAY);
}
}
/* FPS (Frames Per Second) */
function hook_led_fps(fps, paused) {
/* fps is a float-number, 0-50, in frames */
e_led_fps.innerHTML = paused ? "0.0" : fps.toFixed(1);
e_led_fps.style.color = COL_GRAY;
}
/* CPU-usage */
function hook_led_cpu(usage, paused) {
/* usage is a float-number, 0-1000, in percent */
if (paused) {
e_led_cpu.innerHTML = "0&#37;";
e_led_cpu.style.color = COL_GRAY;
} else {
e_led_cpu.innerHTML = usage.toFixed(0) + "&#37;";
if (usage < 90)
e_led_cpu.style.color = COL_GREEN;
else if (usage < 110)
e_led_cpu.style.color = COL_ORANGE;
else
e_led_cpu.style.color = COL_RED;
}
}
function resetLEDs() {
hook_led_power(false);
hook_led_hd(0);
hook_led_df(0, true, 0, 0, 0);
hook_led_df(1, true, 0, 0, 0);
hook_led_df(2, true, 0, 0, 0);
hook_led_df(3, true, 0, 0, 0);
hook_led_fps(0, false);
hook_led_cpu(0, false);
}
function initLEDs() {
e_led_power = document.getElementById("status_led_power");
e_led_hd = document.getElementById("status_led_hd");
e_led_df[0] = document.getElementById("status_led_df0");
e_led_df[1] = document.getElementById("status_led_df1");
e_led_df[2] = document.getElementById("status_led_df2");
e_led_df[3] = document.getElementById("status_led_df3");
e_led_fps = document.getElementById("status_led_fps");
e_led_cpu = document.getElementById("status_led_cpu");
resetLEDs();
}

155
example2.htm Normal file
View file

@ -0,0 +1,155 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<title>SAE - Scripted Amiga Emulator</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" type="text/css" href="example.css" />
<!-- Emulator files. When making them into one file, keep the order -->
<script type="text/javascript" src="sae/prototypes.js"></script>
<script type="text/javascript" src="sae/utils.js"></script>
<script type="text/javascript" src="sae/dms.js"></script>
<script type="text/javascript" src="sae/config.js"></script>
<script type="text/javascript" src="sae/roms.js"></script>
<script type="text/javascript" src="sae/memory.js"></script>
<script type="text/javascript" src="sae/autoconf.js"></script>
<script type="text/javascript" src="sae/expansion.js"></script>
<script type="text/javascript" src="sae/events.js"></script>
<script type="text/javascript" src="sae/gayle.js"></script>
<script type="text/javascript" src="sae/ide.js"></script>
<script type="text/javascript" src="sae/filesys.js"></script>
<script type="text/javascript" src="sae/hardfile.js"></script>
<script type="text/javascript" src="sae/input.js"></script>
<script type="text/javascript" src="sae/serial.js"></script>
<script type="text/javascript" src="sae/custom.js"></script>
<script type="text/javascript" src="sae/blitter.js"></script>
<script type="text/javascript" src="sae/copper.js"></script>
<script type="text/javascript" src="sae/playfield.js"></script>
<script type="text/javascript" src="sae/video.js"></script>
<script type="text/javascript" src="sae/audio.js"></script>
<script type="text/javascript" src="sae/cia.js"></script>
<script type="text/javascript" src="sae/disk.js"></script>
<script type="text/javascript" src="sae/rtc.js"></script>
<script type="text/javascript" src="sae/m68k.js"></script>
<script type="text/javascript" src="sae/cpu.js"></script>
<script type="text/javascript" src="sae/amiga.js"></script>
<!-- API-calls and support functions -->
<script type="text/javascript" src="example.js"></script>
</head>
<body onload="init()">
<noscript>
<div style="height:20px"></div>
<div class="noscript">JavaScript is disabled or not supported!</div>
<div style="height:20px"></div>
</noscript>
<div style="text-align:center">
<div style="height:10px"></div>
<table style="margin:auto">
<!-- Status-leds for our hooks later -->
<tr>
<td class="arm">Status</td>
<td class="alm">
<table style="border:1px solid #333">
<tr>
<td class="acm" style="width:32px"><span id="status_led_power">PWR</span></td>
<td class="acm" style="width:16px"><span id="status_led_hd">HD</span></td>
<td class="arm" style="width:16px"><span id="status_led_df0">0</span></td>
<td class="arm" style="width:16px"><span id="status_led_df1">0</span></td>
<td class="arm" style="width:16px"><span id="status_led_df2">0</span></td>
<td class="arm" style="width:16px"><span id="status_led_df3">0</span></td>
<td class="arm" style="width:32px"><span id="status_led_fps">0</span></td>
<td class="arm" style="width:32px"><span id="status_led_cpu">0</span></td>
</tr>
</table>
</td>
</tr>
<!-- Some config-items -->
<tr>
<td class="arm">Config</td>
<td class="alm">
<table style="border:1px solid #333">
<tr>
<td class="arm">Amiga Model</td>
<td>
<select id="cfg_model">
<option value="A500">A500</option>
<option value="A500P">A500 Plus</option>
<option value="A600">A600</option>
<option value="A1000">A1000</option>
<option value="A1200">A1200</option>
<option value="A2000">A2000</option>
<option value="A3000">A3000</option>
<option value="A4000">A4000</option>
<option value="A4000T">A4000 Tower</option>
</select>
</td>
</tr>
<tr>
<td class="arm">Resolution</td>
<td>
<select id="cfg_res">
<option value="1">Lores</option>
<option value="2">Hires</option>
<option value="3">SuperHires</option>
</select>
<select id="cfg_ntsc">
<option value="0">PAL</option>
<option value="1">NTSC</option>
</select>
</td>
</tr>
<tr>
<td class="arm">Kickstart ROM</td>
<td>
<input id="cfg_rom_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="romSelect()" />
<span id="cfg_rom_name" class="red">&lt;unset&gt; (required)</span>
<button class="button" onclick="document.getElementById('cfg_rom_file').click()">Select</button>
<button class="button" id="cfg_rom_remove" onclick="romRemove()">Remove</button>
</td>
</tr>
<tr>
<td class="arm">Floppy (DF0)</td>
<td>
<input id="cfg_df0_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="floppyInsert(0)" />
<span id="cfg_df0_name" class="gray">&lt;empty&gt;</span>
<button class="button" onclick="document.getElementById('cfg_df0_file').click()">Insert</button>
<button class="button" id="cfg_df0_eject" onclick="floppyEject(0)">Eject</button>
</td>
</tr>
</table>
</td>
</tr>
<!-- Control-buttons -->
<tr>
<td class="arm">Controls</td>
<td class="alm">
<table>
<tr>
<td><button onclick="start()">Start</button></td>
<td><button onclick="stop()">Stop</button></td>
<td><button onclick="reset()">Reset</button></td>
<td><button onclick="pause(1)" id="controls_pr">Pause</button></td>
</tr>
</table>
</td>
</tr>
<!-- Output -->
<tr>
<td class="arm">Output</td>
<td class="alm">
<!-- Method 1: SAE will create a canvas and add it into the div-element below -->
<!--<div id="myVideo" style="margin:auto"></div>-->
<!-- Method 2: The canvas is already defined. SAE will output to the element below.
The size of the canvas is set by SAE according your settings -->
<canvas id="myVideo" style="margin:auto;background-color:#000"></canvas>
</td>
</tr>
</table>
</div>
</body>
</html>

View file

@ -1382,14 +1382,11 @@ function start() {
var s = cache.state();
if (s == S_VALID) { /* all files are downloaded or cached, go! */
freezeButtons(false, true);
switchBaseEmul(true);
var err = sae.start(); /* this does start the emulator */
if (err != SAEE_None) {
switchBaseEmul(false);
if (err != SAEE_None)
alert(saee2text(err));
}
}
else if (s == S_PENDING) { /* files are still downloading, wait... */
setTimeout(start, 250);
}
@ -1423,37 +1420,15 @@ function advandedStart() {
}
function stop() {
sae.stop();
if (paused) {
paused = false;
switchPauseResume(paused);
}
if (dskchg)
dskchgClose();
if (mode == MODE_Advanced)
setAdvandedConfig();
switchBaseEmul(false);
}
function reset() {
sae.reset();
if (paused) {
paused = false;
switchPauseResume(paused);
}
if (dskchg)
dskchgClose();
sae.stop(); /* send stop-request */
}
function pause(p) {
switchPauseResume(p);
paused = p;
sae.pause(p); /* send pause-request */
}
sae.pause(p); /* true == pause, false == resume */
function reset() {
sae.reset(false, false);
}
/*---------------------------------*/
@ -2472,7 +2447,7 @@ function portUpdate(n) {
}
/*-----------------------------------------------------------------------*/
/* status hooks */
/* hooks */
function hook_log_error(err, msg) {
stop();
@ -2480,6 +2455,42 @@ function hook_log_error(err, msg) {
alert(msg);
}
/*---------------------------------*/
function hook_event_started() {
switchBaseEmul(true);
}
function hook_event_stopped() {
if (paused) {
paused = false;
switchPauseResume(paused);
}
if (dskchg)
dskchgClose();
if (mode == MODE_Advanced)
setAdvandedConfig();
switchBaseEmul(false);
}
function hook_event_reseted(hard) {
if (paused) {
paused = false;
switchPauseResume(paused);
}
if (dskchg)
dskchgClose();
}
function hook_event_paused(p) {
paused = p;
switchPauseResume(p);
}
/*---------------------------------*/
const COL_GRAY = "#888";
const COL_GREEN = "#8C8";
const COL_RED = "#E88";
@ -2547,6 +2558,11 @@ function initHooks() {
function setHooks() {
cfg.hook.log.error = hook_log_error;
cfg.hook.event.started = hook_event_started;
cfg.hook.event.stopped = hook_event_stopped;
cfg.hook.event.reseted = hook_event_reseted;
cfg.hook.event.paused = hook_event_paused;
cfg.hook.led.power = hook_led_power;
cfg.hook.led.hd = hook_led_hd;
cfg.hook.led.df = hook_led_df;

View file

@ -390,16 +390,25 @@ function ScriptedAmigaEmulator() {
this.start_program = function() {
this.do_start_program();
if (typeof SAEV_config.hook.event.started === "function")
SAEV_config.hook.event.started();
}
this.leave_program = function() {
this.dump();
this.do_leave_program();
if (typeof SAEV_config.hook.event.stopped === "function")
SAEV_config.hook.event.stopped();
}
this.pause_program = function(p) {
this.audio.pauseResume(p);
this.events.pauseResume(p);
if (typeof SAEV_config.hook.event.paused === "function")
SAEV_config.hook.event.paused(p);
}
/*---------------------------------*/
@ -503,16 +512,16 @@ function ScriptedAmigaEmulator() {
}
};
this.reset = function(hardreset, keyboardreset) { //uae_reset(hardreset, keyboardreset)
if (typeof hardreset == "undefined") var hardreset = 1;
if (typeof keyboardreset == "undefined") var keyboardreset = 0;
this.reset = function(hard, keyboard) { //uae_reset(hard, keyboard)
if (typeof hard == "undefined") var hard = false;
if (typeof keyboard == "undefined") var keyboard = false;
if (this.running) {
SAEF_info("sae.reset() hard %d, keyboard %d", hardreset, keyboardreset);
SAEF_info("sae.reset() hard %d, keyboard %d", hard?1:0, keyboard?1:0);
if (SAEV_command == 0) {
SAEV_command = -SAEC_command_Reset;
if (keyboardreset)
SAEV_command = -SAEC_command_Reset; /* soft */
if (keyboard)
SAEV_command = -SAEC_command_KeyboardReset;
if (hardreset)
if (hard)
SAEV_command = -SAEC_command_HardReset;
}
return SAEE_None;
@ -576,6 +585,10 @@ function ScriptedAmigaEmulator() {
return SAEE_None;
};
this.keyPress = function(e, down) {
this.input.keyPress(e, down);
}
/*---------------------------------*/
SAEF_info("SAE %d.%d.%d", SAEC_Version, SAEC_Revision, SAEC_Patch);

View file

@ -718,6 +718,12 @@ function SAEO_Config() {
df: function(unit, dis, cyl, side, rw) {},
fps: function(fps, paused) {},
cpu: function(usage, paused) {}
},
event: {
started: function() {},
stopped: function() {},
reseted: function(hard) { console.warn("RES", hard); },
paused: function(paused) {}
}
};

View file

@ -741,6 +741,10 @@ function SAEO_Keyboard() {
if (keyState[loc][code] != oldstate)
processKey(loc, code, keyState[loc][code]);
};
this.keyPress = function(e, down) {
handleKey(e, down);
};
}
function SAEO_Input() {
@ -772,6 +776,10 @@ function SAEO_Input() {
potgo.count = 0;
};
this.keyPress = function (e, down) {
this.keyboard.keyPress(e, down);
};
this.POTGO = function (v) {
//SAEF_log("Input.POTGO() $%04x", v);
potgo.data = v;

View file

@ -227,7 +227,6 @@ function SAEO_M68K() {
SAER.memory.clear();
SAEF_log("m68k.m68k_cycle() hardreset, memory cleared.");
}
cpu_hardreset = false;
if (SAEV_config.audio.mode == 0)
SAER_Events_eventtab[SAEC_Events_EV_AUDIO].active = false;
@ -237,6 +236,11 @@ function SAEO_M68K() {
//SAER.audio.check_prefs_changed_audio();
//statusline_clear();
if (typeof SAEV_config.hook.event.reseted === "function")
SAEV_config.hook.event.reseted(cpu_hardreset);
cpu_hardreset = false;
}
if (startup) {

View file

@ -2205,7 +2205,7 @@ function SAEO_Playfield() {
switch (gfxvidinfo.drawbuffer.pixbytes) {
case 2:
pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch2_aga_genlock : linetoscr_16_stretch2_aga;
pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch2_aga_spr_genlock : linetoscr_16_stretch2_aga_spr_genlock;
pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch2_aga_spr_genlock : linetoscr_16_stretch2_aga_spr;
pfield_do_linetoscr_spriteonly = linetoscr_16_stretch2_aga_spronly;
break;
case 4:

View file

@ -92,7 +92,6 @@ function SAEO_Video() {
this.surface = null;
this.div = null;
this.video = null;
this.shown = false;
this.fullscreen = false;
}
@ -198,7 +197,12 @@ function SAEO_Video() {
function CreateWindow(left, top, width, height) {
var hWnd = new HWND();
var el = document.getElementById(SAEV_config.video.id);
if (el.nodeName == "CANVAS")
hWnd.canvas = el;
else
hWnd.canvas = document.createElement("canvas");
hWnd.canvas.width = width;
hWnd.canvas.height = height;
hWnd.canvas.style.backgroundColor = sprintf("#%06X", SAEV_config.video.backgroundColor);
@ -265,40 +269,39 @@ function SAEO_Video() {
const SW_SHOWNORMAL = 1;
//const SW_SHOW = 5;
//const SW_SHOWDEFAULT = 10;
function ShowWindow(hWnd, nCmdShow) {
if (nCmdShow == SW_SHOWNORMAL && !hWnd.shown) {
hWnd.video = document.createElement("div");
hWnd.video.style.webkitTouchCallout = "none";
hWnd.video.style.webkitUserSelect = "none";
hWnd.video.style.khtmlUserSelect = "none";
hWnd.video.style.mozUserSelect = "none";
hWnd.video.style.msUserSelect = "none";
hWnd.video.style.userSelect = "none";
hWnd.video.appendChild(hWnd.canvas);
hWnd.div = document.getElementById(SAEV_config.video.id);
var el = document.getElementById(SAEV_config.video.id);
if (el.nodeName == "DIV") {
hWnd.div = el;
hWnd.div.style.width = String(currentmode.native_width)+"px";
hWnd.div.style.height = String(currentmode.native_height)+"px";
hWnd.div.appendChild(hWnd.video);
hWnd.div.appendChild(hWnd.canvas);
} else
hWnd.div = null;
hWnd.shown = true;
}
else if (nCmdShow == SW_HIDE && hWnd.shown) {
hWnd.div.removeChild(hWnd.video);
//hWnd.div.style.width = "0px";
//hWnd.div.style.height = "0px";
hWnd.video = null;
if (hWnd.div !== null) {
hWnd.div.removeChild(hWnd.canvas);
hWnd.canvas = null;
}
hWnd.shown = false;
}
}
function GetWindowRect(hWnd, rect) {
if (hWnd.shown) {
var bcr = hWnd.div.getBoundingClientRect();
/*if (hWnd.shown) {
var bcr = hWnd.canvas.getBoundingClientRect();
rect.left = Math.floor(bcr.left);
rect.top = Math.floor(bcr.top);
rect.right = Math.floor(bcr.right);
rect.bottom = Math.floor(bcr.bottom);
} else {
console.dir(bcr);
} else*/ {
rect.left = (screen.width >> 1) - (currentmode.native_width >> 1); if (rect.left < 0) rect.left = 0;
rect.top = (screen.height >> 1) - (currentmode.native_height >> 1); if (rect.top < 0) rect.top = 0;
rect.right = rect.left + currentmode.native_width;
@ -1804,7 +1807,8 @@ function SAEO_Video() {
if (!SAEV_config.video.enabled)
return SAEE_None;
if (!document.getElementById(SAEV_config.video.id))
var id = document.getElementById(SAEV_config.video.id);
if (id === null || (id.nodeName != "DIV" && id.nodeName != "CANVAS"))
return SAEE_Video_ElementNotFound;
if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL && !SAEC_info.video.webGL) {