update 0.7.0
This commit is contained in:
parent
032b58df5d
commit
0c5b018866
24 changed files with 21049 additions and 0 deletions
BIN
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
206
index.css
Normal file
206
index.css
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
|
||||||
|
a:link { color:#2040c0; text-decoration:none; }
|
||||||
|
a:visited { color:#2040c0; text-decoration:none; }
|
||||||
|
a:hover { color:#2040c0; text-decoration:underline; }
|
||||||
|
|
||||||
|
.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; }
|
||||||
|
.acmsb { text-align:center; vertical-align:middle; font-size:x-small; font-weight:bold; }
|
||||||
|
.acb { text-align:center; vertical-align:bottom; }
|
||||||
|
|
||||||
|
.art { text-align:right; vertical-align:top; }
|
||||||
|
.arm { text-align:right; vertical-align:middle; }
|
||||||
|
.armb { text-align:right; vertical-align:middle; font-weight:bold; }
|
||||||
|
.arms { text-align:right; vertical-align:middle; font-size:x-small; }
|
||||||
|
.armsb { text-align:right; vertical-align:middle; font-size:x-small; font-weight:bold; }
|
||||||
|
.arb { text-align:right; vertical-align:bottom; }
|
||||||
|
|
||||||
|
.fsxs { font-size:x-small; }
|
||||||
|
.fsl { font-size:large; }
|
||||||
|
.fwb { font-weight:bold; }
|
||||||
|
|
||||||
|
.info {
|
||||||
|
font-size:x-small;
|
||||||
|
color:gray;
|
||||||
|
vertical-align:text-top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gray { color:gray; }
|
||||||
|
.green { color:green; }
|
||||||
|
.red { color:red; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
margin:0;
|
||||||
|
padding:0;
|
||||||
|
font-family:verdana;
|
||||||
|
font-size:small;
|
||||||
|
background-color:#fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noscript {
|
||||||
|
margin:auto;
|
||||||
|
padding:4px;
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:medium;
|
||||||
|
text-align:center;
|
||||||
|
color:red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hr {
|
||||||
|
width:100%;
|
||||||
|
border-top:1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
width:100%;
|
||||||
|
margin:auto;
|
||||||
|
text-align:center;
|
||||||
|
background-color:#f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foot {
|
||||||
|
width:100%;
|
||||||
|
margin:auto;
|
||||||
|
text-align:center;
|
||||||
|
font-size:x-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
#config {
|
||||||
|
width:800px;
|
||||||
|
margin:auto;
|
||||||
|
background-color:#fcfcfc;
|
||||||
|
}
|
||||||
|
#config_simple {
|
||||||
|
width:760px;
|
||||||
|
padding:20px;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
}
|
||||||
|
.config_simple_hof {
|
||||||
|
width:50%;
|
||||||
|
margin:auto;
|
||||||
|
padding:10px;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
background-color:#f8f8f8;
|
||||||
|
}
|
||||||
|
#cfg_info td {
|
||||||
|
padding:2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#config_advanced {
|
||||||
|
width:760px;
|
||||||
|
padding:20px;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
#config_advanced table {
|
||||||
|
width:100%;
|
||||||
|
line-height:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#config .tl {
|
||||||
|
border-top:1px solid #ccc;
|
||||||
|
}
|
||||||
|
#config .bl {
|
||||||
|
border-bottom:1px solid #ccc;
|
||||||
|
}
|
||||||
|
#config .wauto {
|
||||||
|
width:auto;
|
||||||
|
}
|
||||||
|
#config select {
|
||||||
|
border:0;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
}
|
||||||
|
#config .button {
|
||||||
|
width:100px;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
background-color:#fff;
|
||||||
|
}
|
||||||
|
#config .button:hover {
|
||||||
|
background-color:#eee;
|
||||||
|
}
|
||||||
|
#config .sbutton {
|
||||||
|
width:100px;
|
||||||
|
padding:2px;
|
||||||
|
font-weight:bold;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
background-color:#fff;
|
||||||
|
}
|
||||||
|
#config .sbutton:hover {
|
||||||
|
background-color:#eee;
|
||||||
|
}
|
||||||
|
#cfg_demo, #cfg_game {
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#emul {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
width:720px;
|
||||||
|
margin:auto;
|
||||||
|
padding:2px;
|
||||||
|
text-align:center;
|
||||||
|
font-size:x-small;
|
||||||
|
color:#888;
|
||||||
|
background-color:#000;
|
||||||
|
}
|
||||||
|
#status table {
|
||||||
|
margin:auto;
|
||||||
|
}
|
||||||
|
#dskchg, #dskchg_simple {
|
||||||
|
display:none;
|
||||||
|
width:720px;
|
||||||
|
margin:auto;
|
||||||
|
padding:2px;
|
||||||
|
text-align:center;
|
||||||
|
font-size:x-small;
|
||||||
|
color:#888;
|
||||||
|
background-color:#000;
|
||||||
|
}
|
||||||
|
#dskchg, #dskchg_simple table {
|
||||||
|
margin:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dbutton {
|
||||||
|
width:64px;
|
||||||
|
font-size:x-small;
|
||||||
|
color:#888;
|
||||||
|
border:1px solid #888;
|
||||||
|
background-color:#000;
|
||||||
|
}
|
||||||
|
.dbutton:hover {
|
||||||
|
color:#ccc;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readme {
|
||||||
|
width:1004px;
|
||||||
|
margin:auto;
|
||||||
|
padding:10px;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
background-color:#fcfcfc;
|
||||||
|
}
|
||||||
|
.readme table {
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
.readme table td {
|
||||||
|
vertical-align:top;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.float_box {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
div.float_item {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
div.float_clear {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
627
index.htm
Normal file
627
index.htm
Normal file
|
|
@ -0,0 +1,627 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-us">
|
||||||
|
<head>
|
||||||
|
<title>SAE - Scripted Amiga Emulator</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta name="author" content="Rupert Hausberger" />
|
||||||
|
<meta name="publisher" content="Rupert Hausberger" />
|
||||||
|
<meta name="description" content="Experimental Amiga Classic Emulator in Javascript" />
|
||||||
|
<meta name="keywords" content="SAE,Javascript,HTML5,Amiga,AmigaOS,Emulator,Online" />
|
||||||
|
<meta name="robots" content="index,nofollow" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="http://scriptedamigaemulator.net/favicon.ico" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="index.css" />
|
||||||
|
<script type="text/javascript" src="sae/constants.js"></script>
|
||||||
|
<script type="text/javascript" src="sae/utils.js"></script>
|
||||||
|
<script type="text/javascript" src="sae/config.js"></script>
|
||||||
|
<script type="text/javascript" src="sae/memory.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/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/cpu.js"></script>
|
||||||
|
<script type="text/javascript" src="sae/amiga.js"></script>
|
||||||
|
<script type="text/javascript" src="index.js"></script>
|
||||||
|
<script type="text/javascript" src="ga.js"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="init()">
|
||||||
|
|
||||||
|
<div id="base">
|
||||||
|
<div id="head" class="head">
|
||||||
|
<div style="height:8px"></div>
|
||||||
|
<img src="images/logo.png" alt="Scripted Amiga Emulator" />
|
||||||
|
<noscript>
|
||||||
|
<div class="noscript">This site does require javascript, obviously :)</div>
|
||||||
|
</noscript>
|
||||||
|
<div class="hr"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="height:20px"></div>
|
||||||
|
|
||||||
|
<div id="config">
|
||||||
|
<div id="config_simple">
|
||||||
|
<div class="arm">
|
||||||
|
<button class="button" onclick="switchCfg(1)">Advanced</button>
|
||||||
|
</div>
|
||||||
|
<div style="line-height:20px">
|
||||||
|
<h3>Welcome!</h3>
|
||||||
|
This site is a demonstration of the '<a href="javascript:openNewTab('https://github.com/naTmeg/ScriptedAmigaEmulator')">SAE</a>' project,
|
||||||
|
an experimental <a href="javascript:openNewTab('http://en.wikipedia.org/wiki/Amiga')">Amiga</a> emulator in pure javascript and HTML5.<br />
|
||||||
|
For details, please refer to the <a href="javascript:openNewTab('readme.htm')">readme</a> file.<br /><br />
|
||||||
|
Below you find a small collection of games and demos to play...
|
||||||
|
</div>
|
||||||
|
<div style="height:20px"></div>
|
||||||
|
<div class="config_simple_hof">
|
||||||
|
<div class="acm">
|
||||||
|
<span class="fwb">Hall of fame</span>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Game</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_game" size="1" onchange="preSelect(1)">
|
||||||
|
<option value="0">- select -</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Demo</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_demo" size="1" onchange="preSelect(2)">
|
||||||
|
<option value="0">- select -</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="arms">Audio</td>
|
||||||
|
<td><input id="cfg_audio_enabled_1" type="checkbox" checked="checked" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="arms">Scale 4x</td>
|
||||||
|
<td><input id="cfg_video_scale_1" type="checkbox" /><span class="info">(1140 x 1152, press F11 for fullscreen)</span></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div class="hr"></div>
|
||||||
|
<table id="cfg_info">
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Name</td>
|
||||||
|
<td><span id="cfg_info_name"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">From</td>
|
||||||
|
<td><span id="cfg_info_comp"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Year</td>
|
||||||
|
<td><span id="cfg_info_year"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="cfg_info_ctrl_grp">
|
||||||
|
<td class="armsb">Controls</td>
|
||||||
|
<td><span id="cfg_info_ctrl"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="cfg_info_load_grp">
|
||||||
|
<td class="armsb">Loading</td>
|
||||||
|
<td><span id="cfg_info_load"></span></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div style="height:10px"></div>
|
||||||
|
<div class="acm">
|
||||||
|
<button class="sbutton" id="cfg_simple_start" onclick="simpleStart()">Play</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="config_advanced">
|
||||||
|
<div class="arm">
|
||||||
|
<button class="button" onclick="switchCfg(0)">Simple</button>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">CPU</td>
|
||||||
|
<td class="bl">
|
||||||
|
<table class="wauto">
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Speed:</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_cpu_speed" size="1">
|
||||||
|
<option value="0">Original</option>
|
||||||
|
<option value="-1">Maximum</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">RAM</td>
|
||||||
|
<td class="bl">
|
||||||
|
<table class="wauto">
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Chip:</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_mem_chip" size="1">
|
||||||
|
<option value="1">256</option>
|
||||||
|
<option value="2">512</option>
|
||||||
|
<option value="3">1024</option>
|
||||||
|
<option value="4">2048</option>
|
||||||
|
</select>
|
||||||
|
kb
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Slow:</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_mem_slow" size="1">
|
||||||
|
<option value="0">0</option>
|
||||||
|
<option value="1">256</option>
|
||||||
|
<option value="2">512</option>
|
||||||
|
<option value="3">1024</option>
|
||||||
|
<option value="4">1536</option>
|
||||||
|
</select>
|
||||||
|
kb <span class="gray">(pseudo-fast, bogomem)</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Fast:</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_mem_fast" size="1">
|
||||||
|
<option value="0">0</option>
|
||||||
|
<option value="1">512</option>
|
||||||
|
<option value="2">1024</option>
|
||||||
|
<option value="3">2048</option>
|
||||||
|
<option value="4">4096</option>
|
||||||
|
<option value="5">8192</option>
|
||||||
|
</select>
|
||||||
|
kb <span class="gray">(real-fast, commodore a2058 in zorro2)</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">ROM</td>
|
||||||
|
<td class="bl">
|
||||||
|
<table id="cfg_rom_grp">
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Kickstart:</td>
|
||||||
|
<td style="width:100%"><span id="cfg_rom_name" class="red">unset (required)</span></td>
|
||||||
|
<td><input id="cfg_rom_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="romSelect()" /></td>
|
||||||
|
<td><button class="button" onclick="document.getElementById('cfg_rom_file').click()">Select</button></td>
|
||||||
|
<td><button class="button" id="cfg_rom_aros" onclick="romAROS()"><span class="green">Set AROS</span></button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Extended:</td>
|
||||||
|
<td style="width:100%"><span id="cfg_ext_name" class="gray">unset (optional)</span></td>
|
||||||
|
<td><input id="cfg_ext_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="extSelect()" /></td>
|
||||||
|
<td><button class="button" onclick="document.getElementById('cfg_ext_file').click()">Select</button></td>
|
||||||
|
<td><button class="button" id="cfg_ext_remove" onclick="extRemove()">Remove</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="cfg_ext_addr_grp">
|
||||||
|
<td class="arm">Ext. addr:</td>
|
||||||
|
<td colspan="4">
|
||||||
|
<select id="cfg_ext_addr" size="1">
|
||||||
|
<option value="2">0xE00000</option>
|
||||||
|
<option value="3">0xF00000</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Floppy</td>
|
||||||
|
<td class="bl">
|
||||||
|
<table style="border-collapse:collapse">
|
||||||
|
<tr>
|
||||||
|
<td style="width:45px"><input id="cfg_df0_enabled" type="checkbox" onchange="floppyUpdate(0)" />DF0</td>
|
||||||
|
<td>
|
||||||
|
<table id="cfg_df0_grp">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_df0_type" size="1">
|
||||||
|
<option value="1">3.5" DD</option>
|
||||||
|
<option value="2">3.5" HD</option>
|
||||||
|
<option value="3">5.25" SD</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td style="width:100%"><span id="cfg_df0_name" class="gray">empty (optional)</span></td>
|
||||||
|
<td><input id="cfg_df0_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="floppyInsert(0)" /></td>
|
||||||
|
<td><button class="button" onclick="document.getElementById('cfg_df0_file').click()">Insert</button></td>
|
||||||
|
<td><button class="button" id="cfg_df0_eject" onclick="floppyEject(0)">Eject</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="cfg_df1_enabled" type="checkbox" onchange="floppyUpdate(1)" />DF1</td>
|
||||||
|
<td>
|
||||||
|
<table id="cfg_df1_grp">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_df1_type" size="1">
|
||||||
|
<option value="1">3.5" DD</option>
|
||||||
|
<option value="2">3.5" HD</option>
|
||||||
|
<option value="3">5.25" SD</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td style="width:100%"><span id="cfg_df1_name" class="gray">empty (optional)</span></td>
|
||||||
|
<td><input id="cfg_df1_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="floppyInsert(1)" /></td>
|
||||||
|
<td><button class="button" onclick="document.getElementById('cfg_df1_file').click()">Insert</button></td>
|
||||||
|
<td><button class="button" id="cfg_df1_eject" onclick="floppyEject(1)">Eject</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="cfg_df2_enabled" type="checkbox" onchange="floppyUpdate(2)" />DF2</td>
|
||||||
|
<td>
|
||||||
|
<table id="cfg_df2_grp">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_df2_type" size="1">
|
||||||
|
<option value="1">3.5" DD</option>
|
||||||
|
<option value="2">3.5" HD</option>
|
||||||
|
<option value="3">5.25" SD</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td style="width:100%"><span id="cfg_df2_name" class="gray">empty (optional)</span></td>
|
||||||
|
<td><input id="cfg_df2_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="floppyInsert(2)" /></td>
|
||||||
|
<td><button class="button" onclick="document.getElementById('cfg_df2_file').click()">Insert</button></td>
|
||||||
|
<td><button class="button" id="cfg_df2_eject" onclick="floppyEject(2)">Eject</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="cfg_df3_enabled" type="checkbox" onchange="floppyUpdate(3)" />DF3</td>
|
||||||
|
<td>
|
||||||
|
<table id="cfg_df3_grp">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_df3_type" size="1">
|
||||||
|
<option value="1">3.5" DD</option>
|
||||||
|
<option value="2">3.5" HD</option>
|
||||||
|
<option value="3">5.25" SD</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td style="width:100%"><span id="cfg_df3_name" class="gray">empty (optional)</span></td>
|
||||||
|
<td><input id="cfg_df3_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="floppyInsert(3)" /></td>
|
||||||
|
<td><button class="button" onclick="document.getElementById('cfg_df3_file').click()">Insert</button></td>
|
||||||
|
<td><button class="button" id="cfg_df3_eject" onclick="floppyEject(3)">Eject</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
Speed:
|
||||||
|
<select id="cfg_floppy_speed" size="1">
|
||||||
|
<option value="0">Turbo</option>
|
||||||
|
<option value="100">Original</option>
|
||||||
|
<option value="200">2x</option>
|
||||||
|
<option value="500">5x</option>
|
||||||
|
<option value="1000">10x</option>
|
||||||
|
</select>
|
||||||
|
<span class="gray"> ('Turbo' mode is fastest, but not very compatible)</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Audio</td>
|
||||||
|
<td class="bl">
|
||||||
|
<input id="cfg_audio_enabled" type="checkbox" onchange="audioUpdate()" />
|
||||||
|
Enabled
|
||||||
|
<table id="cfg_audio_grp" class="wauto">
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Mode:</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_audio_mode" size="1">
|
||||||
|
<option value="0">Off (emulated)</option>
|
||||||
|
<option value="1">On</option>
|
||||||
|
<option value="2">On (best)</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Channels:</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_audio_channels" size="1">
|
||||||
|
<option value="1">1 - Mono</option>
|
||||||
|
<option value="2">2 - Stereo</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="arm">Samplerate:</td>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_audio_rate" size="1">
|
||||||
|
<option value="1">11025</option>
|
||||||
|
<option value="2">22050</option>
|
||||||
|
<option value="3">44100</option>
|
||||||
|
<option value="4">48000</option>
|
||||||
|
</select>
|
||||||
|
Hz
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Video</td>
|
||||||
|
<td class="bl">
|
||||||
|
<input id="cfg_video_enabled" type="checkbox" onchange="videoUpdate()" />
|
||||||
|
Enabled
|
||||||
|
<div id="cfg_video_grp">
|
||||||
|
<input id="cfg_chipset_cl_enabled" type="checkbox" onchange="spritesUpdate()" />
|
||||||
|
Sprite collisions
|
||||||
|
<span id="cfg_chipset_cl_grp">
|
||||||
|
<select id="cfg_chipset_cl" size="1">
|
||||||
|
<option value="1">Sprite/Sprite</option>
|
||||||
|
<option value="2">Sprite/Sprite + Sprite/Playfield</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
<input id="cfg_video_scale" type="checkbox" />
|
||||||
|
Scale 4x <span class="gray">(1440 x 1152)</span>
|
||||||
|
<br />
|
||||||
|
<input id="cfg_video_ntsc" type="checkbox" />
|
||||||
|
NTSC
|
||||||
|
<br />
|
||||||
|
<input id="cfg_video_skip" type="checkbox" />
|
||||||
|
Frameskip<span class="gray"> (if the emulation is too slow, up to 4 frames will be skipped)</span>
|
||||||
|
<!--<br />
|
||||||
|
<input id="cfg_video_drop" type="checkbox" />
|
||||||
|
Framedrop<span class="gray"> (if the emulation is too fast, a (unprecise) delay is initiated)</span>-->
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Keyboard</td>
|
||||||
|
<td class="bl">
|
||||||
|
<input id="cfg_keyborad_enabled" type="checkbox" onchange="keyboradUpdate()" />
|
||||||
|
Enabled <span class="gray">(joysticks does always work)</span>
|
||||||
|
<div id="cfg_keyborad_grp">
|
||||||
|
<input id="cfg_keyborad_mapshift" type="checkbox" />
|
||||||
|
Map L/R-Shift to L/R-Arrows <span class="gray">(team17 pinball games)</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Port 0</td>
|
||||||
|
<td>
|
||||||
|
<input id="cfg_ports_0_enabled" type="checkbox" onchange="portUpdate(0)" />
|
||||||
|
Enabled
|
||||||
|
<span id="cfg_ports_0_grp">
|
||||||
|
<select id="cfg_ports_0" size="1" onchange="portUpdate2()">
|
||||||
|
<option value="1">Mouse</option>
|
||||||
|
<option value="2">Joystick 0</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span id="cfg_ports_0_grp2">
|
||||||
|
Move
|
||||||
|
<select id="cfg_ports_0_move" size="1">
|
||||||
|
<option value="1">Arrows</option>
|
||||||
|
<option value="2">Numpad</option>
|
||||||
|
<option value="3">WASD</option>
|
||||||
|
</select>
|
||||||
|
Fire 1
|
||||||
|
<select id="cfg_ports_0_fire_1" size="1">
|
||||||
|
<option value="0">None</option>
|
||||||
|
<option value="16">Shift</option>
|
||||||
|
<option value="17">Ctrl</option>
|
||||||
|
<option value="13">Enter</option>
|
||||||
|
<option value="32">Space</option>
|
||||||
|
<option value="8">Backspace</option>
|
||||||
|
<option value="96">Numpad 0</option>
|
||||||
|
<option value="106">Numpad *</option>
|
||||||
|
<option value="107">Numpad </option>
|
||||||
|
<option value="109">Numpad -</option>
|
||||||
|
<option value="110">Numpad .</option>
|
||||||
|
<option value="111">Numpad /</option>
|
||||||
|
<option value="46">Delete</option>
|
||||||
|
<option value="45">Insert</option>
|
||||||
|
<option value="34">Page down</option>
|
||||||
|
<option value="33">Page up</option>
|
||||||
|
<option value="35">End</option>
|
||||||
|
<option value="36">Home</option>
|
||||||
|
<option value="19">Pause</option>
|
||||||
|
<option value="144">Num lock</option>
|
||||||
|
<option value="145">Scroll lock</option>
|
||||||
|
<option value="49">1</option>
|
||||||
|
<option value="50">2</option>
|
||||||
|
<!--<option value="122">F11</option>
|
||||||
|
<option value="123">F12</option>
|
||||||
|
<option value="186">Semi-colon</option>
|
||||||
|
<option value="187">Equal</option>
|
||||||
|
<option value="188">Comma</option>
|
||||||
|
<option value="189">Dash</option>
|
||||||
|
<option value="190">Period</option>
|
||||||
|
<option value="222">Quote</option>
|
||||||
|
<option value="226">Less greater </option>
|
||||||
|
<option value="191">Forward slash</option>
|
||||||
|
<option value="220">Back slash</option>
|
||||||
|
<option value="219">Open bracket</option>
|
||||||
|
<option value="221">Close bracket</option>
|
||||||
|
<option value="192">Grave accent</option>-->
|
||||||
|
</select>
|
||||||
|
Fire 2
|
||||||
|
<select id="cfg_ports_0_fire_2" size="1">
|
||||||
|
<option value="0">None</option>
|
||||||
|
<option value="16">Shift</option>
|
||||||
|
<option value="17">Ctrl</option>
|
||||||
|
<option value="13">Enter</option>
|
||||||
|
<option value="32">Space</option>
|
||||||
|
<option value="8">Backspace</option>
|
||||||
|
<option value="96">Numpad 0</option>
|
||||||
|
<option value="106">Numpad *</option>
|
||||||
|
<option value="107">Numpad </option>
|
||||||
|
<option value="109">Numpad -</option>
|
||||||
|
<option value="110">Numpad .</option>
|
||||||
|
<option value="111">Numpad /</option>
|
||||||
|
<option value="46">Delete</option>
|
||||||
|
<option value="45">Insert</option>
|
||||||
|
<option value="34">Page down</option>
|
||||||
|
<option value="33">Page up</option>
|
||||||
|
<option value="35">End</option>
|
||||||
|
<option value="36">Home</option>
|
||||||
|
<option value="19">Pause</option>
|
||||||
|
<option value="144">Num lock</option>
|
||||||
|
<option value="145">Scroll lock</option>
|
||||||
|
<option value="49">1</option>
|
||||||
|
<option value="50">2</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Port 1</td>
|
||||||
|
<td class="bl">
|
||||||
|
<input id="cfg_ports_1_enabled" type="checkbox" onchange="portUpdate(1)" />
|
||||||
|
Enabled
|
||||||
|
<span id="cfg_ports_1_grp">
|
||||||
|
<select id="cfg_ports_1" size="1" onchange="portsUpdate(1)">
|
||||||
|
<option value="3">Joystick 1</option>
|
||||||
|
</select>
|
||||||
|
Move
|
||||||
|
<select id="cfg_ports_1_move" size="1">
|
||||||
|
<option value="1">Arrows</option>
|
||||||
|
<option value="2">Numpad</option>
|
||||||
|
<option value="3">WASD</option>
|
||||||
|
</select>
|
||||||
|
Fire 1
|
||||||
|
<select id="cfg_ports_1_fire_1" size="1">
|
||||||
|
<option value="0">None</option>
|
||||||
|
<option value="16">Shift</option>
|
||||||
|
<option value="17">Ctrl</option>
|
||||||
|
<option value="13">Enter</option>
|
||||||
|
<option value="32">Space</option>
|
||||||
|
<option value="8">Backspace</option>
|
||||||
|
<option value="96">Numpad 0</option>
|
||||||
|
<option value="106">Numpad *</option>
|
||||||
|
<option value="107">Numpad </option>
|
||||||
|
<option value="109">Numpad -</option>
|
||||||
|
<option value="110">Numpad .</option>
|
||||||
|
<option value="111">Numpad /</option>
|
||||||
|
<option value="46">Delete</option>
|
||||||
|
<option value="45">Insert</option>
|
||||||
|
<option value="34">Page down</option>
|
||||||
|
<option value="33">Page up</option>
|
||||||
|
<option value="35">End</option>
|
||||||
|
<option value="36">Home</option>
|
||||||
|
<option value="19">Pause</option>
|
||||||
|
<option value="144">Num lock</option>
|
||||||
|
<option value="145">Scroll lock</option>
|
||||||
|
<option value="123">F12</option>
|
||||||
|
</select>
|
||||||
|
Fire 2
|
||||||
|
<select id="cfg_ports_1_fire_2" size="1">
|
||||||
|
<option value="0">None</option>
|
||||||
|
<option value="16">Shift</option>
|
||||||
|
<option value="17">Ctrl</option>
|
||||||
|
<option value="13">Enter</option>
|
||||||
|
<option value="32">Space</option>
|
||||||
|
<option value="8">Backspace</option>
|
||||||
|
<option value="96">Numpad 0</option>
|
||||||
|
<option value="106">Numpad *</option>
|
||||||
|
<option value="107">Numpad </option>
|
||||||
|
<option value="109">Numpad -</option>
|
||||||
|
<option value="110">Numpad .</option>
|
||||||
|
<option value="111">Numpad /</option>
|
||||||
|
<option value="46">Delete</option>
|
||||||
|
<option value="45">Insert</option>
|
||||||
|
<option value="34">Page down</option>
|
||||||
|
<option value="33">Page up</option>
|
||||||
|
<option value="35">End</option>
|
||||||
|
<option value="36">Home</option>
|
||||||
|
<option value="19">Pause</option>
|
||||||
|
<option value="144">Num lock</option>
|
||||||
|
<option value="145">Scroll lock</option>
|
||||||
|
<option value="123">F12</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="armsb">Serial</td>
|
||||||
|
<td>
|
||||||
|
<input id="cfg_serial_enabled" type="checkbox" />
|
||||||
|
Enabled
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div style="height:10px"></div>
|
||||||
|
<div class="acm">
|
||||||
|
<button class="sbutton" id="cfg_start" onclick="advandedStart()">Start</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="height:10px"></div>
|
||||||
|
<div id="foot" class="foot">
|
||||||
|
<span class="gray">©2012 Rupert Hausberger</span> |
|
||||||
|
<a href="javascript:openNewTab('https://github.com/naTmeg/ScriptedAmigaEmulator')">Source</a> |
|
||||||
|
<a href="javascript:openNewTab('readme.htm')">Readme</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="emul">
|
||||||
|
<div id="status">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><button class="dbutton" onclick="stop()">Stop</button></td>
|
||||||
|
<!--<td><button class="dbutton" onclick="reset()">Reset</button></td>-->
|
||||||
|
<td><button class="dbutton" onclick="pause(1)" id="status_pr">Pause</button></td>
|
||||||
|
<td><button id="dskchg_grp" class="dbutton" onclick="dskchgOpen()">Disk</button></td>
|
||||||
|
<!--<td><button class="dbutton" onclick="toggleFullScreen()">fullscreen</button></td>-->
|
||||||
|
<td class="arm" style="width:32px"><span id="led_pwr">pwr</span></td>
|
||||||
|
<td class="arm" style="width:32px"><span id="led_df0">df0</span></td>
|
||||||
|
<td class="arm" style="width:32px"><span id="led_df1">df1</span></td>
|
||||||
|
<td class="arm" style="width:32px"><span id="led_df2">df2</span></td>
|
||||||
|
<td class="arm" style="width:32px"><span id="led_df3">df3</span></td>
|
||||||
|
<td class="arm" style="width:32px"><span id="led_fps">fps</span></td>
|
||||||
|
<td class="arm" style="width:32px"><span id="led_cpu">cpu</span></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div id="dskchg_simple">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_dskchg_select" size="1" onchange="dskchgSelect()">
|
||||||
|
<option value="">- select -</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td><button class="dbutton" onclick="dskchgClose()">Abort</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div id="dskchg">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<select id="cfg_dskchg_unit" size="1">
|
||||||
|
<option value="0">DF0</option>
|
||||||
|
<option value="1">DF1</option>
|
||||||
|
<option value="2">DF2</option>
|
||||||
|
<option value="3">DF3</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td><input id="cfg_dskchg_file" type="file" style="position:absolute;left:-10000px;top:-10000px;" onchange="dskchgInsert()" /></td>
|
||||||
|
<td><button class="dbutton" onclick="document.getElementById('cfg_dskchg_file').click()">Insert</button></td>
|
||||||
|
<td><button class="dbutton" onclick="dskchgEject()">Eject</button></td>
|
||||||
|
<td><button class="dbutton" onclick="dskchgClose()">Abort</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div style="height:10px"></div>
|
||||||
|
<div id="myVideo"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
388
readme.htm
Normal file
388
readme.htm
Normal file
|
|
@ -0,0 +1,388 @@
|
||||||
|
<!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="http://scriptedamigaemulator.net/favicon.ico" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="index.css" />
|
||||||
|
<script type="text/javascript">
|
||||||
|
function openNewTab(url) {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
window.focus();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="head">
|
||||||
|
<div style="height:8px"></div>
|
||||||
|
<img src="images/logo.png" alt="Scripted Amiga Emulator" />
|
||||||
|
<noscript>
|
||||||
|
<div class="noscript">This site does require javascript, obviously :)</div>
|
||||||
|
</noscript>
|
||||||
|
<div class="hr"></div>
|
||||||
|
</div>
|
||||||
|
<div style="height:20px"></div>
|
||||||
|
<div class="readme">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Requirements</span>
|
||||||
|
<ul>
|
||||||
|
<li>A very fast computer</li>
|
||||||
|
<li>A browser capable of HTML5 with:
|
||||||
|
<ul>
|
||||||
|
<li>WegGL</li>
|
||||||
|
<li>WebAudio</li>
|
||||||
|
<li>Typed arrays</li>
|
||||||
|
<li>FileReader (GUI)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>A ROM:
|
||||||
|
<ul>
|
||||||
|
<li>Amiga Kickstart 1.x-2.04 (not included for copyright reasons)</li>
|
||||||
|
<li>AROS Kickstart (included)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li style="list-style-type:none"><br /></li>
|
||||||
|
<li>And a bunch of ADF-files to test (optional)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<table>
|
||||||
|
<tr><td colspan="2"><span class="fwb">Supported browsers</span></td></tr>
|
||||||
|
<tr><td class="armb" style="color:green">Chrome</td><td>Fastest</td></tr>
|
||||||
|
<tr><td class="armb" style="color:green">Firefox</td><td>Medium speed</td></tr>
|
||||||
|
<tr><td class="armb" style="color:orange">Opera</td><td>Slow speed, no audio</td></tr>
|
||||||
|
<tr><td class="armb" style="color:red">IE</td><td>No support</td></tr>
|
||||||
|
<tr><td class="armb">Other</td><td>Untested</td></tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div class="hr"></div>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Goals</span>
|
||||||
|
<ul>
|
||||||
|
<li>Make Amiga Classic Emulation available for browsers.</li>
|
||||||
|
<li>Easy integration into websites.</li>
|
||||||
|
<li>API for control from background, useful e.g. for a demo-player.</li>
|
||||||
|
<li>Browsers-plugins should not be required, just HTML5 and javascript.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Possible usage</span>
|
||||||
|
<ul>
|
||||||
|
<li>Demo/Intro/Mod-player</li>
|
||||||
|
<li>Playing games</li>
|
||||||
|
<li>Browser benchmark</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Usage/Hints</span>
|
||||||
|
<ul>
|
||||||
|
<li>Press F11 for fullscreen. Most browsers support that.</li>
|
||||||
|
<li>If something does crash, try another memory setting or a different ROM. The original kickstart (1.3) work's best.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Known bugs/problems</span>
|
||||||
|
<ul>
|
||||||
|
<li>Fast blinking sprites are not displayed if 'Frameskip' is active.</li>
|
||||||
|
<li>Copper initiated color-changes within a scanline are not recognized.</li>
|
||||||
|
<li>Left/right shift/alt/ctrl are the same. That's a browser 'feature' and can't be fixed for now.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Missing features</span>
|
||||||
|
<ul>
|
||||||
|
<li>User-config</li>
|
||||||
|
<li>Maybe ECS support</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Written and ported by</span>
|
||||||
|
<ul>
|
||||||
|
<li>Rupert Hausberger <<a href="mailto:rupert_hausberger@gmx.net">rupert_hausberger@gmx.net</a>> (<a href="javascript:openNewTab('https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZJA3YVT6EP55A')">donate</a>)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Source code</span>
|
||||||
|
<ul>
|
||||||
|
<li><a href="javascript:openNewTab('https://github.com/naTmeg/ScriptedAmigaEmulator')">github.com/naTmeg/ScriptedAmigaEmulator</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Thanks</span>
|
||||||
|
<ul>
|
||||||
|
<li>Bernd Schmidt</li>
|
||||||
|
<li>WinUAE and AROS team.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">License</span>
|
||||||
|
<ul>
|
||||||
|
<li>This is a <b>free</b> project.</li>
|
||||||
|
<li>You may use the emulator in your own website.</li>
|
||||||
|
<li>If you use the emulator in your own website, you <b>must</b> provide a link to this homepage.</li>
|
||||||
|
<li>If you use the emulator in your own website, you <b>must not</b> change the copyright header in the source-files.</li>
|
||||||
|
<li>Commercial use <b>in any form</b> is prohibited. This includes donations.</li>
|
||||||
|
<li>No warranty expressed or implied. Use at your own risk.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="hr"></div>
|
||||||
|
<table>
|
||||||
|
<tr><td colspan="3" class="acm"><span class="fwb">Fully working...</span></td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Games</span>
|
||||||
|
<ul>
|
||||||
|
<li>Alien Breed</li>
|
||||||
|
<li>Alien Breed Special Edition 92<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Alien Breed Tower Assault<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>Alien Breed II - The horror continues<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Boby Blows Galactic<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Agony<span class="fwb"> (0.6.1)</span></li>
|
||||||
|
<li>Another World</li>
|
||||||
|
<li>Barbarian<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Battle Chess</li>
|
||||||
|
<li>Blood Money</li>
|
||||||
|
<li>Crystal Hammer</li>
|
||||||
|
<li>Dynablaster<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Firepower</li>
|
||||||
|
<li>Lotus Turbo Challenge 1/2<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>NorthPrince of Persia<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Pinball Dreams</li>
|
||||||
|
<li>Pinball Fantasies (the demo with 1 desk)</li>
|
||||||
|
<li>Prince of Persia<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Project-X<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Project-X Special Edition '92<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>P.O.W.</li>
|
||||||
|
<li>Rubicon<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>R-Type 2</li>
|
||||||
|
<li>Shadow of the Beast 2<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>Terminator 2<span class="fwb"> (0.7)</span></li>
|
||||||
|
<li>Turrican 1/2</li>
|
||||||
|
<li>Turrican 3<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>Wings<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>Wings of Death<span class="fwb"> (0.6.1)</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Demos</span>
|
||||||
|
<ul>
|
||||||
|
<li>Deja Vu</li>
|
||||||
|
<li>How to skin a cat</li>
|
||||||
|
<li>Project-X (demo-rolling)<span class="fwb"> (0.6)</span></li>
|
||||||
|
<li>State of the Art</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">Apps</span>
|
||||||
|
<ul>
|
||||||
|
<li>Devpak 2.14</li>
|
||||||
|
<li>DPaint 4.1</li>
|
||||||
|
<li>Protracker 3.61</li>
|
||||||
|
<li>SysInfo 3.24</li>
|
||||||
|
<li>Workbench 1.x</li>
|
||||||
|
<li>Workbench 2.04<span class="fwb"> (0.6)</span></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="3" class="acm"><span class="fwb">Note:</span> The lists corresponds to Kickstart 1.3</td></tr>
|
||||||
|
</table>
|
||||||
|
<div class="hr"></div>
|
||||||
|
<ul>
|
||||||
|
<li><span class="fwb">History</span>
|
||||||
|
<ul>
|
||||||
|
<li>0.7.0 (24.12.2012):
|
||||||
|
<ul>
|
||||||
|
<li>Common
|
||||||
|
<ul>
|
||||||
|
<li>Chaned the project-name from 'Janus' to 'SAE' (Scripted Amiga Emulator).<br />
|
||||||
|
This step is necessary because i did'nt enough research before the initial release.<br />
|
||||||
|
There is already a project with that name in it. (<a href="javascript:openNewTab('http://janus-uae.sourceforge.net')">janus-uae</a>)
|
||||||
|
I'm sorry for that, that was kinda stupid :)</li>
|
||||||
|
<li>Separated the GUI form the core and rewrote most of it.</li>
|
||||||
|
<li>Simplified the whole code. This means, that functions are called faster.</li>
|
||||||
|
<li>Ported new Copper-, Blitter-, Audio-, Disk- and event-handling code from WinUAE 2.5.0</li>
|
||||||
|
<li>Moved all "beam-functions" to events.js, for faster access.</li>
|
||||||
|
<li>Added "CPU-usage" to the GUI.</li>
|
||||||
|
<li>Added "Hall of Fame".</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>CPU
|
||||||
|
<ul>
|
||||||
|
<li>Added support for exact cycling. The CPU have now 7.09 MHz on PAL and 7.16 MHz on NTSC resp.</li>
|
||||||
|
<li>Added option for "Original"- and "Maximum"-speed.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Audio
|
||||||
|
<ul>
|
||||||
|
<li>Added a ring-buffer before output. No more "bagpipe"-like audio.</li>
|
||||||
|
<li>Added a option to just emulate the hardware, but not to play any sound, e.g. "Agony" was not starting, if audio was disabled.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Display
|
||||||
|
<ul>
|
||||||
|
<li>Switched from the RGB to the 565 texture-format-encoding in WebGL, which gives a little more speed.</li>
|
||||||
|
<li>Added support and a option for 4x scaling.</li>
|
||||||
|
<li>Fixed screen-draging in lo-/hires-modes.</li>
|
||||||
|
<li>Added a option to disable the output. Can be used to better play music-demos.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Disk
|
||||||
|
<ul>
|
||||||
|
<li>Added support for different speed-modes.</li>
|
||||||
|
<li>Added support for extended ADF-files.</li>
|
||||||
|
<li>Enabled write support. (to memory)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Input
|
||||||
|
<ul>
|
||||||
|
<li>The F-keys does work normaly now, i.e F5 does'nt reload the emulator, backspace does'nt go to the last page, etc...</li>
|
||||||
|
<li>Fixed bug in the joystick-emulation.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li style="list-style-type:none"><br/></li>
|
||||||
|
<li>0.6.1 (05.11.2012):
|
||||||
|
<ul>
|
||||||
|
<li>CPU
|
||||||
|
<ul>
|
||||||
|
<li>Added missing TAS command. ('Wings of Death' game does use it)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>ROM
|
||||||
|
<ul>
|
||||||
|
<li>Added a crc32-checksum test after download. (AROS)</li>
|
||||||
|
<li>Changed transfer-mode from syncronous to asyncronous. (AROS)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Display
|
||||||
|
<ul>
|
||||||
|
<li>Optimized the line-drawing code of the blitter.</li>
|
||||||
|
<li>Fixed decision whether the resulting image is scaled or not. ('Agony' game)</li>
|
||||||
|
<li>Disabled 'Framedrop' in interlace-mode.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Misc
|
||||||
|
<ul>
|
||||||
|
<li>Fixed HTML5 doctype.</li>
|
||||||
|
<li>Added ver/rev to the title.</li>
|
||||||
|
<li>Changed revision to 3 digits.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li style="list-style-type:none"><br/></li>
|
||||||
|
<li>0.6 (25.10.2012):
|
||||||
|
<ul>
|
||||||
|
<li>ROM
|
||||||
|
<ul>
|
||||||
|
<li>Added support for extended-roms.</li>
|
||||||
|
<li>AROS kickstart replacement is now the default-rom, and will be downloaded and used on the fly.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>RAM
|
||||||
|
<ul>
|
||||||
|
<li>Changed internal memory alignment from 8 to 16 bit.</li>
|
||||||
|
<li>Added fast-ram support, through a emulated Commodore A2058 in Zorro2-mode.</li>
|
||||||
|
<li>Removed the D8DC-memory-option from the GUI. This memory space is now always allocated.</li>
|
||||||
|
<li>Sorted access of the memory-routines by priority.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>CPU
|
||||||
|
<ul>
|
||||||
|
<li>Fixed sign-extension for memory to address-register transfers in MOVEM.</li>
|
||||||
|
<li>Fixed sign-extension for absolute-word addresses in exEA.</li>
|
||||||
|
<li>Fixed wrong address when writing a byte to the stack in ldEA.</li>
|
||||||
|
<li>Fixed 32bit calculations for address-regsiters in ADDQ/SUBQ.</li>
|
||||||
|
<li>Fixed remainder calculation in DIVU.</li>
|
||||||
|
<li>Optimized integer-arithmetic functions. Size depending calcalations are now used.</li>
|
||||||
|
<li>Improved exception 2/3 handling.</li>
|
||||||
|
<li>More small cleanups not listed here.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Disk
|
||||||
|
<ul>
|
||||||
|
<li>Ported latest disk-code from WinUAE. Disk-based problems should be gone now, e.g. floopy shown as BAD or read errors.</li>
|
||||||
|
<li>Diskchange does now work.</li>
|
||||||
|
<li>Drives can be disabled now.</li>
|
||||||
|
<li>DD/HD types are now supported.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Display
|
||||||
|
<ul>
|
||||||
|
<li>Added missing support for HAM6.</li>
|
||||||
|
<li>Fixed horizontal and vertical screen-centering.</li>
|
||||||
|
<li>Fixed screen-draging, almost, read the "Known bugs" section.</li>
|
||||||
|
<li>Added better screen-scrolling.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Input
|
||||||
|
<ul>
|
||||||
|
<li>Fixed key-mapping to the amiga key-layout, at least in Chrome. Firefox does not like "öäü", it seems.</li>
|
||||||
|
<li>Added support for individual configurations of joystick-movement and fire-buttons.</li>
|
||||||
|
<li>Fixed bug, that made the fire 1 button on joystick 0 not working.</li>
|
||||||
|
<li>Fixed bug in the mouse-movement function, that calculates the wrong coordinates in some cases.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>GUI
|
||||||
|
<ul>
|
||||||
|
<li>Added eject-button in the disk-change requester.</li>
|
||||||
|
<li>Removed the CPU and OCS/ECS options. They are useless so far.</li>
|
||||||
|
<li>The "Pause" and "Resume" buttons are once now.</li>
|
||||||
|
<li>Made some options to only apear when selected.</li>
|
||||||
|
<li>Did some cosmetics.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>Misc
|
||||||
|
<ul>
|
||||||
|
<li>Added support for Zorro2-expansion cards.</li>
|
||||||
|
<li>Added a more precise event-handling. This makes the audio-output a little smoother.</li>
|
||||||
|
<li>Changed the ratio of CPU-/Chipset-time from 1:8 to 1:4</li>
|
||||||
|
<li>Fixed a bug in the RTC. "Year" is now calculated correctly.</li>
|
||||||
|
<li>Fixed incorrect response of serial.device. Now crashed programms does reset (and show the guru), instead of idle.</li>
|
||||||
|
<li>Any output on the serial.device is now redirected to the debug-log. (dev only)</li>
|
||||||
|
<li>Kickstart/Workbench 2.04 and AROS does now work.</li>
|
||||||
|
<li>Overall about 10-30% more speed, as long as the blitter is not used too much.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li style="list-style-type:none"><br/></li>
|
||||||
|
<li>0.5 (01.09.2012):
|
||||||
|
<ul>
|
||||||
|
<li>Initial.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div style="height:20px"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
459
sae/amiga.js
Normal file
459
sae/amiga.js
Normal file
|
|
@ -0,0 +1,459 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function set_special(x) { AMIGA.spcflags |= x; }
|
||||||
|
function clr_special(x) { AMIGA.spcflags &= ~x; }
|
||||||
|
|
||||||
|
function Amiga() {
|
||||||
|
this.config = new Config();
|
||||||
|
this.mem = new Memory();
|
||||||
|
this.expansion = new Expansion();
|
||||||
|
this.input = new Input();
|
||||||
|
this.serial = new Serial();
|
||||||
|
this.events = new Events();
|
||||||
|
this.disk = new Disk();
|
||||||
|
this.cia = new CIA();
|
||||||
|
this.rtc = new RTC();
|
||||||
|
this.custom = new Custom();
|
||||||
|
this.blitter = new Blitter();
|
||||||
|
this.copper = new Copper();
|
||||||
|
this.playfield = new Playfield();
|
||||||
|
this.video = new Vide0();
|
||||||
|
this.audio = new Audi0();
|
||||||
|
this.cpu = new CPU();
|
||||||
|
|
||||||
|
this.state = CMD_STOP;
|
||||||
|
this.delay = 0;
|
||||||
|
this.spcflags = 0;
|
||||||
|
//this.loading = 0;
|
||||||
|
|
||||||
|
this.intena = 0;
|
||||||
|
this.intena_internal = 0;
|
||||||
|
this.intreq = 0;
|
||||||
|
this.intreq_internal = 0;
|
||||||
|
this.dmacon = 0;
|
||||||
|
this.adkcon = 0;
|
||||||
|
|
||||||
|
configSetDefaults(this.config);
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
if (this.config.chipset.type == SAEV_Config_Chipset_Type_OCS)
|
||||||
|
this.config.chipset.agnus = this.config.video.ntsc ? AGNUS_8370 : AGNUS_8371;
|
||||||
|
|
||||||
|
this.mem.setup();
|
||||||
|
this.expansion.setup();
|
||||||
|
this.events.setup();
|
||||||
|
this.cia.setup();
|
||||||
|
this.rtc.setup();
|
||||||
|
this.input.setup();
|
||||||
|
this.disk.setup();
|
||||||
|
this.playfield.setup();
|
||||||
|
this.video.setup();
|
||||||
|
this.audio.setup();
|
||||||
|
this.custom.setup();
|
||||||
|
this.cpu.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
this.audio.cleanup();
|
||||||
|
this.video.cleanup();
|
||||||
|
this.playfield.cleanup();
|
||||||
|
this.input.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
BUG.info('Amiga.reset()');
|
||||||
|
|
||||||
|
this.delay = 0;
|
||||||
|
//this.loading = 0;
|
||||||
|
|
||||||
|
this.intena = 0;
|
||||||
|
this.intena_internal = 0;
|
||||||
|
this.intreq = 0;
|
||||||
|
this.intreq_internal = 0;
|
||||||
|
this.dmacon = 0;
|
||||||
|
this.adkcon = 0;
|
||||||
|
|
||||||
|
this.expansion.reset();
|
||||||
|
this.events.reset();
|
||||||
|
this.cia.reset();
|
||||||
|
this.disk.reset();
|
||||||
|
this.input.reset();
|
||||||
|
this.serial.reset();
|
||||||
|
this.blitter.reset();
|
||||||
|
this.copper.reset();
|
||||||
|
this.playfield.reset();
|
||||||
|
this.audio.reset();
|
||||||
|
this.custom.reset();
|
||||||
|
this.cpu.reset(this.mem.rom.lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dump = function() {
|
||||||
|
this.cpu.dump();
|
||||||
|
//this.cia.dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
/*this.waitForStart = function() {
|
||||||
|
if (this.loading)
|
||||||
|
setTimeout('AMIGA.waitForStart()', 10);
|
||||||
|
else {
|
||||||
|
this.reset();
|
||||||
|
this.state = CMD_CYCLE;
|
||||||
|
setTimeout('AMIGA.cycle()', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.start = function() {
|
||||||
|
this.setup();
|
||||||
|
this.waitForStart();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
this.start = function() {
|
||||||
|
if (this.state == CMD_STOP) {
|
||||||
|
this.setup();
|
||||||
|
this.reset();
|
||||||
|
this.state = CMD_CYCLE;
|
||||||
|
setTimeout('AMIGA.cycle()', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stop = function() {
|
||||||
|
if (this.state != CMD_STOP) {
|
||||||
|
this.state = CMD_STOP;
|
||||||
|
this.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pause = function(state) {
|
||||||
|
if (this.state != CMD_STOP) {
|
||||||
|
this.state = state ? CMD_PAUSE : CMD_CYCLE;
|
||||||
|
this.audio.pauseResume(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*this.insert = function(unit, name, data) {
|
||||||
|
//this.disk.insert_data(unit, data);
|
||||||
|
this.disk.insert(unit, name, data);
|
||||||
|
this.config.floppy.drive[unit].name = name;
|
||||||
|
}
|
||||||
|
this.eject = function(unit) {
|
||||||
|
if (this.config.floppy.drive[unit].name) {
|
||||||
|
this.disk.eject(unit);
|
||||||
|
//this.disk.eject_data(unit);
|
||||||
|
this.config.floppy.drive[unit].name = null;
|
||||||
|
BUG.info('amiga.eject() DF%d ejected', unit);
|
||||||
|
} else
|
||||||
|
BUG.info('amiga.eject() DF%d in empty', unit);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.insert = function(unit) {
|
||||||
|
if (this.state != CMD_STOP)
|
||||||
|
this.disk.insert(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.eject = function(unit) {
|
||||||
|
if (this.state != CMD_STOP)
|
||||||
|
this.disk.eject(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
/* mainloop */
|
||||||
|
|
||||||
|
this.cycle = function() {
|
||||||
|
try {
|
||||||
|
while (this.state == CMD_CYCLE)
|
||||||
|
this.cpu.cycle();
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof FatalError) {
|
||||||
|
this.stop();
|
||||||
|
this.config.hooks.error(e.error, e.message);
|
||||||
|
} else
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state == CMD_IDLE) {
|
||||||
|
this.state = CMD_CYCLE;
|
||||||
|
setTimeout('AMIGA.cycle()', this.delay);
|
||||||
|
}
|
||||||
|
else if (this.state == CMD_PAUSE)
|
||||||
|
setTimeout('AMIGA.cyclePause()', 0);
|
||||||
|
else
|
||||||
|
setTimeout('AMIGA.cycleExit()', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cyclePause = function() {
|
||||||
|
if (this.state == CMD_CYCLE)
|
||||||
|
setTimeout('AMIGA.cycle()', 0);
|
||||||
|
else if (this.state == CMD_PAUSE)
|
||||||
|
setTimeout('AMIGA.cyclePause()', 500);
|
||||||
|
else
|
||||||
|
setTimeout('AMIGA.cycleExit()', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cycleExit = function() {
|
||||||
|
this.dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.dmaen = function (dmamask) {
|
||||||
|
return ((this.dmacon & DMAF_DMAEN) && (this.dmacon & dmamask));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.DMACONR = function(hpos) {
|
||||||
|
this.dmacon &= ~(0x4000 | 0x2000);
|
||||||
|
//this.dmacon |= (this.blitter.state == BLT_STOP ? 0 : 0x4000) | (this.blitter.zero ? 0x2000 : 0); //old
|
||||||
|
//this.dmacon |= ((blit_interrupt || (!blit_interrupt && currprefs.cs_agnusbltbusybug && !blt_info.got_cycle)) ? 0 : 0x4000) | (blt_info.blitzero ? 0x2000 : 0); //new org
|
||||||
|
var iz = this.blitter.getIntZero();
|
||||||
|
this.dmacon |= (iz[0] ? 0 : 0x4000) | (iz[1] ? 0x2000 : 0);
|
||||||
|
return this.dmacon;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.DMACON = function (v, hpos) {
|
||||||
|
var oldcon = this.dmacon;
|
||||||
|
|
||||||
|
if (v & INTF_SETCLR)
|
||||||
|
this.dmacon |= v & ~INTF_SETCLR;
|
||||||
|
else
|
||||||
|
this.dmacon &= ~v;
|
||||||
|
|
||||||
|
this.dmacon &= 0x1fff;
|
||||||
|
|
||||||
|
var changed = this.dmacon ^ oldcon;
|
||||||
|
|
||||||
|
var oldcop = (oldcon & DMAF_COPEN) && (oldcon & DMAF_DMAEN);
|
||||||
|
var newcop = (this.dmacon & DMAF_COPEN) && (this.dmacon & DMAF_DMAEN);
|
||||||
|
if (oldcop != newcop) {
|
||||||
|
if (newcop && !oldcop) {
|
||||||
|
this.copper.compute_spcflag_copper(this.events.hpos());
|
||||||
|
} else if (!newcop) {
|
||||||
|
this.copper.enabled_thisline = false;
|
||||||
|
clr_special (SPCFLAG_COPPER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if ((this.dmacon & DMAF_COPEN) > (oldcon & DMAF_COPEN))
|
||||||
|
//this.copper.COPJMP(1, 0);
|
||||||
|
|
||||||
|
if ((this.dmacon & DMAF_SPREN) > (oldcon & DMAF_SPREN)) {
|
||||||
|
for (var i = 0; i < 8; i++)
|
||||||
|
this.playfield.sprites.sprite[i].dmastate = 1;
|
||||||
|
}
|
||||||
|
if ((this.dmacon & DMAF_BLTPRI) > (oldcon & DMAF_BLTPRI) && this.blitter.getState() != BLT_done)
|
||||||
|
set_special(SPCFLAG_BLTNASTY);
|
||||||
|
if (this.dmaen(DMAF_BLTEN) && this.blitter.getState() == BLT_init)
|
||||||
|
this.blitter.setState(BLT_work);
|
||||||
|
if ((this.dmacon & (DMAF_BLTPRI | DMAF_BLTEN | DMAF_DMAEN)) != (DMAF_BLTPRI | DMAF_BLTEN | DMAF_DMAEN))
|
||||||
|
clr_special(SPCFLAG_BLTNASTY);
|
||||||
|
|
||||||
|
if (changed & (DMAF_DMAEN | 0x0f))
|
||||||
|
this.audio.state_machine();
|
||||||
|
|
||||||
|
/*if (this.copper.active && !this.events.eventtab[EV_COPPER].active) {
|
||||||
|
this.events.eventtab[EV_COPPER].active = true;
|
||||||
|
this.events.eventtab[EV_COPPER].oldcycles = this.events.currcycle;
|
||||||
|
this.events.eventtab[EV_COPPER].evtime = 1 * CYCLE_UNIT + this.events.currcycle;
|
||||||
|
this.events.schedule();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.ADKCONR = function () {
|
||||||
|
return this.adkcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ADKCON = function (v, hpos) {
|
||||||
|
if (this.config.audio.enabled)
|
||||||
|
this.audio.update();
|
||||||
|
|
||||||
|
this.disk.update(hpos);
|
||||||
|
this.disk.update_adkcon(v);
|
||||||
|
|
||||||
|
if (v & INTF_SETCLR)
|
||||||
|
this.adkcon |= v & ~INTF_SETCLR;
|
||||||
|
else
|
||||||
|
this.adkcon &= ~v;
|
||||||
|
|
||||||
|
this.audio.update_adkmasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.INTENAR = function () {
|
||||||
|
return this.intena;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.INTENA = function(v) {
|
||||||
|
var old = this.intena;
|
||||||
|
|
||||||
|
if (v & INTF_SETCLR)
|
||||||
|
this.intena |= v & ~INTF_SETCLR;
|
||||||
|
else
|
||||||
|
this.intena &= ~v;
|
||||||
|
|
||||||
|
if (!(v & INTF_SETCLR) && old == this.intena)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (AMIGA.config.cpu.exact) {
|
||||||
|
this.events.event2_newevent_xx(-1, INT_PROCESSING_DELAY, this.intena, function(v) {
|
||||||
|
//console.log('INTENA()', v);
|
||||||
|
AMIGA.intena_internal = v;
|
||||||
|
AMIGA.doint();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.intena_internal = this.intena;
|
||||||
|
if (v & INTF_SETCLR)
|
||||||
|
this.doint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.INTREQR = function () {
|
||||||
|
return this.intreq;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.INTREQ_0 = function(v) {
|
||||||
|
var old = this.intreq;
|
||||||
|
|
||||||
|
if (v & INTF_SETCLR)
|
||||||
|
this.intreq |= v & ~INTF_SETCLR;
|
||||||
|
else
|
||||||
|
this.intreq &= ~v;
|
||||||
|
|
||||||
|
if (AMIGA.config.cpu.exact) {
|
||||||
|
if (old == this.intreq && this.intreq_internal == this.intreq)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.events.event2_newevent_xx(-1, INT_PROCESSING_DELAY, this.intreq, function(v) {
|
||||||
|
//console.log('INTREQ_0()', v);
|
||||||
|
AMIGA.intreq_internal = v;
|
||||||
|
AMIGA.doint();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.intreq_internal = this.intreq;
|
||||||
|
if (this.intreq == old)
|
||||||
|
return;
|
||||||
|
if (v & INTF_SETCLR)
|
||||||
|
this.doint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.INTREQ = function(v) {
|
||||||
|
this.INTREQ_0(v);
|
||||||
|
this.cia.reThink();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.intlev = function() {
|
||||||
|
var imask = this.intreq_internal & this.intena_internal;
|
||||||
|
|
||||||
|
if (imask && (this.intena_internal & INTF_INTEN)) {
|
||||||
|
if (imask & 0x2000) return 6;
|
||||||
|
if (imask & (0x1000 | 0x0800)) return 5;
|
||||||
|
if (imask & (0x0400 | 0x0200 | 0x0100 | 0x0080)) return 4;
|
||||||
|
if (imask & (0x0040 | 0x0020 | 0x0010)) return 3;
|
||||||
|
if (imask & 0x0008) return 2;
|
||||||
|
if (imask & (0x0001 | 0x0002 | 0x0004)) return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doint = function() {
|
||||||
|
if (AMIGA.config.cpu.exact) {
|
||||||
|
this.cpu.setIPL(this.intlev());
|
||||||
|
clr_special(SPCFLAG_INT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (AMIGA.config.cpu.compatible)
|
||||||
|
set_special(SPCFLAG_INT);
|
||||||
|
else
|
||||||
|
set_special(SPCFLAG_DOINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send_interrupt = function(num, delay) {
|
||||||
|
if (AMIGA.config.cpu.exact && delay > 0) {
|
||||||
|
if (!(this.intreq & (1 << num))) {
|
||||||
|
this.events.event2_newevent_xx(-1, delay, num, function(v) {
|
||||||
|
AMIGA.INTREQ_0(INTF_SETCLR | (1 << v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
this.INTREQ_0(INTF_SETCLR | (1 << num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* This API will change in the future. */
|
||||||
|
|
||||||
|
function SAE(x) {
|
||||||
|
try {
|
||||||
|
switch (x.cmd) {
|
||||||
|
case 'init':
|
||||||
|
BUG = new Debug();
|
||||||
|
BUG.info('API.init() SEA %d.%d.%d', SAEV_Version, SAEV_Revision, SAEV_Revision_Sub);
|
||||||
|
|
||||||
|
AMIGA = new Amiga();
|
||||||
|
return AMIGA.config;
|
||||||
|
case 'reset':
|
||||||
|
BUG.info('API.reset()');
|
||||||
|
AMIGA.reset();
|
||||||
|
break;
|
||||||
|
case 'start':
|
||||||
|
BUG.info('API.start()');
|
||||||
|
AMIGA.start();
|
||||||
|
break;
|
||||||
|
case 'stop':
|
||||||
|
BUG.info('API.stop()');
|
||||||
|
AMIGA.stop();
|
||||||
|
break;
|
||||||
|
case 'reset':
|
||||||
|
BUG.info('API.reset()');
|
||||||
|
AMIGA.reset();
|
||||||
|
break;
|
||||||
|
case 'pause':
|
||||||
|
BUG.info('API.pause() %d', x.state);
|
||||||
|
AMIGA.pause(x.state);
|
||||||
|
break;
|
||||||
|
/*case 'insert':
|
||||||
|
BUG.info('API.insert() DF%d, name "%s", length %d', x.unit, x.name, x.data.length);
|
||||||
|
AMIGA.insert(x.unit, x.name, x.data);
|
||||||
|
break;*/
|
||||||
|
case 'insert':
|
||||||
|
BUG.info('API.insert() DF%d', x.unit);
|
||||||
|
AMIGA.insert(x.unit);
|
||||||
|
break;
|
||||||
|
case 'eject':
|
||||||
|
BUG.info('API.eject() DF%d', x.unit);
|
||||||
|
AMIGA.eject(x.unit);
|
||||||
|
break;
|
||||||
|
/*case 'getConfig':
|
||||||
|
BUG.info('API.getConfig()');
|
||||||
|
return AMIGA.config;
|
||||||
|
case 'setConfig':
|
||||||
|
BUG.info('API.setConfig() size '+x.data.ext.size);
|
||||||
|
AMIGA.config = x.data;
|
||||||
|
break;*/
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof FatalError) {
|
||||||
|
AMIGA.stop();
|
||||||
|
//return { error:e.error, message:e.message };
|
||||||
|
AMIGA.config.hooks.error(e.error, e.message);
|
||||||
|
} else
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
//return SAEE_None;
|
||||||
|
//return { error:SAEE_None, message:'' };
|
||||||
|
}
|
||||||
1126
sae/audio.js
Normal file
1126
sae/audio.js
Normal file
File diff suppressed because it is too large
Load diff
2904
sae/blitter.js
Normal file
2904
sae/blitter.js
Normal file
File diff suppressed because it is too large
Load diff
738
sae/cia.js
Normal file
738
sae/cia.js
Normal file
|
|
@ -0,0 +1,738 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function CIA_8520(type) {
|
||||||
|
const STARTCYCLESHI = 3;
|
||||||
|
const STARTCYCLESCRA = 2;
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
|
||||||
|
this.icr = 0;
|
||||||
|
this.icrReg = 0;
|
||||||
|
this.iMask = 0;
|
||||||
|
this.iFlag = type == CIA_A ? INTF_PORTS : INTF_EXTER; /* 0x0008 : 0x2000 */
|
||||||
|
|
||||||
|
this.cra = 0;
|
||||||
|
this.crb = 0;
|
||||||
|
this.dra = 0;
|
||||||
|
this.drb = 0;
|
||||||
|
this.pra = 0;
|
||||||
|
this.prb = 0;
|
||||||
|
this.sdr = 0;
|
||||||
|
this.sdrCnt = 0;
|
||||||
|
|
||||||
|
this.ta = 0;
|
||||||
|
this.tb = 0;
|
||||||
|
this.taPassed = 0;
|
||||||
|
this.tbPassed = 0;
|
||||||
|
this.la = 0;
|
||||||
|
this.lb = 0;
|
||||||
|
this.starta = 0;
|
||||||
|
this.startb = 0;
|
||||||
|
|
||||||
|
this.todOn = false;
|
||||||
|
this.tod = 0;
|
||||||
|
this.tol = 0;
|
||||||
|
this.tlatch = 0;
|
||||||
|
this.alarm = 0;
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
this.icr = this.iMask = 0;
|
||||||
|
this.cra = this.crb = 0x4;
|
||||||
|
this.dra = this.drb = 0;
|
||||||
|
this.pra = this.type == CIA_A ? 0 : 0x8c;
|
||||||
|
this.sdr = 0;
|
||||||
|
this.sdrCnt = 0;
|
||||||
|
this.la = this.lb = this.ta = this.tb = 0xffff;
|
||||||
|
this.taPassed = this.tbPassed = 0;
|
||||||
|
this.tod = 0;
|
||||||
|
this.todOn = false;
|
||||||
|
this.tlatch = 0;
|
||||||
|
this.alarm = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dump = function() {
|
||||||
|
BUG.info('CIA_8520.dump() %s | pra $%02x prb $%02x | dra $%02x drb $%02x | ta %5d (la %5d) tb %5d (lb %5d) | tod %5d (tol %5d) alarm %5d latch %d | sdr $%02x | icr $%02x iMask $%02x | cra $%02x crb $%02x',
|
||||||
|
this.type == CIA_A ? 'A' : 'B', this.pra, this.prb, this.dra, this.drb, this.ta, this.la, this.tb, this.lb, this.tod, this.tol, this.alarm, this.latch ? 1 : 0, this.sdr, this.icr, this.iMask, this.cra, this.crb);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setClr = function (val) {
|
||||||
|
if (val & 0x80) this.iMask |= val & 0x7f;
|
||||||
|
else this.iMask &= ~val;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setICR = function (icr, sdr) {
|
||||||
|
if (sdr !== null)
|
||||||
|
this.sdr = sdr;
|
||||||
|
|
||||||
|
this.icr |= icr;
|
||||||
|
this.reThink();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ICR = function() {
|
||||||
|
if (this.iMask & this.icr) {
|
||||||
|
this.icr |= 0x80;
|
||||||
|
AMIGA.INTREQ_0(INTF_SETCLR | this.iFlag);
|
||||||
|
}
|
||||||
|
this.icrReg |= this.icr;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reThink = function() {
|
||||||
|
if (this.icr) {
|
||||||
|
if (AMIGA.config.cpu.exact)
|
||||||
|
AMIGA.events.event2_newevent_xx(-1, CIA_RETHINK_DELAY, this.type, function(v) { AMIGA.cia.ICR(v); });
|
||||||
|
else
|
||||||
|
this.ICR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateCheck = function (ciaclocks) {
|
||||||
|
var ovfla = false;
|
||||||
|
var ovflb = false;
|
||||||
|
var sp = false;
|
||||||
|
var needReThink = false;
|
||||||
|
|
||||||
|
if ((this.cra & 0x21) == 0x01) {
|
||||||
|
//BUG.info('CIA.updateCheck() ciaclocks %d, starta %d, ta %d', ciaclocks, this.starta, this.ta);
|
||||||
|
var check = true;
|
||||||
|
var cc = ciaclocks;
|
||||||
|
if (this.starta > 0) {
|
||||||
|
if (cc > this.starta) {
|
||||||
|
cc -= this.starta;
|
||||||
|
this.starta = 0;
|
||||||
|
} else {
|
||||||
|
this.starta -= cc;
|
||||||
|
check = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (check) {
|
||||||
|
//assert ((this.ta + 1) >= cc);
|
||||||
|
if ((this.ta + 1) == cc) {
|
||||||
|
if ((this.cra & 0x48) == 0x40 && this.sdrCnt > 0 && --this.sdrCnt == 0) sp = true;
|
||||||
|
|
||||||
|
ovfla = true;
|
||||||
|
if ((this.crb & 0x61) == 0x41 || (this.crb & 0x61) == 0x61) {
|
||||||
|
if (this.tb-- == 0) ovflb = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ta -= cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((this.crb & 0x61) == 0x01) {
|
||||||
|
//BUG.info('CIA.updateCheck() ciaclocks %d, startb %d, tb %d', ciaclocks, this.startb, this.tb);
|
||||||
|
var check = true;
|
||||||
|
var cc = ciaclocks;
|
||||||
|
if (this.startb > 0) {
|
||||||
|
if (cc > this.startb) {
|
||||||
|
cc -= this.startb;
|
||||||
|
this.startb = 0;
|
||||||
|
} else {
|
||||||
|
this.startb -= cc;
|
||||||
|
check = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (check) {
|
||||||
|
//assert ((this.tb + 1) >= cc);
|
||||||
|
if ((this.tb + 1) == cc) ovflb = true;
|
||||||
|
this.tb -= cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ovfla) {
|
||||||
|
this.icr |= 1;
|
||||||
|
needReThink = true;
|
||||||
|
this.ta = this.la;
|
||||||
|
if (this.cra & 0x8) {
|
||||||
|
this.cra &= ~1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ovflb) {
|
||||||
|
this.icr |= 2;
|
||||||
|
needReThink = true;
|
||||||
|
this.tb = this.lb;
|
||||||
|
if (this.crb & 0x8) {
|
||||||
|
this.crb &= ~1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sp) {
|
||||||
|
this.icr |= 8;
|
||||||
|
needReThink = true;
|
||||||
|
}
|
||||||
|
return needReThink;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.calcTimers = function (div10diff) {
|
||||||
|
var time = [-1, -1];
|
||||||
|
|
||||||
|
if ((this.cra & 0x21) == 0x01) time[0] = div10diff + DIV10 * (this.ta + this.starta);
|
||||||
|
if ((this.crb & 0x61) == 0x01) time[1] = div10diff + DIV10 * (this.tb + this.startb);
|
||||||
|
|
||||||
|
//if (time[0] != -1 || time[1] != -1) BUG.info('CIA.calcTimers() div10diff %d, timea %d, timeb %d', div10diff, time[0], time[1]);
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.checkAlarm = function (inc) {
|
||||||
|
var alarm;
|
||||||
|
|
||||||
|
if (this.tod == this.alarm) alarm = true;
|
||||||
|
else if (!inc) alarm = false;
|
||||||
|
else if (this.tod & 0x000fff) alarm = false;
|
||||||
|
else if (((this.tod - 1) & 0xfff000) == this.alarm) alarm = true;
|
||||||
|
else alarm = false;
|
||||||
|
|
||||||
|
if (alarm) {
|
||||||
|
this.icr |= 4;
|
||||||
|
this.reThink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.calcPassedTime = function() {
|
||||||
|
var ccount = AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles + AMIGA.cia.div10;
|
||||||
|
var ciaclocks = Math.floor(ccount / DIV10);
|
||||||
|
|
||||||
|
this.taPassed = this.tbPassed = 0;
|
||||||
|
|
||||||
|
if ((this.cra & 0x21) == 0x01) {
|
||||||
|
var cc = ciaclocks;
|
||||||
|
if (cc > this.starta) cc -= this.starta;
|
||||||
|
else cc = 0;
|
||||||
|
//assert ((this.ta + 1) >= cc);
|
||||||
|
this.taPassed = cc;
|
||||||
|
}
|
||||||
|
if ((this.crb & 0x61) == 0x01) {
|
||||||
|
var cc = ciaclocks;
|
||||||
|
if (cc > this.startb) cc -= this.startb;
|
||||||
|
else cc = 0;
|
||||||
|
//assert ((this.tb + 1) >= cc);
|
||||||
|
this.tbPassed = cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.read = function (addr) {
|
||||||
|
var reg = addr & 15;
|
||||||
|
var tmp;
|
||||||
|
|
||||||
|
this.calcPassedTime();
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case 0: {
|
||||||
|
if (this.type == CIA_A) {
|
||||||
|
tmp = AMIGA.disk.status() & 0x3c;
|
||||||
|
|
||||||
|
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) {
|
||||||
|
if (!AMIGA.input.mouse.button[0]) tmp |= 0x40;
|
||||||
|
if (this.dra & 0x40) tmp = (tmp & ~0x40) | (this.pra & 0x40);
|
||||||
|
} else if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) {
|
||||||
|
if (!AMIGA.input.joystick[0].button[0]) tmp |= 0x40;
|
||||||
|
if (this.dra & 0x40) tmp = (tmp & ~0x40) | (this.pra & 0x40);
|
||||||
|
} else tmp |= 0x40;
|
||||||
|
|
||||||
|
if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) {
|
||||||
|
if (!AMIGA.input.joystick[1].button[0]) tmp |= 0x80;
|
||||||
|
if (this.dra & 0x80) tmp = (tmp & ~0x80) | (this.pra & 0x80);
|
||||||
|
} else tmp |= 0x80;
|
||||||
|
|
||||||
|
tmp |= (this.pra | (this.dra ^ 3)) & 3;
|
||||||
|
} else {
|
||||||
|
//tmp = 0xf8;
|
||||||
|
tmp = AMIGA.serial.readStatus(this.dra);
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
if (this.type == CIA_A) {
|
||||||
|
tmp = 0;
|
||||||
|
} else {
|
||||||
|
tmp = this.prb;
|
||||||
|
}
|
||||||
|
if (this.crb & 2) {
|
||||||
|
var pb7 = 0;
|
||||||
|
if (this.crb & 4) pb7 = this.crb & 1;
|
||||||
|
tmp &= ~0x80;
|
||||||
|
tmp |= pb7 ? 0x80 : 0;
|
||||||
|
}
|
||||||
|
if (this.cra & 2) {
|
||||||
|
var pb6 = 0;
|
||||||
|
if (this.cra & 4) pb6 = this.cra & 1;
|
||||||
|
tmp &= ~0x40;
|
||||||
|
tmp |= pb6 ? 0x40 : 0;
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
return this.dra;
|
||||||
|
case 3:
|
||||||
|
return this.drb;
|
||||||
|
case 4:
|
||||||
|
return ((this.ta - this.taPassed) & 0xff);
|
||||||
|
case 5:
|
||||||
|
return ((this.ta - this.taPassed) >> 8) & 0xff;
|
||||||
|
case 6:
|
||||||
|
return ((this.tb - this.tbPassed) & 0xff);
|
||||||
|
case 7:
|
||||||
|
return ((this.tb - this.tbPassed) >> 8) & 0xff;
|
||||||
|
case 8: {
|
||||||
|
if (this.tlatch) {
|
||||||
|
this.tlatch = 0;
|
||||||
|
return this.tol & 0xff;
|
||||||
|
} else return this.tod & 0xff;
|
||||||
|
}
|
||||||
|
case 9: {
|
||||||
|
if (this.tlatch) return (this.tol >> 8) & 0xff;
|
||||||
|
else return (this.tod >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
case 10: {
|
||||||
|
if (!this.tlatch) {
|
||||||
|
if (!(this.crb & 0x80)) this.tlatch = 1;
|
||||||
|
this.tol = this.tod;
|
||||||
|
}
|
||||||
|
return (this.tol >>> 16) & 0xff;
|
||||||
|
}
|
||||||
|
case 12:
|
||||||
|
return this.sdr;
|
||||||
|
case 13: {
|
||||||
|
tmp = this.icrReg;
|
||||||
|
this.icr &= ~this.icrReg;
|
||||||
|
this.icrReg = 0;
|
||||||
|
this.reThink();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
case 14:
|
||||||
|
return this.cra;
|
||||||
|
case 15:
|
||||||
|
return this.crb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.write = function (addr, val) {
|
||||||
|
var reg = addr & 15;
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case 0: {
|
||||||
|
if (this.type == CIA_A) {
|
||||||
|
this.pra = (this.pra & 0x3c) | (val & 0xc3);
|
||||||
|
AMIGA.cia.handlePowerLED(this.pra, this.dra);
|
||||||
|
} else {
|
||||||
|
this.pra = val;
|
||||||
|
AMIGA.serial.writeStatus(this.pra, this.dra);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
if (this.type == CIA_A) {
|
||||||
|
this.prb = val;
|
||||||
|
} else {
|
||||||
|
this.prb = val;
|
||||||
|
AMIGA.disk.select(val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
if (this.type == CIA_A) {
|
||||||
|
this.dra = val;
|
||||||
|
AMIGA.cia.handlePowerLED(this.pra, this.dra);
|
||||||
|
} else {
|
||||||
|
this.dra = val;
|
||||||
|
AMIGA.serial.writeStatus(this.pra, this.dra);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
if (this.type == CIA_A) {
|
||||||
|
this.drb = val;
|
||||||
|
} else {
|
||||||
|
this.drb = val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
AMIGA.cia.update();
|
||||||
|
this.la = (this.la & 0xff00) | val;
|
||||||
|
AMIGA.cia.calcTimers();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
AMIGA.cia.update();
|
||||||
|
this.la = (this.la & 0x00ff) | (val << 8);
|
||||||
|
if ((this.cra & 1) == 0) this.ta = this.la;
|
||||||
|
if (this.cra & 8) {
|
||||||
|
this.ta = this.la;
|
||||||
|
this.cra |= 1;
|
||||||
|
this.starta = STARTCYCLESHI;
|
||||||
|
}
|
||||||
|
AMIGA.cia.calcTimers();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
AMIGA.cia.update();
|
||||||
|
this.lb = (this.lb & 0xff00) | val;
|
||||||
|
AMIGA.cia.calcTimers();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 7: {
|
||||||
|
AMIGA.cia.update();
|
||||||
|
this.lb = (this.lb & 0x00ff) | (val << 8);
|
||||||
|
if ((this.crb & 1) == 0) this.tb = this.lb;
|
||||||
|
if (this.crb & 8) {
|
||||||
|
this.tb = this.lb;
|
||||||
|
this.crb |= 1;
|
||||||
|
this.startb = STARTCYCLESHI;
|
||||||
|
}
|
||||||
|
AMIGA.cia.calcTimers();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 8: {
|
||||||
|
if (this.crb & 0x80) {
|
||||||
|
this.alarm = (this.alarm & 0xffff00) | val;
|
||||||
|
} else {
|
||||||
|
this.tod = (this.tod & 0xffff00) | val;
|
||||||
|
this.todOn = true;
|
||||||
|
this.checkAlarm(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 9: {
|
||||||
|
if (this.crb & 0x80) {
|
||||||
|
this.alarm = (this.alarm & 0xff00ff) | (val << 8);
|
||||||
|
} else {
|
||||||
|
this.tod = (this.tod & 0xff00ff) | (val << 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 10: {
|
||||||
|
if (this.crb & 0x80) {
|
||||||
|
this.alarm = (this.alarm & 0x00ffff) | (val << 16);
|
||||||
|
} else {
|
||||||
|
this.tod = (this.tod & 0x00ffff) | (val << 16);
|
||||||
|
this.todOn = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 12: {
|
||||||
|
AMIGA.cia.update();
|
||||||
|
this.sdr = val;
|
||||||
|
if (this.type == CIA_B && (this.cra & 0x40) == 0) this.sdrCnt = 0;
|
||||||
|
if ((this.cra & 0x41) == 0x41 && this.sdrCnt == 0) this.sdrCnt = 8 * 2;
|
||||||
|
AMIGA.cia.calcTimers();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 13: {
|
||||||
|
this.setClr(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 14: {
|
||||||
|
AMIGA.cia.update();
|
||||||
|
val &= 0x7f;
|
||||||
|
if ((val & 1) && !(this.cra & 1)) this.starta = STARTCYCLESCRA;
|
||||||
|
if (this.type == CIA_A && (val & 0x40) != (this.cra & 0x40)) {
|
||||||
|
AMIGA.input.keyboard.lostsynccnt = 0;
|
||||||
|
//BUG.info('KB_ACK %02x to %02x', val, this.cra);
|
||||||
|
}
|
||||||
|
this.cra = val;
|
||||||
|
if (this.cra & 0x10) {
|
||||||
|
this.cra &= ~0x10;
|
||||||
|
this.ta = this.la;
|
||||||
|
}
|
||||||
|
AMIGA.cia.calcTimers();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 15: {
|
||||||
|
AMIGA.cia.update();
|
||||||
|
if ((val & 1) && !(this.crb & 1)) this.startb = STARTCYCLESCRA;
|
||||||
|
this.crb = val;
|
||||||
|
if (this.crb & 0x10) {
|
||||||
|
this.crb &= ~0x10;
|
||||||
|
this.tb = this.lb;
|
||||||
|
}
|
||||||
|
AMIGA.cia.calcTimers();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function CIA() {
|
||||||
|
this.A = new CIA_8520(CIA_A);
|
||||||
|
this.B = new CIA_8520(CIA_B);
|
||||||
|
this.div10 = 0;
|
||||||
|
|
||||||
|
var led = true;
|
||||||
|
|
||||||
|
var todHack = {
|
||||||
|
active: true,
|
||||||
|
enabled: false,
|
||||||
|
rate: 0.0,
|
||||||
|
tv: 0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
if (todHack.active) todHack.rate = 1000.0 / AMIGA.events.hz;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
this.A.reset();
|
||||||
|
this.B.reset();
|
||||||
|
this.div10 = 0;
|
||||||
|
this.calcTimers();
|
||||||
|
|
||||||
|
led = true;
|
||||||
|
AMIGA.disk.select_set(this.B.prb);
|
||||||
|
|
||||||
|
if (todHack.active) {
|
||||||
|
todHack.enabled = AMIGA.events.maxvpos * AMIGA.events.hz * 10;
|
||||||
|
todHack.tv = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dump = function() {
|
||||||
|
this.A.dump();
|
||||||
|
this.B.dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handlePowerLED = function (pra, dra) {
|
||||||
|
var v = pra | (~dra & 0xff);
|
||||||
|
var newled = (v & 2) ? 0 : 1;
|
||||||
|
|
||||||
|
if (led != newled) {
|
||||||
|
led = newled;
|
||||||
|
AMIGA.audio.filter.led_filter_on = led;
|
||||||
|
AMIGA.config.hooks.power_led(led);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setICR = function (type, icr, sdr) {
|
||||||
|
if (type == CIA_A)
|
||||||
|
this.A.setICR(icr, sdr);
|
||||||
|
else
|
||||||
|
this.B.setICR(icr, sdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ICR = function(type) {
|
||||||
|
if (type == CIA_A)
|
||||||
|
this.A.ICR();
|
||||||
|
else
|
||||||
|
this.B.ICR();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reThink = function() {
|
||||||
|
this.A.reThink();
|
||||||
|
this.B.reThink();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update = function() {
|
||||||
|
var ccount = AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles + this.div10;
|
||||||
|
var ciaclocks = Math.floor(ccount / DIV10);
|
||||||
|
|
||||||
|
this.div10 = ccount % DIV10;
|
||||||
|
|
||||||
|
//BUG.info('CIA.update() %d %d', ciaclocks, this.div10);
|
||||||
|
|
||||||
|
var a = this.A.updateCheck(ciaclocks);
|
||||||
|
var b = this.B.updateCheck(ciaclocks);
|
||||||
|
if (a) this.A.reThink();
|
||||||
|
if (b) this.B.reThink();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.calcTimers = function() {
|
||||||
|
AMIGA.events.eventtab[EV_CIA].oldcycles = AMIGA.events.currcycle;
|
||||||
|
|
||||||
|
var div10diff = DIV10 - this.div10;
|
||||||
|
var a = this.A.calcTimers(div10diff);
|
||||||
|
var b = this.B.calcTimers(div10diff);
|
||||||
|
|
||||||
|
AMIGA.events.eventtab[EV_CIA].active = (a[0] != -1 || a[1] != -1 || b[0] != -1 || b[1] != -1);
|
||||||
|
if (AMIGA.events.eventtab[EV_CIA].active) {
|
||||||
|
var evtime = 0xffffffff;
|
||||||
|
|
||||||
|
if (a[0] != -1) evtime = a[0];
|
||||||
|
if (a[1] != -1 && a[1] < evtime) evtime = a[1];
|
||||||
|
if (b[0] != -1 && b[0] < evtime) evtime = b[0];
|
||||||
|
if (b[1] != -1 && b[1] < evtime) evtime = b[1];
|
||||||
|
|
||||||
|
AMIGA.events.eventtab[EV_CIA].evtime = evtime + AMIGA.events.currcycle;
|
||||||
|
//BUG.info('CIA.calcTimers() evtime %d', evtime);
|
||||||
|
}
|
||||||
|
AMIGA.events.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handler = function() {
|
||||||
|
this.update();
|
||||||
|
this.calcTimers();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleTodHack = function() {
|
||||||
|
if (todHack.enabled > 1) {
|
||||||
|
todHack.enabled--;
|
||||||
|
if (todHack.enabled == 1) {
|
||||||
|
todHack.tv = new Date().getTime();
|
||||||
|
BUG.info('CIA.handleTodHack() enabled');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (new Date().getTime() - todHack.tv >= todHack.rate) {
|
||||||
|
this.A.tod++;
|
||||||
|
this.A.tod &= 0xffffff;
|
||||||
|
this.A.checkAlarm(0);
|
||||||
|
todHack.tv += todHack.rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hSyncPre = function() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hSyncPost = function (doTod) {
|
||||||
|
if (this.B.todOn && doTod) {
|
||||||
|
this.B.tod++;
|
||||||
|
this.B.tod &= 0xffffff;
|
||||||
|
this.B.checkAlarm(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (todHack.active && this.A.todOn) this.handleTodHack();
|
||||||
|
|
||||||
|
AMIGA.input.keyboard.hsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vSyncPre = function() {
|
||||||
|
this.handler();
|
||||||
|
AMIGA.input.keyboard.vsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vSyncPost = function (doTod) {
|
||||||
|
if (todHack.active && todHack.enabled == 1) return;
|
||||||
|
|
||||||
|
if (this.A.todOn && doTod) {
|
||||||
|
this.A.tod++;
|
||||||
|
this.A.tod &= 0xffffff;
|
||||||
|
this.A.checkAlarm(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.waitPre = function() {
|
||||||
|
//if (AMIGA.config.cpu.cachesize) return;
|
||||||
|
|
||||||
|
//#ifndef CUSTOM_SIMPLE
|
||||||
|
/*var div = (AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles) % DIV10;
|
||||||
|
var div2 = Math.floor(DIV10 * ECLOCK_DATA_CYCLE / 10);
|
||||||
|
var cycles;
|
||||||
|
|
||||||
|
if (div >= div2)
|
||||||
|
cycles = DIV10 - div + div2;
|
||||||
|
else if (div)
|
||||||
|
cycles = DIV10 + div2 - div;
|
||||||
|
else
|
||||||
|
cycles = div2 - div;
|
||||||
|
|
||||||
|
//BUG.info('CIA.waitPre() %d %d', div, cycles);
|
||||||
|
|
||||||
|
if (cycles) {
|
||||||
|
if (AMIGA.config.cpu.exact)
|
||||||
|
AMIGA.events.cycle(cycles);
|
||||||
|
else
|
||||||
|
AMIGA.events.cycle(cycles);
|
||||||
|
}*/
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
this.waitPost = function () {
|
||||||
|
AMIGA.events.cycle(6 * CYCLE_UNIT / 2);
|
||||||
|
|
||||||
|
/*if (AMIGA.config.cpu.cachesize)
|
||||||
|
AMIGA.events.cycle(8 * CYCLE_UNIT /2);
|
||||||
|
else*/ {
|
||||||
|
var c = 6 * CYCLE_UNIT / 2;
|
||||||
|
if (AMIGA.config.cpu.exact)
|
||||||
|
AMIGA.events.cycle(c);
|
||||||
|
else
|
||||||
|
AMIGA.events.cycle(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load8 = function (addr) {
|
||||||
|
var v, r = (addr & 0xf00) >> 8;
|
||||||
|
|
||||||
|
this.waitPre();
|
||||||
|
switch ((addr >> 12) & 3) {
|
||||||
|
case 0:
|
||||||
|
v = (addr & 1) ? this.A.read(r) : this.B.read(r);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
v = (addr & 1) ? 0xff : this.B.read(r);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
v = (addr & 1) ? this.A.read(r) : 0xff;
|
||||||
|
break;
|
||||||
|
case 3: {
|
||||||
|
v = 0xff;
|
||||||
|
//if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) v = (addr & 1) ? regs.irc : regs.irc >> 8;
|
||||||
|
BUG.info('CIA.load8() unknown CIA address $%08x', addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.waitPost();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load16 = function (addr) {
|
||||||
|
var v, r = (addr & 0xf00) >> 8;
|
||||||
|
|
||||||
|
this.waitPre();
|
||||||
|
switch ((addr >> 12) & 3) {
|
||||||
|
case 0:
|
||||||
|
v = (this.B.read(r) << 8) | this.A.read(r);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
v = (this.B.read(r) << 8) | 0xff;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
v = (0xff << 8) | this.A.read(r);
|
||||||
|
break;
|
||||||
|
case 3: {
|
||||||
|
v = 0xffff;
|
||||||
|
//if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) v = regs.irc;
|
||||||
|
BUG.info('CIA.load16() unknown CIA address $%08x', addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.waitPost();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load32 = function (addr) {
|
||||||
|
return ((this.load16(addr) << 16) | this.load16(addr + 2)) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store8 = function (addr, value) {
|
||||||
|
var r = (addr & 0xf00) >> 8;
|
||||||
|
|
||||||
|
this.waitPre();
|
||||||
|
if ((addr & 0x3000) != 0) {
|
||||||
|
if ((addr & 0x2000) == 0) this.B.write(r, value);
|
||||||
|
if ((addr & 0x1000) == 0) this.A.write(r, value);
|
||||||
|
}
|
||||||
|
this.waitPost();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store16 = function (addr, value) {
|
||||||
|
var r = (addr & 0xf00) >> 8;
|
||||||
|
|
||||||
|
this.waitPre();
|
||||||
|
if ((addr & 0x3000) != 0) {
|
||||||
|
if ((addr & 0x2000) == 0) this.B.write(r, value >> 8);
|
||||||
|
if ((addr & 0x1000) == 0) this.A.write(r, value & 0xff);
|
||||||
|
}
|
||||||
|
this.waitPost();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store32 = function (addr, value) {
|
||||||
|
this.store16(addr, value >>> 16);
|
||||||
|
this.store16(addr + 2, value & 0xffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
188
sae/config.js
Normal file
188
sae/config.js
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function Config() {
|
||||||
|
this.init = false;
|
||||||
|
|
||||||
|
this.cpu = {
|
||||||
|
model: 68000,
|
||||||
|
speed: 0, /* 0 if cpu.exact */
|
||||||
|
exact: false,
|
||||||
|
compatible: true
|
||||||
|
};
|
||||||
|
this.blitter = {
|
||||||
|
exact: false, /* do not change */
|
||||||
|
immediate: false, /* false if blitter.exact */
|
||||||
|
waiting: 1 /* 0 if cpu.exact or blitter.immediate */
|
||||||
|
};
|
||||||
|
this.chipset = {
|
||||||
|
type: 0,
|
||||||
|
agnus: 0,
|
||||||
|
agnus_rev: 0,
|
||||||
|
denise: 0,
|
||||||
|
paula: 0,
|
||||||
|
colLevel: 0
|
||||||
|
};
|
||||||
|
this.ram = {
|
||||||
|
chip: {
|
||||||
|
size: 0
|
||||||
|
},
|
||||||
|
slow: {
|
||||||
|
size: 0,
|
||||||
|
},
|
||||||
|
fast: {
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.rom = {
|
||||||
|
size: 0,
|
||||||
|
data: null
|
||||||
|
};
|
||||||
|
this.ext = {
|
||||||
|
addr: 0,
|
||||||
|
size: 0,
|
||||||
|
data: null
|
||||||
|
};
|
||||||
|
this.floppy = {
|
||||||
|
drive:[{
|
||||||
|
type: 0,
|
||||||
|
name: null,
|
||||||
|
data: null
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
name: null,
|
||||||
|
data: null
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
name: null,
|
||||||
|
data: null
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
name: null,
|
||||||
|
data: null
|
||||||
|
}],
|
||||||
|
speed:0
|
||||||
|
};
|
||||||
|
this.video = {
|
||||||
|
enabled: false,
|
||||||
|
scale: false,
|
||||||
|
ntsc: false,
|
||||||
|
skip: false,
|
||||||
|
id: ''
|
||||||
|
};
|
||||||
|
this.audio = {
|
||||||
|
enabled: false,
|
||||||
|
mode:0,
|
||||||
|
channels: 0,
|
||||||
|
rate: 0
|
||||||
|
};
|
||||||
|
this.ports = [{
|
||||||
|
type: 0,
|
||||||
|
move: 0,
|
||||||
|
fire: [0,0]
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
move: 0,
|
||||||
|
fire: [0,0]
|
||||||
|
}];
|
||||||
|
this.keyboard = {
|
||||||
|
enabled: false,
|
||||||
|
mapShift: false
|
||||||
|
};
|
||||||
|
this.serial = {
|
||||||
|
enabled: false
|
||||||
|
};
|
||||||
|
this.rtc = {
|
||||||
|
type: 0
|
||||||
|
};
|
||||||
|
this.hooks = {
|
||||||
|
error: null,
|
||||||
|
power_led: null,
|
||||||
|
floppy_motor: null,
|
||||||
|
floppy_step: null,
|
||||||
|
fps: null,
|
||||||
|
cpu: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function configSetDefaults(c) {
|
||||||
|
c.init = true;
|
||||||
|
|
||||||
|
c.cpu.speed = SAEV_Config_CPU_Speed_Original;
|
||||||
|
|
||||||
|
c.chipset.type = SAEV_Config_Chipset_Type_OCS;
|
||||||
|
if (c.chipset.type == SAEV_Config_Chipset_Type_OCS) {
|
||||||
|
c.chipset.agnus = c.video.ntsc ? AGNUS_8370 : AGNUS_8371;
|
||||||
|
c.chipset.agnus_rev = 0;
|
||||||
|
c.chipset.denise = DENISE_8362;
|
||||||
|
} else if (c.chipset.type == SAEV_Config_Chipset_Type_ECS) {
|
||||||
|
c.chipset.agnus = AGNUS_8372;
|
||||||
|
c.chipset.agnus_rev = 5;
|
||||||
|
c.chipset.denise = DENISE_8373;
|
||||||
|
}
|
||||||
|
c.chipset.paula = PAULA_8364;
|
||||||
|
c.chipset.colLevel = SAEV_Config_Chipset_ColLevel_None;
|
||||||
|
|
||||||
|
c.ram.chip.size = SAEV_Config_RAM_Chip_Size_512K;
|
||||||
|
c.ram.slow.size = SAEV_Config_RAM_Slow_Size_512K;
|
||||||
|
c.ram.fast.size = SAEV_Config_RAM_Fast_Size_512K;
|
||||||
|
|
||||||
|
c.rom.size = SAEV_Config_ROM_Size_None;
|
||||||
|
c.rom.data = null;
|
||||||
|
c.ext.addr = SAEV_Config_EXT_Addr_E0;
|
||||||
|
c.ext.size = SAEV_Config_EXT_Size_None;
|
||||||
|
c.ext.data = null;
|
||||||
|
|
||||||
|
c.floppy.drive[0].type = SAEV_Config_Floppy_Type_35_DD;
|
||||||
|
c.floppy.drive[0].name = null;
|
||||||
|
c.floppy.drive[0].data = null;
|
||||||
|
c.floppy.drive[1].type = SAEV_Config_Floppy_Type_35_DD;
|
||||||
|
c.floppy.drive[1].name = null;
|
||||||
|
c.floppy.drive[1].data = null;
|
||||||
|
c.floppy.drive[2].type = SAEV_Config_Floppy_Type_None;
|
||||||
|
c.floppy.drive[2].name = null;
|
||||||
|
c.floppy.drive[2].data = null;
|
||||||
|
c.floppy.drive[3].type = SAEV_Config_Floppy_Type_None;
|
||||||
|
c.floppy.drive[3].name = null;
|
||||||
|
c.floppy.drive[3].data = null;
|
||||||
|
c.floppy.speed = SAEV_Config_Floppy_Speed_Original;
|
||||||
|
|
||||||
|
c.video.enabled = true;
|
||||||
|
c.video.scale = false;
|
||||||
|
c.video.ntsc = false;
|
||||||
|
c.video.skip = true;
|
||||||
|
c.video.id = 'video';
|
||||||
|
|
||||||
|
c.audio.enabled = true;
|
||||||
|
c.audio.mode = SAEV_Config_Audio_Mode_Play_Best;
|
||||||
|
c.audio.channels = SAEV_Config_Audio_Channels_Stereo;
|
||||||
|
c.audio.rate = SAEV_Config_Audio_Rate_44100;
|
||||||
|
|
||||||
|
c.ports[0].type = SAEV_Config_Ports_Type_Mouse;
|
||||||
|
c.ports[0].move = SAEV_Config_Ports_Move_WASD;
|
||||||
|
c.ports[0].fire[0] = 49;
|
||||||
|
c.ports[0].fire[1] = 50;
|
||||||
|
c.ports[1].type = SAEV_Config_Ports_Type_Joy1;
|
||||||
|
c.ports[1].move = SAEV_Config_Ports_Move_Arrows;
|
||||||
|
c.ports[1].fire[0] = 16;
|
||||||
|
c.ports[1].fire[1] = 17;
|
||||||
|
|
||||||
|
c.keyboard.enabled = true;
|
||||||
|
c.keyboard.mapShift = false;
|
||||||
|
|
||||||
|
c.rtc.type = 1 ? SAEV_Config_RTC_Type_MSM6242B : SAEV_Config_RTC_Type_RF5C01A;
|
||||||
|
|
||||||
|
c.hooks.error = function(err, msg) {}
|
||||||
|
c.hooks.power_led = function(on) {}
|
||||||
|
c.hooks.floppy_motor = function(unit, on) {}
|
||||||
|
c.hooks.floppy_step = function(unit, cyl) {}
|
||||||
|
c.hooks.fps = function(fps) {}
|
||||||
|
c.hooks.cpu = function(usage) {}
|
||||||
|
}
|
||||||
317
sae/constants.js
Normal file
317
sae/constants.js
Normal file
|
|
@ -0,0 +1,317 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
const SAEV_Version = 0;
|
||||||
|
const SAEV_Revision = 7;
|
||||||
|
const SAEV_Revision_Sub = 0;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
const SAEV_Null = null;
|
||||||
|
|
||||||
|
const SAEV_True = true;
|
||||||
|
const SAEV_False = false;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* cpu */
|
||||||
|
|
||||||
|
const SAEV_Config_CPU_Speed_Maximum = -1;
|
||||||
|
const SAEV_Config_CPU_Speed_Original = 0;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* chipset */
|
||||||
|
|
||||||
|
const SAEV_Config_Chipset_Type_OCS = 1;
|
||||||
|
const SAEV_Config_Chipset_Type_ECS = 2;
|
||||||
|
|
||||||
|
const SAEV_Config_Chipset_ColLevel_None = 0;
|
||||||
|
const SAEV_Config_Chipset_ColLevel_Sprite_Sprite = 1;
|
||||||
|
const SAEV_Config_Chipset_ColLevel_Sprite_Playfield = 2;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* ram */
|
||||||
|
|
||||||
|
const SAEV_Config_RAM_Chip_Size_256K = 1;
|
||||||
|
const SAEV_Config_RAM_Chip_Size_512K = 2;
|
||||||
|
const SAEV_Config_RAM_Chip_Size_1M = 3;
|
||||||
|
const SAEV_Config_RAM_Chip_Size_2M = 4;
|
||||||
|
|
||||||
|
const SAEV_Config_RAM_Slow_Size_None = 0;
|
||||||
|
const SAEV_Config_RAM_Slow_Size_256K = 1;
|
||||||
|
const SAEV_Config_RAM_Slow_Size_512K = 2;
|
||||||
|
const SAEV_Config_RAM_Slow_Size_1M = 3;
|
||||||
|
const SAEV_Config_RAM_Slow_Size_1536K = 4;
|
||||||
|
|
||||||
|
const SAEV_Config_RAM_Fast_Size_None = 0;
|
||||||
|
const SAEV_Config_RAM_Fast_Size_512K = 1;
|
||||||
|
const SAEV_Config_RAM_Fast_Size_1M = 2;
|
||||||
|
const SAEV_Config_RAM_Fast_Size_2M = 3;
|
||||||
|
const SAEV_Config_RAM_Fast_Size_4M = 4;
|
||||||
|
const SAEV_Config_RAM_Fast_Size_8M = 5;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* rom, ext */
|
||||||
|
|
||||||
|
const SAEV_Config_ROM_Size_None = 0;
|
||||||
|
const SAEV_Config_ROM_Size_256K = 1;
|
||||||
|
const SAEV_Config_ROM_Size_512K = 2;
|
||||||
|
|
||||||
|
const SAEV_Config_EXT_Size_None = 0;
|
||||||
|
const SAEV_Config_EXT_Size_256K = 1;
|
||||||
|
const SAEV_Config_EXT_Size_512K = 2;
|
||||||
|
|
||||||
|
const SAEV_Config_EXT_Addr_A0 = 1;
|
||||||
|
const SAEV_Config_EXT_Addr_E0 = 2;
|
||||||
|
const SAEV_Config_EXT_Addr_F0 = 3;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* disk */
|
||||||
|
|
||||||
|
const SAEV_Config_Floppy_Type_None = 0;
|
||||||
|
const SAEV_Config_Floppy_Type_35_DD = 1;
|
||||||
|
const SAEV_Config_Floppy_Type_35_HD = 2;
|
||||||
|
const SAEV_Config_Floppy_Type_525_SD = 3;
|
||||||
|
|
||||||
|
const SAEV_Config_Floppy_Speed_Turbo = 0;
|
||||||
|
const SAEV_Config_Floppy_Speed_Original = 100;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* audio */
|
||||||
|
|
||||||
|
const SAEV_Config_Audio_Mode_Emul = 0;
|
||||||
|
const SAEV_Config_Audio_Mode_Play = 1;
|
||||||
|
const SAEV_Config_Audio_Mode_Play_Best = 2;
|
||||||
|
|
||||||
|
const SAEV_Config_Audio_Channels_Mono = 1;
|
||||||
|
const SAEV_Config_Audio_Channels_Stereo = 2;
|
||||||
|
|
||||||
|
const SAEV_Config_Audio_Rate_11025 = 1;
|
||||||
|
const SAEV_Config_Audio_Rate_22050 = 2;
|
||||||
|
const SAEV_Config_Audio_Rate_44100 = 3;
|
||||||
|
const SAEV_Config_Audio_Rate_48000 = 4;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* input */
|
||||||
|
|
||||||
|
const SAEV_Config_Ports_Type_None = 0;
|
||||||
|
const SAEV_Config_Ports_Type_Mouse = 1;
|
||||||
|
const SAEV_Config_Ports_Type_Joy0 = 2;
|
||||||
|
const SAEV_Config_Ports_Type_Joy1 = 3;
|
||||||
|
|
||||||
|
const SAEV_Config_Ports_Move_None = 0;
|
||||||
|
const SAEV_Config_Ports_Move_Arrows = 1;
|
||||||
|
const SAEV_Config_Ports_Move_Numpad = 2;
|
||||||
|
const SAEV_Config_Ports_Move_WASD = 3;
|
||||||
|
|
||||||
|
const SAEV_Config_Ports_Fire_None = 0;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* rtc */
|
||||||
|
|
||||||
|
const SAEV_Config_RTC_Type_None = 0;
|
||||||
|
const SAEV_Config_RTC_Type_MSM6242B = 1;
|
||||||
|
const SAEV_Config_RTC_Type_RF5C01A = 2;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* erros */
|
||||||
|
|
||||||
|
const SAEE_None = 0;
|
||||||
|
|
||||||
|
const SAEE_CPU_Internal = 1;
|
||||||
|
const SAEE_CPU_68020_Required = 2;
|
||||||
|
|
||||||
|
const SAEE_Disk_File_Too_Big = 3;
|
||||||
|
|
||||||
|
const SAEE_Video_Shader_Error = 4;
|
||||||
|
const SAEE_Video_ID_Not_Found = 5;
|
||||||
|
const SAEE_Video_Canvas_Not_Supported = 6;
|
||||||
|
const SAEE_Video_WebGL_Not_Avail = 7;
|
||||||
|
|
||||||
|
const SAEE_Audio_WebAudio_Not_Avail = 8;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* methods */
|
||||||
|
|
||||||
|
const SAEM_Init = 1;
|
||||||
|
const SAEM_Start = 2;
|
||||||
|
const SAEM_Stop = 3;
|
||||||
|
const SAEM_Pause = 4;
|
||||||
|
const SAEM_Reset = 5;
|
||||||
|
const SAEM_Insert = 6;
|
||||||
|
const SAEM_Eject = 7;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* debug */
|
||||||
|
|
||||||
|
var BUG = null;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* amiga */
|
||||||
|
|
||||||
|
var AMIGA = null;
|
||||||
|
|
||||||
|
const CMD_STOP = 0;
|
||||||
|
const CMD_CYCLE = 1;
|
||||||
|
const CMD_PAUSE = 2;
|
||||||
|
const CMD_IDLE = 3;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* events */
|
||||||
|
|
||||||
|
const EV_CIA = 0;
|
||||||
|
const EV_AUDIO = 1;
|
||||||
|
const EV_MISC = 2;
|
||||||
|
const EV_HSYNC = 3;
|
||||||
|
const EV_MAX = 4;
|
||||||
|
//const EV_COPPER = ;
|
||||||
|
//const EV_BLITTER = ;
|
||||||
|
//const EV_RENDER = ;
|
||||||
|
|
||||||
|
const EV2_BLITTER = 0;
|
||||||
|
const EV2_DISK = 1;
|
||||||
|
const EV2_MISC = 2;
|
||||||
|
const EV2_MAX = 12;
|
||||||
|
|
||||||
|
const CYCLE_UNIT = 512;
|
||||||
|
const CYCLE_UNIT_INV = 1.0 / CYCLE_UNIT; /* mul is always faster than div */
|
||||||
|
|
||||||
|
const CYCLE_MAX = 0xffffffff * CYCLE_UNIT;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* cia */
|
||||||
|
|
||||||
|
const CIA_A = 1;
|
||||||
|
const CIA_B = 2;
|
||||||
|
|
||||||
|
const ECLOCK_DATA_CYCLE = 4;
|
||||||
|
const ECLOCK_WAIT_CYCLE = 6;
|
||||||
|
|
||||||
|
const DIV10 = ((ECLOCK_DATA_CYCLE + ECLOCK_WAIT_CYCLE) * CYCLE_UNIT) >> 1;
|
||||||
|
|
||||||
|
const CIA_RETHINK_DELAY = (CYCLE_UNIT << 1) + (CYCLE_UNIT >> 1);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* config */
|
||||||
|
|
||||||
|
//OCS
|
||||||
|
const AGNUS_8361 = 1; /* Amiga 1000 NTSC */
|
||||||
|
const AGNUS_8367 = 2; /* Amiga 1000 PAL */
|
||||||
|
const AGNUS_8370 = 3; /* OCS NTSC */
|
||||||
|
const AGNUS_8371 = 4; /* OCS PAL */
|
||||||
|
//ECS
|
||||||
|
const AGNUS_8372 = 5; /* ECS */
|
||||||
|
//AGA
|
||||||
|
const AGNUS_8374 = 6; /* AGA */
|
||||||
|
|
||||||
|
const DENISE_8362 = 1; /* OCS */
|
||||||
|
const DENISE_8373 = 2; /* ECS */
|
||||||
|
|
||||||
|
const PAULA_8364 = 1;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* cpu */
|
||||||
|
|
||||||
|
const SPCFLAG_STOP = 2;
|
||||||
|
const SPCFLAG_COPPER = 4;
|
||||||
|
const SPCFLAG_INT = 8;
|
||||||
|
//const SPCFLAG_BRK = 16;
|
||||||
|
const SPCFLAG_TRACE = 64;
|
||||||
|
const SPCFLAG_DOTRACE = 128;
|
||||||
|
const SPCFLAG_DOINT = 256;
|
||||||
|
const SPCFLAG_BLTNASTY = 512;
|
||||||
|
//const SPCFLAG_EXEC = 1024;
|
||||||
|
//const SPCFLAG_ACTION_REPLAY = 2048;
|
||||||
|
//const SPCFLAG_TRAP = 4096;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* amiga */
|
||||||
|
|
||||||
|
const INTF_TBE = 1 << 0;
|
||||||
|
const INTF_DSKBLK = 1 << 1;
|
||||||
|
const INTF_PORTS = 1 << 3;
|
||||||
|
const INTF_COPER = 1 << 4;
|
||||||
|
const INTF_VERTB = 1 << 5;
|
||||||
|
const INTF_BLIT = 1 << 6;
|
||||||
|
const INTF_AUD0 = 1 << 7;
|
||||||
|
const INTF_AUD1 = 1 << 8;
|
||||||
|
const INTF_AUD2 = 1 << 9;
|
||||||
|
const INTF_AUD3 = 1 << 10;
|
||||||
|
const INTF_RBF = 1 << 11;
|
||||||
|
const INTF_DSKSYN = 1 << 12;
|
||||||
|
const INTF_EXTER = 1 << 13;
|
||||||
|
const INTF_INTEN = 1 << 14;
|
||||||
|
const INTF_SETCLR = 1 << 15;
|
||||||
|
|
||||||
|
const INT_DSKBLK = INTF_SETCLR | INTF_DSKBLK;
|
||||||
|
const INT_VERTB = INTF_SETCLR | INTF_VERTB;
|
||||||
|
const INT_BLIT = INTF_SETCLR | INTF_BLIT;
|
||||||
|
const INT_DSKSYN = INTF_SETCLR | INTF_DSKSYN;
|
||||||
|
|
||||||
|
const DMAF_AUD0EN = 1 << 0;
|
||||||
|
const DMAF_AUD1EN = 1 << 1;
|
||||||
|
const DMAF_AUD2EN = 1 << 2;
|
||||||
|
const DMAF_AUD3EN = 1 << 3;
|
||||||
|
const DMAF_DSKEN = 1 << 4;
|
||||||
|
const DMAF_SPREN = 1 << 5;
|
||||||
|
const DMAF_BLTEN = 1 << 6;
|
||||||
|
const DMAF_COPEN = 1 << 7;
|
||||||
|
const DMAF_BPLEN = 1 << 8;
|
||||||
|
const DMAF_DMAEN = 1 << 9;
|
||||||
|
const DMAF_BLTPRI = 1 << 10;
|
||||||
|
const DMAF_BZERO = 1 << 13;
|
||||||
|
const DMAF_BBUSY = 1 << 14;
|
||||||
|
const DMAF_SETCLR = 1 << 15;
|
||||||
|
|
||||||
|
const INT_PROCESSING_DELAY = 3 * CYCLE_UNIT;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* copper */
|
||||||
|
|
||||||
|
/*const COP_STOP = 0;
|
||||||
|
const COP_READ = 1;
|
||||||
|
const COP_MOVE = 2;
|
||||||
|
const COP_WAIT = 3;
|
||||||
|
const COP_SKIP = 4;*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* blitter */
|
||||||
|
|
||||||
|
/*const BLT_STOP = 0;
|
||||||
|
const BLT_INIT = 1;
|
||||||
|
const BLT_READ = 2;
|
||||||
|
const BLT_WORK = 3;
|
||||||
|
const BLT_WRITE = 4;
|
||||||
|
const BLT_NEXT = 5;*/
|
||||||
|
|
||||||
|
const BLT_done = 0;
|
||||||
|
const BLT_init = 1;
|
||||||
|
const BLT_read = 2;
|
||||||
|
const BLT_work = 3;
|
||||||
|
const BLT_write = 4;
|
||||||
|
const BLT_next = 5;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* video */
|
||||||
|
|
||||||
|
const VIDEO_WIDTH = 720; /* == 360*2 */
|
||||||
|
const VIDEO_HEIGHT = 576; /* == 288*2 */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* playfield */
|
||||||
|
|
||||||
|
const MAX_FRAMESKIP_COUNT = 4;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* audio */
|
||||||
|
|
||||||
|
const PERIOD_MIN = 4;
|
||||||
|
const PERIOD_MIN_NONCE = 60;
|
||||||
|
const PERIOD_MAX = 0xffffffff;
|
||||||
615
sae/copper.js
Normal file
615
sae/copper.js
Normal file
|
|
@ -0,0 +1,615 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
//copper_states
|
||||||
|
const COP_stop = 0;
|
||||||
|
const COP_waitforever = 1;
|
||||||
|
const COP_read1 = 2;
|
||||||
|
const COP_read2 = 3;
|
||||||
|
const COP_bltwait = 4;
|
||||||
|
const COP_wait_in2 = 5;
|
||||||
|
const COP_skip_in2 = 6;
|
||||||
|
const COP_wait1 = 7;
|
||||||
|
const COP_wait = 8;
|
||||||
|
const COP_skip1 = 9;
|
||||||
|
const COP_strobe_delay1 = 10;
|
||||||
|
const COP_strobe_delay2 = 11;
|
||||||
|
const COP_strobe_delay1x = 12;
|
||||||
|
const COP_strobe_delay2x = 13;
|
||||||
|
const COP_strobe_extra = 14;
|
||||||
|
const COP_start_delay = 15;
|
||||||
|
|
||||||
|
function Copper() {
|
||||||
|
this.cop1lc = 0;
|
||||||
|
this.cop2lc = 0,
|
||||||
|
this.copcon = 0;
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
this.access = false;
|
||||||
|
|
||||||
|
var cop_state = {
|
||||||
|
/* The current instruction words. */
|
||||||
|
i1:0, i2:0,
|
||||||
|
saved_i1:0, saved_i2:0,
|
||||||
|
state:0, state_prev:0,
|
||||||
|
/* Instruction pointer. */
|
||||||
|
ip:0, saved_ip:0,
|
||||||
|
hpos:0, vpos:0,
|
||||||
|
ignore_next:0,
|
||||||
|
vcmp:0, hcmp:0,
|
||||||
|
|
||||||
|
strobe:0, /* COPJMP1 / COPJMP2 accessed */
|
||||||
|
last_write:0, last_write_hpos:0,
|
||||||
|
moveaddr:0, movedata:0, movedelay:0
|
||||||
|
};
|
||||||
|
var last_copper_hpos = 0;
|
||||||
|
|
||||||
|
|
||||||
|
this.reset = function () {
|
||||||
|
this.copcon = 0;
|
||||||
|
cop_state.state = COP_stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reset2 = function () {
|
||||||
|
cop_state.hpos = 0;
|
||||||
|
cop_state.last_write = 0;
|
||||||
|
this.compute_spcflag_copper(AMIGA.events.maxhpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.COPCON = function (v) {
|
||||||
|
this.copcon = v;
|
||||||
|
}
|
||||||
|
this.COP1LCH = function (v) {
|
||||||
|
this.cop1lc = ((v << 16) | (this.cop1lc & 0xffff)) >>> 0;
|
||||||
|
}
|
||||||
|
this.COP1LCL = function (v) {
|
||||||
|
this.cop1lc = ((this.cop1lc & 0xffff0000) | (v & 0xfffe)) >>> 0;
|
||||||
|
}
|
||||||
|
this.COP2LCH = function (v) {
|
||||||
|
this.cop2lc = ((v << 16) | (this.cop2lc & 0xffff)) >>> 0;
|
||||||
|
}
|
||||||
|
this.COP2LCL = function (v) {
|
||||||
|
this.cop2lc = ((this.cop2lc & 0xffff0000) | (v & 0xfffe)) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.COPJMP = function (num, vblank) {
|
||||||
|
var oldstrobe = cop_state.strobe;
|
||||||
|
|
||||||
|
//if (AMIGA.dmaen(DMAF_COPEN) && (cop_state.saved_i1 != 0xffff || cop_state.saved_i2 != 0xfffe))
|
||||||
|
//BUG.info('COPJMP(%d) vblank without copper ending %08x (%08x %08x) (%08x %08x)', num, cop_state.ip, this.cop1lc, this.cop2lc, cop_state.saved_i1, cop_state.saved_i2);
|
||||||
|
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
cop_state.ignore_next = 0;
|
||||||
|
if (!oldstrobe)
|
||||||
|
cop_state.state_prev = cop_state.state;
|
||||||
|
|
||||||
|
if ((cop_state.state == COP_wait || cop_state.state == COP_waitforever) && !vblank)
|
||||||
|
cop_state.state = COP_strobe_delay1x;
|
||||||
|
else
|
||||||
|
cop_state.state = vblank ? COP_start_delay : (this.access ? COP_strobe_delay1 : COP_strobe_extra);
|
||||||
|
|
||||||
|
//BUG.info('COPJMP(%d) %d', num, cop_state.state);
|
||||||
|
|
||||||
|
cop_state.vpos = AMIGA.events.vpos;
|
||||||
|
cop_state.hpos = AMIGA.events.hpos() & ~1;
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
cop_state.strobe = num;
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
this.immediate_copper(num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AMIGA.dmaen(DMAF_COPEN))
|
||||||
|
this.compute_spcflag_copper(AMIGA.events.hpos());
|
||||||
|
else if (oldstrobe > 0 && oldstrobe != num && cop_state.state_prev == COP_wait) {
|
||||||
|
/* dma disabled, copper idle and accessed both COPxJMPs -> copper stops! */
|
||||||
|
cop_state.state = COP_stop;
|
||||||
|
//BUG.info('COPJMP(%d) COP_stop');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*function get_copper_address(copno) {
|
||||||
|
switch (copno) {
|
||||||
|
case 1: return this.cop1lc;
|
||||||
|
case 2: return this.cop2lc;
|
||||||
|
case -1: return cop_state.ip;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
this.test_copper_dangerous = function (address) {
|
||||||
|
var addr = address & 0x1fe;
|
||||||
|
if (addr < ((this.copcon & 2) ? ((AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_ECS) ? 0 : 0x40) : 0x80)) {
|
||||||
|
cop_state.state = COP_stop;
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.immediate_copper = function (num) {
|
||||||
|
var pos = 0;
|
||||||
|
var oldpos = 0;
|
||||||
|
|
||||||
|
cop_state.state = COP_stop;
|
||||||
|
cop_state.vpos = AMIGA.events.vpos;
|
||||||
|
cop_state.hpos = AMIGA.events.hpos() & ~1;
|
||||||
|
cop_state.ip = num == 1 ? this.cop1lc : this.cop2lc;
|
||||||
|
|
||||||
|
while (pos < (AMIGA.events.maxvpos << 5)) {
|
||||||
|
if (oldpos > pos)
|
||||||
|
pos = oldpos;
|
||||||
|
if (!AMIGA.dmaen(DMAF_COPEN))
|
||||||
|
break;
|
||||||
|
if (cop_state.ip >= AMIGA.mem.chip.size)
|
||||||
|
break;
|
||||||
|
pos++;
|
||||||
|
oldpos = pos;
|
||||||
|
cop_state.i1 = AMIGA.mem.load16_chip(cop_state.ip);
|
||||||
|
cop_state.i2 = AMIGA.mem.load16_chip(cop_state.ip + 2);
|
||||||
|
cop_state.ip += 4;
|
||||||
|
if (!(cop_state.i1 & 1)) { // move
|
||||||
|
cop_state.i1 &= 0x1fe;
|
||||||
|
if (cop_state.i1 == 0x88) {
|
||||||
|
cop_state.ip = this.cop1lc;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cop_state.i1 == 0x8a) {
|
||||||
|
cop_state.ip = this.cop2lc;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (this.test_copper_dangerous(cop_state.i1))
|
||||||
|
break;
|
||||||
|
AMIGA.custom.store16_real(0, cop_state.i1, cop_state.i2, 0);
|
||||||
|
} else { // wait or skip
|
||||||
|
if ((cop_state.i1 >> 8) > ((pos >> 5) & 0xff))
|
||||||
|
pos = (((pos >> 5) & 0x100) | ((cop_state.i1 >> 8)) << 5) | ((cop_state.i1 & 0xff) >> 3);
|
||||||
|
if (cop_state.i1 >= 0xffdf && cop_state.i2 == 0xfffe)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cop_state.state = COP_stop;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.copper_cant_read = function (hpos, alloc) {
|
||||||
|
//BUG.info('copper_cant_read2() hpos %d / %d', hpos, AMIGA.events.maxhpos);
|
||||||
|
if (hpos + 1 >= AMIGA.events.maxhpos) // first refresh slot
|
||||||
|
return 1;
|
||||||
|
if ((hpos == AMIGA.events.maxhpos - 3) && (AMIGA.events.maxhpos & 1) && alloc >= 0) {
|
||||||
|
//if (alloc) alloc_cycle (hpos, CYCLE_COPPER);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return AMIGA.playfield.is_bitplane_dma(hpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*this.copper_cant_read = function (hpos, alloc) {
|
||||||
|
var cant = this.copper_cant_read2(hpos, alloc);
|
||||||
|
//if (cant && debug_dma) record_dma_event (DMA_EVENT_COPPERWANTED, hpos, vpos);
|
||||||
|
return cant;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
this.custom_store16_copper = function (hpos, addr, value, noget) {
|
||||||
|
//if (addr == 0x88 || addr == 0x8a)
|
||||||
|
//BUG.info('custom_store16_copper() addr %08x, value %04x | vpos %d hpos %d %d cvcmp %d chcmp %d chpos %d cvpos %d', addr, value, AMIGA.events.vpos, AMIGA.events.hpos(), hpos, cop_state.vcmp, cop_state.hcmp, cop_state.hpos, cop_state.vpos);
|
||||||
|
//value = debug_wputpeekdma (0xdff000 + addr, value);
|
||||||
|
this.access = true;
|
||||||
|
var v = AMIGA.custom.store16_real(hpos, addr, value, noget);
|
||||||
|
this.access = false;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dump_copper = function (error, until_hpos) {
|
||||||
|
BUG.info('\n');
|
||||||
|
BUG.info('%s: vpos=%d until_hpos=%d vp=%d', error, AMIGA.events.vpos, until_hpos, AMIGA.events.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80));
|
||||||
|
BUG.info('cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04X ci2=%04X', cop_state.vcmp, cop_state.hcmp, cop_state.hpos, cop_state.vpos, cop_state.saved_i1, cop_state.saved_i2);
|
||||||
|
BUG.info('cstate=%d ip=%x SPCFLAGS=%x iscline=%d', cop_state.state, cop_state.ip, AMIGA.spcflags, this.enabled_thisline?1:0);
|
||||||
|
BUG.info('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'emulate' chip internal delays, not the right place but fast and 99.9% programs
|
||||||
|
// use only copper to write BPLCON1 etc.. (exception is HulkaMania/TSP..)
|
||||||
|
// this table should be filled with zeros and done somewhere else..
|
||||||
|
var customdelay = [
|
||||||
|
1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 - 0x5e */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 - 0x7e */
|
||||||
|
0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, /* 0x80 - 0x9e */
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 32 0xa0 - 0xde */
|
||||||
|
/* BPLxPTH/BPLxPTL */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */
|
||||||
|
/* BPLCON0-3,BPLMOD1-2 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */
|
||||||
|
/* SPRxPTH/SPRxPTL */
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */
|
||||||
|
/* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||||
|
/* COLORxx */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
/* RESERVED */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
];
|
||||||
|
|
||||||
|
/*this.copper_write = function (v) {
|
||||||
|
this.custom_store16_copper(AMIGA.events.hpos(), v >> 16, v & 0xffff, 0);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
this.update_copper = function (until_hpos) {
|
||||||
|
var vp = AMIGA.events.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80);
|
||||||
|
var c_hpos = cop_state.hpos;
|
||||||
|
|
||||||
|
//BUG.info('update_copper() until_hpos %d, vp %d', until_hpos, vp);
|
||||||
|
|
||||||
|
if (cop_state.state == COP_wait && vp < cop_state.vcmp) {
|
||||||
|
this.dump_copper('error2', until_hpos);
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
cop_state.state = COP_stop;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (until_hpos <= last_copper_hpos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (until_hpos > (AMIGA.events.maxhpos & ~1))
|
||||||
|
until_hpos = AMIGA.events.maxhpos & ~1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
var old_hpos = c_hpos;
|
||||||
|
var hp;
|
||||||
|
|
||||||
|
if (c_hpos >= until_hpos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* So we know about the fetch state. */
|
||||||
|
//decide_line (c_hpos);
|
||||||
|
//decide_fetch (c_hpos);
|
||||||
|
|
||||||
|
if (cop_state.movedelay > 0) {
|
||||||
|
cop_state.movedelay--;
|
||||||
|
if (cop_state.movedelay == 0) {
|
||||||
|
this.custom_store16_copper(c_hpos, cop_state.moveaddr, cop_state.movedata, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((c_hpos == AMIGA.events.maxhpos - 3) && (AMIGA.events.maxhpos & 1))
|
||||||
|
c_hpos += 1;
|
||||||
|
else
|
||||||
|
c_hpos += 2;
|
||||||
|
|
||||||
|
switch (cop_state.state) {
|
||||||
|
case COP_wait_in2: {
|
||||||
|
if (this.copper_cant_read(old_hpos, 0))
|
||||||
|
continue;
|
||||||
|
cop_state.state = COP_wait1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_skip_in2: {
|
||||||
|
if (this.copper_cant_read(old_hpos, 0))
|
||||||
|
continue;
|
||||||
|
cop_state.state = COP_skip1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_strobe_extra: {
|
||||||
|
// Wait 1 copper cycle doing nothing
|
||||||
|
cop_state.state = COP_strobe_delay1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_strobe_delay1: {
|
||||||
|
// First cycle after COPJMP is just like normal first read cycle
|
||||||
|
// Cycle is used and needs to be free.
|
||||||
|
if (this.copper_cant_read(old_hpos, 1))
|
||||||
|
continue;
|
||||||
|
cop_state.state = COP_strobe_delay2;
|
||||||
|
//alloc_cycle(old_hpos, CYCLE_COPPER);
|
||||||
|
//if (debug_dma) record_dma (0x8c, AMIGA.mem.load16_chip(cop_state.ip), cop_state.ip, old_hpos, vpos, DMARECORD_COPPER);
|
||||||
|
cop_state.ip += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_strobe_delay2: {
|
||||||
|
// Second cycle after COPJMP. This is the strange one.
|
||||||
|
// This cycle does not need to be free
|
||||||
|
// But it still gets allocated by copper if it is free = CPU and blitter can't use it.
|
||||||
|
/*if (this.copper_cant_read(old_hpos, 1)) {
|
||||||
|
alloc_cycle (old_hpos, CYCLE_COPPER);
|
||||||
|
if (debug_dma) record_dma (0x1fe, AMIGA.mem.load16_chip(cop_state.ip), cop_state.ip, old_hpos, vpos, DMARECORD_COPPER);
|
||||||
|
}*/
|
||||||
|
cop_state.state = COP_read1;
|
||||||
|
// Next cycle finally reads from new pointer
|
||||||
|
if (cop_state.strobe == 1)
|
||||||
|
cop_state.ip = this.cop1lc;
|
||||||
|
else
|
||||||
|
cop_state.ip = this.cop2lc;
|
||||||
|
cop_state.strobe = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_strobe_delay1x: {
|
||||||
|
// First cycle after COPJMP and Copper was waiting. This is the buggy one.
|
||||||
|
// Cycle can be free and copper won't allocate it.
|
||||||
|
// If Blitter uses this cycle = Copper's address gets copied blitter DMA pointer..
|
||||||
|
cop_state.state = COP_strobe_delay2x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_strobe_delay2x: {
|
||||||
|
// Second cycle fetches following word and tosses it away. Must be free cycle
|
||||||
|
// but is not allocated, blitter or cpu can still use it.
|
||||||
|
if (this.copper_cant_read(old_hpos, 1))
|
||||||
|
continue;
|
||||||
|
//cycle_line[old_hpos] |= CYCLE_COPPER_SPECIAL;
|
||||||
|
//if (debug_dma) record_dma (0x1fe, AMIGA.mem.load16_chip(cop_state.ip), cop_state.ip, old_hpos, vpos, DMARECORD_COPPER);
|
||||||
|
cop_state.state = COP_read1;
|
||||||
|
// Next cycle finally reads from new pointer
|
||||||
|
if (cop_state.strobe == 1)
|
||||||
|
cop_state.ip = this.cop1lc;
|
||||||
|
else
|
||||||
|
cop_state.ip = this.cop2lc;
|
||||||
|
cop_state.strobe = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_start_delay: {
|
||||||
|
if (this.copper_cant_read(old_hpos, 1))
|
||||||
|
continue;
|
||||||
|
cop_state.state = COP_read1;
|
||||||
|
//alloc_cycle(old_hpos, CYCLE_COPPER);
|
||||||
|
//if (debug_dma) record_dma (0x1fe, 0, 0xffffffff, old_hpos, vpos, DMARECORD_COPPER);
|
||||||
|
cop_state.ip = this.cop1lc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_read1: {
|
||||||
|
if (this.copper_cant_read(old_hpos, 1))
|
||||||
|
continue;
|
||||||
|
/* workaround for a bug in kick 1.x */
|
||||||
|
if (cop_state.ip == 0x00000004 || cop_state.ip == 0x00000676 || cop_state.ip == 0x00c00276) {
|
||||||
|
//BUG.info('COP_read1() invalid addr $%08x', cop_state.ip);
|
||||||
|
cop_state.state = COP_stop;
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cop_state.i1 = AMIGA.mem.load16_chip(cop_state.ip);
|
||||||
|
//alloc_cycle(old_hpos, CYCLE_COPPER);
|
||||||
|
//if (debug_dma) record_dma (0x8c, cop_state.i1, cop_state.ip, old_hpos, vpos, DMARECORD_COPPER);
|
||||||
|
cop_state.ip += 2;
|
||||||
|
cop_state.state = COP_read2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_read2: {
|
||||||
|
if (this.copper_cant_read(old_hpos, 1))
|
||||||
|
continue;
|
||||||
|
cop_state.i2 = AMIGA.mem.load16_chip(cop_state.ip);
|
||||||
|
//alloc_cycle(old_hpos, CYCLE_COPPER);
|
||||||
|
cop_state.ip += 2;
|
||||||
|
cop_state.saved_i1 = cop_state.i1;
|
||||||
|
cop_state.saved_i2 = cop_state.i2;
|
||||||
|
cop_state.saved_ip = cop_state.ip;
|
||||||
|
|
||||||
|
if (cop_state.i1 & 1) { // WAIT or SKIP
|
||||||
|
cop_state.ignore_next = 0;
|
||||||
|
if (cop_state.i2 & 1)
|
||||||
|
cop_state.state = COP_skip_in2;
|
||||||
|
else
|
||||||
|
cop_state.state = COP_wait_in2;
|
||||||
|
//if (debug_dma) record_dma (0x8c, cop_state.i2, cop_state.ip - 2, old_hpos, vpos, DMARECORD_COPPER);
|
||||||
|
} else { // MOVE
|
||||||
|
//uaecptr debugip = cop_state.ip;
|
||||||
|
var reg = cop_state.i1 & 0x1fe;
|
||||||
|
var data = cop_state.i2;
|
||||||
|
cop_state.state = COP_read1;
|
||||||
|
//if (debug_dma) record_dma (reg, data, cop_state.ip - 2, old_hpos, vpos, DMARECORD_COPPER);
|
||||||
|
this.test_copper_dangerous(reg);
|
||||||
|
if (!this.enabled_thisline) {
|
||||||
|
//goto out; // was 'dangerous' register -> copper stopped
|
||||||
|
cop_state.hpos = c_hpos;
|
||||||
|
last_copper_hpos = until_hpos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cop_state.ignore_next)
|
||||||
|
reg = 0x1fe;
|
||||||
|
|
||||||
|
cop_state.last_write = reg;
|
||||||
|
cop_state.last_write_hpos = old_hpos;
|
||||||
|
if (reg == 0x88) {
|
||||||
|
cop_state.strobe = 1;
|
||||||
|
cop_state.state = COP_strobe_delay1;
|
||||||
|
} else if (reg == 0x8a) {
|
||||||
|
cop_state.strobe = 2;
|
||||||
|
cop_state.state = COP_strobe_delay1;
|
||||||
|
} else {
|
||||||
|
/*#if 0
|
||||||
|
event2_newevent2 (1, (reg << 16) | data, copper_write);
|
||||||
|
#else*/
|
||||||
|
// FIX: all copper writes happen 1 cycle later than CPU writes
|
||||||
|
if (customdelay[reg >> 1]) {
|
||||||
|
cop_state.moveaddr = reg;
|
||||||
|
cop_state.movedata = data;
|
||||||
|
cop_state.movedelay = customdelay[cop_state.moveaddr >> 1];
|
||||||
|
} else {
|
||||||
|
var hpos2 = old_hpos;
|
||||||
|
this.custom_store16_copper(hpos2, reg, data, 0);
|
||||||
|
hpos2++;
|
||||||
|
//if (reg >= 0x140 && reg < 0x180 && hpos2 >= SPR0_HPOS && hpos2 < SPR0_HPOS + 4 * MAX_SPRITES) do_sprites(hpos2);
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
//if (debug_copper && !cop_state.ignore_next) record_copper (debugip - 4, old_hpos, vpos);
|
||||||
|
cop_state.ignore_next = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_wait1: {
|
||||||
|
/*#if 0
|
||||||
|
if (c_hpos >= (AMIGA.events.maxhpos & ~1) || (c_hpos & 1)) break;
|
||||||
|
#endif*/
|
||||||
|
cop_state.state = COP_wait;
|
||||||
|
|
||||||
|
cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
|
||||||
|
cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xfe);
|
||||||
|
|
||||||
|
vp = AMIGA.events.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80);
|
||||||
|
|
||||||
|
if (cop_state.saved_i1 == 0xffff && cop_state.saved_i2 == 0xfffe) {
|
||||||
|
cop_state.state = COP_waitforever;
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
//goto out;
|
||||||
|
cop_state.hpos = c_hpos;
|
||||||
|
last_copper_hpos = until_hpos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (vp < cop_state.vcmp) {
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
//goto out;
|
||||||
|
cop_state.hpos = c_hpos;
|
||||||
|
last_copper_hpos = until_hpos;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case COP_wait: {
|
||||||
|
var ch_comp = c_hpos;
|
||||||
|
if (ch_comp & 1)
|
||||||
|
ch_comp = 0;
|
||||||
|
|
||||||
|
if (this.copper_cant_read(old_hpos, 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hp = ch_comp & (cop_state.saved_i2 & 0xfe);
|
||||||
|
if (vp == cop_state.vcmp && hp < cop_state.hcmp)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Now we know that the comparisons were successful. We might still have to wait for the blitter though. */
|
||||||
|
if ((cop_state.saved_i2 & 0x8000) == 0) {
|
||||||
|
//decide_blitter (old_hpos);
|
||||||
|
if (AMIGA.blitter.getState() != BLT_done) {
|
||||||
|
//We need to wait for the blitter.
|
||||||
|
cop_state.state = COP_bltwait;
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
//goto out;
|
||||||
|
cop_state.hpos = c_hpos;
|
||||||
|
last_copper_hpos = until_hpos;
|
||||||
|
return;
|
||||||
|
} /*else {
|
||||||
|
if (debug_dma) record_dma_event (DMA_EVENT_COPPERWAKE, old_hpos, vp);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
//if (debug_copper) record_copper (cop_state.ip - 4, old_hpos, vpos);
|
||||||
|
cop_state.state = COP_read1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case COP_skip1: {
|
||||||
|
var vcmp, hcmp, vp1, hp1;
|
||||||
|
|
||||||
|
if (c_hpos >= (AMIGA.events.maxhpos & ~1) || (c_hpos & 1))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (this.copper_cant_read(old_hpos, 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
|
||||||
|
hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xfe);
|
||||||
|
vp1 = AMIGA.events.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80);
|
||||||
|
hp1 = c_hpos & (cop_state.saved_i2 & 0xfe);
|
||||||
|
|
||||||
|
if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp)) && ((cop_state.saved_i2 & 0x8000) != 0 || AMIGA.blitter.getState() == BLT_done))
|
||||||
|
cop_state.ignore_next = 1;
|
||||||
|
|
||||||
|
cop_state.state = COP_read1;
|
||||||
|
//if (debug_copper) record_copper (cop_state.ip - 4, old_hpos, vpos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//out:
|
||||||
|
cop_state.hpos = c_hpos;
|
||||||
|
last_copper_hpos = until_hpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.compute_spcflag_copper = function (hpos) {
|
||||||
|
//BUG.info('compute_spcflag_copper() hpos %d', hpos);
|
||||||
|
var wasenabled = this.enabled_thisline;
|
||||||
|
|
||||||
|
this.enabled_thisline = false;
|
||||||
|
clr_special(SPCFLAG_COPPER);
|
||||||
|
if (!AMIGA.dmaen(DMAF_COPEN) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cop_state.state == COP_wait) {
|
||||||
|
var vp = AMIGA.events.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80);
|
||||||
|
|
||||||
|
if (vp < cop_state.vcmp)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// do not use past cycles if starting for the first time in this line
|
||||||
|
// (write to DMACON for example) hpos+1 for long lines
|
||||||
|
if (!wasenabled && cop_state.hpos < hpos && hpos < AMIGA.events.maxhpos) {
|
||||||
|
hpos = (hpos + 2) & ~1;
|
||||||
|
if (hpos > 226)
|
||||||
|
hpos = 226;
|
||||||
|
cop_state.hpos = hpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if COPJMPx was written while DMA was disabled, advance to next state,
|
||||||
|
// COP_strobe_extra is single cycle only and does not need free bus.
|
||||||
|
// (copper state emulation does not run if DMA is disabled)
|
||||||
|
if (!wasenabled && cop_state.state == COP_strobe_extra)
|
||||||
|
cop_state.state = COP_strobe_delay1;
|
||||||
|
|
||||||
|
this.enabled_thisline = true;
|
||||||
|
set_special(SPCFLAG_COPPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.blitter_done_notify = function (hpos) {
|
||||||
|
if (cop_state.state != COP_bltwait)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//BUG.info('blitter_done_notify() hpos %d', hpos);
|
||||||
|
|
||||||
|
var vp = AMIGA.events.vpos;
|
||||||
|
hpos += 3;
|
||||||
|
hpos &= ~1;
|
||||||
|
if (hpos >= AMIGA.events.maxhpos) {
|
||||||
|
hpos -= AMIGA.events.maxhpos;
|
||||||
|
vp++;
|
||||||
|
}
|
||||||
|
cop_state.hpos = hpos;
|
||||||
|
cop_state.vpos = vp;
|
||||||
|
cop_state.state = COP_read1;
|
||||||
|
//if (debug_dma) record_dma_event (DMA_EVENT_COPPERWAKE, hpos, vp);
|
||||||
|
|
||||||
|
if (AMIGA.dmaen(DMAF_COPEN) && vp == AMIGA.events.vpos) {
|
||||||
|
this.enabled_thisline = true;
|
||||||
|
set_special(SPCFLAG_COPPER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cycle = function () {
|
||||||
|
this.update_copper(AMIGA.events.hpos());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sync_copper_with_cpu = function (hpos, do_schedule) {
|
||||||
|
/* Need to let the copper advance to the current position. */
|
||||||
|
if (this.enabled_thisline)
|
||||||
|
this.update_copper(hpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.check = function (n) {
|
||||||
|
if (cop_state.state == COP_wait) {
|
||||||
|
var vp = AMIGA.events.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80);
|
||||||
|
if (vp < cop_state.vcmp) {
|
||||||
|
if (this.enabled_thisline)
|
||||||
|
BUG.info('COPPER BUG %d: vp=%d vpos=%d vcmp=%d thisline=%d', n, vp, AMIGA.events.vpos, cop_state.vcmp, this.enabled_thisline?1:0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5232
sae/cpu.js
Normal file
5232
sae/cpu.js
Normal file
File diff suppressed because it is too large
Load diff
350
sae/custom.js
Normal file
350
sae/custom.js
Normal file
|
|
@ -0,0 +1,350 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function Custom() {
|
||||||
|
this.last_value = 0;
|
||||||
|
|
||||||
|
this.setup = function() {}
|
||||||
|
this.reset = function() {}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.load16_real = function (hpos, addr, noput) {
|
||||||
|
var writeonly = false;
|
||||||
|
var v;
|
||||||
|
|
||||||
|
addr &= 0xfff;
|
||||||
|
|
||||||
|
switch (addr & 0x1fe) {
|
||||||
|
case 0x002: v = AMIGA.DMACONR(hpos); break;
|
||||||
|
case 0x004: v = AMIGA.events.VPOSR(); break;
|
||||||
|
case 0x006: v = AMIGA.events.VHPOSR(); break;
|
||||||
|
|
||||||
|
case 0x00A: v = AMIGA.input.JOY0DAT(); break;
|
||||||
|
case 0x00C: v = AMIGA.input.JOY1DAT(); break;
|
||||||
|
case 0x00E: v = AMIGA.playfield.sprites.CLXDAT(); break;
|
||||||
|
case 0x010: v = AMIGA.ADKCONR(); break;
|
||||||
|
|
||||||
|
case 0x012: v = AMIGA.input.POT0DAT(); break;
|
||||||
|
case 0x014: v = AMIGA.input.POT1DAT(); break;
|
||||||
|
case 0x016: v = AMIGA.input.POTGOR(); break;
|
||||||
|
case 0x018: v = AMIGA.serial.SERDATR(); break;
|
||||||
|
case 0x01A: v = AMIGA.disk.DSKBYTR(hpos); break;
|
||||||
|
case 0x01C: v = AMIGA.INTENAR(); break;
|
||||||
|
case 0x01E: v = AMIGA.INTREQR(); break;
|
||||||
|
case 0x07C: {
|
||||||
|
var result = AMIGA.playfield.DENISEID();
|
||||||
|
if (result[0])
|
||||||
|
writeonly = true;
|
||||||
|
else
|
||||||
|
v = result[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#ifdef AGA
|
||||||
|
case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
|
||||||
|
case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
|
||||||
|
case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
|
||||||
|
case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
|
||||||
|
case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
|
||||||
|
case 0x1BC: case 0x1BE:
|
||||||
|
if (AMIGA.config.chipset.type != SAEV_Config_Chipset_Type_AGA)
|
||||||
|
writeonly = true;
|
||||||
|
v = COLOR_READ ((addr & 0x3E) / 2);
|
||||||
|
break;
|
||||||
|
#endif*/
|
||||||
|
|
||||||
|
default:
|
||||||
|
writeonly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeonly) {
|
||||||
|
v = this.last_value;
|
||||||
|
if (!noput) {
|
||||||
|
var old = this.last_value;
|
||||||
|
var l = 0xffff;
|
||||||
|
var r = this.store16_real(hpos, addr, l, 1);
|
||||||
|
if (r) { // register don't exist
|
||||||
|
if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_ECS) {
|
||||||
|
v = l;
|
||||||
|
} else {
|
||||||
|
if ((addr & 0x1fe) == 0) {
|
||||||
|
/*if (is_cycle_ce())
|
||||||
|
v = this.last_value;
|
||||||
|
else*/
|
||||||
|
v = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (AMIGA.config.chipset.type == SAEV_Config_Chipset_Type_ECS)
|
||||||
|
v = 0xffff;
|
||||||
|
else
|
||||||
|
v = l;
|
||||||
|
}
|
||||||
|
//BUG.info('Custom.load16_real() %08x read = %04x. value written = %04x', 0xdff000 | addr, v, l);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.last_value = v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load16_2 = function (addr) {
|
||||||
|
var hpos = AMIGA.events.hpos();
|
||||||
|
|
||||||
|
AMIGA.copper.sync_copper_with_cpu (hpos, 1);
|
||||||
|
return this.load16_real(hpos, addr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load16 = function (addr) {
|
||||||
|
if (addr & 1) {
|
||||||
|
addr &= ~1;
|
||||||
|
return (this.load16_2(addr) << 8) | (this.load16_2(addr + 2) >> 8);
|
||||||
|
}
|
||||||
|
return this.load16_2(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load8 = function (addr) {
|
||||||
|
return this.load16_2(addr & ~1) >> ((addr & 1) ? 0 : 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load32 = function (addr) {
|
||||||
|
return ((this.load16(addr) << 16) | this.load16(addr + 2)) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.store16_real = function (hpos, addr, value, noget) {
|
||||||
|
if (!noget) this.last_value = value;
|
||||||
|
|
||||||
|
addr &= 0x1fe;
|
||||||
|
value &= 0xffff;
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
//case 0x00E: CLXDAT (); break;
|
||||||
|
|
||||||
|
case 0x020: AMIGA.disk.DSKPTH(value); break;
|
||||||
|
case 0x022: AMIGA.disk.DSKPTL(value); break;
|
||||||
|
case 0x024: AMIGA.disk.DSKLEN(value, hpos); break;
|
||||||
|
case 0x026: /* AMIGA.disk.DSKDAT(value). Writing to DMA write registers won't do anything */; break;
|
||||||
|
|
||||||
|
case 0x02A: AMIGA.events.VPOSW(value); break;
|
||||||
|
case 0x02C: AMIGA.events.VHPOSW(value); break;
|
||||||
|
case 0x02E: AMIGA.copper.COPCON(value); break;
|
||||||
|
case 0x030: AMIGA.serial.SERDAT(value); break;
|
||||||
|
case 0x032: AMIGA.serial.SERPER(value); break;
|
||||||
|
case 0x034: AMIGA.input.POTGO(value); break;
|
||||||
|
|
||||||
|
case 0x040: AMIGA.blitter.BLTCON0(hpos, value); break;
|
||||||
|
case 0x042: AMIGA.blitter.BLTCON1(hpos, value); break;
|
||||||
|
|
||||||
|
case 0x044: AMIGA.blitter.BLTAFWM(hpos, value); break;
|
||||||
|
case 0x046: AMIGA.blitter.BLTALWM(hpos, value); break;
|
||||||
|
|
||||||
|
case 0x050: AMIGA.blitter.BLTAPTH(hpos, value); break;
|
||||||
|
case 0x052: AMIGA.blitter.BLTAPTL(hpos, value); break;
|
||||||
|
case 0x04C: AMIGA.blitter.BLTBPTH(hpos, value); break;
|
||||||
|
case 0x04E: AMIGA.blitter.BLTBPTL(hpos, value); break;
|
||||||
|
case 0x048: AMIGA.blitter.BLTCPTH(hpos, value); break;
|
||||||
|
case 0x04A: AMIGA.blitter.BLTCPTL(hpos, value); break;
|
||||||
|
case 0x054: AMIGA.blitter.BLTDPTH(hpos, value); break;
|
||||||
|
case 0x056: AMIGA.blitter.BLTDPTL(hpos, value); break;
|
||||||
|
|
||||||
|
case 0x058: AMIGA.blitter.BLTSIZE(hpos, value); break;
|
||||||
|
|
||||||
|
case 0x064: AMIGA.blitter.BLTAMOD(hpos, value); break;
|
||||||
|
case 0x062: AMIGA.blitter.BLTBMOD(hpos, value); break;
|
||||||
|
case 0x060: AMIGA.blitter.BLTCMOD(hpos, value); break;
|
||||||
|
case 0x066: AMIGA.blitter.BLTDMOD(hpos, value); break;
|
||||||
|
|
||||||
|
case 0x070: AMIGA.blitter.BLTCDAT(hpos, value); break;
|
||||||
|
case 0x072: AMIGA.blitter.BLTBDAT(hpos, value); break;
|
||||||
|
case 0x074: AMIGA.blitter.BLTADAT(hpos, value); break;
|
||||||
|
|
||||||
|
case 0x07E: AMIGA.disk.DSKSYNC(value, hpos); break;
|
||||||
|
|
||||||
|
case 0x080: AMIGA.copper.COP1LCH(value); break;
|
||||||
|
case 0x082: AMIGA.copper.COP1LCL(value); break;
|
||||||
|
case 0x084: AMIGA.copper.COP2LCH(value); break;
|
||||||
|
case 0x086: AMIGA.copper.COP2LCL(value); break;
|
||||||
|
|
||||||
|
case 0x088: AMIGA.copper.COPJMP(1, 0); break;
|
||||||
|
case 0x08A: AMIGA.copper.COPJMP(2, 0); break;
|
||||||
|
|
||||||
|
case 0x08E: AMIGA.playfield.DIWSTRT(value); break;
|
||||||
|
case 0x090: AMIGA.playfield.DIWSTOP(value); break;
|
||||||
|
case 0x092: AMIGA.playfield.DDFSTRT(value); break;
|
||||||
|
case 0x094: AMIGA.playfield.DDFSTOP(value); break;
|
||||||
|
|
||||||
|
case 0x096: AMIGA.DMACON(value, hpos); break;
|
||||||
|
case 0x098: AMIGA.playfield.sprites.CLXCON(value); break;
|
||||||
|
case 0x09A: AMIGA.INTENA(value); break;
|
||||||
|
case 0x09C: AMIGA.INTREQ(value); break;
|
||||||
|
case 0x09E: AMIGA.ADKCON(value, hpos); break;
|
||||||
|
|
||||||
|
case 0x0A0: AMIGA.audio.AUDxLCH(0, value); break;
|
||||||
|
case 0x0A2: AMIGA.audio.AUDxLCL(0, value); break;
|
||||||
|
case 0x0A4: AMIGA.audio.AUDxLEN(0, value); break;
|
||||||
|
case 0x0A6: AMIGA.audio.AUDxPER(0, value); break;
|
||||||
|
case 0x0A8: AMIGA.audio.AUDxVOL(0, value); break;
|
||||||
|
case 0x0AA: AMIGA.audio.AUDxDAT(0, value); break;
|
||||||
|
|
||||||
|
case 0x0B0: AMIGA.audio.AUDxLCH(1, value); break;
|
||||||
|
case 0x0B2: AMIGA.audio.AUDxLCL(1, value); break;
|
||||||
|
case 0x0B4: AMIGA.audio.AUDxLEN(1, value); break;
|
||||||
|
case 0x0B6: AMIGA.audio.AUDxPER(1, value); break;
|
||||||
|
case 0x0B8: AMIGA.audio.AUDxVOL(1, value); break;
|
||||||
|
case 0x0BA: AMIGA.audio.AUDxDAT(1, value); break;
|
||||||
|
|
||||||
|
case 0x0C0: AMIGA.audio.AUDxLCH(2, value); break;
|
||||||
|
case 0x0C2: AMIGA.audio.AUDxLCL(2, value); break;
|
||||||
|
case 0x0C4: AMIGA.audio.AUDxLEN(2, value); break;
|
||||||
|
case 0x0C6: AMIGA.audio.AUDxPER(2, value); break;
|
||||||
|
case 0x0C8: AMIGA.audio.AUDxVOL(2, value); break;
|
||||||
|
case 0x0CA: AMIGA.audio.AUDxDAT(2, value); break;
|
||||||
|
|
||||||
|
case 0x0D0: AMIGA.audio.AUDxLCH(3, value); break;
|
||||||
|
case 0x0D2: AMIGA.audio.AUDxLCL(3, value); break;
|
||||||
|
case 0x0D4: AMIGA.audio.AUDxLEN(3, value); break;
|
||||||
|
case 0x0D6: AMIGA.audio.AUDxPER(3, value); break;
|
||||||
|
case 0x0D8: AMIGA.audio.AUDxVOL(3, value); break;
|
||||||
|
case 0x0DA: AMIGA.audio.AUDxDAT(3, value); break;
|
||||||
|
|
||||||
|
case 0x0E0: AMIGA.playfield.BPLxPTx(value, 0, 1); break;
|
||||||
|
case 0x0E2: AMIGA.playfield.BPLxPTx(value, 0, 0); break;
|
||||||
|
case 0x0E4: AMIGA.playfield.BPLxPTx(value, 1, 1); break;
|
||||||
|
case 0x0E6: AMIGA.playfield.BPLxPTx(value, 1, 0); break;
|
||||||
|
case 0x0E8: AMIGA.playfield.BPLxPTx(value, 2, 1); break;
|
||||||
|
case 0x0EA: AMIGA.playfield.BPLxPTx(value, 2, 0); break;
|
||||||
|
case 0x0EC: AMIGA.playfield.BPLxPTx(value, 3, 1); break;
|
||||||
|
case 0x0EE: AMIGA.playfield.BPLxPTx(value, 3, 0); break;
|
||||||
|
case 0x0F0: AMIGA.playfield.BPLxPTx(value, 4, 1); break;
|
||||||
|
case 0x0F2: AMIGA.playfield.BPLxPTx(value, 4, 0); break;
|
||||||
|
case 0x0F4: AMIGA.playfield.BPLxPTx(value, 5, 1); break;
|
||||||
|
case 0x0F6: AMIGA.playfield.BPLxPTx(value, 5, 0); break;
|
||||||
|
/*case 0x0F8: AMIGA.playfield.BPLxPTx(value, 6, 1); break;
|
||||||
|
case 0x0FA: AMIGA.playfield.BPLxPTx(value, 6, 0); break;
|
||||||
|
case 0x0FC: AMIGA.playfield.BPLxPTx(value, 7, 1); break;
|
||||||
|
case 0x0FE: AMIGA.playfield.BPLxPTx(value, 7, 0); break;*/
|
||||||
|
|
||||||
|
case 0x100: AMIGA.playfield.BPLCON0(value); break;
|
||||||
|
case 0x102: AMIGA.playfield.BPLCON1(value); break;
|
||||||
|
case 0x104: AMIGA.playfield.BPLCON2(value); break;
|
||||||
|
//case 0x106: AMIGA.playfield.BPLCON3(value); break; //ECS_DENISE
|
||||||
|
|
||||||
|
case 0x108: AMIGA.playfield.BPL1MOD(value); break;
|
||||||
|
case 0x10A: AMIGA.playfield.BPL2MOD(value); break;
|
||||||
|
//case 0x10E: AMIGA.playfield.sprites.CLXCON2 (value); break; //AGA
|
||||||
|
|
||||||
|
case 0x110: AMIGA.playfield.BPLxDAT(value, 0); break;
|
||||||
|
case 0x112: AMIGA.playfield.BPLxDAT(value, 1); break;
|
||||||
|
case 0x114: AMIGA.playfield.BPLxDAT(value, 2); break;
|
||||||
|
case 0x116: AMIGA.playfield.BPLxDAT(value, 3); break;
|
||||||
|
case 0x118: AMIGA.playfield.BPLxDAT(value, 4); break;
|
||||||
|
case 0x11A: AMIGA.playfield.BPLxDAT(value, 5); break;
|
||||||
|
//case 0x11C: AMIGA.playfield.BPLxDAT(value, 6); break;
|
||||||
|
//case 0x11E: AMIGA.playfield.BPLxDAT(value, 7); break;
|
||||||
|
|
||||||
|
case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
|
||||||
|
case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
|
||||||
|
case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
|
||||||
|
case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
|
||||||
|
case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
|
||||||
|
case 0x1BC: case 0x1BE:
|
||||||
|
AMIGA.playfield.COLORxx(value & 0xfff, (addr & 0x3E) >> 1);
|
||||||
|
break;
|
||||||
|
case 0x120: case 0x124: case 0x128: case 0x12C:
|
||||||
|
case 0x130: case 0x134: case 0x138: case 0x13C:
|
||||||
|
AMIGA.playfield.sprites.SPRxPTH(value, (addr - 0x120) >> 2);
|
||||||
|
break;
|
||||||
|
case 0x122: case 0x126: case 0x12A: case 0x12E:
|
||||||
|
case 0x132: case 0x136: case 0x13A: case 0x13E:
|
||||||
|
AMIGA.playfield.sprites.SPRxPTL(value, (addr - 0x122) >> 2);
|
||||||
|
break;
|
||||||
|
case 0x140: case 0x148: case 0x150: case 0x158:
|
||||||
|
case 0x160: case 0x168: case 0x170: case 0x178:
|
||||||
|
AMIGA.playfield.sprites.SPRxPOS(value, (addr - 0x140) >> 3);
|
||||||
|
break;
|
||||||
|
case 0x142: case 0x14A: case 0x152: case 0x15A:
|
||||||
|
case 0x162: case 0x16A: case 0x172: case 0x17A:
|
||||||
|
AMIGA.playfield.sprites.SPRxCTL(value, (addr - 0x142) >> 3);
|
||||||
|
break;
|
||||||
|
case 0x144: case 0x14C: case 0x154: case 0x15C:
|
||||||
|
case 0x164: case 0x16C: case 0x174: case 0x17C:
|
||||||
|
AMIGA.playfield.sprites.SPRxDATA(value, (addr - 0x144) >> 3);
|
||||||
|
break;
|
||||||
|
case 0x146: case 0x14E: case 0x156: case 0x15E:
|
||||||
|
case 0x166: case 0x16E: case 0x176: case 0x17E:
|
||||||
|
AMIGA.playfield.sprites.SPRxDATB(value, (addr - 0x146) >> 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x36: AMIGA.input.JOYTEST(value); break;
|
||||||
|
case 0x5A: AMIGA.blitter.BLTCON0L(hpos, value); break; //ECS
|
||||||
|
case 0x5C: AMIGA.blitter.BLTSIZV(hpos, value); break; //ECS
|
||||||
|
case 0x5E: AMIGA.blitter.BLTSIZH(hpos, value); break; //ECS
|
||||||
|
//case 0x1E4: AMIGA.playfield.DIWHIGH(value); break; //ECS
|
||||||
|
//case 0x10C: AMIGA.playfield.BPLCON4(value); break; //AGA
|
||||||
|
|
||||||
|
//#ifndef CUSTOM_SIMPLE
|
||||||
|
//case 0x1DC: AMIGA.events.BEAMCON0(value); break;
|
||||||
|
/*#ifdef ECS_DENISE
|
||||||
|
case 0x1C0: if (htotal != value) { htotal = value; varsync (); } break;
|
||||||
|
case 0x1C2: if (hsstop != value) { hsstop = value; varsync (); } break;
|
||||||
|
case 0x1C4: if (hbstrt != value) { hbstrt = value; varsync (); } break;
|
||||||
|
case 0x1C6: if (hbstop != value) { hbstop = value; varsync (); } break;
|
||||||
|
case 0x1C8: if (vtotal != value) { vtotal = value; varsync (); } break;
|
||||||
|
case 0x1CA: if (vsstop != value) { vsstop = value; varsync (); } break;
|
||||||
|
case 0x1CC: if (vbstrt < value || vbstrt > value + 1) { vbstrt = value; varsync (); } break;
|
||||||
|
case 0x1CE: if (vbstop < value || vbstop > value + 1) { vbstop = value; varsync (); } break;
|
||||||
|
case 0x1DE: if (hsstrt != value) { hsstrt = value; varsync (); } break;
|
||||||
|
case 0x1E0: if (vsstrt != value) { vsstrt = value; varsync (); } break;
|
||||||
|
case 0x1E2: if (hcenter != value) { hcenter = value; varsync (); } break;
|
||||||
|
endif*/
|
||||||
|
//endif
|
||||||
|
|
||||||
|
//case 0x1FC: FMODE (hpos, value); break; //AGA
|
||||||
|
//case 0x1FE: FNULL (value); break;
|
||||||
|
case 0x1FE: break;
|
||||||
|
|
||||||
|
/* writing to read-only register causes read access */
|
||||||
|
default: {
|
||||||
|
if (!noget) {
|
||||||
|
//BUG.info('Custom.store16_real() %04x written', addr);
|
||||||
|
this.load16_real(hpos, addr, 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store16 = function (addr, value) {
|
||||||
|
var hpos = AMIGA.events.hpos();
|
||||||
|
AMIGA.copper.sync_copper_with_cpu(hpos, 1);
|
||||||
|
if (addr & 1) {
|
||||||
|
addr &= ~1;
|
||||||
|
this.store16_real(hpos, addr, (value >> 8) | (value & 0xff00), 0);
|
||||||
|
this.store16_real(hpos, addr + 2, (value << 8) | (value & 0x00ff), 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.store16_real(hpos, addr, value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store8 = function (addr, value) {
|
||||||
|
this.store16(addr & ~1, ((value << 8) | (value & 0xff)) & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store32 = function (addr, value) {
|
||||||
|
this.store16(addr & 0xfffe, value >>> 16);
|
||||||
|
this.store16((addr + 2) & 0xfffe, value & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
1674
sae/disk.js
Normal file
1674
sae/disk.js
Normal file
File diff suppressed because it is too large
Load diff
803
sae/events.js
Normal file
803
sae/events.js
Normal file
|
|
@ -0,0 +1,803 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function Event() {
|
||||||
|
this.active = false;
|
||||||
|
this.evtime = 0;
|
||||||
|
this.oldcycles = 0;
|
||||||
|
this.handler = function(v) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Event2() {
|
||||||
|
this.active = false;
|
||||||
|
this.evtime = 0;
|
||||||
|
this.handler = function(v) {};
|
||||||
|
this.data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Events() {
|
||||||
|
const SYNCBASE = 1000;
|
||||||
|
|
||||||
|
this.lofChanged = false;
|
||||||
|
this.lofStore = 0;
|
||||||
|
this.lof = 0;
|
||||||
|
this.lol = 0;
|
||||||
|
|
||||||
|
this.vpos = 0;
|
||||||
|
this.vpos_previous = 0;
|
||||||
|
this.hpos_previous = 0;
|
||||||
|
|
||||||
|
this.maxhpos = 0;
|
||||||
|
this.maxvpos = 0;
|
||||||
|
this.hz = 0;
|
||||||
|
|
||||||
|
var dmal = 0
|
||||||
|
var dmal_hpos = 0;
|
||||||
|
|
||||||
|
var vsynctimebase = 0;
|
||||||
|
var vsyncmintime = 0;
|
||||||
|
var vsynctimeperline = 0;
|
||||||
|
var vsyncmaxtime = 0;
|
||||||
|
var vsyncwaittime = 0;
|
||||||
|
var vsync_rendered = false;
|
||||||
|
var is_syncline = 0;
|
||||||
|
var is_syncline_end = 0;
|
||||||
|
|
||||||
|
var frameskip = new mavg(128);
|
||||||
|
var frameskiptime = 0;
|
||||||
|
|
||||||
|
var counter = {
|
||||||
|
lasttime:0,
|
||||||
|
frametime:0,
|
||||||
|
frames:0,
|
||||||
|
fps:new mavg(10),
|
||||||
|
idle:new mavg(10),
|
||||||
|
idletime:0,
|
||||||
|
bogus:0
|
||||||
|
};
|
||||||
|
this.timeframes = 0;
|
||||||
|
|
||||||
|
this.eventtab = null;
|
||||||
|
this.eventtab2 = null;
|
||||||
|
this.currcycle = 0;
|
||||||
|
var nextEvent = 0;
|
||||||
|
var nextEvent2 = EV2_MISC;
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
if (this.eventtab === null) {
|
||||||
|
this.eventtab = new Array(EV_MAX);
|
||||||
|
for (var i = 0; i < EV_MAX; i++)
|
||||||
|
this.eventtab[i] = new Event();
|
||||||
|
|
||||||
|
this.eventtab[EV_CIA].handler = function() { AMIGA.cia.handler(); }
|
||||||
|
this.eventtab[EV_AUDIO].handler = function() { AMIGA.audio.handler(); }
|
||||||
|
this.eventtab[EV_MISC].handler = function() { var stack = { recursive:0, dorecheck:false }; AMIGA.events.MISC_handler(stack); }
|
||||||
|
this.eventtab[EV_HSYNC].handler = function() { AMIGA.events.hSync(); }
|
||||||
|
//this.eventtab[EV_COPPER].handler = function() { AMIGA.copper.handler(); }
|
||||||
|
//this.eventtab[EV_BLITTER].handler = function() { AMIGA.blitter.handler(); }
|
||||||
|
//this.eventtab[EV_RENDER].handler = function() { AMIGA.playfield.hSync(); }
|
||||||
|
|
||||||
|
BUG.info('Events.setup() set %d event handlers', EV_MAX);
|
||||||
|
} else
|
||||||
|
BUG.info('Events.setup() event handlers are cached...');
|
||||||
|
|
||||||
|
if (this.eventtab2 === null) {
|
||||||
|
this.eventtab2 = new Array(EV2_MAX);
|
||||||
|
for (var i = 0; i < EV2_MAX; i++)
|
||||||
|
this.eventtab2[i] = new Event2();
|
||||||
|
|
||||||
|
//this.eventtab[EV2_BLITTER].handler = function() { AMIGA.blitter.handler(); }
|
||||||
|
//this.eventtab[EV2_DISK].handler = function(data) { AMIGA.disk.handler(data); }
|
||||||
|
|
||||||
|
BUG.info('Events.setup() set %d event2 handlers', EV2_MAX);
|
||||||
|
} else
|
||||||
|
BUG.info('Events.setup() event2 handlers are cached...');
|
||||||
|
|
||||||
|
this.initHz();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
this.lofStore = 1;
|
||||||
|
this.lof = 1;
|
||||||
|
this.lol = 0;
|
||||||
|
this.vpos = 0;
|
||||||
|
|
||||||
|
dmal = 0
|
||||||
|
dmal_hpos = 0;
|
||||||
|
|
||||||
|
frameskip.clr();
|
||||||
|
frameskiptime = 0;
|
||||||
|
this.fpscounter_reset();
|
||||||
|
|
||||||
|
this.initHz();
|
||||||
|
|
||||||
|
this.currcycle = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < EV_MAX; i++) {
|
||||||
|
this.eventtab[i].active = false;
|
||||||
|
this.eventtab[i].evtime = 0;
|
||||||
|
this.eventtab[i].oldcycles = 0;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < EV2_MAX; i++) {
|
||||||
|
this.eventtab2[i].active = false;
|
||||||
|
this.eventtab2[i].evtime = 0;
|
||||||
|
}
|
||||||
|
this.eventtab[EV_HSYNC].evtime = this.maxhpos * CYCLE_UNIT; /* 0xe3 */
|
||||||
|
this.eventtab[EV_HSYNC].active = true;
|
||||||
|
/*if (AMIGA.config.video.enabled) {
|
||||||
|
//this.eventtab[EV_RENDER].evtime = 0x38 * CYCLE_UNIT;
|
||||||
|
this.eventtab[EV_RENDER].evtime = 0xd4 * CYCLE_UNIT;
|
||||||
|
this.eventtab[EV_RENDER].active = true;
|
||||||
|
}*/
|
||||||
|
this.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.initHz = function() {
|
||||||
|
if (!AMIGA.config.video.ntsc) {
|
||||||
|
this.maxvpos = 312;
|
||||||
|
this.maxhpos = 227;
|
||||||
|
this.hz = 50;
|
||||||
|
} else {
|
||||||
|
this.maxvpos = 262;
|
||||||
|
this.maxhpos = 227;
|
||||||
|
this.hz = 60;
|
||||||
|
}
|
||||||
|
vsynctimebase = SYNCBASE / this.hz;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hpos = function() {
|
||||||
|
return Math.floor((this.currcycle - this.eventtab[EV_HSYNC].oldcycles) * CYCLE_UNIT_INV);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cycles_in_range = function(endcycles) {
|
||||||
|
return (endcycles - this.currcycle > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*this.get_cycles = function() {
|
||||||
|
return this.currcycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set_cycles = function(x) {
|
||||||
|
this.currcycle = x;
|
||||||
|
this.eventtab[EV_HSYNC].oldcycles = x;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.MISC_handler = function(stack) {
|
||||||
|
//console.log('MISC_handler() recursive %d', stack.recursive);
|
||||||
|
var mintime;
|
||||||
|
var recheck;
|
||||||
|
var ct = AMIGA.events.currcycle;
|
||||||
|
|
||||||
|
if (stack.recursive) {
|
||||||
|
stack.dorecheck = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stack.recursive++;
|
||||||
|
AMIGA.events.eventtab[EV_MISC].active = false;
|
||||||
|
recheck = true;
|
||||||
|
while (recheck) {
|
||||||
|
recheck = false;
|
||||||
|
mintime = CYCLE_MAX;
|
||||||
|
|
||||||
|
for (var i = 0; i < EV2_MAX; i++) {
|
||||||
|
if (AMIGA.events.eventtab2[i].active) {
|
||||||
|
if (AMIGA.events.eventtab2[i].evtime == ct) {
|
||||||
|
AMIGA.events.eventtab2[i].active = false;
|
||||||
|
|
||||||
|
if (i == EV2_BLITTER)
|
||||||
|
AMIGA.blitter.handler(AMIGA.events.eventtab2[i].data);
|
||||||
|
else if (i == EV2_DISK)
|
||||||
|
AMIGA.disk.handler(AMIGA.events.eventtab2[i].data);
|
||||||
|
else
|
||||||
|
AMIGA.events.eventtab2[i].handler(AMIGA.events.eventtab2[i].data);
|
||||||
|
|
||||||
|
if (stack.dorecheck || AMIGA.events.eventtab2[i].active) {
|
||||||
|
recheck = true;
|
||||||
|
stack.dorecheck = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var eventtime = AMIGA.events.eventtab2[i].evtime - ct;
|
||||||
|
if (eventtime < mintime)
|
||||||
|
mintime = eventtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mintime != CYCLE_MAX) {
|
||||||
|
AMIGA.events.eventtab[EV_MISC].active = true;
|
||||||
|
AMIGA.events.eventtab[EV_MISC].oldcycles = ct;
|
||||||
|
AMIGA.events.eventtab[EV_MISC].evtime = ct + mintime;
|
||||||
|
AMIGA.events.schedule();
|
||||||
|
}
|
||||||
|
stack.recursive--;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.event2_newevent_xx = function(no, t, data, func) {
|
||||||
|
var et = this.currcycle + t;
|
||||||
|
if (no < 0) {
|
||||||
|
no = nextEvent2;
|
||||||
|
for (;;) {
|
||||||
|
if (!this.eventtab2[no].active)
|
||||||
|
break;
|
||||||
|
//if (this.eventtab2[no].evtime == et && this.eventtab2[no].handler == func && this.eventtab2[no].data == data)
|
||||||
|
if (this.eventtab2[no].evtime == et && this.eventtab2[no].data == data)
|
||||||
|
break;
|
||||||
|
|
||||||
|
no++;
|
||||||
|
if (no == EV2_MAX)
|
||||||
|
no = EV2_MISC;
|
||||||
|
if (no == nextEvent2) {
|
||||||
|
BUG.info('event2_newevent_xx() out of event2\'s!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextEvent2 = no;
|
||||||
|
}
|
||||||
|
this.eventtab2[no].active = true;
|
||||||
|
this.eventtab2[no].evtime = et;
|
||||||
|
this.eventtab2[no].handler = func;
|
||||||
|
this.eventtab2[no].data = data;
|
||||||
|
|
||||||
|
var stack = { recursive:0, dorecheck:false };
|
||||||
|
this.MISC_handler(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.event2_newevent_x = function(no, t, data, func) {
|
||||||
|
if (t <= 0) {
|
||||||
|
if (no == EV2_BLITTER)
|
||||||
|
AMIGA.blitter.handler(data);
|
||||||
|
else if (no == EV2_DISK)
|
||||||
|
AMIGA.disk.handler(data);
|
||||||
|
else
|
||||||
|
func(data);
|
||||||
|
} else
|
||||||
|
this.event2_newevent_xx(no, t * CYCLE_UNIT, data, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.event2_newevent2 = function(t, data, func) {
|
||||||
|
this.event2_newevent_x(-1, t, data, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.event2_newevent = function(no, t, data) {
|
||||||
|
this.event2_newevent_x(no, t, data, null); //this.eventtab2[no].handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.event2_remevent = function(no) {
|
||||||
|
this.eventtab2[no].active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.schedule = function() {
|
||||||
|
var mintime = CYCLE_MAX;
|
||||||
|
|
||||||
|
for (var i = 0; i < EV_MAX; i++) {
|
||||||
|
if (this.eventtab[i].active) {
|
||||||
|
var evtime = this.eventtab[i].evtime - this.currcycle;
|
||||||
|
if (evtime < mintime) mintime = evtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextEvent = this.currcycle + mintime;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cycle = function (cycles) {
|
||||||
|
while ((nextEvent - this.currcycle) <= cycles) {
|
||||||
|
if (is_syncline) {
|
||||||
|
var rpt = new Date().getTime();
|
||||||
|
var v = rpt - vsyncmintime;
|
||||||
|
var v2 = rpt - is_syncline_end;
|
||||||
|
if (v > vsynctimebase || v < -vsynctimebase) v = 0;
|
||||||
|
if (v < 0 && v2 < 0) return;
|
||||||
|
is_syncline = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cycles -= nextEvent - this.currcycle;
|
||||||
|
this.currcycle = nextEvent;
|
||||||
|
|
||||||
|
for (var i = 0; i < EV_MAX; i++) {
|
||||||
|
if (this.eventtab[i].active && this.eventtab[i].evtime == this.currcycle)
|
||||||
|
this.eventtab[i].handler(this.eventtab[i].data);
|
||||||
|
}
|
||||||
|
this.schedule();
|
||||||
|
}
|
||||||
|
this.currcycle += cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.dmal_emu = function(v) {
|
||||||
|
if (!(AMIGA.dmacon & DMAF_DMAEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//BUG.info('Events.dmal_emu() %d', v);
|
||||||
|
var hpos = this.hpos();
|
||||||
|
if (v >= 6) {
|
||||||
|
v -= 6;
|
||||||
|
var nr = v >>> 1;
|
||||||
|
var pt = AMIGA.audio.getpt(nr, (v & 1) != 0);
|
||||||
|
var dat = AMIGA.mem.load16_chip(pt);
|
||||||
|
AMIGA.audio.AUDxDAT(nr, dat);
|
||||||
|
} else {
|
||||||
|
var w = v & 1;
|
||||||
|
var pt = AMIGA.disk.getpt();
|
||||||
|
if (w) {
|
||||||
|
if (AMIGA.disk.fifostatus() <= 0) {
|
||||||
|
var dat = AMIGA.mem.load16_chip(pt);
|
||||||
|
AMIGA.disk.DSKDAT(dat);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (AMIGA.disk.fifostatus() >= 0) {
|
||||||
|
var dat = AMIGA.disk.DSKDATR();
|
||||||
|
AMIGA.mem.store16_chip(pt, dat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dmal_func = function(v) {
|
||||||
|
this.dmal_emu(v);
|
||||||
|
this.dmal_handle(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dmal_func2 = function(v) {
|
||||||
|
while (dmal) {
|
||||||
|
if (dmal & 3)
|
||||||
|
this.dmal_emu(dmal_hpos + ((dmal & 2) ? 1 : 0));
|
||||||
|
dmal_hpos += 2;
|
||||||
|
dmal >>>= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dmal_handle = function(hp) {
|
||||||
|
if (!dmal)
|
||||||
|
return;
|
||||||
|
if (AMIGA.config.cpu.exact) {
|
||||||
|
while (dmal) {
|
||||||
|
if (dmal & 3)
|
||||||
|
break;
|
||||||
|
hp += 2;
|
||||||
|
dmal >>>= 2;
|
||||||
|
dmal_hpos += 2;
|
||||||
|
}
|
||||||
|
this.event2_newevent2(hp, dmal_hpos + ((dmal & 2) ? 1 : 0), function(v) { AMIGA.events.dmal_func(v); });
|
||||||
|
dmal &= ~3;
|
||||||
|
} else {
|
||||||
|
this.event2_newevent2(hp, 13, function(v) { AMIGA.events.dmal_func2(v); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dmal_hsync = function() {
|
||||||
|
if (dmal) BUG.info('Events.dmal_hsync() DMAL error!? %04x', dmal);
|
||||||
|
dmal = AMIGA.audio.dmal();
|
||||||
|
dmal <<= 6;
|
||||||
|
dmal |= AMIGA.disk.dmal();
|
||||||
|
if (!dmal)
|
||||||
|
return;
|
||||||
|
//BUG.info('Events.dmal_hsync() %04x', dmal);
|
||||||
|
dmal_hpos = 0;
|
||||||
|
this.dmal_handle(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.fpscounter_reset = function() {
|
||||||
|
counter.frames = 0;
|
||||||
|
counter.lasttime = new Date().getTime();
|
||||||
|
counter.fps.clr();
|
||||||
|
counter.idle.clr();
|
||||||
|
counter.idletime = 0;
|
||||||
|
counter.bogus = 2;
|
||||||
|
this.timeframes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fpscounter = function(frameok) {
|
||||||
|
var now = new Date().getTime();
|
||||||
|
var last = now - counter.lasttime;
|
||||||
|
counter.lasttime = now;
|
||||||
|
|
||||||
|
if (counter.bogus || last < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
counter.fps.set(last / 10);
|
||||||
|
counter.idle.set(counter.idletime / 10);
|
||||||
|
counter.idletime = 0;
|
||||||
|
|
||||||
|
counter.frametime += last;
|
||||||
|
counter.frames++;
|
||||||
|
this.timeframes++;
|
||||||
|
if ((counter.frames & 7) == 0) {
|
||||||
|
var idle = 1000 - (counter.idle.average == 0 ? 0 : counter.idle.average * 1000 / vsynctimebase);
|
||||||
|
var fps = counter.fps.average == 0 ? 0 : SYNCBASE * 10 / counter.fps.average;
|
||||||
|
if (fps > 9999) fps = 9999;
|
||||||
|
if (idle < 0) idle = 0;
|
||||||
|
if (idle > 100 * 10) idle = 100 * 10;
|
||||||
|
if (fps < this.hz * 10) idle *= (this.hz * 10 / fps);
|
||||||
|
|
||||||
|
if ((counter.frames & 15) == 0) {
|
||||||
|
AMIGA.config.hooks.fps(Math.round(fps * 0.1));
|
||||||
|
AMIGA.config.hooks.cpu(Math.round(idle * 0.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastskiptime = new Date().getTime();
|
||||||
|
this.testFrameSkip = function() {
|
||||||
|
var now = new Date().getTime();
|
||||||
|
var time = now - lastskiptime;
|
||||||
|
lastskiptime = now;
|
||||||
|
|
||||||
|
var fps = Math.floor(SYNCBASE / (time * 0.1)) * 0.1;
|
||||||
|
if (fps < this.hz) {
|
||||||
|
if (AMIGA.playfield.frame.skip) {
|
||||||
|
if (++AMIGA.playfield.frame.skipcount >= MAX_FRAMESKIP_COUNT) {
|
||||||
|
if (!AMIGA.playfield.state.ilace || (AMIGA.playfield.state.ilace && this.lof == 1)) {
|
||||||
|
AMIGA.playfield.frame.skipcount = 0;
|
||||||
|
AMIGA.playfield.frame.skip = false;
|
||||||
|
//BUG.info('Events.vSyncPost() force frameskip disable');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!AMIGA.playfield.state.ilace || (AMIGA.playfield.state.ilace && this.lof == 0))
|
||||||
|
AMIGA.playfield.frame.skip = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AMIGA.playfield.frame.skip = false;
|
||||||
|
AMIGA.playfield.frame.skipcount = 0;
|
||||||
|
}
|
||||||
|
//AMIGA.playfield.frame.skip = (AMIGA.playfield.frame.count & 1) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
/*function getTime() {
|
||||||
|
return new Date().getTime();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
this.sleep = function(ms) {
|
||||||
|
//console.log('sleep');
|
||||||
|
var start = new Date().getTime();
|
||||||
|
while ((new Date().getTime() - start) < ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rpt_vsync = function(adjust) {
|
||||||
|
var t = new Date().getTime();
|
||||||
|
var v = t - vsyncwaittime + adjust;
|
||||||
|
if (v > SYNCBASE || v < -SYNCBASE) {
|
||||||
|
vsyncmintime = vsyncmaxtime = vsyncwaittime = t;
|
||||||
|
v = 0;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.framewait = function() {
|
||||||
|
var curr_time;
|
||||||
|
var clockadjust = 0;
|
||||||
|
var vstb = vsynctimebase;
|
||||||
|
|
||||||
|
is_syncline = 0;
|
||||||
|
|
||||||
|
var frameskip_avg = frameskip.set(frameskiptime);
|
||||||
|
frameskiptime = 0;
|
||||||
|
//BUG.info(frameskip_avg);
|
||||||
|
|
||||||
|
if (AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Maximum) {
|
||||||
|
curr_time = new Date().getTime();
|
||||||
|
|
||||||
|
var adjust = 0;
|
||||||
|
if (curr_time - vsyncwaittime > 0 && curr_time - vsyncwaittime < vstb / 2)
|
||||||
|
adjust += curr_time - vsyncwaittime;
|
||||||
|
adjust += clockadjust;
|
||||||
|
|
||||||
|
var max = Math.floor(vstb * (1.0 - adjust));
|
||||||
|
vsyncwaittime = curr_time + vstb - adjust;
|
||||||
|
vsyncmintime = curr_time;
|
||||||
|
|
||||||
|
if (max < 0) {
|
||||||
|
max = 0;
|
||||||
|
vsynctimeperline = 1;
|
||||||
|
} else {
|
||||||
|
vsynctimeperline = Math.floor(max / (this.maxvpos + 1));
|
||||||
|
}
|
||||||
|
vsyncmaxtime = curr_time + max;
|
||||||
|
|
||||||
|
//BUG.info("%06d:%06d/%06d", adjust, vsynctimeperline, vstb);
|
||||||
|
} else {
|
||||||
|
var start = new Date().getTime();
|
||||||
|
while (true) {
|
||||||
|
var v = this.rpt_vsync(clockadjust);// / (SYNCBASE / 1000.0);
|
||||||
|
if (v >= -4) break;
|
||||||
|
this.sleep(2);
|
||||||
|
}
|
||||||
|
curr_time = start = new Date().getTime();
|
||||||
|
while (this.rpt_vsync(clockadjust) < 0);
|
||||||
|
counter.idletime += new Date().getTime() - start;
|
||||||
|
|
||||||
|
curr_time = new Date().getTime();
|
||||||
|
vsyncmintime = curr_time;
|
||||||
|
vsyncmaxtime = vsyncwaittime = curr_time + vstb;
|
||||||
|
|
||||||
|
var t = frameskip_avg;
|
||||||
|
vsynctimeperline = (vstb - t) / 3;
|
||||||
|
if (vsynctimeperline < 0)
|
||||||
|
vsynctimeperline = 0;
|
||||||
|
else if (vsynctimeperline > vstb / 3)
|
||||||
|
vsynctimeperline = vstb / 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.is_last_line = function() {
|
||||||
|
return this.vpos + 1 == this.maxvpos + this.lof_store;
|
||||||
|
}
|
||||||
|
this.framewait2 = function() {
|
||||||
|
if (AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Maximum) {
|
||||||
|
if (this.is_last_line()) {
|
||||||
|
vsyncmintime = vsyncmaxtime;
|
||||||
|
is_syncline_end = new Date().getTime() + vsynctimebase;
|
||||||
|
is_syncline = 1;
|
||||||
|
} else {
|
||||||
|
vsyncmintime += vsynctimeperline;
|
||||||
|
is_syncline = 0;
|
||||||
|
if (vsyncmaxtime - vsyncmintime > 0) {
|
||||||
|
if (vsyncwaittime - vsyncmintime > 0) {
|
||||||
|
var rpt = new Date().getTime();
|
||||||
|
if (vsyncmintime - rpt > 0) {
|
||||||
|
is_syncline = 1;
|
||||||
|
is_syncline_end = rpt + vsynctimeperline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.is_last_line() && (this.vpos == Math.floor(this.maxvpos * 1 / 3) || this.vpos == Math.floor(this.maxvpos * 2 / 3))) {
|
||||||
|
vsyncmintime += vsynctimeperline;
|
||||||
|
var rpt = new Date().getTime();
|
||||||
|
while (vsyncmintime - (rpt + vsynctimebase / 10) > 0 && vsyncmintime - rpt < vsynctimebase) {
|
||||||
|
this.sleep(1);
|
||||||
|
rpt = new Date().getTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.vSyncPre = function() {
|
||||||
|
if (counter.bogus > 0)
|
||||||
|
counter.bogus--;
|
||||||
|
|
||||||
|
AMIGA.cia.vSyncPre();
|
||||||
|
|
||||||
|
if (!vsync_rendered) {
|
||||||
|
var start = new Date().getTime();
|
||||||
|
if (AMIGA.config.video.enabled) {
|
||||||
|
AMIGA.playfield.vSync();
|
||||||
|
if (AMIGA.config.video.skip) this.testFrameSkip();
|
||||||
|
}
|
||||||
|
frameskiptime += new Date().getTime() - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.framewait();
|
||||||
|
this.fpscounter();
|
||||||
|
|
||||||
|
vsync_rendered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vSyncPost = function() {
|
||||||
|
AMIGA.disk.vsync();
|
||||||
|
|
||||||
|
if (AMIGA.playfield.bplcon0 & 4)
|
||||||
|
this.lofStore = this.lofStore ? 0 : 1;
|
||||||
|
this.lof = this.lofStore;
|
||||||
|
|
||||||
|
//if ((this.beamcon0 & (0x20|0x80)) != (this.new_beamcon0 & (0x20|0x80)) || this.hack_vpos)
|
||||||
|
//if ((this.beamcon0 & (0x20|0x80)) != (this.new_beamcon0 & (0x20|0x80)) || (abs (vpos_count - vpos_count_prev) > 1)) this.initHz();
|
||||||
|
//if (this.lofChanged) this.compute_vsynctime();
|
||||||
|
|
||||||
|
this.lofChanged = false;
|
||||||
|
|
||||||
|
AMIGA.copper.COPJMP(1, 1);
|
||||||
|
|
||||||
|
if (!AMIGA.playfield.state.ilace || (AMIGA.playfield.state.ilace && this.lof == 1))
|
||||||
|
AMIGA.state = CMD_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hSyncPre = function(isvsync) {
|
||||||
|
AMIGA.copper.sync_copper_with_cpu(this.maxhpos, 0);
|
||||||
|
|
||||||
|
if (AMIGA.config.video.enabled)
|
||||||
|
AMIGA.playfield.hSync();
|
||||||
|
|
||||||
|
AMIGA.disk.hsync();
|
||||||
|
|
||||||
|
if (AMIGA.config.audio.enabled)
|
||||||
|
AMIGA.audio.hsync();
|
||||||
|
|
||||||
|
//AMIGA.cia.hSyncPre(); //empty
|
||||||
|
|
||||||
|
if (AMIGA.config.video.ntsc) {
|
||||||
|
this.lol ^= 1;
|
||||||
|
this.maxhpos = 227 + this.lol;
|
||||||
|
} else {
|
||||||
|
this.lol = 0;
|
||||||
|
this.maxhpos = 227;
|
||||||
|
}
|
||||||
|
this.vpos++;
|
||||||
|
if (isvsync)
|
||||||
|
this.vpos = 0;
|
||||||
|
|
||||||
|
AMIGA.playfield.sprites.clear();
|
||||||
|
|
||||||
|
this.eventtab[EV_HSYNC].oldcycles = this.currcycle;
|
||||||
|
this.eventtab[EV_HSYNC].evtime = this.maxhpos * CYCLE_UNIT + this.currcycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hSyncPost = function(isvsync) {
|
||||||
|
AMIGA.cia.hSyncPost(1);
|
||||||
|
if (isvsync)
|
||||||
|
AMIGA.cia.vSyncPost(1);
|
||||||
|
|
||||||
|
AMIGA.custom.last_value = 0xffff;
|
||||||
|
|
||||||
|
//if (!AMIGA.config.blitter.exact && AMIGA.blitter.getState() != BLT_done && AMIGA.dmaen(DMAF_BPLEN))// && diwstate == DIW_waiting_stop) AMIGA.blitter.slowdown();
|
||||||
|
|
||||||
|
if (isvsync) {
|
||||||
|
this.vpos = 0;
|
||||||
|
this.vSyncPost();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AMIGA.config.chipset.agnus == AGNUS_8361) {
|
||||||
|
if (this.vpos == 1)
|
||||||
|
AMIGA.send_interrupt(5, 1 * CYCLE_UNIT);
|
||||||
|
} else {
|
||||||
|
if (this.vpos == 0)
|
||||||
|
AMIGA.send_interrupt(5, 1 * CYCLE_UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dmal_hsync();
|
||||||
|
|
||||||
|
AMIGA.copper.reset2();
|
||||||
|
//AMIGA.copper.check(2);
|
||||||
|
|
||||||
|
this.framewait2();
|
||||||
|
|
||||||
|
AMIGA.playfield.sprites.cycle(0);
|
||||||
|
|
||||||
|
if (this.vpos + 1 == this.maxvpos + this.lof_store && AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Maximum && !vsync_rendered) {
|
||||||
|
var start = new Date().getTime();
|
||||||
|
if (AMIGA.config.video.enabled) {
|
||||||
|
AMIGA.playfield.vSync();
|
||||||
|
if (AMIGA.config.video.skip) this.testFrameSkip();
|
||||||
|
}
|
||||||
|
frameskiptime += new Date().getTime() - start;
|
||||||
|
vsync_rendered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hSync = function() {
|
||||||
|
var cvp = this.vpos + 1;
|
||||||
|
var mvp = this.maxvpos + this.lofStore;
|
||||||
|
var vsync = cvp == mvp || cvp == mvp + 1;
|
||||||
|
|
||||||
|
this.hSyncPre(vsync);
|
||||||
|
if (vsync)
|
||||||
|
this.vSyncPre();
|
||||||
|
|
||||||
|
this.hSyncPost(vsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.GETVPOS = function() {
|
||||||
|
return ((AMIGA.playfield.bplcon0 & 2) ? this.vpos_previous : this.vpos);
|
||||||
|
}
|
||||||
|
this.GETHPOS = function() {
|
||||||
|
return ((AMIGA.playfield.bplcon0 & 2) ? this.hpos_previous : this.hpos());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.VPOSR = function() {
|
||||||
|
var chipset = 0;
|
||||||
|
|
||||||
|
switch (AMIGA.config.chipset.agnus) {
|
||||||
|
case AGNUS_8367:
|
||||||
|
case AGNUS_8371:
|
||||||
|
chipset = 0;
|
||||||
|
break;
|
||||||
|
case AGNUS_8361:
|
||||||
|
case AGNUS_8370:
|
||||||
|
chipset = 10;
|
||||||
|
break;
|
||||||
|
case AGNUS_8372: {
|
||||||
|
if (AMIGA.config.chipset.agnus_rev <= 4)
|
||||||
|
chipset = AMIGA.config.video.ntsc ? 30 : 20;
|
||||||
|
else
|
||||||
|
chipset = AMIGA.config.video.ntsc ? 31 : 21;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*AGA
|
||||||
|
case AGNUS_8374: {
|
||||||
|
if (AMIGA.config.chipset.agnus_rev <= 2)
|
||||||
|
chipset = AMIGA.config.video.ntsc ? 32 : 22;
|
||||||
|
else
|
||||||
|
chipset = AMIGA.config.video.ntsc ? 33 : 23;
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
var vp = this.GETVPOS();
|
||||||
|
var hp = this.GETHPOS();
|
||||||
|
|
||||||
|
if (hp + 3 >= this.maxhpos) {
|
||||||
|
vp++;
|
||||||
|
if (vp >= this.maxvpos + this.lofStore)
|
||||||
|
vp = 0;
|
||||||
|
}
|
||||||
|
vp = (vp >> 8) & 7;
|
||||||
|
vp &= 1;
|
||||||
|
|
||||||
|
//vp = (vp >> 8) & 1;
|
||||||
|
|
||||||
|
var vpos = (this.lofStore << 15) | (chipset << 8) | (this.lol << 7) | vp;
|
||||||
|
|
||||||
|
//BUG.info('Custom.VPOSR() vp %d, hp %d, vpos $%04x', this.vpos, this.hpos(), vpos);
|
||||||
|
return vpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.VPOSW = function (v) {
|
||||||
|
//BUG.info('Custom.VPOSW() $%04x', v);
|
||||||
|
|
||||||
|
if (this.lofStore != ((v & 0x8000) ? 1 : 0)) {
|
||||||
|
this.lofChanged = true;
|
||||||
|
this.lofStore = (v & 0x8000) ? 1 : 0;
|
||||||
|
}
|
||||||
|
if (AMIGA.config.video.ntsc)
|
||||||
|
this.lol = (v & 0x0080) ? 1 : 0;
|
||||||
|
|
||||||
|
if (this.lofChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.vpos &= 0x00ff;
|
||||||
|
this.vpos |= ((v & 1) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.VHPOSW = function (v) {
|
||||||
|
//BUG.info('Custom.VHPOSW() $%04x', v);
|
||||||
|
|
||||||
|
this.vpos &= 0xff00;
|
||||||
|
this.vpos |= (v >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.VHPOSR = function() {
|
||||||
|
var vp = this.GETVPOS();
|
||||||
|
var hp = this.GETHPOS();
|
||||||
|
|
||||||
|
if (hp >= this.maxhpos) {
|
||||||
|
//console.log(hp);
|
||||||
|
hp -= this.maxhpos;
|
||||||
|
vp++;
|
||||||
|
if (vp >= this.maxvpos + this.lofStore)
|
||||||
|
vp = 0;
|
||||||
|
}
|
||||||
|
hp += 1;
|
||||||
|
if (hp >= this.maxhpos)
|
||||||
|
hp -= this.maxhpos;
|
||||||
|
|
||||||
|
var vhpos = ((vp & 0xff) << 8) | ((hp >> 1) & 0xff);
|
||||||
|
|
||||||
|
//BUG.info('Custom.VHPOSR() vp %d, hp %d, vhpos $%04x', vp, hp, vhpos);
|
||||||
|
return vhpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.BEAMCON0 = function (v) {
|
||||||
|
BUG.info('BEAMCON0() $%04x', v);
|
||||||
|
}
|
||||||
|
}
|
||||||
177
sae/expansion.js
Normal file
177
sae/expansion.js
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function Board_A2058() {
|
||||||
|
const MEM_8MB = 0x00;
|
||||||
|
const MEM_4MB = 0x07;
|
||||||
|
const MEM_2MB = 0x06;
|
||||||
|
const MEM_1MB = 0x05;
|
||||||
|
const MEM_512KB = 0x04;
|
||||||
|
const MEM_256KB = 0x03;
|
||||||
|
//const MEM_128KB = 0x02;
|
||||||
|
//const MEM_64KB = 0x01;
|
||||||
|
|
||||||
|
//const SAME_SLOT = 0x08; /* Next card is in the same Slot */
|
||||||
|
//const ROM_CARD = 0x10; /* Card has valid ROM */
|
||||||
|
const ADD_MEMORY = 0x20; /* Add Memory to List of Free Ram */
|
||||||
|
|
||||||
|
const ZORRO2 = 0xc0; /* Type of Expansion Card */
|
||||||
|
//const ZORRO3 = 0x80;
|
||||||
|
|
||||||
|
const CARE_ADDR = 0x80; /* Adress HAS to be $200000-$9fffff */
|
||||||
|
|
||||||
|
const VENDOR_COMMODORE = 514;
|
||||||
|
const PRODUCT_A2058 = 10;
|
||||||
|
|
||||||
|
this.info = function() {
|
||||||
|
//BUG.info('Board_A2058.info()');
|
||||||
|
var type;
|
||||||
|
switch (AMIGA.mem.fast.size) {
|
||||||
|
case 0x080000: type = ZORRO2 + ADD_MEMORY + MEM_512KB; break;
|
||||||
|
case 0x100000: type = ZORRO2 + ADD_MEMORY + MEM_1MB; break;
|
||||||
|
case 0x200000: type = ZORRO2 + ADD_MEMORY + MEM_2MB; break;
|
||||||
|
case 0x400000: type = ZORRO2 + ADD_MEMORY + MEM_4MB; break;
|
||||||
|
case 0x800000: type = ZORRO2 + ADD_MEMORY + MEM_8MB; break;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name:'Commodore A2058',
|
||||||
|
vendor:VENDOR_COMMODORE,
|
||||||
|
product:PRODUCT_A2058,
|
||||||
|
serial:1,
|
||||||
|
type:type,
|
||||||
|
flags:CARE_ADDR,
|
||||||
|
rom:0,
|
||||||
|
ctrl:0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Board_Dummy() {
|
||||||
|
this.info = function() {
|
||||||
|
//BUG.info('Board_Dummy.info()');
|
||||||
|
return {
|
||||||
|
name:null,
|
||||||
|
vendor:0,
|
||||||
|
product:0,
|
||||||
|
serial:0,
|
||||||
|
type:0,
|
||||||
|
flags:0,
|
||||||
|
rom:0,
|
||||||
|
ctrl:0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Expansion() {
|
||||||
|
const MAX_EXPANSION_BOARDS = 5;
|
||||||
|
|
||||||
|
var mem = {
|
||||||
|
data:null,
|
||||||
|
lo:0,
|
||||||
|
hi:0
|
||||||
|
};
|
||||||
|
var boards = [];
|
||||||
|
var board = 0;
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
mem.data = new Uint16Array(0x8000);
|
||||||
|
boards = [];
|
||||||
|
if (AMIGA.mem.fast.size > 0)
|
||||||
|
boards[0] = new Board_A2058();
|
||||||
|
else
|
||||||
|
boards[0] = new Board_Dummy();
|
||||||
|
|
||||||
|
for (var i = 1; i < MAX_EXPANSION_BOARDS; i++)
|
||||||
|
boards[i] = new Board_Dummy();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
board = 0;
|
||||||
|
this.config(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clear = function() {
|
||||||
|
for (var i = 0; i < mem.data.length; i++)
|
||||||
|
mem.data[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.write = function (addr, value) {
|
||||||
|
mem.data[(addr >> 1)] = (value & 0xf0) << 8;
|
||||||
|
mem.data[(addr >> 1) + 1] = (value & 0x0f) << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load8 = function (addr) {
|
||||||
|
addr &= 0xffff;
|
||||||
|
var value = (mem.data[addr >>> 1] >> ((addr & 1) ? 0 : 8)) & 0xff;
|
||||||
|
if (addr == 0 || addr == 2 || addr == 0x40 || addr == 0x42)
|
||||||
|
return value;
|
||||||
|
return ~value & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store8 = function (addr, value) {
|
||||||
|
switch (addr & 0xff) {
|
||||||
|
case 0x30:
|
||||||
|
case 0x32:
|
||||||
|
mem.hi = 0;
|
||||||
|
mem.lo = 0;
|
||||||
|
this.write(0x48, 0x00);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x48:
|
||||||
|
mem.hi = value;
|
||||||
|
//BUG.info('Expansion.store8() board %d done.', board + 1);
|
||||||
|
++board;
|
||||||
|
if (board <= MAX_EXPANSION_BOARDS)
|
||||||
|
this.config(board);
|
||||||
|
else
|
||||||
|
this.clear();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4a:
|
||||||
|
mem.lo = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4c:
|
||||||
|
//BUG.info('Expansion.store8() board %d faild.', board + 1);
|
||||||
|
++board;
|
||||||
|
if (board <= MAX_EXPANSION_BOARDS)
|
||||||
|
this.config(board);
|
||||||
|
else
|
||||||
|
this.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.config = function(board) {
|
||||||
|
var info = boards[board].info();
|
||||||
|
|
||||||
|
this.clear();
|
||||||
|
if (info.name) {
|
||||||
|
BUG.info('Expansion.config() Added \'%s\' into slot %d', info.name, board + 1);
|
||||||
|
|
||||||
|
this.write(0x00, info.type);
|
||||||
|
this.write(0x08, info.flags);
|
||||||
|
|
||||||
|
this.write(0x04, info.product);
|
||||||
|
this.write(0x10, info.vendor >> 8);
|
||||||
|
this.write(0x14, info.vendor & 0x0f);
|
||||||
|
|
||||||
|
this.write(0x18, (info.serial >> 24) & 0xff);
|
||||||
|
this.write(0x1c, (info.serial >> 16) & 0xff);
|
||||||
|
this.write(0x20, (info.serial >> 8) & 0xff);
|
||||||
|
this.write(0x24, info.serial & 0xff);
|
||||||
|
|
||||||
|
this.write(0x28, (info.rom >> 8) & 0xff);
|
||||||
|
this.write(0x2c, info.rom & 0xff);
|
||||||
|
|
||||||
|
this.write(0x40, info.ctrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
801
sae/input.js
Normal file
801
sae/input.js
Normal file
|
|
@ -0,0 +1,801 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function Mouse() {
|
||||||
|
this.button = [false, false, false];
|
||||||
|
this.pos = 0;
|
||||||
|
|
||||||
|
var cx = 0;
|
||||||
|
var cy = 0;
|
||||||
|
var mx = 0;
|
||||||
|
var my = 0;
|
||||||
|
var lx = -1;
|
||||||
|
var ly = -1;
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
this.button = [0, 0, 0];
|
||||||
|
cx = cy = 0;
|
||||||
|
lx = ly = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mousedown = function (e) {
|
||||||
|
e = e || window.event;
|
||||||
|
if (!e) return;
|
||||||
|
|
||||||
|
this.button[e.button] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mouseup = function (e) {
|
||||||
|
e = e || window.event;
|
||||||
|
if (!e) return;
|
||||||
|
|
||||||
|
this.button[e.button] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mouseover = function (e) {
|
||||||
|
//AMIGA.video.hideCursor(1);
|
||||||
|
this.mousemove(e);
|
||||||
|
lx = cx;
|
||||||
|
ly = cy;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mouseout = function (e) {
|
||||||
|
//AMIGA.video.hideCursor(0);
|
||||||
|
this.mouseup(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mousemove = function (e) {
|
||||||
|
e = e || window.event;
|
||||||
|
if (!e || !AMIGA.video) return;
|
||||||
|
|
||||||
|
if (e.pageX || e.pageY) {
|
||||||
|
cx = e.pageX;
|
||||||
|
cy = e.pageY;
|
||||||
|
} else if (e.clientX || e.clientY) {
|
||||||
|
cx = e.clientX;
|
||||||
|
cy = e.clientY;
|
||||||
|
}
|
||||||
|
if (lx == -1) {
|
||||||
|
lx = cx;
|
||||||
|
ly = cy;
|
||||||
|
}
|
||||||
|
//BUG.info('USER() mousemove %d %d', cx, cy);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update = function() {
|
||||||
|
if (lx != -1) {
|
||||||
|
var dx = cx - lx;
|
||||||
|
var dy = cy - ly;
|
||||||
|
|
||||||
|
if (dx > 127) dx = 127; else if (dx < -127) dx = -127;
|
||||||
|
mx += dx;
|
||||||
|
if (mx > 255) mx -= 256; else if (mx < 0) mx += 256;
|
||||||
|
|
||||||
|
if (dy > 127) dy = 127; else if (dy < -127) dy = -127;
|
||||||
|
my += dy;
|
||||||
|
if (my > 255) my -= 256; else if (my < 0) my += 256;
|
||||||
|
} else
|
||||||
|
mx = my = 0;
|
||||||
|
|
||||||
|
lx = cx;
|
||||||
|
ly = cy;
|
||||||
|
|
||||||
|
this.pos = (my << 8) + mx;
|
||||||
|
//BUG.info('USER() mousemove %d %d, ps $%04x', mx, my, this.pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Joystick(type) {
|
||||||
|
this.type = type;
|
||||||
|
this.button = [false, false, false];
|
||||||
|
this.state = [false, false, false, false];
|
||||||
|
this.dir = 0;
|
||||||
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
this.button = [false, false, false];
|
||||||
|
this.state = [false, false, false, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update = function() {
|
||||||
|
var u = this.state[1];
|
||||||
|
var d = this.state[3];
|
||||||
|
|
||||||
|
if (this.state[0]) u = !u;
|
||||||
|
if (this.state[2]) d = !d;
|
||||||
|
|
||||||
|
this.dir = d | (this.state[2] << 1) | (u << 8) | (this.state[0] << 9);
|
||||||
|
|
||||||
|
/*var l = 1, r = 1, u = 1, d = 1;
|
||||||
|
|
||||||
|
if (this.state[0]) l = 0;
|
||||||
|
if (this.state[1]) u = 0;
|
||||||
|
if (this.state[2]) r = 0;
|
||||||
|
if (this.state[3]) d = 0;
|
||||||
|
|
||||||
|
var b0 = (d ^ r) ? 1 : 0;
|
||||||
|
var b1 = (r ^ 1) ? 2 : 0;
|
||||||
|
var b8 = (u ^ l) ? 1 : 0;
|
||||||
|
var b9 = (l ^ 1) ? 2 : 0;
|
||||||
|
|
||||||
|
this.dir = ((b8 | b9) << 8) | (b0 | b1);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Keyboard() {
|
||||||
|
const RAWKEY_TILDE = 0x00;
|
||||||
|
const RAWKEY_1 = 0x01;
|
||||||
|
const RAWKEY_2 = 0x02;
|
||||||
|
const RAWKEY_3 = 0x03;
|
||||||
|
const RAWKEY_4 = 0x04;
|
||||||
|
const RAWKEY_5 = 0x05;
|
||||||
|
const RAWKEY_6 = 0x06;
|
||||||
|
const RAWKEY_7 = 0x07;
|
||||||
|
const RAWKEY_8 = 0x08;
|
||||||
|
const RAWKEY_9 = 0x09;
|
||||||
|
const RAWKEY_0 = 0x0A;
|
||||||
|
const RAWKEY_MINUS = 0x0B;
|
||||||
|
const RAWKEY_EQUAL = 0x0C;
|
||||||
|
const RAWKEY_BACKSLASH = 0x0D;
|
||||||
|
const RAWKEY_KP_0 = 0x0F;
|
||||||
|
const RAWKEY_Q = 0x10;
|
||||||
|
const RAWKEY_W = 0x11;
|
||||||
|
const RAWKEY_E = 0x12;
|
||||||
|
const RAWKEY_R = 0x13;
|
||||||
|
const RAWKEY_T = 0x14;
|
||||||
|
const RAWKEY_Y = 0x15;
|
||||||
|
const RAWKEY_U = 0x16;
|
||||||
|
const RAWKEY_I = 0x17;
|
||||||
|
const RAWKEY_O = 0x18;
|
||||||
|
const RAWKEY_P = 0x19;
|
||||||
|
const RAWKEY_LBRACKET = 0x1A;
|
||||||
|
const RAWKEY_RBRACKET = 0x1B;
|
||||||
|
const RAWKEY_KP_1 = 0x1D;
|
||||||
|
const RAWKEY_KP_2 = 0x1E;
|
||||||
|
const RAWKEY_KP_3 = 0x1F;
|
||||||
|
const RAWKEY_A = 0x20;
|
||||||
|
const RAWKEY_S = 0x21;
|
||||||
|
const RAWKEY_D = 0x22;
|
||||||
|
const RAWKEY_F = 0x23;
|
||||||
|
const RAWKEY_G = 0x24;
|
||||||
|
const RAWKEY_H = 0x25;
|
||||||
|
const RAWKEY_J = 0x26;
|
||||||
|
const RAWKEY_K = 0x27;
|
||||||
|
const RAWKEY_L = 0x28;
|
||||||
|
const RAWKEY_SEMICOLON = 0x29;
|
||||||
|
const RAWKEY_QUOTE = 0x2A;
|
||||||
|
const RAWKEY_2B = 0x2B;
|
||||||
|
const RAWKEY_KP_4 = 0x2D;
|
||||||
|
const RAWKEY_KP_5 = 0x2E;
|
||||||
|
const RAWKEY_KP_6 = 0x2F;
|
||||||
|
const RAWKEY_LESSGREATER = 0x30;
|
||||||
|
const RAWKEY_Z = 0x31;
|
||||||
|
const RAWKEY_X = 0x32;
|
||||||
|
const RAWKEY_C = 0x33;
|
||||||
|
const RAWKEY_V = 0x34;
|
||||||
|
const RAWKEY_B = 0x35;
|
||||||
|
const RAWKEY_N = 0x36;
|
||||||
|
const RAWKEY_M = 0x37;
|
||||||
|
const RAWKEY_COMMA = 0x38;
|
||||||
|
const RAWKEY_PERIOD = 0x39;
|
||||||
|
const RAWKEY_SLASH = 0x3A;
|
||||||
|
const RAWKEY_KP_DECIMAL = 0x3C;
|
||||||
|
const RAWKEY_KP_7 = 0x3D;
|
||||||
|
const RAWKEY_KP_8 = 0x3E;
|
||||||
|
const RAWKEY_KP_9 = 0x3F;
|
||||||
|
const RAWKEY_SPACE = 0x40;
|
||||||
|
const RAWKEY_BACKSPACE = 0x41;
|
||||||
|
const RAWKEY_TAB = 0x42;
|
||||||
|
const RAWKEY_KP_ENTER = 0x43;
|
||||||
|
const RAWKEY_RETURN = 0x44;
|
||||||
|
const RAWKEY_ESCAPE = 0x45;
|
||||||
|
const RAWKEY_DELETE = 0x46;
|
||||||
|
//const RAWKEY_INSERT = 0x47;
|
||||||
|
//const RAWKEY_PAGEUP = 0x48;
|
||||||
|
//const RAWKEY_PAGEDOWN = 0x49;
|
||||||
|
const RAWKEY_KP_MINUS = 0x4A;
|
||||||
|
//const RAWKEY_F11 = 0x4B;
|
||||||
|
const RAWKEY_UP = 0x4C;
|
||||||
|
const RAWKEY_DOWN = 0x4D;
|
||||||
|
const RAWKEY_RIGHT = 0x4E;
|
||||||
|
const RAWKEY_LEFT = 0x4F;
|
||||||
|
const RAWKEY_F1 = 0x50;
|
||||||
|
const RAWKEY_F2 = 0x51;
|
||||||
|
const RAWKEY_F3 = 0x52;
|
||||||
|
const RAWKEY_F4 = 0x53;
|
||||||
|
const RAWKEY_F5 = 0x54;
|
||||||
|
const RAWKEY_F6 = 0x55;
|
||||||
|
const RAWKEY_F7 = 0x56;
|
||||||
|
const RAWKEY_F8 = 0x57;
|
||||||
|
const RAWKEY_F9 = 0x58;
|
||||||
|
const RAWKEY_F10 = 0x59;
|
||||||
|
const RAWKEY_KP_DIVIDE = 0x5C;
|
||||||
|
const RAWKEY_KP_MULTIPLY = 0x5D;
|
||||||
|
const RAWKEY_KP_PLUS = 0x5E;
|
||||||
|
const RAWKEY_HELP = 0x5F;
|
||||||
|
const RAWKEY_LSHIFT = 0x60;
|
||||||
|
const RAWKEY_RSHIFT = 0x61;
|
||||||
|
const RAWKEY_CAPSLOCK = 0x62;
|
||||||
|
const RAWKEY_CONTROL = 0x63;
|
||||||
|
const RAWKEY_LALT = 0x64;
|
||||||
|
const RAWKEY_RALT = 0x65;
|
||||||
|
const RAWKEY_LAMIGA = 0x66;
|
||||||
|
const RAWKEY_RAMIGA = 0x67;
|
||||||
|
/*const RAWKEY_SCRLOCK = 0x6B;
|
||||||
|
const RAWKEY_PRTSCREEN = 0x6C;
|
||||||
|
const RAWKEY_NUMLOCK = 0x6D;
|
||||||
|
const RAWKEY_PAUSE = 0x6E;
|
||||||
|
const RAWKEY_F12 = 0x6F;
|
||||||
|
const RAWKEY_HOME = 0x70;
|
||||||
|
const RAWKEY_END = 0x71;
|
||||||
|
const RAWKEY_MEDIA1 = 0x72;
|
||||||
|
const RAWKEY_MEDIA2 = 0x73;
|
||||||
|
const RAWKEY_MEDIA3 = 0x74;
|
||||||
|
const RAWKEY_MEDIA4 = 0x75;
|
||||||
|
const RAWKEY_MEDIA5 = 0x76;
|
||||||
|
const RAWKEY_MEDIA6 = 0x77;
|
||||||
|
const RAWKEY_NM_WHEEL_UP = 0x7A;
|
||||||
|
const RAWKEY_NM_WHEEL_DOWN = 0x7B;
|
||||||
|
const RAWKEY_NM_WHEEL_LEFT = 0x7C;
|
||||||
|
const RAWKEY_NM_WHEEL_RIGHT = 0x7D;
|
||||||
|
const RAWKEY_NM_BUTTON_FOURTH = 0x7E;*/
|
||||||
|
const RAWKEY_BAD_CODE = 0xF9;
|
||||||
|
const RAWKEY_BUFFER_OVERFLOW = 0xFA;
|
||||||
|
const RAWKEY_SELFTEST_FAILED = 0xFC;
|
||||||
|
const RAWKEY_INIT_POWER_UP = 0xFD;
|
||||||
|
const RAWKEY_TERM_POWER_UP = 0xFE;
|
||||||
|
|
||||||
|
const defKeyCodeMap = {
|
||||||
|
8:RAWKEY_BACKSPACE, //backspace
|
||||||
|
9:RAWKEY_TAB, //tab
|
||||||
|
13:RAWKEY_RETURN, //enter
|
||||||
|
16:RAWKEY_LSHIFT, //shift
|
||||||
|
17:RAWKEY_CONTROL, //ctrl
|
||||||
|
18:RAWKEY_LALT, //alt
|
||||||
|
//19:RAWKEY_PAUSE, //pause/break
|
||||||
|
20:RAWKEY_CAPSLOCK, //caps lock
|
||||||
|
27:RAWKEY_ESCAPE, //escape
|
||||||
|
32:RAWKEY_SPACE, //space
|
||||||
|
//33:RAWKEY_PAGEUP, //page up
|
||||||
|
//34:RAWKEY_PAGEDOWN, //page down
|
||||||
|
//35:RAWKEY_END, //end
|
||||||
|
//36:RAWKEY_HOME, //home
|
||||||
|
37:RAWKEY_LEFT, //left arrow
|
||||||
|
38:RAWKEY_UP, //up arrow
|
||||||
|
39:RAWKEY_RIGHT, //right arrow
|
||||||
|
40:RAWKEY_DOWN, //down arrow
|
||||||
|
//45:RAWKEY_INSERT, //insert
|
||||||
|
46:RAWKEY_DELETE, //delete
|
||||||
|
48:RAWKEY_0, //0
|
||||||
|
49:RAWKEY_1, //1
|
||||||
|
50:RAWKEY_2, //2
|
||||||
|
51:RAWKEY_3, //3
|
||||||
|
52:RAWKEY_4, //4
|
||||||
|
53:RAWKEY_5, //5
|
||||||
|
54:RAWKEY_6, //6
|
||||||
|
55:RAWKEY_7, //7
|
||||||
|
56:RAWKEY_8, //8
|
||||||
|
57:RAWKEY_9, //9
|
||||||
|
65:RAWKEY_A, //a
|
||||||
|
66:RAWKEY_B, //b
|
||||||
|
67:RAWKEY_C, //c
|
||||||
|
68:RAWKEY_D, //d
|
||||||
|
69:RAWKEY_E, //e
|
||||||
|
70:RAWKEY_F, //f
|
||||||
|
71:RAWKEY_G, //g
|
||||||
|
72:RAWKEY_H, //h
|
||||||
|
73:RAWKEY_I, //i
|
||||||
|
74:RAWKEY_J, //j
|
||||||
|
75:RAWKEY_K, //k
|
||||||
|
76:RAWKEY_L, //l
|
||||||
|
77:RAWKEY_M, //m
|
||||||
|
78:RAWKEY_N, //n
|
||||||
|
79:RAWKEY_O, //o
|
||||||
|
80:RAWKEY_P, //p
|
||||||
|
81:RAWKEY_Q, //q
|
||||||
|
82:RAWKEY_R, //r
|
||||||
|
83:RAWKEY_S, //s
|
||||||
|
84:RAWKEY_T, //t
|
||||||
|
85:RAWKEY_U, //u
|
||||||
|
86:RAWKEY_V, //v
|
||||||
|
87:RAWKEY_W, //w
|
||||||
|
88:RAWKEY_X, //x
|
||||||
|
89:RAWKEY_Z, //y
|
||||||
|
90:RAWKEY_Y, //z
|
||||||
|
91:RAWKEY_LAMIGA, //left window key
|
||||||
|
92:RAWKEY_RAMIGA, //right window key
|
||||||
|
93:RAWKEY_HELP, //select key
|
||||||
|
96:RAWKEY_KP_0, //numpad 0
|
||||||
|
97:RAWKEY_KP_1, //numpad 1
|
||||||
|
98:RAWKEY_KP_2, //numpad 2
|
||||||
|
99:RAWKEY_KP_3, //numpad 3
|
||||||
|
100:RAWKEY_KP_4, //numpad 4
|
||||||
|
101:RAWKEY_KP_5, //numpad 5
|
||||||
|
102:RAWKEY_KP_6, //numpad 6
|
||||||
|
103:RAWKEY_KP_7, //numpad 7
|
||||||
|
104:RAWKEY_KP_8, //numpad 8
|
||||||
|
105:RAWKEY_KP_9, //numpad 9
|
||||||
|
106:RAWKEY_KP_MULTIPLY, //multiply
|
||||||
|
107:RAWKEY_KP_PLUS, //add
|
||||||
|
109:RAWKEY_KP_MINUS, //subtract
|
||||||
|
110:RAWKEY_KP_DECIMAL, //decimal point
|
||||||
|
111:RAWKEY_KP_DIVIDE, //divide
|
||||||
|
112:RAWKEY_F1 , //f1
|
||||||
|
113:RAWKEY_F2 , //f2
|
||||||
|
114:RAWKEY_F3 , //f3
|
||||||
|
115:RAWKEY_F4 , //f4
|
||||||
|
116:RAWKEY_F5 , //f5
|
||||||
|
117:RAWKEY_F6 , //f6
|
||||||
|
118:RAWKEY_F7 , //f7
|
||||||
|
119:RAWKEY_F8 , //f8
|
||||||
|
120:RAWKEY_F9 , //f9
|
||||||
|
121:RAWKEY_F10, //f10
|
||||||
|
//122:RAWKEY_F11, //f11
|
||||||
|
//123:RAWKEY_F12, //f12
|
||||||
|
//144:RAWKEY_NUMLOCK, //num lock
|
||||||
|
//145:RAWKEY_SCRLOCK, //scroll lock
|
||||||
|
/*186:RAWKEY_SEMICOLON, //semi-colon
|
||||||
|
187:RAWKEY_EQUAL, //equal sign
|
||||||
|
188:RAWKEY_COMMA, //comma
|
||||||
|
189:RAWKEY_MINUS, //dash
|
||||||
|
190:RAWKEY_PERIOD, //period
|
||||||
|
191:RAWKEY_SLASH, //forward slash
|
||||||
|
192:RAWKEY_TILDE, //grave accent
|
||||||
|
219:RAWKEY_LBRACKET, //open bracket
|
||||||
|
220:RAWKEY_BACKSLASH, //back slash
|
||||||
|
221:RAWKEY_RBRACKET, //close braket
|
||||||
|
222:RAWKEY_QUOTE, //single quote
|
||||||
|
226:RAWKEY_LESSGREATER*/
|
||||||
|
186:RAWKEY_LBRACKET,
|
||||||
|
187:RAWKEY_RBRACKET,
|
||||||
|
188:RAWKEY_COMMA,
|
||||||
|
189:RAWKEY_SLASH,
|
||||||
|
190:RAWKEY_PERIOD,
|
||||||
|
191:RAWKEY_2B,
|
||||||
|
192:RAWKEY_SEMICOLON,
|
||||||
|
219:RAWKEY_MINUS,
|
||||||
|
220:RAWKEY_TILDE,
|
||||||
|
221:RAWKEY_EQUAL,
|
||||||
|
222:RAWKEY_QUOTE,
|
||||||
|
226:RAWKEY_LESSGREATER
|
||||||
|
};
|
||||||
|
const mozKeyCodeMap = {
|
||||||
|
8:RAWKEY_BACKSPACE, //backspace
|
||||||
|
9:RAWKEY_TAB, //tab
|
||||||
|
13:RAWKEY_RETURN, //enter
|
||||||
|
16:RAWKEY_LSHIFT, //shift
|
||||||
|
17:RAWKEY_CONTROL, //ctrl
|
||||||
|
18:RAWKEY_LALT, //alt
|
||||||
|
//19:RAWKEY_PAUSE, //pause/break
|
||||||
|
20:RAWKEY_CAPSLOCK, //caps lock
|
||||||
|
27:RAWKEY_ESCAPE, //escape
|
||||||
|
32:RAWKEY_SPACE, //space
|
||||||
|
//33:RAWKEY_PAGEUP, //page up
|
||||||
|
//34:RAWKEY_PAGEDOWN, //page down
|
||||||
|
//35:RAWKEY_END, //end
|
||||||
|
//36:RAWKEY_HOME, //home
|
||||||
|
37:RAWKEY_LEFT, //left arrow
|
||||||
|
38:RAWKEY_UP, //up arrow
|
||||||
|
39:RAWKEY_RIGHT, //right arrow
|
||||||
|
40:RAWKEY_DOWN, //down arrow
|
||||||
|
//45:RAWKEY_INSERT, //insert
|
||||||
|
46:RAWKEY_DELETE, //delete
|
||||||
|
48:RAWKEY_0, //0
|
||||||
|
49:RAWKEY_1, //1
|
||||||
|
50:RAWKEY_2, //2
|
||||||
|
51:RAWKEY_3, //3
|
||||||
|
52:RAWKEY_4, //4
|
||||||
|
53:RAWKEY_5, //5
|
||||||
|
54:RAWKEY_6, //6
|
||||||
|
55:RAWKEY_7, //7
|
||||||
|
56:RAWKEY_8, //8
|
||||||
|
57:RAWKEY_9, //9
|
||||||
|
60:RAWKEY_LESSGREATER,
|
||||||
|
63:RAWKEY_MINUS,
|
||||||
|
65:RAWKEY_A, //a
|
||||||
|
66:RAWKEY_B, //b
|
||||||
|
67:RAWKEY_C, //c
|
||||||
|
68:RAWKEY_D, //d
|
||||||
|
69:RAWKEY_E, //e
|
||||||
|
70:RAWKEY_F, //f
|
||||||
|
71:RAWKEY_G, //g
|
||||||
|
72:RAWKEY_H, //h
|
||||||
|
73:RAWKEY_I, //i
|
||||||
|
74:RAWKEY_J, //j
|
||||||
|
75:RAWKEY_K, //k
|
||||||
|
76:RAWKEY_L, //l
|
||||||
|
77:RAWKEY_M, //m
|
||||||
|
78:RAWKEY_N, //n
|
||||||
|
79:RAWKEY_O, //o
|
||||||
|
80:RAWKEY_P, //p
|
||||||
|
81:RAWKEY_Q, //q
|
||||||
|
82:RAWKEY_R, //r
|
||||||
|
83:RAWKEY_S, //s
|
||||||
|
84:RAWKEY_T, //t
|
||||||
|
85:RAWKEY_U, //u
|
||||||
|
86:RAWKEY_V, //v
|
||||||
|
87:RAWKEY_W, //w
|
||||||
|
88:RAWKEY_X, //x
|
||||||
|
89:RAWKEY_Z, //y
|
||||||
|
90:RAWKEY_Y, //z
|
||||||
|
91:RAWKEY_LAMIGA, //left window key
|
||||||
|
92:RAWKEY_RAMIGA, //right window key
|
||||||
|
93:RAWKEY_HELP, //select key
|
||||||
|
96:RAWKEY_KP_0, //numpad 0
|
||||||
|
97:RAWKEY_KP_1, //numpad 1
|
||||||
|
98:RAWKEY_KP_2, //numpad 2
|
||||||
|
99:RAWKEY_KP_3, //numpad 3
|
||||||
|
100:RAWKEY_KP_4, //numpad 4
|
||||||
|
101:RAWKEY_KP_5, //numpad 5
|
||||||
|
102:RAWKEY_KP_6, //numpad 6
|
||||||
|
103:RAWKEY_KP_7, //numpad 7
|
||||||
|
104:RAWKEY_KP_8, //numpad 8
|
||||||
|
105:RAWKEY_KP_9, //numpad 9
|
||||||
|
106:RAWKEY_KP_MULTIPLY, //multiply
|
||||||
|
107:RAWKEY_KP_PLUS, //add
|
||||||
|
109:RAWKEY_KP_MINUS, //subtract
|
||||||
|
110:RAWKEY_KP_DECIMAL, //decimal point
|
||||||
|
111:RAWKEY_KP_DIVIDE, //divide
|
||||||
|
112:RAWKEY_F1 , //f1
|
||||||
|
113:RAWKEY_F2 , //f2
|
||||||
|
114:RAWKEY_F3 , //f3
|
||||||
|
115:RAWKEY_F4 , //f4
|
||||||
|
116:RAWKEY_F5 , //f5
|
||||||
|
117:RAWKEY_F6 , //f6
|
||||||
|
118:RAWKEY_F7 , //f7
|
||||||
|
119:RAWKEY_F8 , //f8
|
||||||
|
120:RAWKEY_F9 , //f9
|
||||||
|
121:RAWKEY_F10, //f10
|
||||||
|
//122:RAWKEY_F11, //f11
|
||||||
|
//123:RAWKEY_F12, //f12
|
||||||
|
//144:RAWKEY_NUMLOCK, //num lock
|
||||||
|
//145:RAWKEY_SCRLOCK, //scroll lock
|
||||||
|
160:RAWKEY_TILDE,
|
||||||
|
163:RAWKEY_2B,
|
||||||
|
171:RAWKEY_RBRACKET,
|
||||||
|
173:RAWKEY_SLASH,
|
||||||
|
188:RAWKEY_COMMA,
|
||||||
|
190:RAWKEY_PERIOD,
|
||||||
|
192:RAWKEY_EQUAL
|
||||||
|
};
|
||||||
|
const MAXKEYS = 256;
|
||||||
|
const KEYBUFSIZE = 512;
|
||||||
|
|
||||||
|
var keyState = new Uint8Array(MAXKEYS);
|
||||||
|
var keyBuf = new Uint8Array(KEYBUFSIZE);
|
||||||
|
var state = 0;
|
||||||
|
var code = 0;
|
||||||
|
var first = 0, last = 0;
|
||||||
|
var capsLock = false;
|
||||||
|
|
||||||
|
var hsynccnt = 0;
|
||||||
|
this.lostsynccnt = 0;
|
||||||
|
|
||||||
|
//for (var k in KeyEvent) document.writeln('KeyEvent.' + k + ' = ' + KeyEvent[k]+'<br />'); //FF
|
||||||
|
for (var i = 0; i < MAXKEYS; i++) keyState[i] = false;
|
||||||
|
for (var i = 0; i < KEYBUFSIZE; i++) keyBuf[i] = 0;
|
||||||
|
|
||||||
|
function _onkeydown(e) { AMIGA.input.keyboard.handleKey(e, true); }
|
||||||
|
function _onkeyup(e) { AMIGA.input.keyboard.handleKey(e, false); }
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
/*document.onkeydown = function (e) {
|
||||||
|
AMIGA.input.keyboard.keydownup(e, true);
|
||||||
|
}
|
||||||
|
document.onkeyup = function (e) {
|
||||||
|
AMIGA.input.keyboard.keydownup(e, false);
|
||||||
|
}*/
|
||||||
|
window.document.addEventListener('keydown', _onkeydown, false);
|
||||||
|
window.document.addEventListener('keyup', _onkeyup, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
//BUG.info('Keyboard.cleanup()');
|
||||||
|
//document.onkeydown = null;
|
||||||
|
//document.onkeyup = null;
|
||||||
|
window.document.removeEventListener('keydown', _onkeydown, false);
|
||||||
|
window.document.removeEventListener('keyup', _onkeyup, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
for (var i = 0; i < MAXKEYS; i++) keyState[i] = false;
|
||||||
|
state = 0;
|
||||||
|
code = 0;
|
||||||
|
first = last = 0;
|
||||||
|
hsynccnt = 0;
|
||||||
|
this.lostsynccnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keysAvail = function() {
|
||||||
|
return first != last;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nextKey = function() {
|
||||||
|
//assert (first != last);
|
||||||
|
var key = keyBuf[last];
|
||||||
|
if (++last == KEYBUFSIZE) last = 0;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recordKey = function (kc) {
|
||||||
|
var next = first + 1;
|
||||||
|
|
||||||
|
if (next == KEYBUFSIZE) next = 0;
|
||||||
|
if (next == last) {
|
||||||
|
BUG.info('Keyboard() buffer overrun!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
keyBuf[first] = kc;
|
||||||
|
first = next;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processKey = function (code, down) {
|
||||||
|
/* Caps-lock */
|
||||||
|
if (code == 20) {
|
||||||
|
if (down) {
|
||||||
|
capsLock = !capsLock;
|
||||||
|
if (!capsLock) return;
|
||||||
|
} else {
|
||||||
|
if (capsLock) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* joystick emul */
|
||||||
|
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) {
|
||||||
|
var l,u,r,d,f1,f2;
|
||||||
|
switch (AMIGA.config.ports[0].move) {
|
||||||
|
case SAEV_Config_Ports_Move_Arrows: { l = 37; u = 38; r = 39; d = 40; break; }
|
||||||
|
case SAEV_Config_Ports_Move_Numpad: { l = 100; u = 104; r = 102; d = 101; break; }
|
||||||
|
case SAEV_Config_Ports_Move_WASD: { l = 65; u = 87; r = 68; d = 83; break; }
|
||||||
|
}
|
||||||
|
f1 = AMIGA.config.ports[0].fire[0];
|
||||||
|
f2 = AMIGA.config.ports[0].fire[1];
|
||||||
|
switch (code) {
|
||||||
|
case f1: { AMIGA.input.joystick[0].button[0] = down; break; }
|
||||||
|
case f2: { AMIGA.input.joystick[0].button[1] = down; break; }
|
||||||
|
case l: { AMIGA.input.joystick[0].state[0] = down; if (down && AMIGA.input.joystick[0].state[2]) AMIGA.input.joystick[0].state[2] = false; break; }
|
||||||
|
case u: { AMIGA.input.joystick[0].state[1] = down; if (down && AMIGA.input.joystick[0].state[3]) AMIGA.input.joystick[0].state[3] = false; break; }
|
||||||
|
case r: { AMIGA.input.joystick[0].state[2] = down; if (down && AMIGA.input.joystick[0].state[0]) AMIGA.input.joystick[0].state[0] = false; break; }
|
||||||
|
case d: { AMIGA.input.joystick[0].state[3] = down; if (down && AMIGA.input.joystick[0].state[1]) AMIGA.input.joystick[0].state[1] = false; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) {
|
||||||
|
var l,u,r,d,f1,f2;
|
||||||
|
switch (AMIGA.config.ports[1].move) {
|
||||||
|
case SAEV_Config_Ports_Move_Arrows: { l = 37; u = 38; r = 39; d = 40; break; }
|
||||||
|
case SAEV_Config_Ports_Move_Numpad: { l = 100; u = 104; r = 102; d = 101; break; }
|
||||||
|
case SAEV_Config_Ports_Move_WASD: { l = 65; u = 87; r = 68; d = 83; break; }
|
||||||
|
}
|
||||||
|
f1 = AMIGA.config.ports[1].fire[0];
|
||||||
|
f2 = AMIGA.config.ports[1].fire[1];
|
||||||
|
switch (code) {
|
||||||
|
case f1: { AMIGA.input.joystick[1].button[0] = down; break; }
|
||||||
|
case f2: { AMIGA.input.joystick[1].button[1] = down; break; }
|
||||||
|
case l: { AMIGA.input.joystick[1].state[0] = down; if (down && AMIGA.input.joystick[1].state[2]) AMIGA.input.joystick[1].state[2] = false; break; }
|
||||||
|
case u: { AMIGA.input.joystick[1].state[1] = down; if (down && AMIGA.input.joystick[1].state[3]) AMIGA.input.joystick[1].state[3] = false; break; }
|
||||||
|
case r: { AMIGA.input.joystick[1].state[2] = down; if (down && AMIGA.input.joystick[1].state[0]) AMIGA.input.joystick[1].state[0] = false; break; }
|
||||||
|
case d: { AMIGA.input.joystick[1].state[3] = down; if (down && AMIGA.input.joystick[1].state[1]) AMIGA.input.joystick[1].state[1] = false; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AMIGA.config.keyboard.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* map shift-keys (team17 pinball games) */
|
||||||
|
if (AMIGA.config.keyboard.mapShift) {
|
||||||
|
switch (code) {
|
||||||
|
case 37: { //left arrow
|
||||||
|
var rawkey = RAWKEY_LSHIFT;
|
||||||
|
if (!down) {
|
||||||
|
this.recordKey((rawkey << 1) | 1);
|
||||||
|
} else {
|
||||||
|
this.recordKey(rawkey << 1);
|
||||||
|
}
|
||||||
|
//break;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 39: { //right arrow
|
||||||
|
var rawkey = RAWKEY_RSHIFT;
|
||||||
|
if (!down) {
|
||||||
|
this.recordKey((rawkey << 1) | 1);
|
||||||
|
} else {
|
||||||
|
this.recordKey(rawkey << 1);
|
||||||
|
}
|
||||||
|
//break;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rawkey = false;
|
||||||
|
if (BrowserDetect.browser == 'Firefox') {
|
||||||
|
if (typeof(mozKeyCodeMap[code]) != 'undefined')
|
||||||
|
rawkey = mozKeyCodeMap[code];
|
||||||
|
} else {
|
||||||
|
if (typeof(defKeyCodeMap[code]) != 'undefined')
|
||||||
|
rawkey = defKeyCodeMap[code];
|
||||||
|
}
|
||||||
|
//BUG.info('Keyboard.processKey() code %d $%04x, rawkey $%04x', code, code, rawkey);
|
||||||
|
|
||||||
|
if (rawkey !== false) {
|
||||||
|
if (down)
|
||||||
|
this.recordKey(rawkey << 1);
|
||||||
|
else
|
||||||
|
this.recordKey((rawkey << 1) | 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleKey = function (e, down) {
|
||||||
|
e = e || window.event;
|
||||||
|
var code = e.which ? e.which : e.keyCode;
|
||||||
|
|
||||||
|
if (AMIGA.config.keyboard.enabled && code != 122 && code != 123) //all but F11 F12
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
//BUG.info('Keyboard.handleKey() down %d, code %d, alt %d, shift %d, ctrl %d', down?1:0, code, e.altKey?1:0, e.shiftKey?1:0, e.ctrlKey?1:0);
|
||||||
|
|
||||||
|
/* Ctrl-Alt fix */
|
||||||
|
if (!down && code == 17 && keyState[18]) {
|
||||||
|
keyState[18] = false;
|
||||||
|
this.processKey(18, keyState[18]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldstate = keyState[code];
|
||||||
|
if (down && !keyState[code]) {
|
||||||
|
keyState[code] = true;
|
||||||
|
}
|
||||||
|
else if (!down) {
|
||||||
|
keyState[code] = false;
|
||||||
|
}
|
||||||
|
if (keyState[code] != oldstate) {
|
||||||
|
this.processKey(code, keyState[code]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setCode = function (keycode) {
|
||||||
|
code = ~((keycode << 1) | (keycode >> 7)) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keyReq = function() {
|
||||||
|
this.lostsynccnt = 8 * AMIGA.events.maxvpos * 8; /* 8 frames * 8 bits */
|
||||||
|
|
||||||
|
AMIGA.cia.setICR(CIA_A, 8, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hsync = function() {
|
||||||
|
if ((this.keysAvail() || state < 3) && !this.lostsynccnt && ((++hsynccnt) & 15) == 0) {
|
||||||
|
switch (state) {
|
||||||
|
case 0:
|
||||||
|
code = 0;
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this.setCode(RAWKEY_INIT_POWER_UP);
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.setCode(RAWKEY_TERM_POWER_UP);
|
||||||
|
state++;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
code = ~this.nextKey() & 0xff;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.keyReq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vsync = function() {
|
||||||
|
if (this.lostsynccnt > 0) {
|
||||||
|
this.lostsynccnt -= AMIGA.events.maxvpos;
|
||||||
|
if (this.lostsynccnt <= 0) {
|
||||||
|
this.lostsynccnt = 0;
|
||||||
|
this.keyReq();
|
||||||
|
//BUG.info('Keyboard() lost sync');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Input() {
|
||||||
|
this.mouse = new Mouse();
|
||||||
|
this.joystick = new Array(2);
|
||||||
|
this.joystick[0] = new Joystick(SAEV_Config_Ports_Type_Joy0);
|
||||||
|
this.joystick[1] = new Joystick(SAEV_Config_Ports_Type_Joy1);
|
||||||
|
this.keyboard = new Keyboard();
|
||||||
|
|
||||||
|
var potgo = {
|
||||||
|
data: 0,
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
this.keyboard.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
this.keyboard.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reset = function() {
|
||||||
|
this.mouse.reset();
|
||||||
|
this.joystick[0].reset();
|
||||||
|
this.joystick[1].reset();
|
||||||
|
this.keyboard.reset();
|
||||||
|
potgo.data = 0;
|
||||||
|
potgo.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.POTGO = function (v) {
|
||||||
|
//BUG.info('Input.POTGO() $%04x', v);
|
||||||
|
potgo.data = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.POTGOR = function() {
|
||||||
|
var v = (potgo.data | (potgo.data << 1)) & 0xaa00;
|
||||||
|
v |= v >> 1;
|
||||||
|
|
||||||
|
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) {
|
||||||
|
if (this.mouse.button[2]) v &= 0xfbff;
|
||||||
|
if (this.mouse.button[1]) v &= 0xfeff;
|
||||||
|
} else if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) {
|
||||||
|
if (this.joystick[0].button[1]) v &= 0xfbff;
|
||||||
|
if (this.joystick[0].button[2]) v &= 0xfeff;
|
||||||
|
}
|
||||||
|
if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) {
|
||||||
|
if (this.joystick[1].button[1]) v &= 0xbfff;
|
||||||
|
if (this.joystick[1].button[2]) v &= 0xefff;
|
||||||
|
}
|
||||||
|
//BUG.info('Input.POTGOR() $%04x', v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.POT0DAT = function() {
|
||||||
|
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) {
|
||||||
|
if (this.mouse.button[2]) potgo.count = (potgo.count & 0xff00) | ((potgo.count + 1) & 0xff);
|
||||||
|
if (this.mouse.button[1]) potgo.count = (potgo.count + 0x100) & 0xffff;
|
||||||
|
}
|
||||||
|
//BUG.info('Input.POT0DAT() $%04x', v);
|
||||||
|
return potgo.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.POT1DAT = function() {
|
||||||
|
//BUG.info('Input.POT1DAT() NOT IMPLEMENTED');
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.JOY0DAT = function() {
|
||||||
|
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) {
|
||||||
|
this.mouse.update();
|
||||||
|
return this.mouse.pos;
|
||||||
|
} else if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) {
|
||||||
|
this.joystick[0].update();
|
||||||
|
return this.joystick[0].dir;
|
||||||
|
}
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.JOY1DAT = function() {
|
||||||
|
if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Mouse) {
|
||||||
|
this.mouse.update();
|
||||||
|
return this.mouse.pos;
|
||||||
|
} else if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) {
|
||||||
|
this.joystick[1].update();
|
||||||
|
return this.joystick[1].dir;
|
||||||
|
}
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.JOYTEST = function (v) {
|
||||||
|
//BUG.info('Input.JOYTEST() $%04x', v);
|
||||||
|
}
|
||||||
|
}
|
||||||
652
sae/memory.js
Normal file
652
sae/memory.js
Normal file
|
|
@ -0,0 +1,652 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
/*
|
||||||
|
0x0000 0000 2024.0 Chip RAM
|
||||||
|
0x00C0 0000 1536.0 Slow RAM
|
||||||
|
|
||||||
|
0x00F8 0000 256.0 256K System ROM (Kickstart 2.04 or higher)
|
||||||
|
0x00FC 0000 256.0 256K System ROM
|
||||||
|
|
||||||
|
0x00DF F000 4.0 Custom chip registers
|
||||||
|
0x00BF D000 3.8 8520-B (even-byte addresses)
|
||||||
|
0x00BF E001 3.8 8520-A (odd-byte addresses)
|
||||||
|
0x00DC 0000 64.0 Real time clock
|
||||||
|
|
||||||
|
0x00F0 0000 512.0 Reserved 512K System ROM (CDTV or CD³²)
|
||||||
|
0x00E0 0000 512.0 Reserved
|
||||||
|
0x00A0 0000 1984.0 Reserved
|
||||||
|
0x00D8 0000 256.0 Reserved
|
||||||
|
0x00DD 0000 188.0 Reserved
|
||||||
|
|
||||||
|
0x0020 0000 8192.0 Primary auto-config space (Fast RAM)
|
||||||
|
0x00E8 0000 64.0 Zorro II auto-config space (before relocation)
|
||||||
|
0x00E9 0000 448.0 Secondary auto-config space (usually 64K I/O boards)
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Memory() {
|
||||||
|
const NULL8 = 0xff;
|
||||||
|
const NULL16 = 0xffff;
|
||||||
|
const NULL32 = 0xffffffff;
|
||||||
|
|
||||||
|
this.chip = {
|
||||||
|
size: 0,
|
||||||
|
align: 0,
|
||||||
|
data: null,
|
||||||
|
lower: 0,
|
||||||
|
upper: 0,
|
||||||
|
};
|
||||||
|
this.slow = {
|
||||||
|
enabled: false,
|
||||||
|
size: 0,
|
||||||
|
align: 0,
|
||||||
|
data: null,
|
||||||
|
lower: 0x00C00000,
|
||||||
|
upper: 0
|
||||||
|
};
|
||||||
|
this.fast = {
|
||||||
|
enabled: false,
|
||||||
|
size: 0,
|
||||||
|
align: 0,
|
||||||
|
data: null,
|
||||||
|
lower: 0x00200000,
|
||||||
|
upper: 0
|
||||||
|
};
|
||||||
|
this.rom = {
|
||||||
|
size: 0,
|
||||||
|
align: 0,
|
||||||
|
data: null,
|
||||||
|
lower: 0xf80000,
|
||||||
|
upper: 0x1000000
|
||||||
|
};
|
||||||
|
this.res_d8 = {
|
||||||
|
size: 0x40000,
|
||||||
|
align: 0x20000,
|
||||||
|
data: null,
|
||||||
|
lower: 0x00D80000,
|
||||||
|
upper: 0x00DC0000
|
||||||
|
};
|
||||||
|
this.res_e0 = {
|
||||||
|
size: 0x80000,
|
||||||
|
align: 0x40000,
|
||||||
|
data: null,
|
||||||
|
lower: 0x00E00000,
|
||||||
|
upper: 0x00E80000
|
||||||
|
};
|
||||||
|
this.res_f0 = {
|
||||||
|
size: 0x80000,
|
||||||
|
align: 0x40000,
|
||||||
|
data: null,
|
||||||
|
lower: 0x00F00000,
|
||||||
|
upper: 0x00F80000
|
||||||
|
};
|
||||||
|
this.ac_z2 = {
|
||||||
|
size: 0x10000,
|
||||||
|
lower: 0x00E80000,
|
||||||
|
upper: 0x00E90000
|
||||||
|
};
|
||||||
|
this.aros = {
|
||||||
|
cached: false,
|
||||||
|
rom: '',
|
||||||
|
ext: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
function getChipSize(v) {
|
||||||
|
switch (v) {
|
||||||
|
case SAEV_Config_RAM_Chip_Size_256K: return 256 << 10;
|
||||||
|
case SAEV_Config_RAM_Chip_Size_512K: return 512 << 10;
|
||||||
|
case SAEV_Config_RAM_Chip_Size_1M: return 1024 << 10;
|
||||||
|
case SAEV_Config_RAM_Chip_Size_2M: return 2048 << 10;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSlowSize(v) {
|
||||||
|
switch (v) {
|
||||||
|
case SAEV_Config_RAM_Slow_Size_None: return 0;
|
||||||
|
case SAEV_Config_RAM_Slow_Size_256K: return 256 << 10;
|
||||||
|
case SAEV_Config_RAM_Slow_Size_512K: return 512 << 10;
|
||||||
|
case SAEV_Config_RAM_Slow_Size_1M: return 1024 << 10;
|
||||||
|
case SAEV_Config_RAM_Slow_Size_1536K: return 1536 << 10;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFastSize(v) {
|
||||||
|
switch (v) {
|
||||||
|
case SAEV_Config_RAM_Fast_Size_None: return 0;
|
||||||
|
case SAEV_Config_RAM_Fast_Size_512K: return 512 << 10;
|
||||||
|
case SAEV_Config_RAM_Fast_Size_1M: return 1024 << 10;
|
||||||
|
case SAEV_Config_RAM_Fast_Size_2M: return 2048 << 10;
|
||||||
|
case SAEV_Config_RAM_Fast_Size_4M: return 4096 << 10;
|
||||||
|
case SAEV_Config_RAM_Fast_Size_8M: return 8192 << 10;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getROMSize(v) {
|
||||||
|
switch (v) {
|
||||||
|
case SAEV_Config_ROM_Size_256K: return 256 << 10;
|
||||||
|
case SAEV_Config_ROM_Size_512K: return 512 << 10;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*function getEXTSize(v) {
|
||||||
|
switch (v) {
|
||||||
|
case SAEV_Config_EXT_Size_256K: return 256 << 10;
|
||||||
|
case SAEV_Config_EXT_Size_512K: return 512 << 10;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getEXTAddr(v) {
|
||||||
|
switch (v) {
|
||||||
|
case SAEV_Config_EXT_Addr_A0: return 0xa00000;
|
||||||
|
case SAEV_Config_EXT_Addr_E0: return 0xe00000;
|
||||||
|
case SAEV_Config_EXT_Addr_F0: return 0xf00000;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
this.chip.size = getChipSize(AMIGA.config.ram.chip.size);
|
||||||
|
this.chip.align = this.chip.size >>> 1;
|
||||||
|
this.chip.data = new Uint16Array(this.chip.align); for (var i = 0; i < this.chip.align; i++) this.chip.data[i] = 0;
|
||||||
|
this.chip.lower = 0;
|
||||||
|
this.chip.upper = this.chip.size;
|
||||||
|
|
||||||
|
if (AMIGA.config.ram.slow.size) {
|
||||||
|
this.slow.enabled = true;
|
||||||
|
this.slow.size = getSlowSize(AMIGA.config.ram.slow.size);
|
||||||
|
this.slow.align = this.slow.size >>> 1;
|
||||||
|
this.slow.data = new Uint16Array(this.slow.align); for (var i = 0; i < this.slow.align; i++) this.slow.data[i] = 0;
|
||||||
|
this.slow.upper = this.slow.lower + this.slow.size;
|
||||||
|
} else {
|
||||||
|
this.slow.enabled = false;
|
||||||
|
this.slow.size = 0;
|
||||||
|
this.slow.align = 0;
|
||||||
|
this.slow.data = null;
|
||||||
|
this.slow.upper = 0;
|
||||||
|
}
|
||||||
|
if (AMIGA.config.ram.fast.size) {
|
||||||
|
this.fast.enabled = true;
|
||||||
|
this.fast.size = getFastSize(AMIGA.config.ram.fast.size);
|
||||||
|
this.fast.align = this.fast.size >>> 1;
|
||||||
|
this.fast.data = new Uint16Array(this.fast.align); for (var i = 0; i < this.fast.align; i++) this.fast.data[i] = 0;
|
||||||
|
this.fast.upper = this.fast.lower + this.fast.size;
|
||||||
|
} else {
|
||||||
|
this.fast.enabled = false;
|
||||||
|
this.fast.size = 0;
|
||||||
|
this.fast.align = 0;
|
||||||
|
this.fast.data = null;
|
||||||
|
this.fast.upper = 0;
|
||||||
|
}
|
||||||
|
BUG.info('Memory.init() chip %d, slow %d, fast %d', this.chip.size >>> 10, this.slow.size >>> 10, this.fast.size >>> 10);
|
||||||
|
|
||||||
|
this.rom.size = getROMSize(AMIGA.config.rom.size);
|
||||||
|
this.rom.align = this.rom.size >>> 1;
|
||||||
|
this.rom.data = new Uint16Array(this.rom.align); for (var i = 0; i < this.rom.align; i++) this.rom.data[i] = 0;
|
||||||
|
|
||||||
|
this.res_d8.data = new Uint16Array(this.res_d8.align); for (var i = 0; i < this.res_d8.align; i++) this.res_d8.data[i] = 0;
|
||||||
|
this.res_e0.data = new Uint16Array(this.res_e0.align); for (var i = 0; i < this.res_e0.align; i++) this.res_e0.data[i] = 0;
|
||||||
|
this.res_f0.data = new Uint16Array(this.res_f0.align); for (var i = 0; i < this.res_f0.align; i++) this.res_f0.data[i] = 0;
|
||||||
|
|
||||||
|
AMIGA.mem.copy_rom(AMIGA.config.rom.data);
|
||||||
|
|
||||||
|
if (AMIGA.config.ext.size != SAEV_Config_EXT_Size_None) {
|
||||||
|
if (AMIGA.config.ext.addr == SAEV_Config_EXT_Addr_E0)
|
||||||
|
AMIGA.mem.copy_e0(AMIGA.config.ext.data);
|
||||||
|
else if (AMIGA.config.ext.addr == SAEV_Config_EXT_Addr_F0)
|
||||||
|
AMIGA.mem.copy_f0(AMIGA.config.ext.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (AMIGA.config.rom.mode == 1) {
|
||||||
|
if (!this.aros.cached) {
|
||||||
|
BUG.info('Memory.setup() AROS-ROM is not cached, downloading...');
|
||||||
|
AMIGA.loading += 2;
|
||||||
|
loadRemote('aros-amiga-m68k-rom.bin', 0xfc4635e1, function(data) {
|
||||||
|
AMIGA.mem.aros.cached = true;
|
||||||
|
AMIGA.mem.aros.rom = data;
|
||||||
|
AMIGA.mem.copy_rom(data);
|
||||||
|
AMIGA.loading--;
|
||||||
|
});
|
||||||
|
loadRemote('aros-amiga-m68k-ext.bin', 0xc612f82e, function(data) {
|
||||||
|
AMIGA.mem.aros.cached = true;
|
||||||
|
AMIGA.mem.aros.ext = data;
|
||||||
|
AMIGA.mem.copy_e0(data);
|
||||||
|
AMIGA.loading--;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
BUG.info('Memory.setup() AROS-ROM is cached, download skipped.');
|
||||||
|
this.copy_rom(this.aros.rom);
|
||||||
|
this.copy_e0(this.aros.ext);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AMIGA.loading++;
|
||||||
|
loadLocal('cfg_rom_name', function(event) {
|
||||||
|
AMIGA.mem.copy_rom(event.target.result);
|
||||||
|
AMIGA.loading--;
|
||||||
|
});
|
||||||
|
if (AMIGA.config.ext.size > 0) {
|
||||||
|
AMIGA.loading++;
|
||||||
|
loadLocal('cfg_ext_name', function(event) {
|
||||||
|
if (AMIGA.config.ext.addr == 0xe00000)
|
||||||
|
AMIGA.mem.copy_e0(event.target.result);
|
||||||
|
else
|
||||||
|
AMIGA.mem.copy_f0(event.target.result);
|
||||||
|
|
||||||
|
AMIGA.loading--;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load8 = function (addr) {
|
||||||
|
//BUG.info('Memory.load8() addr $%08x', addr);
|
||||||
|
|
||||||
|
if (addr >= 0x000000 && addr < this.chip.size) {
|
||||||
|
return (addr & 1) ? (this.chip.data[addr >>> 1] & 0xff) : (this.chip.data[addr >>> 1] >> 8);
|
||||||
|
}
|
||||||
|
else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper) {
|
||||||
|
return (addr & 1) ? (this.slow.data[(addr - this.slow.lower) >>> 1] & 0xff) : (this.slow.data[(addr - this.slow.lower) >>> 1] >> 8);
|
||||||
|
}
|
||||||
|
else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper) {
|
||||||
|
return (addr & 1) ? (this.fast.data[(addr - this.fast.lower) >>> 1] & 0xff) : (this.fast.data[(addr - this.fast.lower) >>> 1] >> 8);
|
||||||
|
}
|
||||||
|
else if (addr >= this.rom.lower && addr < this.rom.upper) {
|
||||||
|
return (addr & 1) ? (this.rom.data[(addr - this.rom.lower) >>> 1] & 0xff) : (this.rom.data[(addr - this.rom.lower) >>> 1] >> 8);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdff000 && addr < 0xe00000) {
|
||||||
|
return AMIGA.custom.load8(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfd000 && addr < 0xbfdf01) {
|
||||||
|
return AMIGA.cia.load8(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfe001 && addr < 0xbfef02) {
|
||||||
|
return AMIGA.cia.load8(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdc0000 && addr < 0xdd0000) {
|
||||||
|
return AMIGA.rtc.load8(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_e0.lower && addr < this.res_e0.upper) {
|
||||||
|
return (addr & 1) ? (this.res_e0.data[(addr - this.res_e0.lower) >>> 1] & 0xff) : (this.res_e0.data[(addr - this.res_e0.lower) >>> 1] >> 8);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_f0.lower && addr < this.res_f0.upper) {
|
||||||
|
return (addr & 1) ? (this.res_f0.data[(addr - this.res_f0.lower) >>> 1] & 0xff) : (this.res_f0.data[(addr - this.res_f0.lower) >>> 1] >> 8);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_d8.lower && addr < this.res_d8.upper) {
|
||||||
|
return (addr & 1) ? (this.res_d0.data[(addr - this.res_d0.lower) >>> 1] & 0xff) : (this.res_d0.data[(addr - this.res_d0.lower) >>> 1] >> 8);
|
||||||
|
}
|
||||||
|
else if (addr >= this.ac_z2.lower && addr < this.ac_z2.upper) {
|
||||||
|
return AMIGA.expansion.load8(addr);
|
||||||
|
}
|
||||||
|
//else BUG.info('Memory.load8() ILLEGAL MEMORY ACCESS addr $%08x', addr);
|
||||||
|
|
||||||
|
return NULL8;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load16 = function (addr) {
|
||||||
|
//BUG.info('Memory.load16() addr $%08x', addr);
|
||||||
|
|
||||||
|
if (addr >= 0 && addr < this.chip.size - 1) {
|
||||||
|
return this.chip.data[addr >>> 1];
|
||||||
|
}
|
||||||
|
else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 1) {
|
||||||
|
return this.slow.data[(addr - this.slow.lower) >>> 1];
|
||||||
|
}
|
||||||
|
else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 1) {
|
||||||
|
return this.fast.data[(addr - this.fast.lower) >>> 1];
|
||||||
|
}
|
||||||
|
else if (addr >= this.rom.lower && addr < this.rom.upper - 1) {
|
||||||
|
return this.rom.data[(addr - this.rom.lower) >>> 1];
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdff000 && addr < 0xe00000 - 1) {
|
||||||
|
return AMIGA.custom.load16(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 1) {
|
||||||
|
return AMIGA.cia.load16(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfe001 && addr < 0xbfef02 - 1) {
|
||||||
|
return AMIGA.cia.load16(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdc0000 && addr < 0xdd0000 - 1) {
|
||||||
|
return AMIGA.rtc.load16(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 1) {
|
||||||
|
return this.res_e0.data[(addr - this.res_e0.lower) >>> 1];
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 1) {
|
||||||
|
return this.res_f0.data[(addr - this.res_f0.lower) >>> 1];
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 1) {
|
||||||
|
return this.res_d0.data[(addr - this.res_d0.lower) >>> 1];
|
||||||
|
}
|
||||||
|
//else BUG.info('Memory.load16() ILLEGAL MEMORY ACCESS addr $%08x', addr);
|
||||||
|
|
||||||
|
return NULL16;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load32 = function (addr) {
|
||||||
|
//BUG.info('Memory.load32() addr $%08x', addr);
|
||||||
|
|
||||||
|
if (addr >= 0 && addr < this.chip.size - 3) {
|
||||||
|
addr >>>= 1;
|
||||||
|
return ((this.chip.data[addr] << 16) | this.chip.data[addr + 1]) >>> 0;
|
||||||
|
}
|
||||||
|
else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 3) {
|
||||||
|
addr = (addr - this.slow.lower) >>> 1;
|
||||||
|
return ((this.slow.data[addr] << 16) | this.slow.data[addr + 1]) >>> 0;
|
||||||
|
}
|
||||||
|
else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 3) {
|
||||||
|
addr = (addr - this.fast.lower) >>> 1;
|
||||||
|
return ((this.fast.data[addr] << 16) | this.fast.data[addr + 1]) >>> 0;
|
||||||
|
}
|
||||||
|
else if (addr >= this.rom.lower && addr < this.rom.upper - 3) {
|
||||||
|
addr = (addr - this.rom.lower) >>> 1;
|
||||||
|
return ((this.rom.data[addr] << 16) | this.rom.data[addr + 1]) >>> 0;
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdff000 && addr < 0xe00000 - 3) {
|
||||||
|
return AMIGA.custom.load32(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 3) {
|
||||||
|
return AMIGA.cia.load32(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfe001 && addr < 0xbfef02 - 3) {
|
||||||
|
return AMIGA.cia.load32(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdc0000 && addr < 0xdd0000 - 3) {
|
||||||
|
return AMIGA.rtc.load32(addr);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 3) {
|
||||||
|
addr = (addr - this.res_e0.lower) >>> 1;
|
||||||
|
return ((this.res_e0.data[addr] << 16) | this.res_e0.data[addr + 1]) >>> 0;
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 3) {
|
||||||
|
addr = (addr - this.res_f0.lower) >>> 1;
|
||||||
|
return ((this.res_f0.data[addr] << 16) | this.res_f0.data[addr + 1]) >>> 0;
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 3) {
|
||||||
|
addr = (addr - this.res_d0.lower) >>> 1;
|
||||||
|
return ((this.res_d0.data[addr] << 16) | this.res_d0.data[addr + 1]) >>> 0;
|
||||||
|
}
|
||||||
|
//else BUG.info('Memory.load32() ILLEGAL MEMORY ACCESS addr $%08x', addr);
|
||||||
|
|
||||||
|
return NULL32;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store8 = function (addr, value) {
|
||||||
|
//BUG.info('Memory.store8() addr $%08x, val $%02x', addr, value);
|
||||||
|
|
||||||
|
if (addr >= 0 && addr < this.chip.size) {
|
||||||
|
if (addr & 1) {
|
||||||
|
addr >>>= 1;
|
||||||
|
this.chip.data[addr] = (this.chip.data[addr] & 0xff00) | value;
|
||||||
|
} else {
|
||||||
|
addr >>>= 1;
|
||||||
|
this.chip.data[addr] = (value << 8) | (this.chip.data[addr] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper) {
|
||||||
|
if (addr & 1) {
|
||||||
|
addr = (addr - this.slow.lower) >>> 1;
|
||||||
|
this.slow.data[addr] = (this.slow.data[addr] & 0xff00) | value;
|
||||||
|
} else {
|
||||||
|
addr = (addr - this.slow.lower) >>> 1;
|
||||||
|
this.slow.data[addr] = (value << 8) | (this.slow.data[addr] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper) {
|
||||||
|
if (addr & 1) {
|
||||||
|
addr = (addr - this.fast.lower) >>> 1;
|
||||||
|
this.fast.data[addr] = (this.fast.data[addr] & 0xff00) | value;
|
||||||
|
} else {
|
||||||
|
addr = (addr - this.fast.lower) >>> 1;
|
||||||
|
this.fast.data[addr] = (value << 8) | (this.fast.data[addr] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdff000 && addr < 0xe00000) {
|
||||||
|
AMIGA.custom.store8(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfd000 && addr < 0xbfdf01) {
|
||||||
|
AMIGA.cia.store8(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfe001 && addr < 0xbfef02) {
|
||||||
|
AMIGA.cia.store8(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdc0000 && addr < 0xdd0000) {
|
||||||
|
AMIGA.rtc.store8(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_e0.lower && addr < this.res_e0.upper) {
|
||||||
|
if (addr & 1) {
|
||||||
|
addr = (addr - this.res_e0.lower) >>> 1;
|
||||||
|
this.res_e0.data[addr] = (this.res_e0.data[addr] & 0xff00) | value;
|
||||||
|
} else {
|
||||||
|
addr = (addr - this.res_e0.lower) >>> 1;
|
||||||
|
this.res_e0.data[addr] = (value << 8) | (this.res_e0.data[addr] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_f0.lower && addr < this.res_f0.upper) {
|
||||||
|
if (addr & 1) {
|
||||||
|
addr = (addr - this.res_f0.lower) >>> 1;
|
||||||
|
this.res_f0.data[addr] = (this.res_f0.data[addr] & 0xff00) | value;
|
||||||
|
} else {
|
||||||
|
addr = (addr - this.res_f0.lower) >>> 1;
|
||||||
|
this.res_f0.data[addr] = (value << 8) | (this.res_f0.data[addr] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_d8.lower && addr < this.res_d8.upper) {
|
||||||
|
if (addr & 1) {
|
||||||
|
addr = (addr - this.res_d0.lower) >>> 1;
|
||||||
|
this.res_d0.data[addr] = (this.res_d0.data[addr] & 0xff00) | value;
|
||||||
|
} else {
|
||||||
|
addr = (addr - this.res_d0.lower) >>> 1;
|
||||||
|
this.res_d0.data[addr] = (value << 8) | (this.res_d0.data[addr] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr >= this.ac_z2.lower && addr < this.ac_z2.upper) {
|
||||||
|
AMIGA.expansion.store8(addr, value);
|
||||||
|
}
|
||||||
|
//else BUG.info('Memory.store8() ILLEGAL MEMORY ACCESS addr $%08x, val %02x', addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store16 = function (addr, value) {
|
||||||
|
//BUG.info('Memory.store16() addr $%08x, val $%04x', addr, value);
|
||||||
|
|
||||||
|
if (addr >= 0 && addr < this.chip.size - 1) {
|
||||||
|
this.chip.data[addr >>> 1] = value;
|
||||||
|
}
|
||||||
|
else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 1) {
|
||||||
|
this.slow.data[(addr - this.slow.lower) >>> 1] = value;
|
||||||
|
}
|
||||||
|
else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 1) {
|
||||||
|
this.fast.data[(addr - this.fast.lower) >>> 1] = value;
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdff000 && addr < 0xe00000 - 1) {
|
||||||
|
AMIGA.custom.store16(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 1) {
|
||||||
|
AMIGA.cia.store16(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfe001 && addr < 0xbfef02 - 1) {
|
||||||
|
AMIGA.cia.store16(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdc0000 && addr < 0xdd0000 - 1) {
|
||||||
|
AMIGA.rtc.store16(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 1) {
|
||||||
|
this.res_e0.data[(addr - this.res_e0.lower) >>> 1] = value;
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 1) {
|
||||||
|
this.res_f0.data[(addr - this.res_f0.lower) >>> 1] = value;
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 1) {
|
||||||
|
this.res_d0.data[(addr - this.res_d0.lower) >>> 1] = value;
|
||||||
|
}
|
||||||
|
//else BUG.info('Memory.store16() ILLEGAL MEMORY ACCESS addr $%08x, val %04x', addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store32 = function (addr, value) {
|
||||||
|
//BUG.info('Memory.store32() addr $%08x, val $%08x', addr, value);
|
||||||
|
|
||||||
|
if (addr >= 0 && addr < this.chip.size - 3) {
|
||||||
|
addr >>>= 1;
|
||||||
|
this.chip.data[addr] = value >>> 16;
|
||||||
|
this.chip.data[addr + 1] = value & 0xffff;
|
||||||
|
}
|
||||||
|
else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 3) {
|
||||||
|
addr = (addr - this.slow.lower) >>> 1;
|
||||||
|
this.slow.data[addr] = value >>> 16;
|
||||||
|
this.slow.data[addr + 1] = value & 0xffff;
|
||||||
|
}
|
||||||
|
else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 3) {
|
||||||
|
addr = (addr - this.fast.lower) >>> 1;
|
||||||
|
this.fast.data[addr] = value >>> 16;
|
||||||
|
this.fast.data[addr + 1] = value & 0xffff;
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdff000 && addr < 0xe00000 - 3) {
|
||||||
|
AMIGA.custom.store32(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 3) {
|
||||||
|
AMIGA.cia.store32(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xbfe001 && addr < 0xbfef02 - 3) {
|
||||||
|
AMIGA.cia.store32(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= 0xdc0000 && addr < 0xdd0000 - 3) {
|
||||||
|
AMIGA.rtc.store32(addr, value);
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 3) {
|
||||||
|
addr = (addr - this.res_e0.lower) >>> 1;
|
||||||
|
this.res_e0.data[addr] = value >>> 16;
|
||||||
|
this.res_e0.data[addr + 1] = value & 0xffff;
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 3) {
|
||||||
|
addr = (addr - this.res_f0.lower) >>> 1;
|
||||||
|
this.res_f0.data[addr] = value >>> 16;
|
||||||
|
this.res_f0.data[addr + 1] = value & 0xffff;
|
||||||
|
}
|
||||||
|
else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 3) {
|
||||||
|
addr = (addr - this.res_d0.lower) >>> 1;
|
||||||
|
this.res_d0.data[addr] = value >>> 16;
|
||||||
|
this.res_d0.data[addr + 1] = value & 0xffff;
|
||||||
|
}
|
||||||
|
//else if (!(addr & 0xc80000)) BUG.info('Memory.store32() ILLEGAL MEMORY ACCESS addr $%08x, val %08x', addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.check16_chip = function (addr, size) {
|
||||||
|
return (addr >= 0 && addr + size < this.chip.size - 1);
|
||||||
|
}
|
||||||
|
/*this.load16_chip = function (addr) {
|
||||||
|
if (this.check16_chip(addr, 1)) {
|
||||||
|
var v = this.chip.data[addr >>> 1];
|
||||||
|
AMIGA.custom.last_value = v;
|
||||||
|
return v;
|
||||||
|
} else BUG.info('load16_chip() ILLEGAL MEMORY ACCESS addr %x', addr);
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
this.store16_chip = function (addr, value) {
|
||||||
|
if (this.check16_chip(addr, 1)) {
|
||||||
|
this.chip.data[addr >>> 1] = value;
|
||||||
|
AMIGA.custom.last_value = value;
|
||||||
|
} else BUG.info('store16_chip() ILLEGAL MEMORY ACCESS addr %x, value %x', addr, value);
|
||||||
|
}*/
|
||||||
|
this.load16_chip = function (addr) {
|
||||||
|
if (addr < this.chip.size - 1)
|
||||||
|
AMIGA.custom.last_value = this.chip.data[addr >>> 1];
|
||||||
|
else
|
||||||
|
AMIGA.custom.last_value = 0xffff;
|
||||||
|
|
||||||
|
return AMIGA.custom.last_value;
|
||||||
|
}
|
||||||
|
this.store16_chip = function (addr, value) {
|
||||||
|
if (addr < this.chip.size - 1)
|
||||||
|
this.chip.data[addr >>> 1] = AMIGA.custom.last_value = value;
|
||||||
|
else
|
||||||
|
AMIGA.custom.last_value = 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.copy_rom = function(data) {
|
||||||
|
//BUG.info('copyrom() size %d', data.length);
|
||||||
|
//BUG.info('copyrom() crc32 $%08x', crc32(data));
|
||||||
|
|
||||||
|
if (data.length == 0x80000) {
|
||||||
|
/*var lo = crc32(data.substr(0, 0x40000));
|
||||||
|
var hi = crc32(data.substr(0x40000, 0x80000));
|
||||||
|
if (lo != hi) {
|
||||||
|
BUG.info('copyrom() lo crc32 $%08x', lo);
|
||||||
|
BUG.info('copyrom() hi crc32 $%08x', hi);
|
||||||
|
}*/
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var v = data.charCodeAt(i) & 0xff;
|
||||||
|
if (i & 1) {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.rom.data[j] = (this.rom.data[j] & 0xff00) | v;
|
||||||
|
} else {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.rom.data[j] = (v << 8) | (this.rom.data[j] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.rom.lower = 0xf80000;
|
||||||
|
}
|
||||||
|
else if (data.length == 0x40000) {
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var v = data.charCodeAt(i) & 0xff;
|
||||||
|
if (i & 1) {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.rom.data[j] = (this.rom.data[j] & 0xff00) | v;
|
||||||
|
this.rom.data[0x20000 + j] = (this.rom.data[0x20000 + j] & 0xff00) | v;
|
||||||
|
} else {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.rom.data[j] = (v << 8) | (this.rom.data[j] & 0x00ff);
|
||||||
|
this.rom.data[0x20000 + j] = (v << 8) | (this.rom.data[0x20000 + j] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.rom.lower = 0xfc0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.copy_e0 = function(data) {
|
||||||
|
if (data.length <= 0x80000) {
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var v = data.charCodeAt(i) & 0xff;
|
||||||
|
if (i & 1) {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.res_e0.data[j] = (this.res_e0.data[j] & 0xff00) | v;
|
||||||
|
} else {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.res_e0.data[j] = (v << 8) | (this.res_e0.data[j] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.copy_f0 = function(data) {
|
||||||
|
if (data.length <= 0x80000) {
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var v = data.charCodeAt(i) & 0xff;
|
||||||
|
if (i & 1) {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.res_f0.data[j] = (this.res_f0.data[j] & 0xff00) | v;
|
||||||
|
} else {
|
||||||
|
var j = i >>> 1;
|
||||||
|
this.res_f0.data[j] = (v << 8) | (this.res_f0.data[j] & 0x00ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*this.mirror_rom_to_chipram = function() {
|
||||||
|
for (var i = 0; i < this.rom.size; i++)
|
||||||
|
this.chip.data[i] = this.rom.data[i];
|
||||||
|
|
||||||
|
if (this.ext.size > 0) {
|
||||||
|
for (var i = 0; i < this.ext.size; i++)
|
||||||
|
this.chip.data[this.rom.size + i] = this.ext.data[i];
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
1376
sae/playfield.js
Normal file
1376
sae/playfield.js
Normal file
File diff suppressed because it is too large
Load diff
191
sae/rtc.js
Normal file
191
sae/rtc.js
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function RTC() {
|
||||||
|
const RF5C01A_RAM_SIZE = 16;
|
||||||
|
|
||||||
|
var clock_control_d;
|
||||||
|
var clock_control_e;
|
||||||
|
var clock_control_f;
|
||||||
|
|
||||||
|
var rtc_memory = null;
|
||||||
|
var rtc_alarm = null;
|
||||||
|
|
||||||
|
this.read = function() {
|
||||||
|
/*struct zfile *f;
|
||||||
|
f = zfile_fopen (currprefs.flashfile, "rb", ZFD_NORMAL);
|
||||||
|
if (f) {
|
||||||
|
zfile_fread (rtc_memory, RF5C01A_RAM_SIZE, 1, f);
|
||||||
|
zfile_fread (rtc_alarm, RF5C01A_RAM_SIZE, 1, f);
|
||||||
|
zfile_fclose (f);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
this.write = function() {
|
||||||
|
/*struct zfile *f = zfile_fopen (currprefs.flashfile, L"rb+", ZFD_NORMAL);
|
||||||
|
if (!f) {
|
||||||
|
f = zfile_fopen (currprefs.flashfile, L"wb", 0);
|
||||||
|
if (f) {
|
||||||
|
zfile_fwrite (rtc_memory, RF5C01A_RAM_SIZE, 1, f);
|
||||||
|
zfile_fwrite (rtc_alarm, RF5C01A_RAM_SIZE, 1, f);
|
||||||
|
zfile_fclose (f);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zfile_fseek (f, 0, SEEK_END);
|
||||||
|
if (zfile_ftell (f) <= 2 * RF5C01A_RAM_SIZE) {
|
||||||
|
zfile_fseek (f, 0, SEEK_SET);
|
||||||
|
zfile_fwrite (rtc_memory, RF5C01A_RAM_SIZE, 1, f);
|
||||||
|
zfile_fwrite (rtc_alarm, RF5C01A_RAM_SIZE, 1, f);
|
||||||
|
}
|
||||||
|
zfile_fclose (f);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
BUG.info('RTC.setup() type ' + (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B ? 'MSM6242B' : 'RF5C01A'));
|
||||||
|
|
||||||
|
if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B) {
|
||||||
|
clock_control_d = 0x1;
|
||||||
|
clock_control_e = 0;
|
||||||
|
clock_control_f = 0x4; /* 24/12 */
|
||||||
|
} else if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_RF5C01A) {
|
||||||
|
clock_control_d = 0x4; /* Timer EN */
|
||||||
|
clock_control_e = 0;
|
||||||
|
clock_control_f = 0;
|
||||||
|
|
||||||
|
rtc_memory = new Uint8Array(RF5C01A_RAM_SIZE);
|
||||||
|
rtc_alarm = new Uint8Array(RF5C01A_RAM_SIZE);
|
||||||
|
|
||||||
|
for (var i = 0; i < RF5C01A_RAM_SIZE; i++)
|
||||||
|
rtc_memory[i] = rtc_alarm[i] = 0;
|
||||||
|
|
||||||
|
this.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load8 = function (addr) {
|
||||||
|
addr &= 0x3f;
|
||||||
|
if ((addr & 3) == 2 || (addr & 3) == 0 || AMIGA.config.rtc.type == SAEV_Config_RTC_Type_None) {
|
||||||
|
if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible)
|
||||||
|
return 0xff; //regs.irc >> 8;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
var t = new Date();
|
||||||
|
|
||||||
|
addr >>= 2;
|
||||||
|
if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B) {
|
||||||
|
switch (addr) {
|
||||||
|
case 0x0: return t.getSeconds() % 10;
|
||||||
|
case 0x1: return Math.floor(t.getSeconds() / 10);
|
||||||
|
case 0x2: return t.getMinutes() % 10;
|
||||||
|
case 0x3: return Math.floor(t.getMinutes() / 10);
|
||||||
|
case 0x4: return t.getHours() % 10;
|
||||||
|
case 0x5: return Math.floor(t.getHours() / 10);
|
||||||
|
case 0x6: return t.getDate() % 10;
|
||||||
|
case 0x7: return Math.floor(t.getDate() / 10);
|
||||||
|
case 0x8: return (t.getMonth() + 1) % 10;
|
||||||
|
case 0x9: return Math.floor((t.getMonth() + 1) / 10);
|
||||||
|
case 0xA: return (t.getFullYear() - 1900) % 10;
|
||||||
|
case 0xB: return Math.floor((t.getFullYear() - 1900) / 10);
|
||||||
|
case 0xC: return t.getDay();
|
||||||
|
case 0xD: return clock_control_d;
|
||||||
|
case 0xE: return clock_control_e;
|
||||||
|
case 0xF: return clock_control_f;
|
||||||
|
}
|
||||||
|
} else if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_RF5C01A) {
|
||||||
|
var bank = clock_control_d & 3;
|
||||||
|
|
||||||
|
if (bank >= 2 && addr < 0x0d) return (rtc_memory[addr] >> ((bank == 2) ? 0 : 4)) & 0x0f;
|
||||||
|
if (bank == 1 && addr < 0x0d) return rtc_alarm[addr];
|
||||||
|
|
||||||
|
switch (addr) {
|
||||||
|
case 0x0: return t.getSeconds() % 10;
|
||||||
|
case 0x1: return Math.floor(t.getSeconds() / 10);
|
||||||
|
case 0x2: return t.getMinutes() % 10;
|
||||||
|
case 0x3: return Math.floor(t.getMinutes() / 10);
|
||||||
|
case 0x4: return t.getHours() % 10;
|
||||||
|
case 0x5: return Math.floor(t.getHours() / 10);
|
||||||
|
case 0x6: return t.getDate() % 10;
|
||||||
|
case 0x7: return Math.floor(t.getDate() / 10);
|
||||||
|
case 0x8: return (t.getMonth() + 1) % 10;
|
||||||
|
case 0x9: return Math.floor((t.getMonth() + 1) / 10);
|
||||||
|
case 0xA: return (t.getFullYear() - 1900) % 10;
|
||||||
|
case 0xB: return Math.floor((t.getFullYear() - 1900) / 10);
|
||||||
|
case 0xC: return t.getDay();
|
||||||
|
case 0xD: return clock_control_d;
|
||||||
|
/* E and F = write-only */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load16 = function (addr) {
|
||||||
|
return (this.load8(addr) << 8) | this.load8(addr + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load32 = function (addr) {
|
||||||
|
return ((this.load16(addr) << 16) | this.load16(addr + 2)) >>> 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store8 = function (addr, value) {
|
||||||
|
addr &= 0x3f;
|
||||||
|
if ((addr & 1) != 1 || AMIGA.config.rtc.type == SAEV_Config_RTC_Type_None) return;
|
||||||
|
|
||||||
|
addr >>= 2;
|
||||||
|
value &= 0x0f;
|
||||||
|
if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B) {
|
||||||
|
switch (addr) {
|
||||||
|
case 0xD: clock_control_d = value & (1 | 8); break;
|
||||||
|
case 0xE: clock_control_e = value; break;
|
||||||
|
case 0xF: clock_control_f = value; break;
|
||||||
|
}
|
||||||
|
} else if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_RF5C01A) {
|
||||||
|
var bank = clock_control_d & 3;
|
||||||
|
|
||||||
|
if (bank >= 2 && addr < 0x0d) {
|
||||||
|
rtc_memory[addr] &= ((bank == 2) ? 0xf0 : 0x0f);
|
||||||
|
rtc_memory[addr] |= value << ((bank == 2) ? 0 : 4);
|
||||||
|
|
||||||
|
var ov = rtc_memory[addr];
|
||||||
|
if (rtc_memory[addr] != value) this.write();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bank == 1 && addr < 0x0d) {
|
||||||
|
rtc_alarm[addr] = value;
|
||||||
|
rtc_alarm[0] = rtc_alarm[1] = rtc_alarm[9] = rtc_alarm[12] = 0;
|
||||||
|
rtc_alarm[3] &= ~0x8;
|
||||||
|
rtc_alarm[5] &= ~0xc;
|
||||||
|
rtc_alarm[6] &= ~0x8;
|
||||||
|
rtc_alarm[8] &= ~0xc;
|
||||||
|
rtc_alarm[10] &= ~0xe;
|
||||||
|
rtc_alarm[11] &= ~0xc;
|
||||||
|
|
||||||
|
var ov = rtc_alarm[addr];
|
||||||
|
if (rtc_alarm[addr] != value) this.write();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (addr) {
|
||||||
|
case 0xD: clock_control_d = value; break;
|
||||||
|
case 0xE: clock_control_e = value; break;
|
||||||
|
case 0xF: clock_control_f = value; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store16 = function (addr, value) {
|
||||||
|
this.store8(addr, (value >> 8) & 0xff);
|
||||||
|
this.store8(addr + 1, value & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store32 = function (addr, value) {
|
||||||
|
this.store16(addr, (value >>> 16) & 0xffff);
|
||||||
|
this.store16(addr + 2, value & 0xffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
86
sae/serial.js
Normal file
86
sae/serial.js
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function Serial()
|
||||||
|
{
|
||||||
|
var buf = new Uint8Array(1024);
|
||||||
|
var pos = 0, dtr = false;
|
||||||
|
var serper = 0, serdat = 0x2000;
|
||||||
|
|
||||||
|
this.reset = function()
|
||||||
|
{
|
||||||
|
this.flushBuffer();
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
dtr = false;
|
||||||
|
serper = 0;
|
||||||
|
serdat = 0x2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.flushBuffer = function()
|
||||||
|
{
|
||||||
|
if (pos > 0) {
|
||||||
|
var str = ''
|
||||||
|
for (var i = 0; i < pos; i++) {
|
||||||
|
/*if (buf[i] == 13)
|
||||||
|
str += '<br/>';
|
||||||
|
else if (buf[i] == 9)
|
||||||
|
str += ' ';
|
||||||
|
else*/
|
||||||
|
str += String.fromCharCode(buf[i]);
|
||||||
|
}
|
||||||
|
pos = 0;
|
||||||
|
BUG.col = 3;
|
||||||
|
BUG.info(str);
|
||||||
|
BUG.col = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.readStatus = function()
|
||||||
|
{
|
||||||
|
//ciabpra |= 0x20; //Push up Carrier Detect line
|
||||||
|
//ciabpra |= 0x08; //DSR ON
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeStatus = function(old, nw)
|
||||||
|
{
|
||||||
|
if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00) dtr = true;
|
||||||
|
if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80) dtr = false;
|
||||||
|
//if ((old & 0x40) != (nw & 0x40)) BUG.info('RTS %s.', (nw & 0x40) == 0x40 ? 'set' : 'clr');
|
||||||
|
//if ((old & 0x10) != (nw & 0x10)) BUG.info('CTS %s.', (nw & 0x10) == 0x10 ? 'set' : 'clr');
|
||||||
|
return nw;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SERPER = function(v)
|
||||||
|
{
|
||||||
|
if (serper != v)
|
||||||
|
serper = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SERDAT = function(v)
|
||||||
|
{
|
||||||
|
//BUG.info('SERDAT $%04x', v);
|
||||||
|
|
||||||
|
if (AMIGA.config.serial.enabled) {
|
||||||
|
buf[pos++] = v & 0xff;
|
||||||
|
if (pos == 1024)
|
||||||
|
this.flushBuffer();
|
||||||
|
}
|
||||||
|
serdat |= 0x2000; /* Set TBE in the SERDATR ... */
|
||||||
|
AMIGA.intreq |= 1; /* ... and in INTREQ register */
|
||||||
|
}
|
||||||
|
|
||||||
|
this.SERDATR = function()
|
||||||
|
{
|
||||||
|
//BUG.info('SERDATR $%04x', serdat);
|
||||||
|
return serdat;
|
||||||
|
}
|
||||||
|
}
|
||||||
419
sae/utils.js
Normal file
419
sae/utils.js
Normal file
|
|
@ -0,0 +1,419 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/* moving average algorithm */
|
||||||
|
|
||||||
|
function mavg(size) {
|
||||||
|
this.values = new Array(size);
|
||||||
|
this.size = size;
|
||||||
|
this.usage = 0;
|
||||||
|
this.offset = 0;
|
||||||
|
this.average = 0;
|
||||||
|
|
||||||
|
this.clr = function() {
|
||||||
|
this.usage = 0;
|
||||||
|
this.offset = 0;
|
||||||
|
this.average = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set = function(newval) {
|
||||||
|
if (this.usage < this.size) {
|
||||||
|
this.values[this.usage++] = newval;
|
||||||
|
this.average += newval;
|
||||||
|
} else {
|
||||||
|
this.average -= this.values[this.offset];
|
||||||
|
this.values[this.offset] = newval;
|
||||||
|
this.average += newval;
|
||||||
|
if (++this.offset >= this.size)
|
||||||
|
this.offset -= this.size;
|
||||||
|
}
|
||||||
|
return Math.floor(this.average / this.usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*function crc32(str, crc) {
|
||||||
|
const tab =
|
||||||
|
'00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 '+
|
||||||
|
'0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 '+
|
||||||
|
'1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 '+
|
||||||
|
'136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 '+
|
||||||
|
'3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B '+
|
||||||
|
'35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 '+
|
||||||
|
'26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F '+
|
||||||
|
'2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D '+
|
||||||
|
'76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 '+
|
||||||
|
'7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 '+
|
||||||
|
'6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 '+
|
||||||
|
'65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 '+
|
||||||
|
'4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB '+
|
||||||
|
'4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 '+
|
||||||
|
'5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F '+
|
||||||
|
'5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD '+
|
||||||
|
'EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 '+
|
||||||
|
'E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 '+
|
||||||
|
'F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 '+
|
||||||
|
'FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 '+
|
||||||
|
'D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B '+
|
||||||
|
'D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 '+
|
||||||
|
'CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F '+
|
||||||
|
'C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D '+
|
||||||
|
'9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 '+
|
||||||
|
'95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 '+
|
||||||
|
'86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 '+
|
||||||
|
'88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 '+
|
||||||
|
'A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB '+
|
||||||
|
'AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 '+
|
||||||
|
'BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF '+
|
||||||
|
'B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D';
|
||||||
|
|
||||||
|
if (crc == window.undefined) crc = 0;
|
||||||
|
|
||||||
|
crc = crc ^ (-1);
|
||||||
|
for (var i = 0, len = str.length; i < len; i++)
|
||||||
|
crc = (crc >>> 8) ^ parseInt(tab.substr(((crc ^ str.charCodeAt(i)) & 0xff) * 9, 8), 16);
|
||||||
|
crc = crc ^ (-1);
|
||||||
|
|
||||||
|
return crc < 0 ? crc + 0x100000000 : crc;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/*
|
||||||
|
* Javascript sprintf
|
||||||
|
* http://www.webtoolkit.info/
|
||||||
|
*/
|
||||||
|
|
||||||
|
sprintfWrapper = {
|
||||||
|
init: function () {
|
||||||
|
if (typeof arguments == "undefined") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (arguments.length < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (typeof arguments[0] != "string") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (typeof RegExp == "undefined") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var string = arguments[0];
|
||||||
|
var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
|
||||||
|
var matches = new Array();
|
||||||
|
var strings = new Array();
|
||||||
|
var convCount = 0;
|
||||||
|
var stringPosStart = 0;
|
||||||
|
var stringPosEnd = 0;
|
||||||
|
var matchPosEnd = 0;
|
||||||
|
var newString = '';
|
||||||
|
var match = null;
|
||||||
|
|
||||||
|
while (match = exp.exec(string)) {
|
||||||
|
if (match[9]) {
|
||||||
|
convCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stringPosStart = matchPosEnd;
|
||||||
|
stringPosEnd = exp.lastIndex - match[0].length;
|
||||||
|
strings[strings.length] = string.substring(stringPosStart, stringPosEnd);
|
||||||
|
|
||||||
|
matchPosEnd = exp.lastIndex;
|
||||||
|
matches[matches.length] = {
|
||||||
|
match: match[0],
|
||||||
|
left: match[3] ? true : false,
|
||||||
|
sign: match[4] || '',
|
||||||
|
pad: match[5] || ' ',
|
||||||
|
min: match[6] || 0,
|
||||||
|
precision: match[8],
|
||||||
|
code: match[9] || '%',
|
||||||
|
negative: parseInt(arguments[convCount]) < 0 ? true : false,
|
||||||
|
argument: String(arguments[convCount])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
strings[strings.length] = string.substring(matchPosEnd);
|
||||||
|
|
||||||
|
if (matches.length == 0) {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
if ((arguments.length - 1) < convCount) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var code = null;
|
||||||
|
var match = null;
|
||||||
|
var i = null;
|
||||||
|
|
||||||
|
for (i = 0; i < matches.length; i++) {
|
||||||
|
|
||||||
|
if (matches[i].code == '%') {
|
||||||
|
substitution = '%'
|
||||||
|
} else if (matches[i].code == 'b') {
|
||||||
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2));
|
||||||
|
substitution = sprintfWrapper.convert(matches[i], true);
|
||||||
|
} else if (matches[i].code == 'c') {
|
||||||
|
matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument)))));
|
||||||
|
substitution = sprintfWrapper.convert(matches[i], true);
|
||||||
|
} else if (matches[i].code == 'd') {
|
||||||
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)));
|
||||||
|
substitution = sprintfWrapper.convert(matches[i]);
|
||||||
|
} else if (matches[i].code == 'f') {
|
||||||
|
matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6));
|
||||||
|
substitution = sprintfWrapper.convert(matches[i]);
|
||||||
|
} else if (matches[i].code == 'o') {
|
||||||
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8));
|
||||||
|
substitution = sprintfWrapper.convert(matches[i]);
|
||||||
|
} else if (matches[i].code == 's') {
|
||||||
|
matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length)
|
||||||
|
substitution = sprintfWrapper.convert(matches[i], true);
|
||||||
|
} else if (matches[i].code == 'x') {
|
||||||
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
|
||||||
|
substitution = sprintfWrapper.convert(matches[i]);
|
||||||
|
} else if (matches[i].code == 'X') {
|
||||||
|
matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
|
||||||
|
substitution = sprintfWrapper.convert(matches[i]).toUpperCase();
|
||||||
|
} else {
|
||||||
|
substitution = matches[i].match;
|
||||||
|
}
|
||||||
|
|
||||||
|
newString += strings[i];
|
||||||
|
newString += substitution;
|
||||||
|
|
||||||
|
}
|
||||||
|
newString += strings[i];
|
||||||
|
|
||||||
|
return newString;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
convert: function (match, nosign) {
|
||||||
|
if (nosign) {
|
||||||
|
match.sign = '';
|
||||||
|
} else {
|
||||||
|
match.sign = match.negative ? '-' : match.sign;
|
||||||
|
}
|
||||||
|
var l = match.min - match.argument.length + 1 - match.sign.length;
|
||||||
|
var pad = new Array(l < 0 ? 0 : l).join(match.pad);
|
||||||
|
if (!match.left) {
|
||||||
|
if (match.pad == "0" || nosign) {
|
||||||
|
return match.sign + pad + match.argument;
|
||||||
|
} else {
|
||||||
|
return pad + match.sign + match.argument;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (match.pad == "0" || nosign) {
|
||||||
|
return match.sign + match.argument + pad.replace(/0/g, ' ');
|
||||||
|
} else {
|
||||||
|
return match.sign + match.argument + pad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf = sprintfWrapper.init;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/*
|
||||||
|
* http://www.quirksmode.org/js/detect.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
var BrowserDetect = {
|
||||||
|
init: function () {
|
||||||
|
this.browser = this.searchString(this.dataBrowser) || 'An unknown browser';
|
||||||
|
this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || 'an unknown version';
|
||||||
|
this.OS = this.searchString(this.dataOS) || 'an unknown OS';
|
||||||
|
},
|
||||||
|
searchString: function (data) {
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var dataString = data[i].string;
|
||||||
|
var dataProp = data[i].prop;
|
||||||
|
this.versionSearchString = data[i].versionSearch || data[i].identity;
|
||||||
|
if (dataString) {
|
||||||
|
if (dataString.indexOf(data[i].subString) != -1) return data[i].identity;
|
||||||
|
} else if (dataProp) return data[i].identity;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
searchVersion: function (dataString) {
|
||||||
|
var index = dataString.indexOf(this.versionSearchString);
|
||||||
|
if (index == -1) return;
|
||||||
|
return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
|
||||||
|
},
|
||||||
|
dataBrowser: [{
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'Chrome',
|
||||||
|
identity: 'Chrome'
|
||||||
|
}, {
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'OmniWeb',
|
||||||
|
versionSearch: 'OmniWeb/',
|
||||||
|
identity: 'OmniWeb'
|
||||||
|
}, {
|
||||||
|
string: navigator.vendor,
|
||||||
|
subString: 'Apple',
|
||||||
|
identity: 'Safari',
|
||||||
|
versionSearch: 'Version'
|
||||||
|
}, {
|
||||||
|
prop: window.opera,
|
||||||
|
identity: 'Opera',
|
||||||
|
versionSearch: 'Version'
|
||||||
|
}, {
|
||||||
|
string: navigator.vendor,
|
||||||
|
subString: 'iCab',
|
||||||
|
identity: 'iCab'
|
||||||
|
}, {
|
||||||
|
string: navigator.vendor,
|
||||||
|
subString: 'KDE',
|
||||||
|
identity: 'Konqueror'
|
||||||
|
}, {
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'Firefox',
|
||||||
|
identity: 'Firefox'
|
||||||
|
}, {
|
||||||
|
string: navigator.vendor,
|
||||||
|
subString: 'Camino',
|
||||||
|
identity: 'Camino'
|
||||||
|
}, { // for newer Netscapes (6+)
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'Netscape',
|
||||||
|
identity: 'Netscape'
|
||||||
|
}, {
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'MSIE',
|
||||||
|
identity: 'Explorer',
|
||||||
|
versionSearch: 'MSIE'
|
||||||
|
}, {
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'Gecko',
|
||||||
|
identity: 'Mozilla',
|
||||||
|
versionSearch: 'rv'
|
||||||
|
}, { // for older Netscapes (4-)
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'Mozilla',
|
||||||
|
identity: 'Netscape',
|
||||||
|
versionSearch: 'Mozilla'
|
||||||
|
}],
|
||||||
|
dataOS: [{
|
||||||
|
string: navigator.platform,
|
||||||
|
subString: 'Win',
|
||||||
|
identity: 'Windows'
|
||||||
|
}, {
|
||||||
|
string: navigator.platform,
|
||||||
|
subString: 'Mac',
|
||||||
|
identity: 'Mac'
|
||||||
|
}, {
|
||||||
|
string: navigator.userAgent,
|
||||||
|
subString: 'iPhone',
|
||||||
|
identity: 'iPhone/iPod'
|
||||||
|
}, {
|
||||||
|
string: navigator.platform,
|
||||||
|
subString: 'Linux',
|
||||||
|
identity: 'Linux'
|
||||||
|
}]
|
||||||
|
|
||||||
|
};
|
||||||
|
BrowserDetect.init();
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
function dump(obj) {
|
||||||
|
var out = '';
|
||||||
|
if (obj) {
|
||||||
|
for (var i in obj) {
|
||||||
|
out += i + ': ' + obj[i] + '\n';
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
out = 'undefined';
|
||||||
|
|
||||||
|
alert(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
function FatalError(err, msg) {
|
||||||
|
this.error = err;
|
||||||
|
this.message = msg;
|
||||||
|
}
|
||||||
|
FatalError.prototype = new Error;
|
||||||
|
|
||||||
|
function Fatal(err, msg) {
|
||||||
|
//alert(str);
|
||||||
|
throw new FatalError(err, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*function SafeFatal(str) {
|
||||||
|
alert(str);
|
||||||
|
console.log(str);
|
||||||
|
//API_stop();
|
||||||
|
API({cmd:'stop'});
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*function loadLocal(id, callback) {
|
||||||
|
var e = document.getElementById(id).files[0];
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = callback;
|
||||||
|
reader.readAsBinaryString(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadRemote(file, crc, callback) {
|
||||||
|
//var url = 'http://'+window.location.hostname+'/'+file;
|
||||||
|
var url = file;
|
||||||
|
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.open('GET', url, true);
|
||||||
|
req.overrideMimeType('text\/plain; charset=x-user-defined');
|
||||||
|
req.onreadystatechange = function(e) {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status == 200) {
|
||||||
|
var newcrc = crc32(req.responseText, 0);
|
||||||
|
BUG.info('loadRemote() %s (length %d, crc32 $%08x)', file, req.responseText.length, newcrc);
|
||||||
|
if (newcrc == crc)
|
||||||
|
callback(req.responseText);
|
||||||
|
else
|
||||||
|
SafeFatal('Wrong checksum for file '+file);
|
||||||
|
} else
|
||||||
|
SafeFatal('Can\'t download file '+file+' (http status: '+req.status+')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.send(null);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
function Debug() {
|
||||||
|
this.col = 1;
|
||||||
|
this.on = 1;
|
||||||
|
|
||||||
|
this.say = function (str) {
|
||||||
|
if (this.on) {
|
||||||
|
/*var e = document.createElement('span');
|
||||||
|
e.style.color = this.col == 1 ? '#888' : (this.col == 2 ? '#448' : '#484');
|
||||||
|
e.innerHTML = buf;
|
||||||
|
this.debug.appendChild(e);
|
||||||
|
this.debug.appendChild(document.createElement('br'));
|
||||||
|
this.debug.scrollTop = this.debug.scrollHeight;*/
|
||||||
|
|
||||||
|
console.log(str);
|
||||||
|
/*console.info(str);
|
||||||
|
console.warn(str);
|
||||||
|
console.error(str);
|
||||||
|
console.assert(str);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.info = function () {
|
||||||
|
if (this.on) {
|
||||||
|
var str = sprintf.apply(this, arguments);
|
||||||
|
console.log(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
245
sae/video.js
Normal file
245
sae/video.js
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* SAE - Scripted Amiga Emulator
|
||||||
|
*
|
||||||
|
* https://github.com/naTmeg/ScriptedAmigaEmulator
|
||||||
|
*
|
||||||
|
* ©2012 Rupert Hausberger
|
||||||
|
* Commercial use is prohibited.
|
||||||
|
*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
function Vide0() {
|
||||||
|
const vertexShader =
|
||||||
|
'attribute vec2 a_position;'+
|
||||||
|
'attribute vec2 a_texCoord;'+
|
||||||
|
'uniform vec2 u_resolution;'+
|
||||||
|
'varying vec2 v_texCoord;'+
|
||||||
|
'void main() {'+
|
||||||
|
'vec2 zeroToOne = a_position / u_resolution;'+
|
||||||
|
'vec2 zeroToTwo = zeroToOne * 2.0;'+
|
||||||
|
'vec2 clipSpace = zeroToTwo - 1.0;'+
|
||||||
|
'gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);'+
|
||||||
|
'v_texCoord = a_texCoord;'+
|
||||||
|
'}';
|
||||||
|
const fragmentShader =
|
||||||
|
'precision mediump float;'+
|
||||||
|
'uniform sampler2D u_image;'+
|
||||||
|
'varying vec2 v_texCoord;'+
|
||||||
|
'void main() {'+
|
||||||
|
'gl_FragColor = texture2D(u_image, v_texCoord);'+
|
||||||
|
'}';
|
||||||
|
const glParams = {
|
||||||
|
alpha: false,
|
||||||
|
stencil: false,
|
||||||
|
antialias: false
|
||||||
|
};
|
||||||
|
|
||||||
|
var width = 0;
|
||||||
|
var height = 0;
|
||||||
|
var size = 0;
|
||||||
|
var pixels = null;
|
||||||
|
|
||||||
|
var div = null;
|
||||||
|
var canvas = null;
|
||||||
|
var gl = null;
|
||||||
|
var video = null;
|
||||||
|
var open = false;
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
function getShader(gl, id) {
|
||||||
|
var shader, source;
|
||||||
|
|
||||||
|
if (id == 'vertex') {
|
||||||
|
shader = gl.createShader(gl.VERTEX_SHADER);
|
||||||
|
source = vertexShader;
|
||||||
|
} else if (id == 'fragment') {
|
||||||
|
shader = gl.createShader(gl.FRAGMENT_SHADER);
|
||||||
|
source = fragmentShader;
|
||||||
|
}
|
||||||
|
gl.shaderSource(shader, source);
|
||||||
|
gl.compileShader(shader);
|
||||||
|
|
||||||
|
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
|
||||||
|
Fatal(SAEE_Video_Shader_Error, gl.getShaderInfoLog(shader));
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initGL() {
|
||||||
|
var vertexShader = getShader(gl, 'vertex');
|
||||||
|
var fragmentShader = getShader(gl, 'fragment');
|
||||||
|
var program = gl.createProgram();
|
||||||
|
gl.attachShader(program, vertexShader);
|
||||||
|
gl.attachShader(program, fragmentShader);
|
||||||
|
gl.linkProgram(program);
|
||||||
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
|
||||||
|
Fatal(SAEE_Video_Shader_Error, 'Can\'t initialise the shaders for WebGL.');
|
||||||
|
|
||||||
|
gl.useProgram(program);
|
||||||
|
|
||||||
|
var positionLocation = gl.getAttribLocation(program, "a_position");
|
||||||
|
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
|
||||||
|
|
||||||
|
var texCoordBuffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||||
|
0.0, 0.0,
|
||||||
|
1.0, 0.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
1.0, 0.0,
|
||||||
|
1.0, 1.0]), gl.STATIC_DRAW);
|
||||||
|
gl.enableVertexAttribArray(texCoordLocation);
|
||||||
|
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
|
||||||
|
var texture = gl.createTexture();
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
|
||||||
|
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
|
||||||
|
gl.uniform2f(resolutionLocation, width, height);
|
||||||
|
|
||||||
|
var buffer = gl.createBuffer();
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||||
|
gl.enableVertexAttribArray(positionLocation);
|
||||||
|
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
|
||||||
|
gl.viewport(0, 0, width, height);
|
||||||
|
gl.clearColor(0, 0, 0, 1);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
gl.colorMask(true, true, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setup = function() {
|
||||||
|
if (!AMIGA.config.video.enabled) return;
|
||||||
|
if (open) this.cleanup();
|
||||||
|
|
||||||
|
width = AMIGA.config.video.scale ? VIDEO_WIDTH << 1 : VIDEO_WIDTH;
|
||||||
|
height = AMIGA.config.video.scale ? VIDEO_HEIGHT << 1 : VIDEO_WIDTH;
|
||||||
|
size = width * height;
|
||||||
|
//BUG.info('Video.init() %d x %d, %s mode', width, height, AMIGA.config.video.ntsc ? 'ntsc' : 'pal');
|
||||||
|
|
||||||
|
div = document.getElementById(AMIGA.config.video.id);
|
||||||
|
if (!div)
|
||||||
|
Fatal(SAEE_Video_ID_Not_Found, 'Video DIV-element not found. Check your code. (Malformed-DIV-name: '+AMIGA.config.video.id+')');
|
||||||
|
|
||||||
|
if ((canvas = document.createElement('canvas'))) {
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
} else {
|
||||||
|
if (confirm('Can\'t create a CANVAS-element. Continue without video-playback?'))
|
||||||
|
AMIGA.config.video.enabled = false;
|
||||||
|
else
|
||||||
|
Fatal(SAEE_Video_Canvas_Not_Supported, 'Can\'t create a CANVAS-element. Please update the browser.');
|
||||||
|
}
|
||||||
|
if (AMIGA.config.video.enabled) {
|
||||||
|
if ((gl = canvas.getContext('experimental-webgl', glParams) || canvas.getContext('webgl', glParams)))
|
||||||
|
initGL();
|
||||||
|
else
|
||||||
|
if (confirm('Can\'t initialise WebGL. Continue without video-playback?'))
|
||||||
|
AMIGA.config.video.enabled = false;
|
||||||
|
else
|
||||||
|
Fatal(SAEE_Video_WebGL_Not_Avail, 'Can\'t initialise WebGL. Is WebGL enabled in the browser-config?');
|
||||||
|
}
|
||||||
|
if (AMIGA.config.video.enabled) {
|
||||||
|
pixels = new Uint16Array(size);
|
||||||
|
for (var i = 0; i < size; i++) pixels[i] = 0;
|
||||||
|
}
|
||||||
|
if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) {
|
||||||
|
canvas.onmousedown = function(e) { AMIGA.input.mouse.mousedown(e); }
|
||||||
|
canvas.onmouseup = function(e) { AMIGA.input.mouse.mouseup(e); }
|
||||||
|
canvas.onmouseover = function(e) { AMIGA.input.mouse.mouseover(e); }
|
||||||
|
canvas.onmouseout = function(e) { AMIGA.input.mouse.mouseout(e); }
|
||||||
|
canvas.onmousemove = function(e) { AMIGA.input.mouse.mousemove(e); }
|
||||||
|
}
|
||||||
|
canvas.oncontextmenu = function() { return false; }
|
||||||
|
|
||||||
|
video = document.createElement('div');
|
||||||
|
video.style.width = width + 'px';
|
||||||
|
video.style.height = height + 'px';
|
||||||
|
video.style.margin = 'auto';
|
||||||
|
video.style.webkitTouchCallout = 'none';
|
||||||
|
video.style.webkitUserSelect = 'none';
|
||||||
|
video.style.khtmlUserSelect = 'none';
|
||||||
|
video.style.mozUserSelect = 'none';
|
||||||
|
video.style.msUserSelect = 'none';
|
||||||
|
video.style.userSelect = 'none';
|
||||||
|
video.appendChild(canvas);
|
||||||
|
div.appendChild(video);
|
||||||
|
open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
if (open) {
|
||||||
|
div.removeChild(video);
|
||||||
|
canvas = null;
|
||||||
|
pixels = null;
|
||||||
|
video = null;
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------*/
|
||||||
|
|
||||||
|
this.hideCursor = function(hide) {
|
||||||
|
canvas.style.cursor = hide ? 'none' : 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clear_pixels = function () {
|
||||||
|
for (var i = 0; i < size; i++)
|
||||||
|
pixels[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.drawpixel = function (x, y, rgb) {
|
||||||
|
pixels[y * width + x] = rgb;
|
||||||
|
}
|
||||||
|
this.draw2pixel = function (x, y, rgb) {
|
||||||
|
var ptr = y * width + x;
|
||||||
|
pixels[ptr] = pixels[ptr + 1] = rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.drawline = function (y, rgb) {
|
||||||
|
var ptr = y * width;
|
||||||
|
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
pixels[ptr++] = rgb;
|
||||||
|
}
|
||||||
|
this.drawline_from_to = function (x1, x2, y, rgb) {
|
||||||
|
var ptr = y * width + x1;
|
||||||
|
|
||||||
|
for (var i = 0; i < x2 - x1; i++)
|
||||||
|
pixels[ptr++] = rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.draw = function (rgb, scalex, scaley, colorOnly) {
|
||||||
|
var r = 0.0625 * (((rgb >> 11) & 31) >> 1);
|
||||||
|
var g = 0.0625 * (((rgb >> 5) & 63) >> 2);
|
||||||
|
var b = 0.0625 * ((rgb & 31) >> 1);
|
||||||
|
|
||||||
|
gl.viewport(0, 0, width, height);
|
||||||
|
gl.clearColor(r, g, b, 1);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
if (!colorOnly) {
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_SHORT_5_6_5, pixels);
|
||||||
|
|
||||||
|
var s = AMIGA.config.video.scale ? 1 : 0;
|
||||||
|
var x1 = 0;
|
||||||
|
//var x2 = 0 + (width << (scalex ? (s+1) : s));
|
||||||
|
var x2 = 0 + (width << s);
|
||||||
|
var y1 = 0;
|
||||||
|
var y2 = 0 + (height << (scaley ? (s+1) : s));
|
||||||
|
//var y2 = 0 + (height << s);
|
||||||
|
|
||||||
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||||
|
x1, y1, x2, y1, x1, y2,
|
||||||
|
x1, y2, x2, y1, x2, y2]), gl.STATIC_DRAW);
|
||||||
|
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue