Cleanup and refactoring.

This commit is contained in:
Will Scullin 2016-11-21 21:17:34 -08:00
parent 1dfbc0b61b
commit f9f0239d86
40 changed files with 4487 additions and 3964 deletions

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.js]
indent_size = 4
[*.md]
trim_trailing_whitespace = true

25
.eslintrc.json Normal file
View File

@ -0,0 +1,25 @@
{
"rules": {
"indent": [
2,
4
],
"quotes": [
2,
"single"
],
"linebreak-style": [
2,
"unix"
],
"semi": [
2,
"always"
]
},
"env": {
"browser": true,
"jquery": true
},
"extends": "eslint:recommended"
}

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
<!-- Copyright 2010 Will Scullin -->
<!-- Copyright 2010-2016 Will Scullin -->
<html>
<head>
<base href="/apple" />
@ -10,17 +10,17 @@
<link rel="stylesheet" type="text/css" href="css/apple2.css" />
<title>About Apple ][js/Apple //jse</title>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-19205057-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<meta property="og:title" content="About Apple ][js" />
<meta property="og:type" content="website" />
@ -35,7 +35,7 @@
</div>
<div style="max-width: 800px; margin: auto">
<h2>What is this?</h2>
<span class="motter"><a href="../apple2/">Apple ][js</a></span> and
<span class="motter"><a href="../apple2/">Apple ][js</a></span> and
<span class="motter"><a href="../apple//e">Apple //jse</a></span>
are Apple ][ and Apple //e emulators written entirely in JavaScript
and HTML5.
@ -45,10 +45,10 @@
I now simulate having a 1 Megabyte RAMFactor card in slot 2.
<li><h3>Thunderclock Emulation (//jse)</h3>
There is cursory emulation of the Thunderclock card, enough
to keep ProDOS applications from asking you to enter the date
to keep ProDOS applications from asking you to enter the date
all the time. ProDOS attempts to guess the year from the month,
the day and the day of the week, something that needs to be
patched every 6 years. This means newer versions think it's 1996,
patched every 6 years. This means newer versions think it's 1996,
older versions are stuck in the 80s.
<li><h3>Firefox Nightly Joystick Support</h3>
Joystick support has yet to officially land, but the latest
@ -95,7 +95,7 @@
score.
</li>
<li><h3>Competition</h3>
Now in addition to
Now in addition to
<a href="http://www.megidish.net/apple2js/">Gil Megidish's</a>
Apple2JS, there's a couple of new kids on the block, including
<a href="http://porkrind.org/a2/">David Caldwell's</a> Apple II+
@ -157,7 +157,7 @@
<a href="http://jqueryui.com">jQuery UI</a>
</li>
<li>
Base64 Utilities via
Base64 Utilities via
<a href="http://kevin.vanzonneveld.net/">KvZ</a>
</li>
<li>
@ -173,7 +173,7 @@
<i>Beneath Apple DOS</i>
</a>
by Don Worth and Pieter Lechner
</li>
</li>
<li>
<i>Inside the Apple //e</i> by Gary B. Little
</li>
@ -224,7 +224,7 @@
realized there was, in fact, another apple2js in the world.
</li>
</ul>
</li>
</li>
<h2>Contact</h2>
<ul>
<li>

View File

@ -1,6 +1,6 @@
<!DOCTYPE html><!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
<!--
Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
@ -50,6 +50,7 @@
<script type="text/javascript" src="js/langcard.js"></script>
<script type="text/javascript" src="js/fpbasic.js"></script>
<script type="text/javascript" src="js/apple2char.js"></script>
<script type="text/javascript" src="js/applesoft/decompiler.js"></script>
<script type="text/javascript" src="js/canvas2.js"></script>
<script type="text/javascript" src="js/apple2io.js"></script>
<script type="text/javascript" src="js/parallel.js"></script>
@ -66,772 +67,8 @@
<!-- Disk Index -->
<script type="text/javascript" src="json/disks/index.js"></script>
<script type="text/javascript">
<script type="text/javascript" src="js/main2.js"></script>
var kHz = 1023;
var focused = false;
var startTime = Date.now();
var lastCycles = 0;
var frames = 0, lastFrames = 0;
var paused = false;
var sound = true;
var hashtag;
var disk_categories = {'Local Saves': []};
var disk_sets = {}
var disk_cur_name = [];
var disk_cur_cat = [];
function DriveLights()
{
return {
driveLight: function(drive, on) {
$("#disk" + drive).css("background-image",
on ? "url(css/red-on-16.png)" :
"url(css/red-off-16.png)");
},
dirty: function(drive, dirty) {
},
label: function(drive, label) {
$("#disklabel" + drive).text(label);
}
}
}
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
var _saveDrive = 1;
var _loadDrive = 1;
function openLoad(drive, event)
{
_loadDrive = drive;
if (disk_cur_cat[drive]) {
$("#category_select").val(disk_cur_cat[drive]).change();
}
$("#load").dialog("open");
}
function openSave(drive, event)
{
_saveDrive = drive;
$("#save_name").val($("#disklabel" + drive).text());
$("#save").dialog("open");
}
var loading = false;
function loadAjax(url) {
loading = true;
$("#loading").dialog("open");
$.ajax({ url: url,
cache: false,
dataType: "jsonp",
jsonp: false,
global: false
});
}
function doLoad() {
var urls = $("#disk_select").val(), url;
if (urls && urls.length) {
if (typeof(urls) == "string") {
url = urls;
} else {
url = urls[0];
}
}
var files = $("#local_file").prop("files");
if (files.length == 1) {
doLoadLocal();
} else if (url) {
var filename;
$("#load").dialog("close");
if (url.substr(0,6) == "local:") {
filename = url.substr(6);
if (filename == "__manage") {
openManage();
} else {
loadLocalStorage(_loadDrive, filename);
}
} else {
var r1 = /json\/disks\/(.*).json$/.exec(url);
if (r1 && _loadDrive == 1) {
filename = r1[1];
document.location.hash = filename;
}
loadAjax(url);
}
}
}
function doSave() {
var name = $("#save_name").val();
saveLocalStorage(_saveDrive, name);
$("#save").dialog("close");
}
function doDelete(name) {
if (confirm("Delete " + name + "?")) {
deleteLocalStorage(name);
}
}
function doLoadLocal() {
var files = $("#local_file").prop("files")
if (files.length == 1) {
var file = files[0];
var parts = file.name.split(".");
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
doLoadLocalTape(file);
} else {
alert('Unknown file type: ' + ext);
$("#load").dialog("close");
}
}
}
function doLoadLocalDisk(file) {
var fileReader = new FileReader();
fileReader.onload = function(event) {
var parts = file.name.split(".");
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
$("#disklabel" + _saveDrive).text(name);
$("#load").dialog("close");
initGamepad();
}
}
fileReader.readAsArrayBuffer(file);
}
function doLoadLocalTape(file) {
// Audio Buffer Source
if (typeof webkitAudioContext != "undefined") {
var context = new webkitAudioContext();
} else {
alert("Not supported by your browser");
$("#load").dialog("close");
return;
}
var fileReader = new FileReader();
fileReader.onload = function(ev) {
context.decodeAudioData(ev.target.result, function(buffer) {
var buf = [];
var data = buffer.getChannelData(0), datum = data[0];
var old = (datum > 0.0), current;
var last = 0, delta, ival;
debug('Sample Count: ' + data.length);
debug('Sample rate: ' + buffer.sampleRate);
for (var idx = 1; idx < data.length; idx++) {
datum = data[idx];
if ((datum > 0.1) || (datum < -0.1)) {
current = (datum > 0.0);
if (current != old) {
delta = idx - last;
if (delta > 2000000) {
delta = 2000000;
}
ival = delta / buffer.sampleRate * 1000;
if (ival >= 0.550 && ival < 0.750) {
ival = 0.650; // Header
} else if (ival >= 0.175 && ival < 0.225) {
ival = 0.200; // sync 1
} else if (ival >= 0.225 && ival < 0.275) {
ival = 0.250; // 0 / sync 2
} else if (ival >= 0.450 && ival < 0.550) {
ival = 0.500; // 1
} else {
// debug(idx + ' ' + buf.length + ' ' + ival);
}
buf.push(parseInt(ival * kHz));
old = current;
last = idx;
}
}
}
io.setTape(buf);
$("#load").dialog("close");
});
};
fileReader.readAsArrayBuffer(file);
}
function openManage() {
$("#manage").dialog("open");
}
function loadHTTP(url) {
loading = true;
$("#loading").dialog("open");
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(event) {
var parts = url.split(/[\/\.]/);
var name = decodeURIComponent(parts[parts.length - 2]);
var ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
$("#disklabel" + _saveDrive).text(name);
$("#loading").dialog("close");
loading = false;
}
}
req.send(null);
}
var prefs = new Prefs();
var runTimer = null;
var cpu = new CPU6502();
var ram1 = new RAM(0x00, 0x03),
ram2 = new RAM(0x0C, 0x1F),
ram3 = new RAM(0x60, 0xBF);
var hgr = new HiresPage(1);
var hgr2 = new HiresPage(2);
var gr = new LoresPage(1);
var gr2 = new LoresPage(2);
var rom = new Apple2ROM();
var vm = new VideoModes(gr, hgr, gr2, hgr2);
var mmu = {
auxRom: function(slot, rom) {
cpu.addPageHandler(rom);
}
};
var drivelights = new DriveLights();
var io = new Apple2IO(cpu, vm);
var keyboard = new KeyBoard(io);
var parallel = new Parallel(io, new Printer(), 1);
var disk2 = new DiskII(io, drivelights, 6);
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
var clock = new Thunderclock(mmu, io, 7);
var lc = new LanguageCard(io, rom);
cpu.addPageHandler(ram1);
cpu.addPageHandler(gr);
cpu.addPageHandler(gr2);
cpu.addPageHandler(ram2);
cpu.addPageHandler(hgr);
cpu.addPageHandler(hgr2);
cpu.addPageHandler(ram3);
cpu.addPageHandler(lc);
cpu.addPageHandler(io);
cpu.addPageHandler(parallel);
cpu.addPageHandler(slinky);
cpu.addPageHandler(disk2);
cpu.addPageHandler(clock);
var showFPS = false;
function updateKHz() {
var now = Date.now();
var ms = now - startTime;
var cycles = cpu.cycles();
var delta;
if (showFPS) {
delta = frames - lastFrames;
var fps = parseInt(delta/(ms/1000), 10);
$("#khz").html( fps + "fps");
} else {
delta = cycles - lastCycles;
khz = parseInt(delta/ms);
$("#khz").html( khz + "KHz");
}
startTime = now;
lastCycles = cycles;
lastFrames = frames;
}
/* Audio Handling */
initAudio(io);
function updateSound()
{
enableSound($("#enable_sound").attr("checked"));
}
function dumpDisk(drive) {
var wind = window.open("", "_blank");
wind.document.title = $("#disklabel" + drive).text();
wind.document.write("<pre>");
wind.document.write(disk2.getJSON(drive, true));
wind.document.write("</pre>");
wind.document.close();
}
function step()
{
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
cpu.step(function() {
debug(cpu.dumpRegisters());
debug(cpu.dumpPC());
});
}
var running = false;
var accelerated = false;
function updateSpeed()
{
accelerated = $("#accelerator_toggle").prop("checked");
kHz = accelerated ? 4092 : 1023;
io.updateHz(kHz * 1000);
if (runTimer) {
run();
}
}
var _requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function run(pc) {
if (runTimer) {
clearInterval(runTimer);
}
if (pc) {
cpu.setPC(pc);
}
var ival = 30;
var now, last = Date.now();
var runFn = function() {
now = Date.now();
frames++;
var step = (now - last) * kHz, stepMax = kHz * ival;
last = now;
if (step > stepMax) {
step = stepMax;
}
if (document.location.hash != hashtag) {
hashtag = document.location.hash;
filename = hup()
if (filename) {
if (filename.indexOf("://") > 0) {
loadHTTP(disk);
} else {
loadAjax("json/disks/" + filename + ".json");
}
}
}
if (!loading) {
running = true;
cpu.stepCycles(step);
running = false;
vm.blit();
io.sampleTick();
}
processGamepad(io);
if (!paused && _requestAnimationFrame) {
_requestAnimationFrame(runFn);
}
};
if (_requestAnimationFrame) {
_requestAnimationFrame(runFn);
} else {
runTimer = setInterval(runFn, ival);
}
}
function stop() {
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
}
function reset()
{
cpu.reset();
}
function loadBinary(bin) {
stop();
for (var idx = 0; idx < bin.length; idx++) {
var pos = bin.start + idx;
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
}
run(bin.start);
}
function selectCategory(event) {
$("#disk_select").empty();
var cat = disk_categories[$("#category_select").val()];
if (cat) {
for (var idx = 0; idx < cat.length; idx++) {
var file = cat[idx], name = file.name;
if (file.disk) {
name += " - " + file.disk;
}
var option = $("<option />").val(file.filename).text(name)
.appendTo("#disk_select");
if (disk_cur_name[_loadDrive] == name) {
option.attr("selected", "selected");
}
}
}
}
function selectDisk(event) {
// Maybe display some info.
}
function clickDisk(event) {
doLoad();
}
function loadDisk(data) {
var name = data.name;
var category = data.category;
if (data.disk) {
name += " - " + data.disk;
}
disk_cur_cat[_loadDrive] = category;
disk_cur_name[_loadDrive] = name;
$("#disklabel" + _loadDrive).text(name);
disk2.setDisk(_loadDrive, data);
initGamepad(data.gamepad);
}
function loadJSON(data) {
if (data.type == "binary") {
loadBinary(data);
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
loadDisk(data);
}
initGamepad(data.gamepad);
$("#loading").dialog("close");
loading = false;
}
/*
* LocalStorage Disk Storage
*/
function updateLocalStorage() {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
var names = [], name, cat;
for (name in diskIndex) {
if (diskIndex.hasOwnProperty(name)) {
names.push(name);
}
}
cat = disk_categories['Local Saves'] = [];
$("#manage").empty();
names.forEach(function(name) {
cat.push({'category': 'Local Saves',
'name': name,
'filename': 'local:' + name});
$("#manage").append("<span class='local_save'>" +
name +
" <a href='#' onclick='doDelete(\"" +
name +
"\")'>Delete</a><br /></span>");
});
cat.push({'category': 'Local Saves',
'name': 'Manage Saves...',
'filename': 'local:__manage'});
}
function saveLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
var json = disk2.getJSON(drive);
diskIndex[name] = json;
window.localStorage.diskIndex = JSON.stringify(diskIndex);
window.alert("Saved");
drivelights.label(drive, name);
drivelights.dirty(drive, false);
updateLocalStorage();
}
function deleteLocalStorage(name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
if (diskIndex[name]) {
delete diskIndex[name];
window.alert("Deleted");
}
window.localStorage.diskIndex = JSON.stringify(diskIndex);
updateLocalStorage();
}
function loadLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
if (diskIndex[name]) {
disk2.setJSON(drive, diskIndex[name]);
drivelights.label(drive, name);
drivelights.dirty(drive, false);
}
}
/*
* Keyboard/Gamepad routines
*/
var _key;
function _keydown(evt) {
if (evt.keyCode === 112) { // F1 - Reset
cpu.reset();
} else if (evt.keyCode === 113) { // F2 - Full Screen
var elem = document.getElementById("screen");
if (document.webkitCancelFullScreen) {
if (document.webkitIsFullScreen) {
document.webkitCancelFullScreen();
} else {
if (Element.ALLOW_KEYBOARD_INPUT) {
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
} else {
elem.webkitRequestFullScreen();
}
}
} else if (document.mozCancelFullScreen) {
if (document.mozIsFullScreen) {
document.mozCancelFullScreen();
} else {
elem.mozRequestFullScreen();
}
}
} else if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(true);
io.buttonDown(2);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(true);
} else if (!focused && (!evt.metaKey || evt.ctrlKey)) {
evt.preventDefault();
var key = keyboard.mapKeyEvent(evt);
if (key != 0xff) {
io.keyDown(key);
_key = key;
}
}
}
function _keyup(evt) {
_key = 0xff;
if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(false);
io.buttonUp(2);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(false);
} else {
if (!focused) {
io.keyUp();
}
}
}
function updateScreen() {
var green = $("#green_screen").prop("checked");
scanlines = $("#show_scanlines").prop("checked");
vm.green(green);
}
var flipX = false;
var flipY = false;
var swapXY = false;
function updateJoystick() {
flipX = $("#flip_x").prop("checked");
flipY = $("#flip_y").prop("checked");
swapXY = $("#swap_x_y").prop("checked");
}
function _mousemove(evt) {
if (gamepad) {
return;
}
var s = $("#screen");
var offset = s.offset();
var x = (evt.pageX - offset.left) / s.width(),
y = (evt.pageY - offset.top) / s.height(),
z = x;
if (swapXY) {
x = y;
y = z;
}
io.paddle(0, flipX ? 1 - x : x);
io.paddle(1, flipY ? 1 - y : y);
}
var paused = false;
function pauseRun(b) {
if (paused) {
run();
b.value = "Pause";
} else {
stop();
b.value = "Run";
}
paused = !paused;
}
$(function() {
hashtag = document.location.hash;
$("button,input[type=button],a.button").button().focus(function() {
// Crazy hack required by Chrome
var self = this;
window.setTimeout(function() {
self.blur();
}, 1)
});
var canvas = document.getElementById("screen");
var context = canvas.getContext('2d');
vm.setContext(context);
/*
* Input Handling
*/
$(window).keydown(_keydown);
$(window).keyup(_keyup);
$("canvas").mousedown(function(evt) {
if (!gamepad) {
io.buttonDown(evt.which == 1 ? 0 : 1);
}
evt.preventDefault();
})
.mouseup(function(evt) {
if (!gamepad) {
io.buttonUp(evt.which == 1 ? 0 : 1);
}
})
.bind("contextmenu", function(e) { e.preventDefault(); });
$('body').mousemove(_mousemove);
$("input,textarea").focus(function() { focused = true; });
$("input,textarea").blur(function() { focused = false; });
keyboard.create($("#keyboard"));
if (prefs.havePrefs()) {
$("input[type=checkbox]").each(function() {
var val = prefs.readPref(this.id);
if (val != null)
this.checked = JSON.parse(val);
});
$("input[type=checkbox]").change(function() {
prefs.writePref(this.id, JSON.stringify(this.checked));
});
}
reset();
run();
setInterval(updateKHz, 1000);
updateSound();
updateScreen();
updateSpeed();
var cancel = function() { $(this).dialog("close"); };
$("#loading").dialog({ autoOpen: false, modal: true });
$("#options").dialog({ autoOpen: false,
modal: true,
width: 320,
height: 400,
buttons: {"Close": cancel }});
$("#load").dialog({ autoOpen: false,
modal: true,
width: 540,
buttons: {"Cancel": cancel, "Load": doLoad }});
$("#save").dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {"Cancel": cancel, "Save": doSave }});
$("#manage").dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {"Close": cancel }});
if (window.localStorage !== undefined) {
$("button.disksave").show();
}
var oldcat = "";
for (var idx = 0; idx < disk_index.length; idx++) {
var file = disk_index[idx];
var cat = file.category;
var name = file.name, disk = file.disk;
if (cat != oldcat) {
$("<option />").val(cat).text(cat).appendTo("#category_select");
disk_categories[cat] = [];
oldcat = cat;
}
disk_categories[cat].push(file);
if (disk) {
if (!disk_sets[name]) {
disk_sets[name] = []
}
disk_sets[name].push(file);
}
}
$("<option/>").text("Local Saves").appendTo("#category_select");
updateLocalStorage();
initGamepad();
// Check for disks in hashtag
var filename = gup("disk") || hup();
if (filename) {
if (filename.indexOf("://") > 0) {
loadHTTP(filename);
} else {
loadAjax("json/disks/" + filename + ".json");
}
}
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
$("select").removeAttr("multiple").css("height", "auto");
}
});
</script>
</head>
<body>
<div style="margin: auto; width: 604px">

View File

@ -1,6 +1,6 @@
<!DOCTYPE html><!-- -*- mode: HTML; indent-tabs-mode: nil -*- -->
<!--
Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
@ -51,6 +51,7 @@
<script type="text/javascript" src="js/apple2e.js"></script>
<script type="text/javascript" src="js/apple2e-enhanced.js"></script>
<script type="text/javascript" src="js/apple2echar.js"></script>
<script type="text/javascript" src="js/applesoft/decompiler.js"></script>
<script type="text/javascript" src="js/canvas2e.js"></script>
<script type="text/javascript" src="js/slot3.js"></script>
<script type="text/javascript" src="js/apple2io.js"></script>
@ -68,774 +69,7 @@
<!-- Disk Index -->
<script type="text/javascript" src="json/disks/index.js"></script>
<script type="text/javascript">
var enhanced = true;
var focused = false;
var startTime = Date.now();
var lastCycles = 0;
var frames = 0, lastFrames = 0;
var paused = false;
var sound = true;
var hashtag;
var disk_categories = {'Local Saves': []};
var disk_sets = {}
var disk_cur_name = [];
var disk_cur_cat = [];
function DriveLights()
{
return {
driveLight: function(drive, on) {
$("#disk" + drive).css("background-image",
on ? "url(css/red-on-16.png)" :
"url(css/red-off-16.png)");
},
dirty: function(drive, dirty) {
},
label: function(drive, label) {
$("#disklabel" + drive).text(label);
}
}
}
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
var _saveDrive = 1;
var _loadDrive = 1;
function openLoad(drive, event)
{
_loadDrive = drive;
if (disk_cur_cat[drive]) {
$("#category_select").val(disk_cur_cat[drive]).change();
}
$("#load").dialog("open");
}
function openSave(drive, event)
{
_saveDrive = drive;
$("#save_name").val($("#disklabel" + drive).text());
$("#save").dialog("open");
}
var loading = false;
function loadAjax(url) {
loading = true;
$("#loading").dialog("open");
$.ajax({ url: url,
cache: false,
dataType: "jsonp",
jsonp: false,
global: false
});
}
function doLoad() {
var urls = $("#disk_select").val(), url;
if (urls && urls.length) {
if (typeof(urls) == "string") {
url = urls;
} else {
url = urls[0];
}
}
var files = $("#local_file").prop("files");
if (files.length == 1) {
doLoadLocal();
} else if (url) {
var filename;
$("#load").dialog("close");
if (url.substr(0,6) == "local:") {
filename = url.substr(6);
if (filename == "__manage") {
openManage();
} else {
loadLocalStorage(_loadDrive, filename);
}
} else {
var r1 = /json\/disks\/(.*).json$/.exec(url);
if (r1 && _loadDrive == 1) {
filename = r1[1];
document.location.hash = filename;
}
loadAjax(url);
}
}
}
function doSave() {
var name = $("#save_name").val();
saveLocalStorage(_saveDrive, name);
$("#save").dialog("close");
}
function doDelete(name) {
if (confirm("Delete " + name + "?")) {
deleteLocalStorage(name);
}
}
function doLoadLocal() {
var files = $("#local_file").prop("files")
if (files.length == 1) {
var file = files[0];
var parts = file.name.split(".");
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
doLoadLocalTape(file);
} else {
alert('Unknown file type: ' + ext);
$("#load").dialog("close");
}
}
}
function doLoadLocalDisk(file) {
var fileReader = new FileReader();
fileReader.onload = function(event) {
var parts = file.name.split(".");
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
$("#disklabel" + _saveDrive).text(name);
$("#load").dialog("close");
initGamepad();
}
}
fileReader.readAsArrayBuffer(file);
}
function doLoadLocalTape(file) {
// Audio Buffer Source
if (typeof webkitAudioContext != "undefined") {
var context = new webkitAudioContext();
} else {
alert("Not supported by your browser");
$("#load").dialog("close");
return;
}
var fileReader = new FileReader();
fileReader.onload = function(ev) {
context.decodeAudioData(ev.target.result, function(buffer) {
var buf = [];
var data = buffer.getChannelData(0), datum = data[0];
var old = (datum > 0.0), current;
var last = 0, delta, ival;
debug('Sample Count: ' + data.length);
debug('Sample rate: ' + buffer.sampleRate);
for (var idx = 1; idx < data.length; idx++) {
datum = data[idx];
if ((datum > 0.1) || (datum < -0.1)) {
current = (datum > 0.0);
if (current != old) {
delta = idx - last;
if (delta > 2000000) {
delta = 2000000;
}
ival = delta / buffer.sampleRate * 1000;
if (ival >= 0.550 && ival < 0.750) {
ival = 0.650; // Header
} else if (ival >= 0.175 && ival < 0.225) {
ival = 0.200; // sync 1
} else if (ival >= 0.225 && ival < 0.275) {
ival = 0.250; // 0 / sync 2
} else if (ival >= 0.450 && ival < 0.550) {
ival = 0.500; // 1
} else {
// debug(idx + ' ' + buf.length + ' ' + ival);
}
buf.push(parseInt(ival * kHz));
old = current;
last = idx;
}
}
}
io.setTape(buf);
$("#load").dialog("close");
});
};
fileReader.readAsArrayBuffer(file);
}
function openManage() {
$("#manage").dialog("open");
}
function loadHTTP(url) {
loading = true;
$("#loading").dialog("open");
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(event) {
var parts = url.split(/[\/\.]/);
var name = decodeURIComponent(parts[parts.length - 2]);
var ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
$("#disklabel" + _saveDrive).text(name);
$("#loading").dialog("close");
loading = false;
}
}
req.send(null);
}
var prefs = new Prefs();
var runTimer = null;
var cpu = new CPU6502({"65C02": enhanced});
var hgr = new HiresPage(1);
var hgr2 = new HiresPage(2);
var gr = new LoresPage(1);
var gr2 = new LoresPage(2);
var rom;
if (enhanced) {
rom = new Apple2eEnhancedROM();
} else {
rom = new Apple2eROM();
}
var vm = new VideoModes(gr, hgr, gr2, hgr2);
var drivelights = new DriveLights();
var io = new Apple2IO(cpu, vm);
var keyboard = new KeyBoard(io);
var mmu = new MMU(cpu, gr, gr2, hgr, hgr2, io, rom);
var parallel = new Parallel(io, new Printer(), 1);
var disk2 = new DiskII(io, drivelights, 6);
var slot3 = new Slot3(mmu, rom);
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
var clock = new Thunderclock(mmu, io, 7);
mmu.addSlot(1, parallel);
mmu.addSlot(2, slinky);
mmu.addSlot(3, slot3);
mmu.addSlot(6, disk2);
mmu.addSlot(7, clock);
cpu.addPageHandler(mmu);
var showFPS = false;
function updateKHz() {
var now = Date.now();
var ms = now - startTime;
var cycles = cpu.cycles();
var delta;
if (showFPS) {
delta = frames - lastFrames;
var fps = parseInt(delta/(ms/1000), 10);
$("#khz").html( fps + "fps");
} else {
delta = cycles - lastCycles;
khz = parseInt(delta/ms);
$("#khz").html( khz + "KHz");
}
startTime = now;
lastCycles = cycles;
lastFrames = frames;
}
/* Audio Handling */
initAudio(io);
function updateSound()
{
enableSound($("#enable_sound").attr("checked"));
}
function dumpDisk(drive) {
var wind = window.open("", "_blank");
wind.document.title = $("#disklabel" + drive).text();
wind.document.write("<pre>");
wind.document.write(disk2.getJSON(drive, true));
wind.document.write("</pre>");
wind.document.close();
}
function step()
{
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
cpu.step(function() {
debug(cpu.dumpRegisters());
debug(cpu.dumpPC());
});
}
var running = false;
var accelerated = false;
function updateSpeed()
{
accelerated = $("#accelerator_toggle").prop("checked");
kHz = accelerated ? 4092 : 1023;
io.updateHz(kHz * 1000);
if (runTimer) {
run();
}
}
var _requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function run(pc) {
if (runTimer) {
clearInterval(runTimer);
}
if (pc) {
cpu.setPC(pc);
}
var ival = 30;
var now, last = Date.now();
var runFn = function() {
now = Date.now();
frames++;
var step = (now - last) * kHz, stepMax = kHz * ival;
last = now;
if (step > stepMax) {
step = stepMax;
}
if (document.location.hash != hashtag) {
hashtag = document.location.hash;
filename = hup()
if (filename) {
if (filename.indexOf("://") > 0) {
loadHTTP(disk);
} else {
loadAjax("json/disks/" + filename + ".json");
}
}
}
if (!loading) {
mmu.resetVB();
running = true;
cpu.stepCycles(step);
running = false;
vm.blit();
io.sampleTick();
}
processGamepad(io);
if (!paused && _requestAnimationFrame) {
_requestAnimationFrame(runFn);
}
};
if (_requestAnimationFrame) {
_requestAnimationFrame(runFn);
} else {
runTimer = setInterval(runFn, ival);
}
}
function stop() {
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
}
function reset()
{
cpu.reset();
}
function loadBinary(bin) {
stop();
for (var idx = 0; idx < bin.length; idx++) {
var pos = bin.start + idx;
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
}
run(bin.start);
}
function selectCategory(event) {
$("#disk_select").empty();
var cat = disk_categories[$("#category_select").val()];
if (cat) {
for (var idx = 0; idx < cat.length; idx++) {
var file = cat[idx], name = file.name;
if (file.disk) {
name += " - " + file.disk;
}
var option = $("<option />").val(file.filename).text(name)
.appendTo("#disk_select");
if (disk_cur_name[_loadDrive] == name) {
option.attr("selected", "selected");
}
}
}
}
function selectDisk(event) {
// Maybe display some info.
}
function clickDisk(event) {
doLoad();
}
function loadDisk(data) {
var name = data.name;
var category = data.category;
if (data.disk) {
name += " - " + data.disk;
}
disk_cur_cat[_loadDrive] = category;
disk_cur_name[_loadDrive] = name;
$("#disklabel" + _loadDrive).text(name);
disk2.setDisk(_loadDrive, data);
initGamepad(data.gamepad);
}
function loadJSON(data) {
if (data.type == "binary") {
loadBinary(data);
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
loadDisk(data);
}
initGamepad(data.gamepad);
$("#loading").dialog("close");
loading = false;
}
/*
* LocalStorage Disk Storage
*/
function updateLocalStorage() {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
var names = [], name, cat;
for (name in diskIndex) {
if (diskIndex.hasOwnProperty(name)) {
names.push(name);
}
}
cat = disk_categories['Local Saves'] = [];
$("#manage").empty();
names.forEach(function(name) {
cat.push({'category': 'Local Saves',
'name': name,
'filename': 'local:' + name});
$("#manage").append("<span class='local_save'>" +
name +
" <a href='#' onclick='doDelete(\"" +
name +
"\")'>Delete</a><br /></span>");
});
cat.push({'category': 'Local Saves',
'name': 'Manage Saves...',
'filename': 'local:__manage'});
}
function saveLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
var json = disk2.getJSON(drive);
diskIndex[name] = json;
window.localStorage.diskIndex = JSON.stringify(diskIndex);
window.alert("Saved");
drivelights.label(drive, name);
drivelights.dirty(drive, false);
updateLocalStorage();
}
function deleteLocalStorage(name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
if (diskIndex[name]) {
delete diskIndex[name];
window.alert("Deleted");
}
window.localStorage.diskIndex = JSON.stringify(diskIndex);
updateLocalStorage();
}
function loadLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || "{}");
if (diskIndex[name]) {
disk2.setJSON(drive, diskIndex[name]);
drivelights.label(drive, name);
drivelights.dirty(drive, false);
}
}
/*
* Keyboard/Gamepad routines
*/
var _key;
function _keydown(evt) {
if (evt.keyCode === 112) { // F1 - Reset
cpu.reset();
} else if (evt.keyCode === 113) { // F2 - Full Screen
var elem = document.getElementById("screen");
if (document.webkitCancelFullScreen) {
if (document.webkitIsFullScreen) {
document.webkitCancelFullScreen();
} else {
if (Element.ALLOW_KEYBOARD_INPUT) {
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
} else {
elem.webkitRequestFullScreen();
}
}
} else if (document.mozCancelFullScreen) {
if (document.mozIsFullScreen) {
document.mozCancelFullScreen();
} else {
elem.mozRequestFullScreen();
}
}
} else if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(true);
io.buttonDown(2);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(true);
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
keyboard.commandKey(true);
} else if (evt.keyCode == 18) { // Alt
keyboard.optionKey(true);
} else if (!focused) {
evt.preventDefault();
var key = keyboard.mapKeyEvent(evt);
if (key != 0xff) {
io.keyDown(key);
_key = key;
}
}
}
function _keyup(evt) {
_key = 0xff;
if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(false);
io.buttonUp(2);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(false);
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
keyboard.commandKey(false);
} else if (evt.keyCode == 18) { // Alt
keyboard.optionKey(false);
} else {
if (!focused) {
io.keyUp();
}
}
}
function updateScreen() {
var green = $("#green_screen").prop("checked");
scanlines = $("#show_scanlines").prop("checked");
vm.green(green);
}
var flipX = false;
var flipY = false;
var swapXY = false;
function updateJoystick() {
flipX = $("#flip_x").prop("checked");
flipY = $("#flip_y").prop("checked");
swapXY = $("#swap_x_y").prop("checked");
}
function _mousemove(evt) {
if (gamepad) {
return;
}
var s = $("#screen");
var offset = s.offset();
var x = (evt.pageX - offset.left) / s.width(),
y = (evt.pageY - offset.top) / s.height(),
z = x;
if (swapXY) {
x = y;
y = z;
}
io.paddle(0, flipX ? 1 - x : x);
io.paddle(1, flipY ? 1 - y : y);
}
var paused = false;
function pauseRun(b) {
if (paused) {
run();
b.value = "Pause";
} else {
stop();
b.value = "Run";
}
paused = !paused;
}
$(function() {
hashtag = document.location.hash;
$("button,input[type=button],a.button").button().focus(function() {
// Crazy hack required by Chrome
var self = this;
window.setTimeout(function() {
self.blur();
}, 1)
});
var canvas = document.getElementById("screen");
var context = canvas.getContext('2d');
vm.setContext(context);
/*
* Input Handling
*/
$(window).keydown(_keydown);
$(window).keyup(_keyup);
$("canvas").mousedown(function(evt) {
if (!gamepad) {
io.buttonDown(evt.which == 1 ? 0 : 1);
}
evt.preventDefault();
})
.mouseup(function(evt) {
if (!gamepad) {
io.buttonUp(evt.which == 1 ? 0 : 1);
}
})
.mousemove(_mousemove)
.bind("contextmenu", function(e) { e.preventDefault(); });
$("input,textarea").focus(function() { focused = true; })
.blur(function() { focused = false; });
$("body > div").hover(function() { focused = false; },
function() { focused = true; });
keyboard.create($("#keyboard"));
if (prefs.havePrefs()) {
$("input[type=checkbox]").each(function() {
var val = prefs.readPref(this.id);
if (val != null)
this.checked = JSON.parse(val);
});
$("input[type=checkbox]").change(function() {
prefs.writePref(this.id, JSON.stringify(this.checked));
});
}
reset();
run();
setInterval(updateKHz, 1000);
updateSound();
updateScreen();
updateSpeed();
var cancel = function() { $(this).dialog("close"); };
$("#loading").dialog({ autoOpen: false, modal: true });
$("#options").dialog({ autoOpen: false,
modal: true,
width: 320,
height: 400,
buttons: {"Close": cancel }});
$("#load").dialog({ autoOpen: false,
modal: true,
width: 540,
buttons: {"Cancel": cancel, "Load": doLoad }});
$("#save").dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {"Cancel": cancel, "Save": doSave }});
$("#manage").dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {"Close": cancel }});
if (window.localStorage !== undefined) {
$("button.disksave").show();
}
var oldcat = "";
for (var idx = 0; idx < disk_index.length; idx++) {
var file = disk_index[idx];
var cat = file.category;
var name = file.name, disk = file.disk;
if (cat != oldcat) {
$("<option />").val(cat).text(cat).appendTo("#category_select");
disk_categories[cat] = [];
oldcat = cat;
}
disk_categories[cat].push(file);
if (disk) {
if (!disk_sets[name]) {
disk_sets[name] = []
}
disk_sets[name].push(file);
}
}
$("<option/>").text("Local Saves").appendTo("#category_select");
updateLocalStorage();
// Check for disks in hashtag
var filename = gup("disk") || hup();
if (filename) {
if (filename.indexOf("://") > 0) {
loadHTTP(filename);
} else {
loadAjax("json/disks/" + filename + ".json");
}
}
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
$("select").removeAttr("multiple").css("height", "auto");
}
});
</script>
<script type="text/javascript" src="js/main2e.js"></script>
</head>
<body class="apple2e">
<div style="margin: auto; width: 604px">

View File

@ -1,4 +1,4 @@
/* Copyright 2010-2013 Will Scullin */
/* Copyright 2010-2016 Will Scullin */
.disklabel {
color: #000;

View File

@ -1,265 +1,260 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*exported apple2_charset */
/*global bytify */
/*exported charset */
var charset = [
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88,
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88
];
charset = bytify(charset);
var apple2_charset = [
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88,
0x00,0x1c,0x22,0x2a,0x2e,0x2c,0x20,0x1e,
0x00,0x08,0x14,0x22,0x22,0x3e,0x22,0x22,
0x00,0x3c,0x22,0x22,0x3c,0x22,0x22,0x3c,
0x00,0x1c,0x22,0x20,0x20,0x20,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x22,0x22,0x22,0x3c,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x3e,
0x00,0x3e,0x20,0x20,0x3c,0x20,0x20,0x20,
0x00,0x1e,0x20,0x20,0x20,0x26,0x22,0x1e,
0x00,0x22,0x22,0x22,0x3e,0x22,0x22,0x22,
0x00,0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,
0x00,0x02,0x02,0x02,0x02,0x02,0x22,0x1c,
0x00,0x22,0x24,0x28,0x30,0x28,0x24,0x22,
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,
0x00,0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,
0x00,0x22,0x22,0x32,0x2a,0x26,0x22,0x22,
0x00,0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,0x20,
0x00,0x1c,0x22,0x22,0x22,0x2a,0x24,0x1a,
0x00,0x3c,0x22,0x22,0x3c,0x28,0x24,0x22,
0x00,0x1c,0x22,0x20,0x1c,0x02,0x22,0x1c,
0x00,0x3e,0x08,0x08,0x08,0x08,0x08,0x08,
0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1c,
0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x08,
0x00,0x22,0x22,0x22,0x2a,0x2a,0x36,0x22,
0x00,0x22,0x22,0x14,0x08,0x14,0x22,0x22,
0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x08,
0x00,0x3e,0x02,0x04,0x08,0x10,0x20,0x3e,
0x00,0x3e,0x30,0x30,0x30,0x30,0x30,0x3e,
0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x00,
0x00,0x3e,0x06,0x06,0x06,0x06,0x06,0x3e,
0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,
0x00,0x14,0x14,0x14,0x00,0x00,0x00,0x00,
0x00,0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,
0x00,0x08,0x1e,0x28,0x1c,0x0a,0x3c,0x08,
0x00,0x30,0x32,0x04,0x08,0x10,0x26,0x06,
0x00,0x10,0x28,0x28,0x10,0x2a,0x24,0x1a,
0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,
0x00,0x08,0x10,0x20,0x20,0x20,0x10,0x08,
0x00,0x08,0x04,0x02,0x02,0x02,0x04,0x08,
0x00,0x08,0x2a,0x1c,0x08,0x1c,0x2a,0x08,
0x00,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,
0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,
0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,
0x00,0x1c,0x22,0x26,0x2a,0x32,0x22,0x1c,
0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x1c,
0x00,0x1c,0x22,0x02,0x0c,0x10,0x20,0x3e,
0x00,0x3e,0x02,0x04,0x0c,0x02,0x22,0x1c,
0x00,0x04,0x0c,0x14,0x24,0x3e,0x04,0x04,
0x00,0x3e,0x20,0x3c,0x02,0x02,0x22,0x1c,
0x00,0x0e,0x10,0x20,0x3c,0x22,0x22,0x1c,
0x00,0x3e,0x02,0x04,0x08,0x10,0x10,0x10,
0x00,0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,
0x00,0x1c,0x22,0x22,0x1e,0x02,0x04,0x38,
0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
0x00,0x00,0x00,0x08,0x00,0x08,0x08,0x10,
0x00,0x04,0x08,0x10,0x20,0x10,0x08,0x04,
0x00,0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,
0x00,0x10,0x08,0x04,0x02,0x04,0x08,0x10,
0x00,0x1c,0x22,0x04,0x08,0x08,0x00,0x08,
0x80,0x9c,0xa2,0xaa,0xae,0xac,0xa0,0x9e,
0x80,0x88,0x94,0xa2,0xa2,0xbe,0xa2,0xa2,
0x80,0xbc,0xa2,0xa2,0xbc,0xa2,0xa2,0xbc,
0x80,0x9c,0xa2,0xa0,0xa0,0xa0,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xa2,0xa2,0xa2,0xbc,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xbe,
0x80,0xbe,0xa0,0xa0,0xbc,0xa0,0xa0,0xa0,
0x80,0x9e,0xa0,0xa0,0xa0,0xa6,0xa2,0x9e,
0x80,0xa2,0xa2,0xa2,0xbe,0xa2,0xa2,0xa2,
0x80,0x9c,0x88,0x88,0x88,0x88,0x88,0x9c,
0x80,0x82,0x82,0x82,0x82,0x82,0xa2,0x9c,
0x80,0xa2,0xa4,0xa8,0xb0,0xa8,0xa4,0xa2,
0x80,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xbe,
0x80,0xa2,0xb6,0xaa,0xaa,0xa2,0xa2,0xa2,
0x80,0xa2,0xa2,0xb2,0xaa,0xa6,0xa2,0xa2,
0x80,0x9c,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xbc,0xa2,0xa2,0xbc,0xa0,0xa0,0xa0,
0x80,0x9c,0xa2,0xa2,0xa2,0xaa,0xa4,0x9a,
0x80,0xbc,0xa2,0xa2,0xbc,0xa8,0xa4,0xa2,
0x80,0x9c,0xa2,0xa0,0x9c,0x82,0xa2,0x9c,
0x80,0xbe,0x88,0x88,0x88,0x88,0x88,0x88,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0x9c,
0x80,0xa2,0xa2,0xa2,0xa2,0xa2,0x94,0x88,
0x80,0xa2,0xa2,0xa2,0xaa,0xaa,0xb6,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x94,0xa2,0xa2,
0x80,0xa2,0xa2,0x94,0x88,0x88,0x88,0x88,
0x80,0xbe,0x82,0x84,0x88,0x90,0xa0,0xbe,
0x80,0xbe,0xb0,0xb0,0xb0,0xb0,0xb0,0xbe,
0x80,0x80,0xa0,0x90,0x88,0x84,0x82,0x80,
0x80,0xbe,0x86,0x86,0x86,0x86,0x86,0xbe,
0x80,0x80,0x80,0x88,0x94,0xa2,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbe,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x88,0x88,0x88,0x88,0x88,0x80,0x88,
0x80,0x94,0x94,0x94,0x80,0x80,0x80,0x80,
0x80,0x94,0x94,0xbe,0x94,0xbe,0x94,0x94,
0x80,0x88,0x9e,0xa8,0x9c,0x8a,0xbc,0x88,
0x80,0xb0,0xb2,0x84,0x88,0x90,0xa6,0x86,
0x80,0x90,0xa8,0xa8,0x90,0xaa,0xa4,0x9a,
0x80,0x88,0x88,0x88,0x80,0x80,0x80,0x80,
0x80,0x88,0x90,0xa0,0xa0,0xa0,0x90,0x88,
0x80,0x88,0x84,0x82,0x82,0x82,0x84,0x88,
0x80,0x88,0xaa,0x9c,0x88,0x9c,0xaa,0x88,
0x80,0x80,0x88,0x88,0xbe,0x88,0x88,0x80,
0x80,0x80,0x80,0x80,0x80,0x88,0x88,0x90,
0x80,0x80,0x80,0x80,0xbe,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x88,
0x80,0x80,0x82,0x84,0x88,0x90,0xa0,0x80,
0x80,0x9c,0xa2,0xa6,0xaa,0xb2,0xa2,0x9c,
0x80,0x88,0x98,0x88,0x88,0x88,0x88,0x9c,
0x80,0x9c,0xa2,0x82,0x8c,0x90,0xa0,0xbe,
0x80,0xbe,0x82,0x84,0x8c,0x82,0xa2,0x9c,
0x80,0x84,0x8c,0x94,0xa4,0xbe,0x84,0x84,
0x80,0xbe,0xa0,0xbc,0x82,0x82,0xa2,0x9c,
0x80,0x8e,0x90,0xa0,0xbc,0xa2,0xa2,0x9c,
0x80,0xbe,0x82,0x84,0x88,0x90,0x90,0x90,
0x80,0x9c,0xa2,0xa2,0x9c,0xa2,0xa2,0x9c,
0x80,0x9c,0xa2,0xa2,0x9e,0x82,0x84,0xb8,
0x80,0x80,0x80,0x88,0x80,0x88,0x80,0x80,
0x80,0x80,0x80,0x88,0x80,0x88,0x88,0x90,
0x80,0x84,0x88,0x90,0xa0,0x90,0x88,0x84,
0x80,0x80,0x80,0xbe,0x80,0xbe,0x80,0x80,
0x80,0x90,0x88,0x84,0x82,0x84,0x88,0x90,
0x80,0x9c,0xa2,0x84,0x88,0x88,0x80,0x88
];

View File

@ -1,6 +1,3 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*global bytify:false */
/*exported Apple2eEnhancedROM */
function Apple2eEnhancedROM()
@ -2056,8 +2053,6 @@ function Apple2eEnhancedROM()
0xf5,0x03,0xfb,0x03,0x62,0xfa,0xfa,0xc3
];
rom = bytify(rom);
return {
start: function apple2e_start() {
return 0xc1;

View File

@ -1,5 +1,3 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*global bytify:false */
/*exported Apple2eROM*/
function Apple2eROM()
@ -2057,8 +2055,6 @@ function Apple2eROM()
0xf5,0x03,0xfb,0x03,0x62,0xfa,0x40,0xfa
];
rom = bytify(rom);
return {
start: function apple2e_start() {
return 0xc1;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -15,7 +14,7 @@
function Apple2IO(cpu, callbacks)
{
"use strict";
'use strict';
var _hz = 1023000;
var _rate = 44000;
@ -36,7 +35,7 @@ function Apple2IO(cpu, callbacks)
var _low = -0.5;
var _audioListener = null;
var _trigger = 0;
var _tape = [];
@ -45,7 +44,7 @@ function Apple2IO(cpu, callbacks)
var _tapeFlip = false;
var LOC = {
KEYBOARD: 0x00, // keyboard data (latched) (Read),
KEYBOARD: 0x00, // keyboard data (latched) (Read),
CLR80VID: 0x0C, // clear 80 column mode
SET80VID: 0x0D, // set 80 column mode
CLRALTCH: 0x0E, // clear mousetext
@ -89,7 +88,7 @@ function Apple2IO(cpu, callbacks)
SETIOUDIS:0x7E, // Enable double hires
CLRIOUDIS:0x7F // Disable double hires
};
function _debug() {
// debug.apply(arguments);
}
@ -116,43 +115,43 @@ function Apple2IO(cpu, callbacks)
var delta = now - _trigger;
switch (off) {
case LOC.CLR80VID:
// _debug("80 Column Mode off");
// _debug('80 Column Mode off');
if ('_80col' in callbacks) callbacks._80col(false);
break;
case LOC.SET80VID:
// _debug("80 Column Mode on");
// _debug('80 Column Mode on');
if ('_80col' in callbacks) callbacks._80col(true);
break;
case LOC.CLRALTCH:
// _debug("Alt Char off");
// _debug('Alt Char off');
if ('altchar' in callbacks) callbacks.altchar(false);
break;
case LOC.SETALTCH:
// _debug("Alt Char on");
// _debug('Alt Char on');
if ('altchar' in callbacks) callbacks.altchar(true);
break;
case LOC.CLRTEXT:
_debug("Graphics Mode");
_debug('Graphics Mode');
callbacks.text(false);
break;
case LOC.SETTEXT:
_debug("Text Mode");
_debug('Text Mode');
callbacks.text(true);
break;
case LOC.CLRMIXED:
_debug("Mixed Mode off");
_debug('Mixed Mode off');
callbacks.mixed(false);
break;
case LOC.SETMIXED:
_debug("Mixed Mode on");
_debug('Mixed Mode on');
callbacks.mixed(true);
break;
case LOC.CLRHIRES:
_debug("LoRes Mode");
_debug('LoRes Mode');
callbacks.hires(false);
break;
case LOC.SETHIRES:
_debug("HiRes Mode");
_debug('HiRes Mode');
callbacks.hires(true);
break;
case LOC.PAGE1:
@ -162,27 +161,27 @@ function Apple2IO(cpu, callbacks)
callbacks.page(2);
break;
case LOC.RDTEXT:
if ('isText' in callbacks)
if ('isText' in callbacks)
result = callbacks.isText() ? 0x80 : 0x0;
break;
case LOC.RDMIXED:
if ('isMixed' in callbacks)
if ('isMixed' in callbacks)
result = callbacks.isMixed() ? 0x80 : 0x0;
break;
case LOC.RDPAGE2:
if ('isPage2' in callbacks)
if ('isPage2' in callbacks)
result = callbacks.isPage2() ? 0x80 : 0x0;
break;
case LOC.RDHIRES:
if ('isHires' in callbacks)
if ('isHires' in callbacks)
result = callbacks.isHires() ? 0x80 : 0x0;
break;
case LOC.RD80VID:
if ('is80Col' in callbacks)
if ('is80Col' in callbacks)
result = callbacks.is80Col() ? 0x80 : 0x0;
break;
case LOC.RDALTCH:
if ('isAltChar' in callbacks)
if ('isAltChar' in callbacks)
result = callbacks.isAltChar() ? 0x80 : 0x0;
break;
case LOC.SETAN0:
@ -262,7 +261,7 @@ function Apple2IO(cpu, callbacks)
_trigger = cpu.cycles();
break;
case LOC.TAPEIN:
var flipped = false;
// var flipped = false;
if (_tapeOffset == -1) {
_tapeOffset = 0;
_tapeNext = now;
@ -270,22 +269,22 @@ function Apple2IO(cpu, callbacks)
if (_tapeOffset < _tape.length) {
while (now >= _tapeNext) {
if ((_tapeOffset % 1000) === 0) {
debug("Read " + (_tapeOffset / 1000));
debug('Read ' + (_tapeOffset / 1000));
}
_tapeFlip = !_tapeFlip;
flipped = true;
// flipped = true;
_tapeNext += _tape[_tapeOffset++];
}
result = _tapeFlip ? 0x80 : 0x00;
}
/*
if (flipped) {
debug("now=" + now + " next=" + _tapeNext + " (" + (_tapeNext - now) + ")");
debug('now=' + now + ' next=' + _tapeNext + ' (' + (_tapeNext - now) + ')');
}
*/
/*
var progress =
var progress =
Math.round(_tapeOffset / _tapeBuffer.length * 100) / 100;
if (_progress != progress) {
@ -294,9 +293,9 @@ function Apple2IO(cpu, callbacks)
}
*/
}
return result;
return result;
}
return {
registerSwitches: function apple2io_registerSwitches(a, locs) {
each(locs, function(key) {
@ -314,12 +313,12 @@ function Apple2IO(cpu, callbacks)
end: function apple2io_end() {
return 0xc0;
},
read: function apple2io_read(page, off) {
read: function apple2io_read(page, off) {
var result = 0;
if (_locs[off]) {
result = _locs[off].ioSwitch(off);
} else {
debug("I/O read: C0" + toHex(off));
debug('I/O read: C0' + toHex(off));
}
return result;
},
@ -327,7 +326,7 @@ function Apple2IO(cpu, callbacks)
if (_locs[off]) {
_locs[off].ioSwitch(off, val);
} else {
debug("I/O write: C0" + toHex(off));
debug('I/O write: C0' + toHex(off));
}
},
getState: function apple2io_getState() { return {}; },
@ -339,7 +338,7 @@ function Apple2IO(cpu, callbacks)
_keyDown = true;
_key = ascii | 0x80;
},
keyUp: function apple2io_keyUp() {
keyUp: function apple2io_keyUp() {
_keyDown = false;
_key = 0;
},
@ -353,10 +352,10 @@ function Apple2IO(cpu, callbacks)
paddle: function apple2io_paddle(p, v) {
_paddle[p] = v;
},
updateHz: function apple2io_updateHz(hz) {
_hz = hz;
_cycles_per_sample = _hz / _rate;
},
setKeyBuffer: function apple2io_setKeyBuffer(buffer) {
@ -373,15 +372,15 @@ function Apple2IO(cpu, callbacks)
_tapeOffset = -1;
},
sampleRate: function sampleRate(rate) {
sampleRate: function sampleRate(rate) {
_rate = rate;
_cycles_per_sample = _hz / _rate;
},
sampleTick: function sampleTick() {
_tick();
},
addSampleListener: function addSampleListener(cb) {
_audioListener = cb;
}

173
js/applesoft/decompiler.js Normal file
View File

@ -0,0 +1,173 @@
function ApplesoftDump(mem)
{
var _mem = mem;
var LETTERS =
" " +
" !\"#$%&'()*+,-./0123456789:;<=>?" +
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
"`abcdefghijklmnopqrstuvwxyz{|}~ ";
var TOKENS = {
0x80: "END",
0x81: "FOR",
0x82: "NEXT",
0x83: "DATA",
0x84: "INPUT",
0x85: "DEL",
0x86: "DIM",
0x87: "READ",
0x88: "GR",
0x89: "TEXT",
0x8a: "PR#",
0x8b: "IN#",
0x8c: "CALL",
0x8d: "PLOT",
0x8e: "HLIN",
0x8f: "VLIN",
0x90: "HGR2",
0x91: "HGR",
0x92: "HCOLOR=",
0x93: "HPLOT",
0x94: "DRAW",
0x95: "XDRAW",
0x96: "HTAB",
0x97: "HOME",
0x98: "ROT=",
0x99: "SCALE=",
0x9a: "SHLOAD",
0x9b: "TRACE",
0x9c: "NOTRACE",
0x9d: "NORMAL",
0x9e: "INVERSE",
0x9f: "FLASH",
0xa0: "COLOR=",
0xa1: "POP=",
0xa2: "VTAB",
0xa3: "HIMEM:",
0xa4: "LOMEM:",
0xa5: "ONERR",
0xa6: "RESUME",
0xa7: "RECALL",
0xa8: "STORE",
0xa9: "SPEED=",
0xaa: "LET",
0xab: "GOTO",
0xac: "RUN",
0xad: "IF",
0xae: "RESTORE",
0xaf: "&",
0xb0: "GOSUB",
0xb1: "RETURN",
0xb2: "REM",
0xb3: "STOP",
0xb4: "ON",
0xb5: "WAIT",
0xb6: "LOAD",
0xb7: "SAVE",
0xb8: "DEF",
0xb9: "POKE",
0xba: "PRINT",
0xbb: "CONT",
0xbc: "LIST",
0xbd: "CLEAR",
0xbe: "GET",
0xbf: "NEW",
0xc0: "TAB(",
0xc1: "TO",
0xc2: "FN",
0xc3: "SPC(",
0xc4: "THEN",
0xc5: "AT",
0xc6: "NOT",
0xc7: "STEP",
0xc8: "+",
0xc9: "-",
0xca: "*",
0xcb: "/",
0xcc: "^",
0xcd: "AND",
0xce: "OR",
0xcf: ">",
0xd0: "=",
0xd1: "<",
0xd2: "SGN",
0xd3: "INT",
0xd4: "ABS",
0xd5: "USR",
0xd6: "FRE",
0xd7: "SCRN(",
0xd8: "PDL",
0xd9: "POS",
0xda: "SQR",
0xdb: "RND",
0xdc: "LOG",
0xdd: "EXP",
0xde: "COS",
0xdf: "SIN",
0xe0: "TAN",
0xe1: "ATN",
0xe2: "PEEK",
0xe3: "LEN",
0xe4: "STR$",
0xe5: "VAL",
0xe6: "ASC",
0xe7: "CHR$",
0xe8: "LEFT$",
0xe9: "RIGHT$",
0xea: "MID$"
};
function readByte(addr) {
var page = addr >> 8,
off = addr & 0xff;
return _mem.read(page, off);
}
function readWord(addr) {
var lsb, msb;
lsb = readByte(addr, debug);
msb = readByte(addr + 1, debug);
return (msb << 8) | lsb;
}
return {
toString: function () {
var str = "";
var start = readWord(0x67); // Start
var end = readWord(0xaf); // End of program
var addr = start;
do {
var line = "";
var next = readWord(addr);
addr += 2;
var lineno = readWord(addr);
addr += 2;
line += lineno;
line += " ";
var val = false;
do {
if (addr < start || addr > end)
return str;
var val = readByte(addr++);
if (val > 0x80) {
line += " ";
line += TOKENS[val];
line += " ";
}
else
line += LETTERS[val];
} while (val);
line += "\n";
str += line;
addr = next;
} while (addr && addr >= start && addr < end);
return str;
}
};
}

View File

@ -2,7 +2,7 @@
function base64_encode (data) {
// Twacked by Will Scullin to handle arrays of "bytes"
// http://kevin.vanzonneveld.net
// + original by: Tyler Akins (http://rumkin.com)
// + improved by: Bayron Guevara
@ -19,9 +19,9 @@ function base64_encode (data) {
//if (typeof this.window['atob'] == 'function') {
// return atob(data);
//}
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc="", tmp_arr = [];
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc='', tmp_arr = [];
if (!data) {
return data;
@ -42,15 +42,15 @@ function base64_encode (data) {
// use hexets to index into b64, and append result to encoded string
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);
enc = tmp_arr.join('');
switch (data.length % 3) {
case 1:
enc = enc.slice(0, -2) + '==';
case 1:
enc = enc.slice(0, -2) + '==';
break;
case 2:
enc = enc.slice(0, -1) + '=';
case 2:
enc = enc.slice(0, -1) + '=';
break;
}
@ -59,7 +59,7 @@ function base64_encode (data) {
function base64_decode(data) {
// Twacked by Will Scullin to handle arrays of "bytes"
// http://kevin.vanzonneveld.net
// + original by: Tyler Akins (http://rumkin.com)
// + improved by: Thunder.m
@ -80,7 +80,7 @@ function base64_decode(data) {
// return btoa(data);
//}
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, tmp_arr = [];
if (!data) {
@ -99,10 +99,10 @@ function base64_decode(data) {
o2 = bits>>8 & 0xff;
o3 = bits & 0xff;
tmp_arr[ac++] = o1;
tmp_arr[ac++] = o1;
if (h3 != 64) {
tmp_arr[ac++] = o2;
}
}
if (h4 != 64) {
tmp_arr[ac++] = o3;
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,16 +9,14 @@
* implied warranty.
*/
/*jshint browser:true */
/*globals allocMemPages: false,
charset: false,
base64_encode: false, base64_decode: false */
/*exported LoresPage, HiresPage, VideoModes*/
/*
* Text Page 1 Drawing
*/
/*globals allocMemPages: false,
base64_encode: false, base64_decode: false */
/*exported LoresPage, HiresPage, VideoModes*/
var textMode = true;
var mixedMode = true;
var hiresMode = false;
@ -34,8 +31,10 @@ var scanlines = false;
*
***************************************************************************/
function LoresPage(page)
function LoresPage(page, charset)
{
'use strict';
// $00-$3F inverse
// $40-$7F flashing
// $80-$FF normal
@ -108,16 +107,16 @@ function LoresPage(page)
data[off + 560 * 4 + 2] = c2 >> 1;
}
}
_init();
return {
start: function() {
start: function() {
var self = this;
window.setInterval(function() {
self.blink();
}, 267);
return (0x04 * _page);
return (0x04 * _page);
},
end: function() { return (0x04 * _page) + 0x03; },
read: function(page, off) {
@ -136,10 +135,10 @@ function LoresPage(page)
var col = (base % 0x80) % 0x28,
adj = off - col;
// 000001cd eabab000 -> 000abcde
// 000001cd eabab000 -> 000abcde
var ab = (adj & 0x18),
cd = (page & 0x03) << 1,
e = adj >> 7;
e = adj >> 7;
var row = ab | cd | e, color, idx, jdx, b;
@ -159,7 +158,7 @@ function LoresPage(page)
back = _greenMode ? _green : _white;
}
for (jdx = 0; jdx < 8; jdx++) {
b = charset[(val & 0x3f) * 8 + jdx];
b = charset[val * 8 + jdx];
b <<= 1;
for (idx = 0; idx < 7; idx++) {
color = (b & 0x80) ? fore : back;
@ -177,7 +176,7 @@ function LoresPage(page)
b = (jdx < 4) ? (val & 0x0f) : (val >> 4);
b |= (b << 4);
b |= (b << 8);
if (col & 0x1) {
if ((col & 0x1) !== 0) {
b <<= 2;
}
for (idx = 0; idx < 14; idx++) {
@ -187,7 +186,7 @@ function LoresPage(page)
off += 4;
}
off += 546 * 4 + 560 * 4;
}
}
} else {
for (jdx = 0; jdx < 8; jdx++) {
b = (jdx < 4) ? (val & 0x0f) : (val >> 4);
@ -212,7 +211,7 @@ function LoresPage(page)
},
blink: function() {
var addr = 0x400 * _page;
_refreshing = true;
_refreshing = true;
_blink = !_blink;
for (var idx = 0; idx < 0x400; idx++, addr++) {
var b = _buffer[idx];
@ -247,14 +246,14 @@ function LoresPage(page)
}
function HiresPage(page)
{
{
var _page = page;
var orangeCol = [0xff, 0x65, 0x00];
var greenCol = [0x00, 0xff, 0x00];
var blueCol = [0x09, 0x2a, 0xff];
var violetCol = [0xc9, 0x39, 0xc7];
var whiteCol = [0xff, 0xff, 0xff];
var whiteCol = [0xff, 0xff, 0xff];
var blackCol = [0x00, 0x00, 0x00];
var _buffer = [];
@ -269,7 +268,7 @@ function HiresPage(page)
for (var idx = 0; idx < 0x2000; idx++)
_buffer[idx] = 0; // Math.floor(Math.random()*256);
}
function _drawPixel(data, off, color) {
var c0 = color[0], c1 = color[1], c2 = color[2];
@ -286,7 +285,7 @@ function HiresPage(page)
data[off + 560 * 4 + 2] = data[off + 560 * 4 + 6] = c2 >> 1;
}
}
_init();
return {
@ -306,17 +305,17 @@ function HiresPage(page)
if (_buffer[base] === val && !_refreshing)
return;
_buffer[base] = val;
var hbs = val & 0x80;
val &= 0x7f;
var col = (base % 0x80) % 0x28,
adj = off - col;
// 000001cd eabab000 -> 000abcde
// 000001cd eabab000 -> 000abcde
var ab = (adj & 0x18),
cd = (page & 0x03) << 1,
e = adj >> 7;
e = adj >> 7;
var rowa = ab | cd | e,
rowb = base >> 10;
@ -324,18 +323,18 @@ function HiresPage(page)
if ((rowa < 24) && (col < 40)) {
if (textMode || !hiresMode || (mixedMode && rowa > 19))
return;
var data = pages[_page].data,
dy = rowa * 8 + rowb,
dx = col * 14 - 2,
b0 = col > 0 ? _buffer[base - 1] : 0,
b2 = col < 39 ? _buffer[base + 1] : 0;
dy = rowa * 8 + rowb,
dx = col * 14 - 2,
b0 = col > 0 ? _buffer[base - 1] : 0,
b2 = col < 39 ? _buffer[base + 1] : 0;
val |= (b2 & 0x3) << 7;
var v0 = b0 & 0x20, v1 = b0 & 0x40, v2 = val & 0x1,
odd = !(col & 0x1),
color,
oddCol = (hbs ? orangeCol : greenCol),
evenCol = (hbs ? blueCol : violetCol);
odd = (col & 0x1) === 0,
color,
oddCol = (hbs ? orangeCol : greenCol),
evenCol = (hbs ? blueCol : violetCol);
off = dx * 4 + dy * 560 * 4 * 2;
for (var idx = 0; idx < 9; idx++, off += 8) {
@ -434,7 +433,7 @@ function VideoModes(gr,hgr,gr2,hgr2) {
_refresh();
}
},
mixed: function(on) {
mixed: function(on) {
var old = mixedMode;
mixedMode = on;
if (old != on) {
@ -490,4 +489,3 @@ function VideoModes(gr,hgr,gr2,hgr2) {
}
};
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,8 +9,9 @@
* implied warranty.
*/
/*jshint browser:true */
/*globals allocMemPages: false, charset: false, base64_encode: false, base64_decode: false, enhanced: false */
/*globals allocMemPages: false, debug: false,
base64_encode: false, base64_decode: false,
enhanced: false */
/*exported LoresPage, HiresPage, VideoModes */
@ -22,6 +22,12 @@ var pageMode = 1;
var _80colMode = false;
var altCharMode = false;
var doubleHiresMode = false;
var monoDHRMode = false;
var colorDHRMode = false;
var mixedDHRMode = false;
var highColorHGRMode = false;
var highColorTextMode = false;
var pages = [];
var context = null;
var scanlines = false;
@ -32,9 +38,9 @@ var scanlines = false;
*
***************************************************************************/
function LoresPage(page)
function LoresPage(page, charset)
{
"use strict";
'use strict';
// $00-$3F inverse
// $40-$7F flashing
@ -72,7 +78,7 @@ function LoresPage(page)
function _init() {
_buffer[0] = allocMemPages(0x4);
_buffer[1] = allocMemPages(0x4);
for (var idx = 0; idx < 0x400; idx++) {
_buffer[0][idx] = 0; // idx & 0x2 ? 0xff : 0x00;
_buffer[1][idx] = 0; // idx & 0x2 ? 0xff : 0x00;
@ -110,7 +116,7 @@ function LoresPage(page)
data[off + 560 * 4 + 2] = c2 >> 1;
}
}
_init();
return {
@ -176,16 +182,13 @@ function LoresPage(page)
return;
_buffer[bank][base] = val;
if (bank !== 0 && !_80colMode)
return;
var col = (base % 0x80) % 0x28,
adj = off - col;
// 000001cd eabab000 -> 000abcde
// 000001cd eabab000 -> 000abcde
var ab = (adj & 0x18),
cd = (page & 0x03) << 1,
e = adj >> 7;
e = adj >> 7;
var idx, jdx;
var row = ab | cd | e;
var b;
@ -197,19 +200,20 @@ function LoresPage(page)
var color;
if (textMode || (mixedMode && row > 19)) {
var flash = ((val & 0xc0) == 0x40) &&
_blink && !_80colMode && !altCharMode;
var flash = ((val & 0xc0) == 0x40) &&
_blink && !_80colMode && !altCharMode;
fore = flash ? _black : (_greenMode ? _green : _white);
back = flash ? (_greenMode ? _green : _white) : _black;
if (!enhanced) {
val = (val >= 0x40 && val < 0x60) ? val - 0x40 : val;
} else if (!altCharMode) {
val = (val >= 0x40 && val < 0x80) ? val - 0x40 : val;
}
if (_80colMode) {
if (!enhanced) {
val = (val >= 0x40 && val < 0x60) ? val - 0x40 : val;
} else if (!altCharMode) {
val = (val >= 0x40 && val < 0x80) ? val - 0x40 : val;
}
off = (col * 14 + (bank ? 0 : 1) * 7 + row * 560 * 8 * 2) * 4;
for (jdx = 0; jdx < 8; jdx++) {
b = charset[val * 8 + jdx];
for (idx = 0; idx < 7; idx++) {
@ -221,8 +225,21 @@ function LoresPage(page)
off += 553 * 4 + 560 * 4;
}
} else {
val = _buffer[0][base];
if (!enhanced) {
val = (val >= 0x40 && val < 0x60) ? val - 0x40 : val;
} else if (!altCharMode) {
val = (val >= 0x40 && val < 0x80) ? val - 0x40 : val;
}
off = (col * 14 + row * 560 * 8 * 2) * 4;
if (highColorTextMode) {
fore = _colors[_buffer[0][base] >> 4];
back = _colors[_buffer[0][base] & 0x0f];
}
for (jdx = 0; jdx < 8; jdx++) {
b = charset[val * 8 + jdx];
for (idx = 0; idx < 7; idx++) {
@ -253,13 +270,13 @@ function LoresPage(page)
off += 4;
}
off += 553 * 4 + 560 * 4;
}
}
} else {
if (bank & 0x1) {
val = ((val & 0x77) << 1) | ((val & 0x88) >> 3);
}
for (jdx = 0; jdx < 8; jdx++) {
color = _colors[(jdx < 4) ?
color = _colors[(jdx < 4) ?
(val & 0x0f) : (val >> 4)];
for (idx = 0; idx < 7; idx++) {
_drawHalfPixel(data, off, color);
@ -288,12 +305,12 @@ function LoresPage(page)
off += 4;
}
off += 546 * 4 + 560 * 4;
}
}
} else {
for (jdx = 0; jdx < 8; jdx++) {
color = _colors[(jdx < 4) ?
color = _colors[(jdx < 4) ?
(val & 0x0f) : (val >> 4)];
for (idx = 0; idx < 7; idx++) {
for (idx = 0; idx < 7; idx++) {
_drawPixel(data, off, color);
off += 8;
}
@ -305,11 +322,9 @@ function LoresPage(page)
}
},
refresh: function() {
var page, off, addr = 0x400 * _page;
var addr = 0x400 * _page;
_refreshing = true;
for (var idx = 0; idx < 0x400; idx++, addr++) {
page = addr >> 8;
off = addr & 0xff;
this._write(addr >> 8, addr & 0xff, _buffer[0][idx], 0);
if (_80colMode)
this._write(addr >> 8, addr & 0xff, _buffer[1][idx], 1);
@ -318,7 +333,7 @@ function LoresPage(page)
},
blink: function() {
var addr = 0x400 * _page;
_refreshing = true;
_refreshing = true;
_blink = !_blink;
for (var idx = 0; idx < 0x400; idx++, addr++) {
var b = _buffer[0][idx];
@ -361,8 +376,8 @@ function LoresPage(page)
***************************************************************************/
function HiresPage(page)
{
"use strict";
{
'use strict';
var _page = page;
@ -410,14 +425,14 @@ function HiresPage(page)
var greenCol = [0x00, 0xff, 0x00];
var blueCol = [0x09, 0x2a, 0xff];
var violetCol = [0xc9, 0x39, 0xc7];
var whiteCol = [0xff, 0xff, 0xff];
var whiteCol = [0xff, 0xff, 0xff];
var blackCol = [0x00, 0x00, 0x00];
var _buffer = [];
var _refreshing = false;
var _green = [0x00, 0xff, 0x80];
var _greenMode = false;
var _green = [0x00, 0xff, 0x80];
function _init() {
_buffer[0] = allocMemPages(0x20);
@ -430,6 +445,7 @@ function HiresPage(page)
function _drawPixel(data, off, color) {
var c0 = color[0], c1 = color[1], c2 = color[2];
data[off + 0] = data[off + 4] = c0;
data[off + 1] = data[off + 5] = c1;
data[off + 2] = data[off + 6] = c2;
@ -459,7 +475,7 @@ function HiresPage(page)
data[off + 560 * 4 + 2] = c2 >> 1;
}
}
_init();
return {
@ -510,13 +526,10 @@ function HiresPage(page)
return [c[0] * 0.75, c[1] * 0.75, c[2] * 0.75];
}
var addr = (page << 8) | off, base = addr - 0x2000 * _page,
idx, jdx;
idx, jdx;
if (_buffer[bank][base] == val && !_refreshing)
return;
_buffer[bank][base] = val;
if (bank !== 0 && !doubleHiresMode)
return;
var hbs = val & 0x80;
val &= 0x7f;
@ -524,10 +537,10 @@ function HiresPage(page)
var col = (base % 0x80) % 0x28,
adj = off - col;
// 000001cd eabab000 -> 000abcde
// 000001cd eabab000 -> 000abcde
var ab = (adj & 0x18),
cd = (page & 0x03) << 1,
e = adj >> 7;
e = adj >> 7;
var rowa = ab | cd | e,
rowb = base >> 10;
@ -536,9 +549,9 @@ function HiresPage(page)
if ((rowa < 24) && (col < 40)) {
if (textMode || !hiresMode || (mixedMode && rowa > 19))
return;
dy = rowa * 16 + rowb * 2;
var bz, b0, b1, b2, b3, b4, c;
var bz, b0, b1, b2, b3, b4, c, hb;
if (doubleHiresMode) {
// Every 4 bytes is 7 pixels
// 2 bytes per bank
@ -557,26 +570,57 @@ function HiresPage(page)
((b2 & 0x3c) >> 2), // 4
((b2 & 0x40) >> 6) | ((b3 & 0x07) << 1), // 5
((b3 & 0x78) >> 3), // 6
0], // 7
hb = [0,
b0 & 0x80, // 0
b0 & 0x80, // 1
b1 & 0x80, // 2
b2 & 0x80, // 3
b2 & 0x80, // 4
b3 & 0x80, // 5
b3 & 0x80, // 6
0]; // 7
if (col > 0) {
c[0] = (bz & 0x78) >> 3;
hb[0] = bz & 0x80;
}
if (col < 39) {
c[8] = b4 & 0x0f;
hb[8] = b4 & 0x80;
}
dx = mcol * 14;
off = dx * 4 + dy * 280 * 4 * 2;
var monoColor = null;
if (_greenMode) {
monoColor = _green;
} else if (monoDHRMode) {
monoColor = whiteCol;
}
for (idx = 1; idx < 8; idx++) {
hbs = hb[idx];
var dcolor = dcolors[r4[c[idx]]];
var bits = c[idx-1] | (c[idx] << 4) | (c[idx+1] << 8);
for (jdx = 0; jdx < 4; jdx++, off += 4) {
if (_greenMode) {
if (monoColor) {
if (bits & 0x10) {
_drawHalfPixel(data, off, _green);
_drawHalfPixel(data, off, monoColor);
} else {
_drawHalfPixel(data, off, blackCol);
}
} else if (mixedDHRMode) {
if (hbs) {
_drawHalfPixel(data, off, dcolor);
} else {
if (bits & 0x10) {
_drawHalfPixel(data, off, whiteCol);
} else {
_drawHalfPixel(data, off, blackCol);
}
}
} else if (colorDHRMode) {
_drawHalfPixel(data, off, dcolor);
} else if (((bits & 0x3c) == 0x3c) ||
((bits & 0xf0) == 0xf0) ||
((bits & 0x1e) == 0x1e) ||
@ -590,7 +634,7 @@ function HiresPage(page)
_drawHalfPixel(data, off, dcolor);
} else if ((bits & 0x28) == 0x28) {
_drawHalfPixel(data, off, dcolor);
} else {
} else {
_drawHalfPixel(data, off, blackCol);
}
bits >>= 1;
@ -607,22 +651,25 @@ function HiresPage(page)
_refreshing = false;
}
} else {
val = _buffer[0][base] & 0x7f;
dx = col * 14 - 2;
b0 = col > 0 ? _buffer[bank][base - 1] : 0;
b2 = col < 39 ? _buffer[bank][base + 1] : 0;
b0 = col > 0 ? _buffer[0][base - 1] : 0;
b2 = col < 39 ? _buffer[0][base + 1] : 0;
val |= (b2 & 0x3) << 7;
var v0 = b0 & 0x20, v1 = b0 & 0x40, v2 = val & 0x1,
odd = !(col & 0x1),
color,
oddCol = (hbs ? orangeCol : greenCol),
evenCol = (hbs ? blueCol : violetCol);
odd = !(col & 0x1),
color,
oddCol = (hbs ? orangeCol : greenCol),
evenCol = (hbs ? blueCol : violetCol);
off = dx * 4 + dy * 280 * 4 * 2;
for (idx = 0; idx < 9; idx++, off += 8) {
val >>= 1;
if (v1) {
if (_greenMode) {
color = _green;
} else if (highColorHGRMode) {
color = dcolors[_buffer[1][base] >> 4];
} else if (v0 || v2) {
color = whiteCol;
} else {
@ -631,6 +678,8 @@ function HiresPage(page)
} else {
if (_greenMode) {
color = blackCol;
} else if (highColorHGRMode) {
color = dcolors[_buffer[1][base] & 0x0f];
} else if (odd && v2 && v0) {
color = v0 ? dim(evenCol) : evenCol;
} else if (!odd && v0 && v2) {
@ -644,7 +693,7 @@ function HiresPage(page)
_drawPixel(data, off, color);
}
dx += 2;
v0 = v1;
v1 = v2;
v2 = val & 0x01;
@ -694,6 +743,7 @@ function HiresPage(page)
function VideoModes(gr,hgr,gr2,hgr2) {
var _grs = [gr, gr2];
var _hgrs = [hgr, hgr2];
var _seq = '';
function _refresh() {
gr.refresh();
@ -711,15 +761,28 @@ function VideoModes(gr,hgr,gr2,hgr2) {
mixedMode = false;
hiresMode = true;
pageMode = 1;
_80colMode = false;
altCharMode = false;
doubleHiresMode = false;
monoDHRMode = false;
colorDHRMode = false;
mixedDHRMode = false;
highColorHGRMode = false;
highColorTextMode = false;
_refresh();
},
text: function(on) {
var old = textMode;
textMode = on;
highColorTextMode = false;
_seq = on ? 'T+' : 'T-';
// debug('_seq=', _seq);
if (old != on) {
_refresh();
}
@ -727,6 +790,11 @@ function VideoModes(gr,hgr,gr2,hgr2) {
_80col: function(on) {
var old = _80colMode;
_80colMode = on;
_seq += on ? '8+' : '8-';
_seq = _seq.substr(0, 16);
// debug('_seq=', _seq);
if (old != on) {
_refresh();
}
@ -741,6 +809,11 @@ function VideoModes(gr,hgr,gr2,hgr2) {
hires: function(on) {
var old = hiresMode;
hiresMode = on;
highColorHGRMode = false;
_seq = (on ? 'H+' : 'H-');
// debug('_seq=', _seq);
if (old != on) {
_refresh();
}
@ -748,6 +821,41 @@ function VideoModes(gr,hgr,gr2,hgr2) {
doublehires: function(on) {
var old = doubleHiresMode;
doubleHiresMode = on;
_seq += on ? 'D+' : 'D-';
_seq = _seq.substr(0, 16);
// debug('_seq=', _seq);
if (on) {
if (_seq == 'T+D+') {
debug('High color text mode');
highColorTextMode = true;
doubleHiresMode = false;
} else if (_seq == 'H+8-D+') {
debug('High color hgr');
highColorHGRMode = true;
doubleHiresMode = false;
} else if (_seq == 'H+8+D+D-D+D-D+') {
debug('DoubleHires color');
colorDHRMode = true;
monoDHRMode = false;
mixedDHRMode = false;
_seq = '';
} else if (_seq == 'H+8-D+D-D+D-8+D+') {
debug('DoubleHires mono');
colorDHRMode = false;
monoDHRMode = true;
mixedDHRMode = false;
_seq = '';
} else if (_seq == 'H+8-D+D-8+D+D-D+') {
debug('DoubleHires mixed');
colorDHRMode = false;
monoDHRMode = false;
mixedDHRMode = true;
_seq = '';
}
}
if (old != on) {
if (on) {
this.page(1);
@ -755,7 +863,7 @@ function VideoModes(gr,hgr,gr2,hgr2) {
_refresh();
}
},
mixed: function(on) {
mixed: function(on) {
var old = mixedMode;
mixedMode = on;
if (old != on) {
@ -835,5 +943,3 @@ function VideoModes(gr,hgr,gr2,hgr2) {
}
};
}

View File

@ -1,11 +1,11 @@
/*!
* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,18 +9,20 @@
* implied warranty.
*/
/*jshint browser: true */
/*globals extend: false, bytify: false, base64_encode: false, base64_decode: false, each: false */
/*exported DiskII */
/*globals bytify, each: false, extend: false
base64_encode, base64_decode
Uint8Array
*/
function DiskII(io, callbacks, slot)
{
"use strict";
'use strict';
slot = slot || 6;
var _drives = [
{ // Drive 1
format: "dsk",
format: 'dsk',
volume: 254,
tracks: [],
track: 0,
@ -31,7 +32,7 @@ function DiskII(io, callbacks, slot)
dirty: false
},
{ // Drive 2
format: "dsk",
format: 'dsk',
volume: 254,
tracks: [],
track: 0,
@ -68,12 +69,12 @@ function DiskII(io, callbacks, slot)
DRIVEREADMODE: 0x8E, // Q7L
DRIVEWRITEMODE: 0x8F // Q7H
};
// var DO = [0x0,0x7,0xE,0x6,0xD,0x5,0xC,0x4,
// 0xB,0x3,0xA,0x2,0x9,0x1,0x8,0xF];
var _DO = [0x0,0xD,0xB,0x9,0x7,0x5,0x3,0x1,
0xE,0xC,0xA,0x8,0x6,0x4,0x2,0xF];
// var PO = [0x0,0x8,0x1,0x9,0x2,0xa,0x3,0xb,
// 0x4,0xc,0x5,0xd,0x6,0xe,0x7,0xf];
var _PO = [0x0,0x2,0x4,0x6,0x8,0xa,0xc,0xe,
@ -116,9 +117,9 @@ function DiskII(io, callbacks, slot)
}
/**
* From Beneath Apple DOS
* From Beneath Apple DOS
*/
function _fourXfour(val) {
var xx = val & 0xaa;
var yy = val & 0x55;
@ -170,7 +171,7 @@ function DiskII(io, callbacks, slot)
/*
* Gap 2 (5 bytes)
*/
for (idx = 0; idx < 0x05; idx++) {
buf.push(0xff);
}
@ -180,33 +181,33 @@ function DiskII(io, callbacks, slot)
*/
extend(buf, [0xd5, 0xaa, 0xad]); // Data Prolog D5 AA AD
var nibbles = [];
var ptr2 = 0;
var ptr6 = 0x56;
var idx2, idx6;
for (idx = 0; idx < 0x156; idx++) {
nibbles[idx] = 0;
}
idx2 = 0x55;
for (idx6 = 0x101; idx6 >= 0; idx6--) {
var val6 = data[idx6 % 0x100];
var val2 = nibbles[ptr2 + idx2];
val2 = (val2 << 1) | (val6 & 1);
val6 >>= 1;
val2 = (val2 << 1) | (val6 & 1);
val6 >>= 1;
nibbles[ptr6 + idx6] = val6;
nibbles[ptr2 + idx2] = val2;
if (--idx2 < 0)
if (--idx2 < 0)
idx2 = 0x55;
}
var last = 0;
for (idx = 0; idx < 0x156; idx++) {
var val = nibbles[idx];
@ -214,13 +215,13 @@ function DiskII(io, callbacks, slot)
last = val;
}
buf.push(_trans[last]);
extend(buf, [0xde, 0xaa, 0xeb]); // Epilog DE AA EB
/*
* Gap 3
*/
buf.push(0xff);
return buf;
@ -229,11 +230,11 @@ function DiskII(io, callbacks, slot)
function _json_encode(drive, pretty) {
var cur = _drives[drive - 1];
var data = [];
var format = "dsk";
var format = 'dsk';
for (var t = 0; t < cur.tracks.length; t++) {
data[t] = [];
if (cur.format === "nib") {
format = "nib";
if (cur.format === 'nib') {
format = 'nib';
data[t] = base64_encode(cur.tracks[t]);
} else {
for (var s = 0; s < 0x10; s++) {
@ -241,12 +242,12 @@ function DiskII(io, callbacks, slot)
}
}
}
return JSON.stringify({"type": format,
"encoding": "base64",
"volume": cur.volume,
"data": data},
null,
pretty ? " " : null);
return JSON.stringify({'type': format,
'encoding': 'base64',
'volume': cur.volume,
'data': data},
null,
pretty ? ' ' : null);
}
function _json_decode(drive, data) {
@ -261,14 +262,14 @@ function DiskII(io, callbacks, slot)
var d = base64_decode(json.data[t][_s]);
extend(track, _explodeSector(v, t, _DO[_s], d));
}
tracks[t] = bytify(track);
tracks[t] = bytify(track);
}
_cur.volume = v;
_cur.format = json.type;
_cur.tracks = tracks;
}
function _readNext() {
function _readNext() {
var result = 0;
if (_skip || _writeMode) {
var t = _cur.tracks[_cur.track >> 1];
@ -283,8 +284,8 @@ function DiskII(io, callbacks, slot)
++_cur.head;
}
}
_skip = (++_skip % 4);
}
_skip = (++_skip % 4);
return result;
}
@ -383,9 +384,9 @@ function DiskII(io, callbacks, slot)
[-1, 0, 1, 2],
[-2,-1, 0, 1],
[ 1,-2,-1, 0]];
function setPhase(phase, on) {
_debug("phase " + phase + (on ? " on" : " off"));
_debug('phase ' + phase + (on ? ' on' : ' off'));
if (on) {
_cur.track += _phase_delta[_cur.phase][phase];
_cur.phase = phase;
@ -395,10 +396,10 @@ function DiskII(io, callbacks, slot)
if (_cur.track < 0x0)
_cur.track = 0x0;
/* _debug("Drive " + _drive +
", track " + toHex(_cur.track >> 1) +
" (" + toHex(_cur.track) + ")" +
" [" + (_cur.track % 4) + "/" + phase + "]"); */
/* _debug('Drive ' + _drive +
', track ' + toHex(_cur.track >> 1) +
' (' + toHex(_cur.track) + ')' +
' [' + (_cur.track % 4) + '/' + phase + ']'); */
}
}
@ -429,20 +430,20 @@ function DiskII(io, callbacks, slot)
case LOC.PHASE3ON:
setPhase(3, true);
break;
case LOC.DRIVEOFF:
_debug("Drive Off");
_debug('Drive Off');
_on = false;
if (callbacks.driveLight) { callbacks.driveLight(_drive, false); }
break;
case LOC.DRIVEON:
_debug("Drive On");
_debug('Drive On');
_on = true;
if (callbacks.driveLight) { callbacks.driveLight(_drive, true); }
break;
case LOC.DRIVE1:
_debug("Disk 1");
_debug('Disk 1');
_drive = 1;
_cur = _drives[_drive - 1];
if (_on && callbacks.driveLight) {
@ -451,7 +452,7 @@ function DiskII(io, callbacks, slot)
}
break;
case LOC.DRIVE2:
_debug("Disk 2");
_debug('Disk 2');
_drive = 2;
_cur = _drives[_drive - 1];
if (_on && callbacks.driveLight) {
@ -459,25 +460,25 @@ function DiskII(io, callbacks, slot)
callbacks.driveLight(2, true);
}
break;
case LOC.DRIVEREAD:
result = _readNext();
// _debug("read: " + toHex(result));
// _debug('read: ' + toHex(result));
break;
case LOC.DRIVEWRITE:
// _debug("write: " + toHex(val));
// _debug('write: ' + toHex(val));
if (val !== undefined) {
_writeNext(val);
}
break;
case LOC.DRIVEREADMODE:
_debug("Read Mode");
_debug('Read Mode');
_writeMode = false;
result = (_readNext() & 0x7f) | (_cur.readOnly ? 0x80 : 0x00);
break;
case LOC.DRIVEWRITEMODE:
_debug("Write Mode");
_debug('Write Mode');
_writeMode = true;
break;
default:
@ -650,10 +651,10 @@ function DiskII(io, callbacks, slot)
var fmt = disk.type, readOnly = disk.readOnly;
var data, t, s;
if (disk.encoding == "base64") {
if (disk.encoding == 'base64') {
data = [];
for (t = 0; t < disk.data.length; t++) {
if (fmt == "nib") {
if (fmt == 'nib') {
data[t] = base64_decode(disk.data[t]);
} else {
data[t] = [];
@ -667,7 +668,7 @@ function DiskII(io, callbacks, slot)
}
var cur = _drives[drive - 1];
// var v = (fmt === "dsk" ? data[0x11][0x00][0x06] : 0xfe);
// var v = (fmt === 'dsk' ? data[0x11][0x00][0x06] : 0xfe);
// if (v == 0x00) {
var v = disk.volume || 0xfe;
// }
@ -679,19 +680,19 @@ function DiskII(io, callbacks, slot)
for (t = 0; t < data.length; t++) {
var track = [];
if (fmt === "nib") {
if (fmt === 'nib') {
track = data[t];
} else {
for (s = 0; s < data[t].length; s++) {
var _s = 15 - s;
if (fmt === "po") { // ProDOS Order
if (fmt === 'po') { // ProDOS Order
extend(track,
_explodeSector(v, t, _PO[s], data[t][s]));
} else if (fmt === "dsk") { // DOS Order
} else if (fmt === 'dsk') { // DOS Order
extend(track,
_explodeSector(v, t, _DO[_s], data[t][_s]));
} else { // flat
extend(track,
extend(track,
_explodeSector(v, t, s, data[t][s]));
}
}
@ -712,32 +713,32 @@ function DiskII(io, callbacks, slot)
var _cur = _drives[drive - 1];
var tracks = [];
var v = 254;
if (fmt === "do") {
fmt = "dsk";
if (fmt === 'do') {
fmt = 'dsk';
}
_cur.readOnly = false;
if (fmt === "2mg") {
if (fmt === '2mg') {
// Standard header size is 64 bytes. Make assumptions.
var prefix = new Uint8Array(data.slice(0, 64));
data = data.slice(64);
// Check image format.
// Sure, it's really 64 bits. But only 2 are actually used.
switch (prefix[0xc]) {
case 0:
fmt = "dsk";
fmt = 'dsk';
break;
case 1:
fmt = "po";
fmt = 'po';
break;
case 2:
fmt = "nib";
fmt = 'nib';
break;
default: // Something hinky, assume "dsk"
fmt = "dsk";
default: // Something hinky, assume 'dsk'
fmt = 'dsk';
break;
}
var flags =
var flags =
prefix[0x10] | (prefix[0x11] << 8) |
(prefix[0x12] << 16) | (prefix[0x13] << 24);
_cur.readOnly = (flags & 0x80000000) ? true : false;
@ -749,20 +750,20 @@ function DiskII(io, callbacks, slot)
}
for (var t = 0; t < 35; t++) {
var track, off, d;
if (fmt === "nib") {
if (fmt === 'nib') {
off = t * 0x1a00;
track = new Uint8Array(data.slice(off, off + 0x1a00));
} else {
track = [];
for (var s = 0; s < 16; s++) {
var _s = 15 - s;
if (fmt == "po") { // ProDOS Order
off = (16 * t + s) * 256;
if (fmt == 'po') { // ProDOS Order
off = (16 * t + s) * 256;
d = new Uint8Array(data.slice(off, off + 256));
extend(track,
_explodeSector(v, t, _PO[s], d));
} else if (fmt == "dsk") { // DOS Order
off = (16 * t + _s) * 256;
} else if (fmt == 'dsk') { // DOS Order
off = (16 * t + _s) * 256;
d = new Uint8Array(data.slice(off, off + 256));
extend(track,
_explodeSector(v, t, _DO[_s], d));
@ -786,9 +787,9 @@ function DiskII(io, callbacks, slot)
var len = (16 * cur.tracks.length * 256);
var data = new Uint8Array(len);
var idx = 0;
for (var t = 0; t < cur.tracks.length; t++) {
if (cur.format === "nib") {
if (cur.format === 'nib') {
data[idx++] = cur.tracks[t];
} else {
for (var s = 0; s < 0x10; s++) {
@ -808,7 +809,7 @@ function DiskII(io, callbacks, slot)
var data = [];
for (var t = 0; t < cur.tracks.length; t++) {
data[t] = [];
if (cur.format === "nib") {
if (cur.format === 'nib') {
data += base64_encode(cur.tracks[t]);
} else {
for (var s = 0; s < 0x10; s++) {

View File

@ -1,5 +1,3 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*global bytify:false */
/*exported Apple2ROM */
function Apple2ROM()
{
@ -1542,8 +1540,6 @@ function Apple2ROM()
0xf5,0x03,0xfb,0x03,0x62,0xfa,0x59,0xff
];
rom = bytify(rom);
return {
start: function() {
return 0xd0;

View File

@ -1,10 +1,10 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*exported IntBASIC */
function IntBASIC()
{
var rom = [
0xa9,0x20,0x8d,0x26,0x03,0xad,0x57,0xc0,
0xad,0x53,0xc0,0xad,0x50,0xc0,0xa9,0x00,
var rom = [
0xa9,0x20,0x8d,0x26,0x03,0xad,0x57,0xc0,
0xad,0x53,0xc0,0xad,0x50,0xc0,0xa9,0x00,
0x85,0x1c,0xad,0x26,0x03,0x85,0x1b,0xa0,
0x00,0x84,0x1a,0xa5,0x1c,0x91,0x1a,0x20,
0xa2,0xd0,0xc8,0xd0,0xf6,0xe6,0x1b,0xa5,
@ -1551,8 +1551,7 @@ function IntBASIC()
read: function(page, off) {
return rom[((page - 0xD0) << 8) + off];
},
write: function(page, off, val) {
write: function() {
}
};
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,10 +9,12 @@
* implied warranty.
*/
/*globals RAM */
/*exported LanguageCard */
/*globals RAM: false */
function LanguageCard(io, rom) {
'use strict';
var _io = io;
var _rom = rom;
var _bank1 = null;
@ -88,28 +89,28 @@ function LanguageCard(io, rom) {
_readbsr = true;
_writebsr = false;
_bsr2 = true;
_debug("Bank 2 Read");
_debug('Bank 2 Read');
break;
case LOC.WRITEBSR2:
case LOC._WRITEBSR2:
_readbsr = false;
_writebsr = ((_last & 0xF3) == (off & 0xF3));
_bsr2 = true;
_debug("Bank 2 Write");
_debug('Bank 2 Write');
break;
case LOC.OFFBSR2:
case LOC._OFFBSR2:
_readbsr = false;
_writebsr = false;
_bsr2 = true;
_debug("Bank 2 Off");
_debug('Bank 2 Off');
break;
case LOC.READWRBSR2:
case LOC._READWRBSR2:
case LOC._READWRBSR2:
_readbsr = true;
_writebsr = ((_last & 0xF3) == (off & 0xF3));
_bsr2 = true;
_debug("Bank 2 Read/Write");
_debug('Bank 2 Read/Write');
break;
case LOC.READBSR1:
@ -117,37 +118,37 @@ function LanguageCard(io, rom) {
_readbsr = true;
_writebsr = false;
_bsr2 = false;
_debug("Bank 1 Read");
_debug('Bank 1 Read');
break;
case LOC.WRITEBSR1:
case LOC._WRITEBSR1:
_readbsr = false;
_writebsr = ((_last & 0xF3) == (off & 0xF3));
_bsr2 = false;
_debug("Bank 1 Write");
_debug('Bank 1 Write');
break;
case LOC.OFFBSR1:
case LOC._OFFBSR1:
_readbsr = false;
_writebsr = false;
_bsr2 = false;
_debug("Bank 1 Off");
_debug('Bank 1 Off');
break;
case LOC.READWRBSR1:
case LOC._READWRBSR1:
_readbsr = true;
_writebsr = ((_last & 0xF3) == (off & 0xF3));
_bsr2 = false;
_debug("Bank 1 Read/Write");
_debug('Bank 1 Read/Write');
break;
case LOC.BSRBANK2:
result = _bsr2 ? 0x80 : 0x00;
_debug("Bank 2 Read " + _bsr2);
result = _bsr2 ? 0x80 : 0x00;
_debug('Bank 2 Read ' + _bsr2);
break;
case LOC.BSRREADRAM:
result = _readbsr ? 0x80 : 0x00;
_debug("Bank SW RAM Read " + _readbsr);
_debug('Bank SW RAM Read ' + _readbsr);
break;
default:
break;

876
js/main2.js Normal file
View File

@ -0,0 +1,876 @@
/* globals debug: false, gup: false, hup: false
CPU6502: false,
RAM: false,
Apple2ROM: false
apple2_charset: false,
Apple2IO: false
LoresPage: false, HiresPage: false, VideoModes: false
KeyBoard: false,
Parallel: false,
DiskII: false,
RAMFactor: false,
Printer: false,
LanguageCard: false,
Thunderclock: false,
Prefs: false,
disk_index: false,
initAudio: false, enableSound: false,
initGamepad: false, processGamepad: false, gamepad: false,
ApplesoftDump: false
*/
/* exported openLoad, openSave, doDelete,
selectCategory, selectDisk, clickDisk, loadJSON,
updateJoystick,
pauseRun, step
dumpProgram, PageDebug
*/
var kHz = 1023;
var focused = false;
var startTime = Date.now();
var lastCycles = 0;
var renderedFrames = 0, lastFrames = 0;
var paused = false;
var hashtag;
var disk_categories = {'Local Saves': []};
var disk_sets = {};
var disk_cur_name = [];
var disk_cur_cat = [];
function DriveLights()
{
return {
driveLight: function(drive, on) {
$('#disk' + drive).css('background-image',
on ? 'url(css/red-on-16.png)' :
'url(css/red-off-16.png)');
},
dirty: function(drive, dirty) {
$('#disksave' + drive).button('option', 'disabled', !dirty);
},
label: function(drive, label) {
if (label) {
$('#disklabel' + drive).text(label);
}
return $('#disklabel' + drive).text();
},
getState: function() {
return {
disks: [
this.label(1),
this.label(2)
]
};
},
setState: function(state) {
if (state && state.disks) {
this.label(1, state.disks[0].label);
this.label(2, state.disks[1].label);
}
}
};
}
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
var _saveDrive = 1;
var _loadDrive = 1;
function openLoad(drive, event)
{
_loadDrive = drive;
if (event.metaKey) {
openLoadHTTP(drive);
} else {
if (disk_cur_cat[drive]) {
$('#category_select').val(disk_cur_cat[drive]).change();
}
$('#load').dialog('open');
}
}
function openSave(drive, event)
{
_saveDrive = drive;
if (event.metaKey) {
dumpDisk(drive);
} else if (event.altKey) {
openSaveLocal(drive);
} else {
$('#save_name').val(drivelights.label(drive));
$('#save').dialog('open');
}
}
var loading = false;
function loadAjax(url) {
loading = true;
$('#loading').dialog('open');
$.ajax({ url: url,
cache: false,
dataType: 'jsonp',
jsonp: false,
global: false
});
}
function doLoad() {
var urls = $('#disk_select').val(), url;
if (urls && urls.length) {
if (typeof(urls) == 'string') {
url = urls;
} else {
url = urls[0];
}
}
var files = $('#local_file').prop('files');
if (files.length == 1) {
doLoadLocal();
} else if (url) {
var filename;
$('#load').dialog('close');
if (url.substr(0,6) == 'local:') {
filename = url.substr(6);
if (filename == '__manage') {
openManage();
} else {
loadLocalStorage(_loadDrive, filename);
}
} else {
var r1 = /json\/disks\/(.*).json$/.exec(url);
if (r1 && _loadDrive == 1) {
filename = r1[1];
document.location.hash = filename;
}
loadAjax(url);
}
}
}
function doSave() {
var name = $('#save_name').val();
saveLocalStorage(_saveDrive, name);
$('#save').dialog('close');
}
function doDelete(name) {
if (window.confirm('Delete ' + name + '?')) {
deleteLocalStorage(name);
}
}
function doLoadLocal() {
var files = $('#local_file').prop('files');
if (files.length == 1) {
var file = files[0];
var parts = file.name.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
doLoadLocalTape(file);
} else {
window.alert('Unknown file type: ' + ext);
$('#load').dialog('close');
}
}
}
function doLoadLocalDisk(file) {
var fileReader = new FileReader();
fileReader.onload = function() {
var parts = file.name.split('.');
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
drivelights.label(_saveDrive, name);
$('#load').dialog('close');
initGamepad();
}
};
fileReader.readAsArrayBuffer(file);
}
function doLoadLocalTape(file) {
// Audio Buffer Source
var context;
if (typeof window.AudioContext != 'undefined') {
context = new window.AudioContext();
} else {
window.alert('Not supported by your browser');
$('#load').dialog('close');
return;
}
var fileReader = new FileReader();
fileReader.onload = function(ev) {
context.decodeAudioData(ev.target.result, function(buffer) {
var buf = [];
var data = buffer.getChannelData(0), datum = data[0];
var old = (datum > 0.0), current;
var last = 0, delta, ival;
debug('Sample Count: ' + data.length);
debug('Sample rate: ' + buffer.sampleRate);
for (var idx = 1; idx < data.length; idx++) {
datum = data[idx];
if ((datum > 0.1) || (datum < -0.1)) {
current = (datum > 0.0);
if (current != old) {
delta = idx - last;
if (delta > 2000000) {
delta = 2000000;
}
ival = delta / buffer.sampleRate * 1000;
if (ival >= 0.550 && ival < 0.750) {
ival = 0.650; // Header
} else if (ival >= 0.175 && ival < 0.225) {
ival = 0.200; // sync 1
} else if (ival >= 0.225 && ival < 0.275) {
ival = 0.250; // 0 / sync 2
} else if (ival >= 0.450 && ival < 0.550) {
ival = 0.500; // 1
} else {
// debug(idx + ' ' + buf.length + ' ' + ival);
}
buf.push(parseInt(ival * kHz));
old = current;
last = idx;
}
}
}
io.setTape(buf);
$('#load').dialog('close');
});
};
fileReader.readAsArrayBuffer(file);
}
function doLoadHTTP(_url) {
var url = _url || $('#http_url').val();
if (url) {
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.responseType = 'arraybuffer';
req.onload = function() {
var parts = url.split(/[\/\.]/);
var name = decodeURIComponent(parts[parts.length - 2]);
var ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
drivelights.label(_saveDrive, name);
$('#http_load').dialog('close');
initGamepad();
}
};
req.send(null);
}
}
function openLoadHTTP(drive) {
_saveDrive = drive;
$('#http_load').dialog('open');
}
function openSaveLocal(drive) {
_saveDrive = drive;
var mimetype = 'application/octet-stream';
var data = disk2.getBinary(drive);
var a = $('#local_save_link');
var blob = new Blob([data], { 'type': mimetype });
a.attr('href', window.URL.createObjectURL(blob));
a.attr('download', drivelights.label(drive) + '.dsk');
$('#local_save').dialog('open');
}
function openManage() {
$('#manage').dialog('open');
}
var prefs = new Prefs();
var runTimer = null;
var cpu = new CPU6502();
var ram1 = new RAM(0x00, 0x03),
ram2 = new RAM(0x0C, 0x1F),
ram3 = new RAM(0x60, 0xBF);
var hgr = new HiresPage(1);
var hgr2 = new HiresPage(2);
var gr = new LoresPage(1, apple2_charset);
var gr2 = new LoresPage(2, apple2_charset);
var rom = new Apple2ROM();
var dumper = new ApplesoftDump(ram2);
var vm = new VideoModes(gr, hgr, gr2, hgr2);
var mmu = {
auxRom: function(slot, rom) {
cpu.addPageHandler(rom);
}
};
var drivelights = new DriveLights();
var io = new Apple2IO(cpu, vm);
var keyboard = new KeyBoard(io);
var parallel = new Parallel(io, new Printer(), 1);
var disk2 = new DiskII(io, drivelights, 6);
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
var clock = new Thunderclock(mmu, io, 7);
var lc = new LanguageCard(io, rom);
cpu.addPageHandler(ram1);
cpu.addPageHandler(gr);
cpu.addPageHandler(gr2);
cpu.addPageHandler(ram2);
cpu.addPageHandler(hgr);
cpu.addPageHandler(hgr2);
cpu.addPageHandler(ram3);
cpu.addPageHandler(lc);
cpu.addPageHandler(io);
cpu.addPageHandler(parallel);
cpu.addPageHandler(slinky);
cpu.addPageHandler(disk2);
cpu.addPageHandler(clock);
var showFPS = false;
function updateKHz() {
var now = Date.now();
var ms = now - startTime;
var cycles = cpu.cycles();
var delta;
if (showFPS) {
delta = renderedFrames - lastFrames;
var fps = parseInt(delta/(ms/1000), 10);
$('#khz').text( fps + 'fps');
} else {
delta = cycles - lastCycles;
var khz = parseInt(delta/ms);
$('#khz').text( khz + 'KHz');
}
startTime = now;
lastCycles = cycles;
lastFrames = renderedFrames;
}
/* Audio Handling */
initAudio(io);
function updateSound() {
enableSound($('#enable_sound').attr('checked'));
}
function dumpDisk(drive) {
var wind = window.open('', '_blank');
wind.document.title = drivelights.label(drive);
wind.document.write('<pre>');
wind.document.write(disk2.getJSON(drive, true));
wind.document.write('</pre>');
wind.document.close();
}
function dumpProgram() {
var wind = window.open('', '_blank');
wind.document.title = 'Program Listing';
wind.document.write('<pre>');
wind.document.write(dumper.toString());
wind.document.write('</pre>');
wind.document.close();
}
function step()
{
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
cpu.step(function() {
debug(cpu.dumpRegisters());
debug(cpu.dumpPC());
});
}
var accelerated = false;
function updateSpeed()
{
accelerated = $('#accelerator_toggle').prop('checked');
kHz = accelerated ? 4092 : 1023;
io.updateHz(kHz * 1000);
if (runTimer) {
run();
}
}
var _requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function run(pc) {
if (runTimer) {
clearInterval(runTimer);
}
if (pc) {
cpu.setPC(pc);
}
var ival = 30;
var now, last = Date.now();
var runFn = function() {
now = Date.now();
renderedFrames++;
var step = (now - last) * kHz, stepMax = kHz * ival;
last = now;
if (step > stepMax) {
step = stepMax;
}
if (document.location.hash != hashtag) {
hashtag = document.location.hash;
var hash = hup();
if (hash) {
processHash(hash);
}
}
if (!loading) {
cpu.stepCycles(step);
vm.blit();
io.sampleTick();
}
processGamepad(io);
if (!paused && _requestAnimationFrame) {
_requestAnimationFrame(runFn);
}
};
if (_requestAnimationFrame) {
_requestAnimationFrame(runFn);
} else {
runTimer = setInterval(runFn, ival);
}
}
function stop() {
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
}
function reset()
{
cpu.reset();
}
function loadBinary(bin) {
stop();
for (var idx = 0; idx < bin.length; idx++) {
var pos = bin.start + idx;
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
}
run(bin.start);
}
function selectCategory() {
$('#disk_select').empty();
var cat = disk_categories[$('#category_select').val()];
if (cat) {
for (var idx = 0; idx < cat.length; idx++) {
var file = cat[idx], name = file.name;
if (file.disk) {
name += ' - ' + file.disk;
}
var option = $('<option />').val(file.filename).text(name)
.appendTo('#disk_select');
if (disk_cur_name[_loadDrive] == name) {
option.attr('selected', 'selected');
}
}
}
}
function selectDisk() {
$('#local_file').val('');
}
function clickDisk() {
doLoad();
}
function loadDisk(disk) {
var name = disk.name;
var category = disk.category;
if (disk.disk) {
name += ' - ' + disk.disk;
}
disk_cur_cat[_loadDrive] = category;
disk_cur_name[_loadDrive] = name;
drivelights.label(_loadDrive, name);
disk2.setDisk(_loadDrive, disk);
initGamepad(disk.gamepad);
}
function loadJSON(data) {
if (data.type == 'binary') {
loadBinary(data);
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
loadDisk(data);
}
initGamepad(data.gamepad);
$('#loading').dialog('close');
loading = false;
}
/*
* LocalStorage Disk Storage
*/
function updateLocalStorage() {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
var names = [], name, cat;
for (name in diskIndex) {
if (diskIndex.hasOwnProperty(name)) {
names.push(name);
}
}
cat = disk_categories['Local Saves'] = [];
$('#manage').empty();
names.forEach(function(name) {
cat.push({'category': 'Local Saves',
'name': name,
'filename': 'local:' + name});
$('#manage').append('<span class="local_save">' +
name +
' <a href="#" onclick="doDelete(\'' +
name +
'\')">Delete</a><br /></span>');
});
cat.push({'category': 'Local Saves',
'name': 'Manage Saves...',
'filename': 'local:__manage'});
}
function saveLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
var json = disk2.getJSON(drive);
diskIndex[name] = json;
window.localStorage.diskIndex = JSON.stringify(diskIndex);
window.alert('Saved');
drivelights.label(drive, name);
drivelights.dirty(drive, false);
updateLocalStorage();
}
function deleteLocalStorage(name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
if (diskIndex[name]) {
delete diskIndex[name];
window.alert('Deleted');
}
window.localStorage.diskIndex = JSON.stringify(diskIndex);
updateLocalStorage();
}
function loadLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
if (diskIndex[name]) {
disk2.setJSON(drive, diskIndex[name]);
drivelights.label(drive, name);
drivelights.dirty(drive, false);
}
}
function processHash(hash) {
if (hash.indexOf('://') > 0) {
var parts = hash.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if (ext == 'json') {
loadAjax(hash);
} else {
doLoadHTTP(hash);
}
} else {
loadAjax('json/disks/' + hash + '.json');
}
}
/*
* Keyboard/Gamepad routines
*/
function _keydown(evt) {
if (evt.keyCode === 112) { // F1 - Reset
cpu.reset();
} else if (evt.keyCode === 113) { // F2 - Full Screen
var elem = document.getElementById('screen');
if (document.webkitCancelFullScreen) {
if (document.webkitIsFullScreen) {
document.webkitCancelFullScreen();
} else {
if (Element.ALLOW_KEYBOARD_INPUT) {
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
} else {
elem.webkitRequestFullScreen();
}
}
} else if (document.mozCancelFullScreen) {
if (document.mozIsFullScreen) {
document.mozCancelFullScreen();
} else {
elem.mozRequestFullScreen();
}
}
} else if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(true);
io.buttonDown(2);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(true);
} else if (!focused && (!evt.metaKey || evt.ctrlKey)) {
evt.preventDefault();
var key = keyboard.mapKeyEvent(evt);
if (key != 0xff) {
io.keyDown(key);
}
}
}
function _keyup(evt) {
if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(false);
io.buttonUp(2);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(false);
} else {
if (!focused) {
io.keyUp();
}
}
}
function updateScreen() {
var green = $('#green_screen').prop('checked');
vm.green(green);
}
var disableMouseJoystick = false;
var flipX = false;
var flipY = false;
var swapXY = false;
function updateJoystick() {
disableMouseJoystick = $('#disable_mouse').prop('checked');
flipX = $('#flip_x').prop('checked');
flipY = $('#flip_y').prop('checked');
swapXY = $('#swap_x_y').prop('checked');
if (disableMouseJoystick) {
io.paddle(0, 0.5);
io.paddle(1, 0.5);
return;
}
}
function _mousemove(evt) {
if (gamepad || disableMouseJoystick) {
return;
}
var s = $('#screen');
var offset = s.offset();
var x = (evt.pageX - offset.left) / s.width(),
y = (evt.pageY - offset.top) / s.height(),
z = x;
if (swapXY) {
x = y;
y = z;
}
io.paddle(0, flipX ? 1 - x : x);
io.paddle(1, flipY ? 1 - y : y);
}
function pauseRun(b) {
if (paused) {
run();
b.value = 'Pause';
} else {
stop();
b.value = 'Run';
}
paused = !paused;
}
$(function() {
hashtag = document.location.hash;
$('button,input[type=button],a.button').button().focus(function() {
// Crazy hack required by Chrome
var self = this;
window.setTimeout(function() {
self.blur();
}, 1);
});
var canvas = document.getElementById('screen');
var context = canvas.getContext('2d');
vm.setContext(context);
/*
* Input Handling
*/
$(window).keydown(_keydown);
$(window).keyup(_keyup);
$('canvas').mousedown(function(evt) {
if (!gamepad) {
io.buttonDown(evt.which == 1 ? 0 : 1);
}
evt.preventDefault();
})
.mouseup(function(evt) {
if (!gamepad) {
io.buttonUp(evt.which == 1 ? 0 : 1);
}
})
.bind('contextmenu', function(evt) { evt.preventDefault(); });
$('body').mousemove(_mousemove);
$('input,textarea').focus(function() { focused = true; })
.blur(function() { focused = false; });
keyboard.create($('#keyboard'));
if (prefs.havePrefs()) {
$('input[type=checkbox]').each(function() {
var val = prefs.readPref(this.id);
if (val)
this.checked = JSON.parse(val);
}).change(function() {
prefs.writePref(this.id, JSON.stringify(this.checked));
});
}
reset();
run();
setInterval(updateKHz, 1000);
updateSound();
updateScreen();
updateSpeed();
var cancel = function() { $(this).dialog('close'); };
$('#loading').dialog({ autoOpen: false, modal: true });
$('#options').dialog({ autoOpen: false,
modal: true,
width: 320,
height: 400,
buttons: {'Close': cancel }});
$('#load').dialog({ autoOpen: false,
modal: true,
width: 540,
buttons: {'Cancel': cancel, 'Load': doLoad }});
$('#save').dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {'Cancel': cancel, 'Save': doSave }});
$('#manage').dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {'Close': cancel }});
$('#local_save').dialog({ autoOpen: false,
modal: true,
width: 530,
buttons: {'OK': cancel }});
$('#http_load').dialog({ autoOpen: false,
modal: true,
width: 530,
buttons: {'Cancel': cancel, 'OK': doLoadHTTP }});
if (window.localStorage !== undefined) {
$('.disksave').show();
}
var oldcat = '';
for (var idx = 0; idx < disk_index.length; idx++) {
var file = disk_index[idx];
var cat = file.category;
var name = file.name, disk = file.disk;
if (file.e) {
continue;
}
if (cat != oldcat) {
$('<option />').val(cat).text(cat).appendTo('#category_select');
disk_categories[cat] = [];
oldcat = cat;
}
disk_categories[cat].push(file);
if (disk) {
if (!disk_sets[name]) {
disk_sets[name] = [];
}
disk_sets[name].push(file);
}
}
$('<option/>').text('Local Saves').appendTo('#category_select');
updateLocalStorage();
initGamepad();
// Check for disks in hashtag
var hash = gup('disk') || hup();
if (hash) {
processHash(hash);
}
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
$('select').removeAttr('multiple').css('height', 'auto');
}
if (navigator.standalone) {
$('body').addClass('standalone');
}
$('.key-REPT').click(function() {
$('#keyboard').hide();
$('#textarea').show();
$('#text_input').focus();
});
$('#text_input').keydown(function() {
focused = $('#buffering').prop('checked');
}).keyup(function() {
focused = $('#buffering').prop('checked');
});
});

877
js/main2e.js Normal file
View File

@ -0,0 +1,877 @@
/* globals debug: false, gup: false, hup: false,
CPU6502: false,
Apple2eROM: false, Apple2eEnhancedROM: false,
apple2e_charset: false,
Apple2IO: false
LoresPage: false, HiresPage: false, VideoModes: false
KeyBoard: false,
Parallel: false,
DiskII: false,
RAMFactor: false,
Printer: false,
MMU: false,
Slot3: false,
Thunderclock: false,
Prefs: false,
disk_index: false,
initAudio: false, enableSound: false,
initGamepad: false, processGamepad: false, gamepad: false,
ApplesoftDump: false
*/
/* exported openLoad, openSave, doDelete,
selectCategory, selectDisk, clickDisk, loadJSON,
updateJoystick,
pauseRun, step,
restoreState, saveState,
dumpProgram, PageDebug
*/
var kHz = 1023;
var focused = false;
var startTime = Date.now();
var lastCycles = 0;
var renderedFrames = 0, lastFrames = 0;
var paused = false;
var hashtag;
var disk_categories = {'Local Saves': []};
var disk_sets = {};
var disk_cur_name = [];
var disk_cur_cat = [];
function DriveLights()
{
return {
driveLight: function(drive, on) {
$('#disk' + drive).css('background-image',
on ? 'url(css/red-on-16.png)' :
'url(css/red-off-16.png)');
},
dirty: function(drive, dirty) {
$('#disksave' + drive).button('option', 'disabled', !dirty);
},
label: function(drive, label) {
if (label) {
$('#disklabel' + drive).text(label);
}
return $('#disklabel' + drive).text();
},
getState: function() {
return {
disks: [
this.label(1),
this.label(2)
]
};
},
setState: function(state) {
if (state && state.disks) {
this.label(1, state.disks[0].label);
this.label(2, state.disks[1].label);
}
}
};
}
var DISK_TYPES = ['dsk','do','po','raw','nib','2mg'];
var TAPE_TYPES = ['wav','aiff','aif','mp3'];
var _saveDrive = 1;
var _loadDrive = 1;
function openLoad(drive, event)
{
_loadDrive = drive;
if (event.metaKey) {
openLoadHTTP(drive);
} else {
if (disk_cur_cat[drive]) {
$('#category_select').val(disk_cur_cat[drive]).change();
}
$('#load').dialog('open');
}
}
function openSave(drive, event)
{
_saveDrive = drive;
if (event.metaKey) {
dumpDisk(drive);
} else if (event.altKey) {
openSaveLocal(drive);
} else {
$('#save_name').val(drivelights.label(drive));
$('#save').dialog('open');
}
}
var loading = false;
function loadAjax(url) {
loading = true;
$('#loading').dialog('open');
$.ajax({ url: url,
cache: false,
dataType: 'jsonp',
jsonp: false,
global: false
});
}
function doLoad() {
var urls = $('#disk_select').val(), url;
if (urls && urls.length) {
if (typeof(urls) == 'string') {
url = urls;
} else {
url = urls[0];
}
}
var files = $('#local_file').prop('files');
if (files.length == 1) {
doLoadLocal();
} else if (url) {
var filename;
$('#load').dialog('close');
if (url.substr(0,6) == 'local:') {
filename = url.substr(6);
if (filename == '__manage') {
openManage();
} else {
loadLocalStorage(_loadDrive, filename);
}
} else {
var r1 = /json\/disks\/(.*).json$/.exec(url);
if (r1 && _loadDrive == 1) {
filename = r1[1];
document.location.hash = filename;
}
loadAjax(url);
}
}
}
function doSave() {
var name = $('#save_name').val();
saveLocalStorage(_saveDrive, name);
$('#save').dialog('close');
}
function doDelete(name) {
if (window.confirm('Delete ' + name + '?')) {
deleteLocalStorage(name);
}
}
function doLoadLocal() {
var files = $('#local_file').prop('files');
if (files.length == 1) {
var file = files[0];
var parts = file.name.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if ($.inArray(ext, DISK_TYPES) >= 0) {
doLoadLocalDisk(file);
} else if ($.inArray(ext, TAPE_TYPES) >= 0) {
doLoadLocalTape(file);
} else {
window.alert('Unknown file type: ' + ext);
$('#load').dialog('close');
}
}
}
function doLoadLocalDisk(file) {
var fileReader = new FileReader();
fileReader.onload = function() {
var parts = file.name.split('.');
var name = parts[0], ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, this.result)) {
drivelights.label(_saveDrive, name);
$('#load').dialog('close');
initGamepad();
}
};
fileReader.readAsArrayBuffer(file);
}
function doLoadLocalTape(file) {
// Audio Buffer Source
var context;
if (typeof window.AudioContext != 'undefined') {
context = new window.AudioContext();
} else {
window.alert('Not supported by your browser');
$('#load').dialog('close');
return;
}
var fileReader = new FileReader();
fileReader.onload = function(ev) {
context.decodeAudioData(ev.target.result, function(buffer) {
var buf = [];
var data = buffer.getChannelData(0), datum = data[0];
var old = (datum > 0.0), current;
var last = 0, delta, ival;
debug('Sample Count: ' + data.length);
debug('Sample rate: ' + buffer.sampleRate);
for (var idx = 1; idx < data.length; idx++) {
datum = data[idx];
if ((datum > 0.1) || (datum < -0.1)) {
current = (datum > 0.0);
if (current != old) {
delta = idx - last;
if (delta > 2000000) {
delta = 2000000;
}
ival = delta / buffer.sampleRate * 1000;
if (ival >= 0.550 && ival < 0.750) {
ival = 0.650; // Header
} else if (ival >= 0.175 && ival < 0.225) {
ival = 0.200; // sync 1
} else if (ival >= 0.225 && ival < 0.275) {
ival = 0.250; // 0 / sync 2
} else if (ival >= 0.450 && ival < 0.550) {
ival = 0.500; // 1
} else {
// debug(idx + ' ' + buf.length + ' ' + ival);
}
buf.push(parseInt(ival * kHz));
old = current;
last = idx;
}
}
}
io.setTape(buf);
$('#load').dialog('close');
});
};
fileReader.readAsArrayBuffer(file);
}
function doLoadHTTP(_url) {
var url = _url || $('#http_url').val();
if (url) {
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.responseType = 'arraybuffer';
req.onload = function() {
var parts = url.split(/[\/\.]/);
var name = decodeURIComponent(parts[parts.length - 2]);
var ext = parts[parts.length - 1].toLowerCase();
if (disk2.setBinary(_saveDrive, name, ext, req.response)) {
drivelights.label(_saveDrive, name);
$('#http_load').dialog('close');
initGamepad();
}
};
req.send(null);
}
}
function openLoadHTTP(drive) {
_saveDrive = drive;
$('#http_load').dialog('open');
}
function openSaveLocal(drive) {
_saveDrive = drive;
var mimetype = 'application/octet-stream';
var data = disk2.getBinary(drive);
var a = $('#local_save_link');
var blob = new Blob([data], { 'type': mimetype });
a.attr('href', window.URL.createObjectURL(blob));
a.attr('download', drivelights.label(drive) + '.dsk');
$('#local_save').dialog('open');
}
function openManage() {
$('#manage').dialog('open');
}
var prefs = new Prefs();
var enhanced = true;
var runTimer = null;
var cpu = new CPU6502({'65C02': enhanced});
var hgr = new HiresPage(1);
var hgr2 = new HiresPage(2);
var gr = new LoresPage(1, apple2e_charset);
var gr2 = new LoresPage(2, apple2e_charset);
var rom;
if (enhanced) {
rom = new Apple2eEnhancedROM();
} else {
rom = new Apple2eROM();
}
var vm = new VideoModes(gr, hgr, gr2, hgr2);
var drivelights = new DriveLights();
var io = new Apple2IO(cpu, vm);
var keyboard = new KeyBoard(io);
var mmu = new MMU(cpu, gr, gr2, hgr, hgr2, io, rom);
var dumper = new ApplesoftDump(mmu);
var parallel = new Parallel(io, new Printer(), 1);
var disk2 = new DiskII(io, drivelights, 6);
var slot3 = new Slot3(mmu, rom);
var slinky = new RAMFactor(mmu, io, 2, 1024 * 1024);
var clock = new Thunderclock(mmu, io, 7);
mmu.addSlot(1, parallel);
mmu.addSlot(2, slinky);
mmu.addSlot(3, slot3);
mmu.addSlot(6, disk2);
mmu.addSlot(7, clock);
cpu.addPageHandler(mmu);
var showFPS = false;
function updateKHz() {
var now = Date.now();
var ms = now - startTime;
var cycles = cpu.cycles();
var delta;
if (showFPS) {
delta = renderedFrames - lastFrames;
var fps = parseInt(delta/(ms/1000), 10);
$('#khz').text( fps + 'fps');
} else {
delta = cycles - lastCycles;
var khz = parseInt(delta/ms);
$('#khz').text( khz + 'KHz');
}
startTime = now;
lastCycles = cycles;
lastFrames = renderedFrames;
}
/* Audio Handling */
initAudio(io);
function updateSound() {
enableSound($('#enable_sound').attr('checked'));
}
function dumpDisk(drive) {
var wind = window.open('', '_blank');
wind.document.title = drivelights.label(drive);
wind.document.write('<pre>');
wind.document.write(disk2.getJSON(drive, true));
wind.document.write('</pre>');
wind.document.close();
}
function dumpProgram() {
var wind = window.open('', '_blank');
wind.document.title = 'Program Listing';
wind.document.write('<pre>');
wind.document.write(dumper.toString());
wind.document.write('</pre>');
wind.document.close();
}
function step()
{
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
cpu.step(function() {
debug(cpu.dumpRegisters());
debug(cpu.dumpPC());
});
}
var accelerated = false;
function updateSpeed()
{
accelerated = $('#accelerator_toggle').prop('checked');
kHz = accelerated ? 4092 : 1023;
io.updateHz(kHz * 1000);
if (runTimer) {
run();
}
}
var _requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function run(pc) {
if (runTimer) {
clearInterval(runTimer);
}
if (pc) {
cpu.setPC(pc);
}
var ival = 30;
var now, last = Date.now();
var runFn = function() {
now = Date.now();
renderedFrames++;
var step = (now - last) * kHz, stepMax = kHz * ival;
last = now;
if (step > stepMax) {
step = stepMax;
}
if (document.location.hash != hashtag) {
hashtag = document.location.hash;
var hash = hup();
if (hash) {
processHash(hash);
}
}
if (!loading) {
mmu.resetVB();
cpu.stepCycles(step);
vm.blit();
io.sampleTick();
}
processGamepad(io);
if (!paused && _requestAnimationFrame) {
_requestAnimationFrame(runFn);
}
};
if (_requestAnimationFrame) {
_requestAnimationFrame(runFn);
} else {
runTimer = setInterval(runFn, ival);
}
}
function stop() {
if (runTimer) {
clearInterval(runTimer);
}
runTimer = null;
}
function reset()
{
cpu.reset();
}
function loadBinary(bin) {
stop();
for (var idx = 0; idx < bin.length; idx++) {
var pos = bin.start + idx;
cpu.write(pos >> 8, pos & 0xff, bin.data[idx]);
}
run(bin.start);
}
function selectCategory() {
$('#disk_select').empty();
var cat = disk_categories[$('#category_select').val()];
if (cat) {
for (var idx = 0; idx < cat.length; idx++) {
var file = cat[idx], name = file.name;
if (file.disk) {
name += ' - ' + file.disk;
}
var option = $('<option />').val(file.filename).text(name)
.appendTo('#disk_select');
if (disk_cur_name[_loadDrive] == name) {
option.attr('selected', 'selected');
}
}
}
}
function selectDisk() {
$('#local_file').val('');
}
function clickDisk() {
doLoad();
}
function loadDisk(disk) {
var name = disk.name;
var category = disk.category;
if (disk.disk) {
name += ' - ' + disk.disk;
}
disk_cur_cat[_loadDrive] = category;
disk_cur_name[_loadDrive] = name;
drivelights.label(_loadDrive, name);
disk2.setDisk(_loadDrive, disk);
initGamepad(disk.gamepad);
}
function loadJSON(data) {
if (data.type == 'binary') {
loadBinary(data);
} else if ($.inArray(data.type, DISK_TYPES) >= 0) {
loadDisk(data);
}
initGamepad(data.gamepad);
$('#loading').dialog('close');
loading = false;
}
/*
* LocalStorage Disk Storage
*/
function updateLocalStorage() {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
var names = [], name, cat;
for (name in diskIndex) {
if (diskIndex.hasOwnProperty(name)) {
names.push(name);
}
}
cat = disk_categories['Local Saves'] = [];
$('#manage').empty();
names.forEach(function(name) {
cat.push({'category': 'Local Saves',
'name': name,
'filename': 'local:' + name});
$('#manage').append('<span class="local_save">' +
name +
' <a href="#" onclick="doDelete(\'' +
name +
'\')">Delete</a><br /></span>');
});
cat.push({'category': 'Local Saves',
'name': 'Manage Saves...',
'filename': 'local:__manage'});
}
function saveLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
var json = disk2.getJSON(drive);
diskIndex[name] = json;
window.localStorage.diskIndex = JSON.stringify(diskIndex);
window.alert('Saved');
drivelights.label(drive, name);
drivelights.dirty(drive, false);
updateLocalStorage();
}
function deleteLocalStorage(name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
if (diskIndex[name]) {
delete diskIndex[name];
window.alert('Deleted');
}
window.localStorage.diskIndex = JSON.stringify(diskIndex);
updateLocalStorage();
}
function loadLocalStorage(drive, name) {
var diskIndex = JSON.parse(window.localStorage.diskIndex || '{}');
if (diskIndex[name]) {
disk2.setJSON(drive, diskIndex[name]);
drivelights.label(drive, name);
drivelights.dirty(drive, false);
}
}
function processHash(hash) {
if (hash.indexOf('://') > 0) {
var parts = hash.split('.');
var ext = parts[parts.length - 1].toLowerCase();
if (ext == 'json') {
loadAjax(hash);
} else {
doLoadHTTP(hash);
}
} else {
loadAjax('json/disks/' + hash + '.json');
}
}
/*
* Keyboard/Gamepad routines
*/
var _key;
function _keydown(evt) {
if (!focused) {
evt.preventDefault();
var key = keyboard.mapKeyEvent(evt);
if (key != 0xff) {
if (_key != 0xff) io.keyUp();
io.keyDown(key, evt.shiftKey);
_key = key;
}
}
if (evt.keyCode === 112) {
cpu.reset();
} else if (evt.keyCode === 113) { // F2 - Full Screen
var elem = document.getElementById('screen');
if (document.webkitCancelFullScreen) {
if (document.webkitIsFullScreen) {
document.webkitCancelFullScreen();
} else {
if (Element.ALLOW_KEYBOARD_INPUT) {
elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
} else {
elem.webkitRequestFullScreen();
}
}
} else if (document.mozCancelFullScreen) {
if (document.mozIsFullScreen) {
document.mozCancelFullScreen();
} else {
elem.mozRequestFullScreen();
}
}
} else if (evt.keyCode === 114) {
io.keyDown(0x1b);
_key = 0x1b;
} else if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(true);
io.buttonDown(2, true);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(true);
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
keyboard.commandKey(true);
} else if (evt.keyCode == 18) { // Alt
keyboard.optionKey(true);
}
}
function _keyup(evt) {
_key = 0xff;
if (!focused)
io.keyUp();
if (evt.keyCode == 16) { // Shift
keyboard.shiftKey(false);
io.buttonDown(2, false);
} else if (evt.keyCode == 17) { // Control
keyboard.controlKey(false);
} else if (evt.keyCode == 91 || evt.keyCode == 93) { // Command
keyboard.commandKey(false);
} else if (evt.keyCode == 18) { // Alt
keyboard.optionKey(false);
}
}
function updateScreen() {
var green = $('#green_screen').prop('checked');
vm.green(green);
}
var disableMouseJoystick = false;
var flipX = false;
var flipY = false;
var swapXY = false;
function updateJoystick() {
disableMouseJoystick = $('#disable_mouse').prop('checked');
flipX = $('#flip_x').prop('checked');
flipY = $('#flip_y').prop('checked');
swapXY = $('#swap_x_y').prop('checked');
if (disableMouseJoystick) {
io.paddle(0, 0.5);
io.paddle(1, 0.5);
return;
}
}
function _mousemove(evt) {
if (gamepad || disableMouseJoystick) {
return;
}
var s = $('#screen');
var offset = s.offset();
var x = (evt.pageX - offset.left) / s.width(),
y = (evt.pageY - offset.top) / s.height(),
z = x;
if (swapXY) {
x = y;
y = z;
}
io.paddle(0, flipX ? 1 - x : x);
io.paddle(1, flipY ? 1 - y : y);
}
function pauseRun(b) {
if (paused) {
run();
b.value = 'Pause';
} else {
stop();
b.value = 'Run';
}
paused = !paused;
}
$(function() {
hashtag = document.location.hash;
$('button,input[type=button],a.button').button().focus(function() {
// Crazy hack required by Chrome
var self = this;
window.setTimeout(function() {
self.blur();
}, 1);
});
var canvas = document.getElementById('screen');
var context = canvas.getContext('2d');
vm.setContext(context);
/*
* Input Handling
*/
$(window).keydown(_keydown);
$(window).keyup(_keyup);
$('canvas').mousedown(function(evt) {
if (!gamepad) {
io.buttonDown(evt.which == 1 ? 0 : 1);
}
evt.preventDefault();
})
.mouseup(function(evt) {
if (!gamepad) {
io.buttonUp(evt.which == 1 ? 0 : 1);
}
})
.bind('contextmenu', function(evt) { evt.preventDefault(); });
$('body').mousemove(_mousemove);
$('body > div').hover(function() { focused = false; },
function() { focused = true; });
$('input,textarea').focus(function() { focused = true; })
.blur(function() { focused = false; });
keyboard.create($('#keyboard'));
if (prefs.havePrefs()) {
$('input[type=checkbox]').each(function() {
var val = prefs.readPref(this.id);
if (val)
this.checked = JSON.parse(val);
}).change(function() {
prefs.writePref(this.id, JSON.stringify(this.checked));
});
}
reset();
run();
setInterval(updateKHz, 1000);
updateSound();
updateScreen();
updateSpeed();
var cancel = function() { $(this).dialog('close'); };
$('#loading').dialog({ autoOpen: false, modal: true });
$('#options').dialog({ autoOpen: false,
modal: true,
width: 320,
height: 400,
buttons: {'Close': cancel }});
$('#load').dialog({ autoOpen: false,
modal: true,
width: 540,
buttons: {'Cancel': cancel, 'Load': doLoad }});
$('#save').dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {'Cancel': cancel, 'Save': doSave }});
$('#manage').dialog({ autoOpen: false,
modal: true,
width: 320,
buttons: {'Close': cancel }});
$('#local_save').dialog({ autoOpen: false,
modal: true,
width: 530,
buttons: {'OK': cancel }});
$('#http_load').dialog({ autoOpen: false,
modal: true,
width: 530,
buttons: {'Cancel': cancel, 'OK': doLoadHTTP }});
if (window.localStorage !== undefined) {
$('.disksave').show();
}
var oldcat = '';
for (var idx = 0; idx < disk_index.length; idx++) {
var file = disk_index[idx];
var cat = file.category;
var name = file.name, disk = file.disk;
if (cat != oldcat) {
$('<option />').val(cat).text(cat).appendTo('#category_select');
disk_categories[cat] = [];
oldcat = cat;
}
disk_categories[cat].push(file);
if (disk) {
if (!disk_sets[name]) {
disk_sets[name] = [];
}
disk_sets[name].push(file);
}
}
$('<option/>').text('Local Saves').appendTo('#category_select');
updateLocalStorage();
initGamepad();
// Check for disks in hashtag
var hash = gup('disk') || hup();
if (hash) {
processHash(hash);
}
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
$('select').removeAttr('multiple').css('height', 'auto');
}
if (navigator.standalone) {
$('body').addClass('standalone');
}
});

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,10 +9,16 @@
* implied warranty.
*/
/*globals RAM: false, toHex: false, hiresMode: false, debug: false */
/*exported MMU */
/*globals debug: false, toHex: false
hiresMode: false,
RAM: false
*/
function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
{
'use strict';
var idx;
var _auxRom = 0x00;
@ -28,14 +33,14 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
var _writebsr;
// Auxilliary ROM
var _intcxrom;
var _intcxrom;
var _slot3rom;
// Auxilliary RAM
var _auxRamRead;
var _auxRamWrite;
var _altzp;
// Video
var _80store = false;
var _page2;
@ -51,7 +56,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
_auxRamWrite = false;
_altzp = false;
_intcxrom = false;
_intcxrom = false;
_slot3rom = false;
_80store = false;
@ -93,7 +98,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
var memC0_C0 = [io];
// var memC1_CF = [emptyslots, rom];
var memD0_DF = [rom,
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF),
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF),
new RAM(0xD0,0xDF), new RAM(0xD0,0xDF)];
var memE0_FF = [rom, new RAM(0xE0,0xFF), new RAM(0xE0,0xFF)];
@ -172,7 +177,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
_readPages[idx] = _pages[idx][0];
_writePages[idx] = _pages[idx][0];
}
/*
* I/O Switch locations
*/
@ -235,7 +240,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
_OFFBSR1: 0x8e,
_READWRBSR1: 0x8f
};
function _updateBanks() {
if (_auxRamRead) {
for (idx = 0x02; idx < 0xC0; idx++) {
@ -372,35 +377,35 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
if (typeof val != 'undefined') {
_80store = true;
// _debug("80 Store On");
} else
} else
result = 0;
break;
case LOC.RAMRDOFF:
if (typeof val != 'undefined') {
_auxRamRead = false;
_debug("Aux RAM Read Off");
} else
} else
result = 0;
break;
case LOC.RAMRDON:
if (typeof val != 'undefined') {
_auxRamRead = true;
_debug("Aux RAM Read On");
} else
} else
result = 0;
break;
case LOC.RAMWROFF:
if (typeof val != 'undefined') {
_auxRamWrite = false;
_debug("Aux RAM Write Off");
} else
} else
result = 0;
break;
case LOC.RAMWRON:
if (typeof val != 'undefined') {
_auxRamWrite = true;
_debug("Aux RAM Write On");
} else
} else
result = 0;
break;
@ -416,7 +421,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
// _debug("Int CX ROM On");
}
break;
case LOC.ALTZPOFF: // 0x08
case LOC.ALTZPOFF: // 0x08
if (typeof val != 'undefined') {
_altzp = false;
_debug("Alt ZP Off");
@ -515,7 +520,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
case LOC.BSRBANK2:
_debug("Bank 2 Read " + !_bank1);
result = !_bank1 ? 0x80 : 0x00;
result = !_bank1 ? 0x80 : 0x00;
break;
case LOC.BSRREADRAM:
_debug("Bank SW RAM Read " + _readbsr);
@ -571,10 +576,10 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
io.start();
lores1.start();
lores2.start();
// Do us afterward because we override some of the above
io.registerSwitches(this, LOC);
return 0x00;
},
end: function mmu_end() {
@ -632,7 +637,7 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
auxRamRead: _auxRamRead,
auxRamWrite: _auxRamWrite,
altzp: _altzp,
_80store: _80store,
page2: _page2,
@ -649,14 +654,14 @@ function MMU(cpu, lores1, lores2, hires1, hires2, io, rom)
_readbsr = state.readbsr;
_writebsr = state.writebsr;
_bank1 = state.bank1;
_auxRom = state.auxRom;
_intcxrom = state.intcxrom;
_slot3rom = state.slot3rom;
_auxRamRead = state.auxRamRead;
_auxRamWrite = state.auxRamWrite;
_altzp = state.altzp;
_80store = state._80store;
_page2 = state.page2;

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -13,6 +12,8 @@
/*exported Parallel */
function Parallel(io, cbs, slot) {
'use strict';
slot = slot || 1;
var LOC = {
@ -75,5 +76,3 @@ function Parallel(io, cbs, slot) {
write: function() {}
};
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,23 +9,24 @@
* implied warranty.
*/
/*jshint browser: true */
/*exported Prefs */
function Prefs()
{
'use strict';
return {
havePrefs: function() {
return typeof(localStorage) != "undefined";
return typeof(localStorage) != 'undefined';
},
readPref: function(name) {
if (localStorage)
return localStorage.getItem(name);
return localStorage.getItem(name);
return null;
},
writePref: function(name, value) {
if (localStorage)
localStorage.setItem(name, value);
localStorage.setItem(name, value);
}
};
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,10 +9,14 @@
* implied warranty.
*/
/*globals allocMemPages, base64_encode, base64_decode */
/*exported RAM */
/*globals allocMemPages: false
base64_encode: false, base64_decode: false
*/
function RAM(sp, ep) {
'use strict';
var mem;
var start_page = sp;
var end_page = ep;

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,10 +9,13 @@
* implied warranty.
*/
/*globals allocMem:false, bytify, base64_encode, base64_decode, each: false */
/*exported RAMFactor*/
/*globals allocMem: false, bytify: false, each: false,
base64_encode: false, base64_decode: false
*/
function RAMFactor(mmu, io, slot, size) {
'use strict';
var rom = [
0x43,0x4f,0x50,0x59,0x52,0x49,0x47,0x48,
0x54,0x20,0x28,0x43,0x29,0x20,0x31,0x39,
@ -1079,14 +1081,14 @@ function RAMFactor(mmu, io, slot, size) {
}
function _setmid(val) {
if ((_rammid & 0x80) && !(val & 0x80)) {
if (((_rammid & 0x80) !== 0) && ((val & 0x80) === 0)) {
_sethi(_ramhi + 1);
}
_rammid = (val & 0xff);
}
function _setlo(val) {
if ((_ramlo & 0x80) && !(val & 0x80)) {
if (((_ramlo & 0x80) !== 0) && ((val & 0x80) === 0)) {
_setmid(_rammid + 1);
}
_ramlo = (val & 0xff);

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -14,6 +13,8 @@
function Slot3(mmu, rom)
{
'use strict';
var auxRomFn = {
start: function auxRom_start() {
return 0xc8;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -11,17 +10,19 @@
*/
/*exported Thunderclock */
/*global each */
/*global each: false */
function Thunderclock(mmu, io, slot)
{
'use strict';
var rom = [
0x08,0x78,0x28,0x2c,0x58,0xff,0x70,0x05, // 00
0x38,0xb0,0x01,0x18,0xb8,0x08,0x78,0x48,
0x8a,0x48,0x98,0x48,0xad,0xff,0xcf,0x20, // 10
0x1a,0xc8,0x68,0x68,0xba,0x8d,0xf8,0x07,
0x0a,0x0a,0x0a,0x0a,0x8d,0x78,0x07,0x68, // 20
0x68,0x68,0xa8,0x68,0x9a,0x09,0x04,0x48,
0x68,0x68,0xa8,0x68,0x9a,0x09,0x04,0x48,
0x28,0x98,0xac,0x78,0x07,0xae,0xf8,0x07, // 30
0x29,0x7f,0x48,0x50,0x0e,0xb8,0xa5,0x36,
0xd0,0x04,0xe4,0x37,0xf0,0x0a,0xa9,0x08, // 40
@ -340,7 +341,7 @@ function Thunderclock(mmu, io, slot)
switch (off) {
case LOC.CONTROL:
if (val !== undefined) {
if (val & FLAGS.STROBE) {
if ((val & FLAGS.STROBE) !== 0) {
if ((_command & 0x78) == 0x18) {
_calcbits();
}
@ -390,4 +391,3 @@ function Thunderclock(mmu, io, slot)
}
};
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,7 +9,6 @@
* implied warranty.
*/
/*jshint jquery: true, browser: true */
/*globals debug: false */
/*exported enableSound, initAudio */
@ -18,46 +16,46 @@
* Audio Handling
*/
var sound = true;
var _samples = [];
var sound = true;
var _samples = [];
var audioContext;
var audioNode;
var AC = window.webkitAudioContext || window.AudioContext;
var audioContext;
var audioNode;
var AC = window.AudioContext;
if (typeof AC !== 'undefined') {
audioContext = new AC();
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
if (typeof AC !== 'undefined') {
audioContext = new AC();
audioNode = audioContext.createScriptProcessor(4096, 1, 1);
audioNode.onaudioprocess = function(event) {
var data = event.outputBuffer.getChannelData(0);
var sample = _samples.shift();
var idx = 0;
audioNode.onaudioprocess = function(event) {
var data = event.outputBuffer.getChannelData(0);
var sample = _samples.shift();
var idx = 0;
var len = data.length;
if (sample) {
len = Math.min(sample.length, len);
for (; idx < len; idx++) {
data[idx] = sample[idx];
}
}
for (; idx < data.length; idx++) {
data[idx] = 0.0;
}
};
var len = data.length;
if (sample) {
len = Math.min(sample.length, len);
for (; idx < len; idx++) {
data[idx] = sample[idx];
}
}
/*
// Create and specify parameters for the low-pass filter.
var filter = audioContext.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = 11000;
filter.connect(audioContext.destination);
audioNode.connect(filter);
*/
for (; idx < data.length; idx++) {
data[idx] = 0.0;
}
};
audioNode.connect(audioContext.destination);
}
/*
// Create and specify parameters for the low-pass filter.
var filter = audioContext.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = 11000;
filter.connect(audioContext.destination);
audioNode.connect(filter);
*/
audioNode.connect(audioContext.destination);
}
function initAudio(io) {
if (audioContext) {

View File

@ -1,11 +1,11 @@
/*!
* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*/

View File

@ -1,5 +1,5 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2014 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -14,7 +14,7 @@
/*globals flipX: false, flipY: false */
/*exported processGamepad, initGamepad, gamepad */
var gamepadSupportAvailable = !!navigator.webkitGetGamepads;
var getGamepads = navigator.getGamepads || navigator.webkitGetGamepads;
var gamepad;
var gamepadMap = [];
var gamepadState = [];
@ -54,17 +54,17 @@ var DEFAULT_GAMEPAD = {
'START': '\033'
};
window.addEventListener("gamepadconnected", function(e) {
window.addEventListener('gamepadconnected', function(e) {
gamepad = e.gamepad;
});
function processGamepad(io) {
if (gamepadSupportAvailable) {
gamepad = navigator.webkitGetGamepads()[0];
if (getGamepads) {
gamepad = getGamepads.call(navigator)[0];
}
if (gamepad) {
var x = (gamepad.axes[0] * 1.414 + 1) / 2.0;
var y = (gamepad.axes[1] * 1.414 + 1) / 2.0;
var x = (gamepad.axes[0] * 1.414 + 1) / 2.0;
var y = (gamepad.axes[1] * 1.414 + 1) / 2.0;
io.paddle(0, flipX ? 1.0 - x : x);
io.paddle(1, flipY ? 1.0 - y : y);
var val;
@ -74,12 +74,12 @@ function processGamepad(io) {
var old = gamepadState[idx];
var button = gamepad.buttons[idx];
var pressed;
if (typeof(button) == "object") {
if (typeof(button) == 'object') {
pressed = button.pressed;
} else {
pressed = (button == 1.0);
}
if (pressed && !old) {
if (val <= 0) {
io.buttonDown(-val);
@ -117,5 +117,3 @@ function initGamepad(data) {
}
});
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,7 +9,6 @@
* implied warranty.
*/
/*jshint jquery: true, browser: true */
/*globals debug: false, toHex: false, reset: false */
/*exported KeyBoard */
@ -18,46 +16,46 @@ function KeyBoard(io) {
// keycode: [plain, cntl, shift]
var keymap = {
// Most of these won't happen
0x00: [0x00, 0x00, 0x00], //
0x01: [0x01, 0x01, 0x01], //
0x02: [0x02, 0x02, 0x02], //
0x03: [0x03, 0x03, 0x03], //
0x04: [0x04, 0x04, 0x04], //
0x05: [0x05, 0x05, 0x05], //
0x06: [0x06, 0x06, 0x06], //
0x07: [0x07, 0x07, 0x07], //
0x00: [0x00, 0x00, 0x00], //
0x01: [0x01, 0x01, 0x01], //
0x02: [0x02, 0x02, 0x02], //
0x03: [0x03, 0x03, 0x03], //
0x04: [0x04, 0x04, 0x04], //
0x05: [0x05, 0x05, 0x05], //
0x06: [0x06, 0x06, 0x06], //
0x07: [0x07, 0x07, 0x07], //
0x08: [0x08, 0x08, 0x08], // BS
0x09: [0x09, 0x09, 0x09], // TAB
0x0A: [0x0A, 0x0A, 0x0A], //
0x0B: [0x0B, 0x0B, 0x0B], //
0x0C: [0x0C, 0x0C, 0x0C], //
0x0A: [0x0A, 0x0A, 0x0A], //
0x0B: [0x0B, 0x0B, 0x0B], //
0x0C: [0x0C, 0x0C, 0x0C], //
0x0D: [0x0D, 0x0D, 0x0D], // CR
0x0E: [0x0E, 0x0E, 0x0E], //
0x0F: [0x0F, 0x0F, 0x0F], //
0x0E: [0x0E, 0x0E, 0x0E], //
0x0F: [0x0F, 0x0F, 0x0F], //
0x10: [0xff, 0xff, 0xff], // SHIFT
0x11: [0xff, 0xff, 0xff], // CTRL
0x12: [0xff, 0xff, 0xff], // OPTION
0x13: [0x13, 0x13, 0x13], //
0x14: [0x14, 0x14, 0x14], //
0x15: [0x15, 0x15, 0x15], //
0x16: [0x16, 0x16, 0x16], //
0x17: [0x17, 0x17, 0x18], //
0x18: [0x18, 0x18, 0x18], //
0x19: [0x19, 0x19, 0x19], //
0x1A: [0x1A, 0x1A, 0x1A], //
0x13: [0x13, 0x13, 0x13], //
0x14: [0x14, 0x14, 0x14], //
0x15: [0x15, 0x15, 0x15], //
0x16: [0x16, 0x16, 0x16], //
0x17: [0x17, 0x17, 0x18], //
0x18: [0x18, 0x18, 0x18], //
0x19: [0x19, 0x19, 0x19], //
0x1A: [0x1A, 0x1A, 0x1A], //
0x1B: [0x1B, 0x1B, 0x1B], // ESC
0x1C: [0x1C, 0x1C, 0x1C], //
0x1D: [0x1D, 0x1D, 0x1D], //
0x1E: [0x1E, 0x1E, 0x1E], //
0x1F: [0x1F, 0x1F, 0x1F], //
0x1C: [0x1C, 0x1C, 0x1C], //
0x1D: [0x1D, 0x1D, 0x1D], //
0x1E: [0x1E, 0x1E, 0x1E], //
0x1F: [0x1F, 0x1F, 0x1F], //
// Most of these besides space won't happen
0x20: [0x20, 0x20, 0x20], //
0x21: [0x21, 0x21, 0x21], //
0x22: [0x22, 0x22, 0x22], //
0x23: [0x23, 0x23, 0x23], //
0x24: [0x24, 0x24, 0x24], //
0x20: [0x20, 0x20, 0x20], //
0x21: [0x21, 0x21, 0x21], //
0x22: [0x22, 0x22, 0x22], //
0x23: [0x23, 0x23, 0x23], //
0x24: [0x24, 0x24, 0x24], //
0x25: [0x08, 0x08, 0x08], // <- left
0x26: [0x0B, 0x0B, 0x0B], // ^ up
0x27: [0x15, 0x15, 0x15], // -> right
@ -69,7 +67,7 @@ function KeyBoard(io) {
0x2D: [0x2D, 0x2D, 0x5F], // - - _
0x2E: [0x2E, 0x2E, 0x3E], // . - >
0x2F: [0x2F, 0x2F, 0x3F], // / - ?
0x30: [0x30, 0x30, 0x29], // 0 - )
0x31: [0x31, 0x31, 0x21], // 1 - !
0x32: [0x32, 0x00, 0x40], // 2 - @
@ -86,7 +84,7 @@ function KeyBoard(io) {
0x3D: [0x3D, 0x3D, 0x2B], // = - +
0x3E: [0x3E, 0x3E, 0x3E], // >
0x3F: [0x3F, 0x3F, 0x3F], // ?
// Alpha and control
0x40: [0x40, 0x00, 0x40], // @
0x41: [0x41, 0x01, 0x41], // A
@ -99,12 +97,12 @@ function KeyBoard(io) {
0x48: [0x48, 0x08, 0x48], // H
0x49: [0x49, 0x09, 0x49], // I - TAB
0x4A: [0x4A, 0x0A, 0x4A], // J - NL
0x4B: [0x4B, 0x0B, 0x4B], // K - VT
0x4B: [0x4B, 0x0B, 0x4B], // K - VT
0x4C: [0x4C, 0x0C, 0x4C], // L
0x4D: [0x4D, 0x0D, 0x4D], // M - CR
0x4E: [0x4E, 0x0E, 0x4E], // N
0x4F: [0x4F, 0x0F, 0x4F], // O
0x50: [0x50, 0x10, 0x50], // P
0x51: [0x51, 0x11, 0x51], // Q
0x52: [0x52, 0x12, 0x52], // R
@ -121,7 +119,7 @@ function KeyBoard(io) {
// 0x5D: [0x5D, 0x1D, 0x5D], // ]
0x5E: [0x5E, 0x1E, 0x5E], // ^
0x5F: [0x5F, 0x1F, 0x5F], // _
// Stray keys
0xBA: [0x3B, 0x3B, 0x3A], // ; - :
0xBB: [0x3D, 0x3D, 0x2B], // = - +
@ -132,35 +130,35 @@ function KeyBoard(io) {
0xDB: [0x5B, 0x5B, 0x5B], // [
0xDC: [0x5C, 0x5C, 0x5C], // \
0xDD: [0x5D, 0x5D, 0x5D], // ]
0xDE: [0x27, 0x27, 0x22], // ' - "
0xDE: [0x27, 0x27, 0x22], // ' - '
0xFF: [0xFF, 0xFF, 0xFF] // No comma line
};
var keys =
var keys =
[[['1','2','3','4','5','6','7','8','9','0',':','-','RESET'],
['ESC','Q','W','E','R','T','Y','U','I','O','P','REPT','RETURN'],
['CTRL','A','S','D','F','G','H','J','K','L',';','&larr;','&rarr;'],
['SHIFT','Z','X','C','V','B','N','M',',','.','/','SHIFT'],
['POWER', '&nbsp;']],
[['!','"','#','$','%','&',"'",'(',')','0','*','=','RESET'],
[['!','"','#','$','%','&','\'','(',')','0','*','=','RESET'],
['ESC','Q','W','E','R','T','Y','U','I','O','@','REPT','RETURN'],
['CTRL','A','S','D','F','BELL','H','J','K','L','+','&larr;','&rarr;'],
['SHIFT','Z','X','C','V','B','^',']','<','>','?','SHIFT'],
['POWER', '&nbsp;']]];
var shifted = false;
var controlled = false;
return {
mapKeyEvent: function keyboard_mapKeyEvent(evt) {
var code = evt.keyCode;
if (code in keymap) {
return keymap[code][evt.shiftKey ? 2 : (evt.ctrlKey ? 1 : 0)];
}
debug("Unhandled key = " + toHex(code));
debug('Unhandled key = ' + toHex(code));
return 0xFF;
},
@ -168,125 +166,125 @@ function KeyBoard(io) {
shifted = down;
if (down) {
io.buttonDown(2);
$("#keyboard .key-SHIFT").addClass("active");
$('#keyboard .key-SHIFT').addClass('active');
} else {
io.buttonUp(2);
$("#keyboard .key-SHIFT").removeClass("active");
$('#keyboard .key-SHIFT').removeClass('active');
}
},
controlKey: function keyboard_controlKey(down) {
controlled = down;
if (down) {
$("#keyboard .key-CTRL").addClass("active");
$('#keyboard .key-CTRL').addClass('active');
} else {
$("#keyboard .key-CTRL").removeClass("active");
$('#keyboard .key-CTRL').removeClass('active');
}
},
create: function keyboard_create(kb) {
var x, y, row, key, key1, key2, label, label1, label2;
kb.disableSelection();
function buildLabel(k) {
var span = $("<span>" + k + "</span>");
var span = $('<span>' + k + '</span>');
if (k.length > 1 && k.substr(0,1) != '&')
span.addClass("small");
span.addClass('small');
return span;
}
function _mouseup(ev) {
$(ev.currentTarget).removeClass("pressed");
$(ev.currentTarget).removeClass('pressed');
}
function _mousedown(ev) {
$(ev.currentTarget).addClass("pressed");
var key = $(ev.currentTarget).data(shifted ? "key2" : "key1");
$(ev.currentTarget).addClass('pressed');
var key = $(ev.currentTarget).data(shifted ? 'key2' : 'key1');
switch (key) {
case "BELL":
key = "G";
case 'BELL':
key = 'G';
break;
case "RETURN":
key = "\r";
case 'RETURN':
key = '\r';
break;
case "&larr;":
key = "\010";
case '&larr;':
key = '\010';
break;
case "&rarr;":
key = "\025";
case '&rarr;':
key = '\025';
break;
case "&nbsp;":
key = " ";
case '&nbsp;':
key = ' ';
break;
case "ESC":
key = "\033";
case 'ESC':
key = '\033';
break;
default:
break;
}
if (key.length > 1) {
switch (key) {
case "SHIFT":
case 'SHIFT':
shifted = !shifted;
$("#keyboard .key-SHIFT").toggleClass("active");
$('#keyboard .key-SHIFT').toggleClass('active');
break;
case "CTRL":
case 'CTRL':
controlled = !controlled;
$("#keyboard .key-CTRL").toggleClass("active");
$('#keyboard .key-CTRL').toggleClass('active');
break;
case "RESET":
case 'RESET':
reset();
break;
case "POWER":
if (window.confirm("Power Cycle?"))
case 'POWER':
if (window.confirm('Power Cycle?'))
window.location.reload();
break;
default:
break;
}
} else {
if (controlled && key >= "@" && key <= "_") {
if (controlled && key >= '@' && key <= '_') {
io.keyDown(key.charCodeAt(0) - 0x40);
} else {
io.keyDown(key.charCodeAt(0));
}
}
}
}
for (y = 0; y < 5; y++) {
row = $("<div class='row row" + y + "'/>");
row = $('<div class="row row' + y + '"/>');
kb.append(row);
for (x = 0; x < keys[0][y].length; x++) {
key1 = keys[0][y][x];
key2 = keys[1][y][x];
label = $("<div />");
label = $('<div />');
label1 = buildLabel(key1);
label2 = buildLabel(key2);
key = $("<div class='key'>");
key.addClass("key-" + key1.replace(/[&;]/g,""));
key = $('<div class="key">');
key.addClass('key-' + key1.replace(/[&;]/g,''));
if (key1.length > 1)
key.addClass("vcenter");
key.addClass('vcenter');
if (key1 != key2) {
key.addClass("key-" + key2.replace(/[&;]/g,""));
key.addClass('key-' + key2.replace(/[&;]/g,''));
label.append(label2);
label.append("<br/>");
label.append('<br/>');
}
label.append(label1);
key.append(label);
key.data({"key1": key1, "key2": key2});
key.data({'key1': key1, 'key2': key2});
if (window.ontouchstart === undefined) {
key.bind("mousedown", _mousedown);
key.bind("mouseup mouseout", _mouseup);
key.bind('mousedown', _mousedown);
key.bind('mouseup mouseout', _mouseup);
} else {
key.bind("touchstart", _mousedown);
key.bind("touchend touchleave", _mouseup);
key.bind('touchstart', _mousedown);
key.bind('touchend touchleave', _mouseup);
}
row.append(key);
}
@ -294,4 +292,3 @@ function KeyBoard(io) {
}
};
}

View File

@ -1,5 +1,5 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -18,46 +18,46 @@ function KeyBoard(io) {
// keycode: [plain, cntl, shift]
var keymap = {
// Most of these won't happen
0x00: [0x00, 0x00, 0x00], //
0x01: [0x01, 0x01, 0x01], //
0x02: [0x02, 0x02, 0x02], //
0x03: [0x03, 0x03, 0x03], //
0x04: [0x04, 0x04, 0x04], //
0x05: [0x05, 0x05, 0x05], //
0x06: [0x06, 0x06, 0x06], //
0x07: [0x07, 0x07, 0x07], //
0x00: [0x00, 0x00, 0x00], //
0x01: [0x01, 0x01, 0x01], //
0x02: [0x02, 0x02, 0x02], //
0x03: [0x03, 0x03, 0x03], //
0x04: [0x04, 0x04, 0x04], //
0x05: [0x05, 0x05, 0x05], //
0x06: [0x06, 0x06, 0x06], //
0x07: [0x07, 0x07, 0x07], //
0x08: [0x7F, 0x7F, 0x7F], // BS/DELETE
0x09: [0x09, 0x09, 0x09], // TAB
0x0A: [0x0A, 0x0A, 0x0A], //
0x0B: [0x0B, 0x0B, 0x0B], //
0x0C: [0x0C, 0x0C, 0x0C], //
0x0A: [0x0A, 0x0A, 0x0A], //
0x0B: [0x0B, 0x0B, 0x0B], //
0x0C: [0x0C, 0x0C, 0x0C], //
0x0D: [0x0D, 0x0D, 0x0D], // CR
0x0E: [0x0E, 0x0E, 0x0E], //
0x0F: [0x0F, 0x0F, 0x0F], //
0x0E: [0x0E, 0x0E, 0x0E], //
0x0F: [0x0F, 0x0F, 0x0F], //
0x10: [0xff, 0xff, 0xff], // SHIFT
0x11: [0xff, 0xff, 0xff], // CTRL
0x12: [0xff, 0xff, 0xff], // ALT/OPTION
0x13: [0x13, 0x13, 0x13], //
0x14: [0x14, 0x14, 0x14], //
0x15: [0x15, 0x15, 0x15], //
0x16: [0x16, 0x16, 0x16], //
0x17: [0x17, 0x17, 0x18], //
0x18: [0x18, 0x18, 0x18], //
0x19: [0x19, 0x19, 0x19], //
0x1A: [0x1A, 0x1A, 0x1A], //
0x13: [0x13, 0x13, 0x13], //
0x14: [0x14, 0x14, 0x14], //
0x15: [0x15, 0x15, 0x15], //
0x16: [0x16, 0x16, 0x16], //
0x17: [0x17, 0x17, 0x18], //
0x18: [0x18, 0x18, 0x18], //
0x19: [0x19, 0x19, 0x19], //
0x1A: [0x1A, 0x1A, 0x1A], //
0x1B: [0x1B, 0x1B, 0x1B], // ESC
0x1C: [0x1C, 0x1C, 0x1C], //
0x1D: [0x1D, 0x1D, 0x1D], //
0x1E: [0x1E, 0x1E, 0x1E], //
0x1F: [0x1F, 0x1F, 0x1F], //
0x1C: [0x1C, 0x1C, 0x1C], //
0x1D: [0x1D, 0x1D, 0x1D], //
0x1E: [0x1E, 0x1E, 0x1E], //
0x1F: [0x1F, 0x1F, 0x1F], //
// Most of these besides space won't happen
0x20: [0x20, 0x20, 0x20], //
0x21: [0x21, 0x21, 0x21], //
0x22: [0x22, 0x22, 0x22], //
0x23: [0x23, 0x23, 0x23], //
0x24: [0x24, 0x24, 0x24], //
0x20: [0x20, 0x20, 0x20], //
0x21: [0x21, 0x21, 0x21], //
0x22: [0x22, 0x22, 0x22], //
0x23: [0x23, 0x23, 0x23], //
0x24: [0x24, 0x24, 0x24], //
0x25: [0x08, 0x08, 0x08], // <- left
0x26: [0x0B, 0x0B, 0x0B], // ^ up
0x27: [0x15, 0x15, 0x15], // -> right
@ -69,7 +69,7 @@ function KeyBoard(io) {
0x2D: [0x2D, 0x2D, 0x5F], // - - _
0x2E: [0x2E, 0x2E, 0x3E], // . - >
0x2F: [0x2F, 0x2F, 0x3F], // / - ?
0x30: [0x30, 0x30, 0x29], // 0 - )
0x31: [0x31, 0x31, 0x21], // 1 - !
0x32: [0x32, 0x00, 0x40], // 2 - @
@ -86,7 +86,7 @@ function KeyBoard(io) {
0x3D: [0x3D, 0x3D, 0x2B], // = - +
0x3E: [0x3E, 0x3E, 0x3E], // >
0x3F: [0x3F, 0x3F, 0x3F], // ?
// Alpha and control
0x40: [0x40, 0x00, 0x40], // @
0x41: [0x61, 0x01, 0x41], // A
@ -99,12 +99,12 @@ function KeyBoard(io) {
0x48: [0x68, 0x08, 0x48], // H
0x49: [0x69, 0x09, 0x49], // I - TAB
0x4A: [0x6A, 0x0A, 0x4A], // J - NL
0x4B: [0x6B, 0x0B, 0x4B], // K - VT
0x4B: [0x6B, 0x0B, 0x4B], // K - VT
0x4C: [0x6C, 0x0C, 0x4C], // L
0x4D: [0x6D, 0x0D, 0x4D], // M - CR
0x4E: [0x6E, 0x0E, 0x4E], // N
0x4F: [0x6F, 0x0F, 0x4F], // O
0x50: [0x70, 0x10, 0x50], // P
0x51: [0x71, 0x11, 0x51], // Q
0x52: [0x72, 0x12, 0x52], // R
@ -119,7 +119,7 @@ function KeyBoard(io) {
0x5B: [0xFF, 0xFF, 0xFF], // Left window
0x5C: [0xFF, 0xFF, 0xFF], // Right window
0x5D: [0xFF, 0xFF, 0xFF], // Select
0x5E: [0x5E, 0x1E, 0x5E], //
0x5E: [0x5E, 0x1E, 0x5E], //
0x5F: [0x5F, 0x1F, 0x5F], // _
// Numeric pad
@ -139,7 +139,7 @@ function KeyBoard(io) {
0x6D: [0x2D, 0x2D, 0x2D], // -
0x6E: [0x2E, 0x2E, 0x2E], // .
0x6F: [0x2F, 0x2F, 0x39], // /
// Stray keys
0xBA: [0x3B, 0x3B, 0x3A], // ; - :
0xBB: [0x3D, 0x3D, 0x2B], // = - +
@ -151,23 +151,23 @@ function KeyBoard(io) {
0xDB: [0x5B, 0x5B, 0x7B], // [
0xDC: [0x5C, 0x5C, 0x7C], // \
0xDD: [0x5D, 0x5D, 0x7D], // ]
0xDE: [0x27, 0x22, 0x22], // ' - "
0xDE: [0x27, 0x22, 0x22], // ' - '
0xFF: [0xFF, 0xFF, 0xFF] // No comma line
};
var keys =
var keys =
[[['ESC','1','2','3','4','5','6','7','8','9','0','-','=','DELETE'],
['TAB','Q','W','E','R','T','Y','U','I','O','P','[',']','\\'],
['CTRL','A','S','D','F','G','H','J','K','L',';','\'','RETURN'],
['CTRL','A','S','D','F','G','H','J','K','L',';','"','RETURN'],
['SHIFT','Z','X','C','V','B','N','M',',','.','/','SHIFT'],
['LOCK','`','POW','OPEN_APPLE','&nbsp;','CLOSED_APPLE','&larr;','&rarr;','&darr;','&uarr;']],
[['ESC','!','@','#','$','%','^','&',"*",'(',')','_','+','DELETE'],
[['ESC','!','@','#','$','%','^','&','*','(',')','_','+','DELETE'],
['TAB','Q','W','E','R','T','Y','U','I','O','P','{','}','|'],
['CTRL','A','S','D','F','G','H','J','K','L',':','"','RETURN'],
['CTRL','A','S','D','F','G','H','J','K','L',':','\'','RETURN'],
['SHIFT','Z','X','C','V','B','N','M','<','>','?','SHIFT'],
['CAPS','~','POW','OPEN_APPLE','&nbsp;','CLOSED_APPLE','&larr;','&rarr;','&darr;','&uarr;']]];
var shifted = false;
var controlled = false;
var capslocked = true;
@ -177,15 +177,15 @@ function KeyBoard(io) {
return {
mapKeyEvent: function keyboard_mapKeyEvent(evt) {
var code = evt.keyCode, key = 0xff;
if (code in keymap) {
key = keymap[code][evt.shiftKey ? 2 : (evt.ctrlKey ? 1 : 0)];
if (capslocked && key >= 0x61 && key <= 0x7A)
key -= 0x20;
} else {
debug("Unhandled key = " + toHex(code));
debug('Unhandled key = ' + toHex(code));
}
return key;
},
@ -193,19 +193,19 @@ function KeyBoard(io) {
shifted = down;
if (down) {
io.buttonDown(2);
$("#keyboard .key-SHIFT").addClass("active");
$('#keyboard .key-SHIFT').addClass('active');
} else {
io.buttonUp(2);
$("#keyboard .key-SHIFT").removeClass("active");
$('#keyboard .key-SHIFT').removeClass('active');
}
},
controlKey: function keyboard_controlKey(down) {
controlled = down;
if (down) {
$("#keyboard .key-CTRL").addClass("active");
$('#keyboard .key-CTRL').addClass('active');
} else {
$("#keyboard .key-CTRL").removeClass("active");
$('#keyboard .key-CTRL').removeClass('active');
}
},
@ -213,10 +213,10 @@ function KeyBoard(io) {
commanded = down;
if (down) {
io.buttonDown(0);
$("#keyboard .key-OPEN_APPLE").addClass("active");
$('#keyboard .key-OPEN_APPLE').addClass('active');
} else {
io.buttonUp(0);
$("#keyboard .key-OPEN_APPLE").removeClass("active");
$('#keyboard .key-OPEN_APPLE').removeClass('active');
}
},
@ -224,106 +224,106 @@ function KeyBoard(io) {
optioned = down;
if (down) {
io.buttonDown(1);
$("#keyboard .key-CLOSED_APPLE").addClass("active");
$('#keyboard .key-CLOSED_APPLE').addClass('active');
} else {
io.buttonUp(1);
$("#keyboard .key-CLOSED_APPLE").removeClass("active");
$('#keyboard .key-CLOSED_APPLE').removeClass('active');
}
},
capslockKey: function keyboard_caplockKey(down) {
capslocked = down;
if (down) {
$("#keyboard .key-LOCK").addClass("active");
$('#keyboard .key-LOCK').addClass('active');
} else {
$("#keyboard .key-LOCK").removeClass("active");
$('#keyboard .key-LOCK').removeClass('active');
}
},
create: function keyboard_create(kb) {
var x, y, row, key, key1, key2, label, label1, label2, self = this;
kb.disableSelection();
function buildLabel(k) {
var span = $("<span>" + k + "</span>");
var span = $('<span>' + k + '</span>');
if (k.length > 1 && k.substr(0,1) != '&')
span.addClass("small");
span.addClass('small');
return span;
}
function _mouseup(ev) {
$(ev.currentTarget).removeClass("pressed");
$(ev.currentTarget).removeClass('pressed');
}
function _mousedown(ev) {
$(this).addClass("pressed");
var key = $(ev.currentTarget).data(shifted ? "key2" : "key1");
$(this).addClass('pressed');
var key = $(ev.currentTarget).data(shifted ? 'key2' : 'key1');
switch (key) {
case "BELL":
key = "G";
case 'BELL':
key = 'G';
break;
case "RETURN":
key = "\r";
case 'RETURN':
key = '\r';
break;
case "TAB":
key = "\t";
case 'TAB':
key = '\t';
break;
case "DELETE":
key = "\0177";
case 'DELETE':
key = '\0177';
break;
case "&larr;":
key = "\010";
case '&larr;':
key = '\010';
break;
case "&rarr;":
key = "\025";
case '&rarr;':
key = '\025';
break;
case "&darr;":
key = "\012";
case '&darr;':
key = '\012';
break;
case "&uarr;":
key = "\013";
case '&uarr;':
key = '\013';
break;
case "&nbsp;":
key = " ";
case '&nbsp;':
key = ' ';
break;
case "ESC":
key = "\033";
case 'ESC':
key = '\033';
break;
default:
break;
}
if (key.length > 1) {
switch (key) {
case "SHIFT":
case 'SHIFT':
self.shiftKey(!shifted);
break;
case "CTRL":
case 'CTRL':
self.controlKey(!controlled);
break;
case "CAPS":
case "LOCK":
case 'CAPS':
case 'LOCK':
self.capslockKey(!capslocked);
break;
case "POW":
if (window.confirm("Power Cycle?"))
case 'POW':
if (window.confirm('Power Cycle?'))
window.location.reload();
break;
case "OPEN_APPLE":
case 'OPEN_APPLE':
self.commandKey(!commanded);
break;
case "CLOSED_APPLE":
case 'CLOSED_APPLE':
self.optionKey(!optioned);
break;
default:
break;
}
} else {
if (controlled && key >= "@" && key <= "_") {
if (controlled && key >= '@' && key <= '_') {
io.keyDown(key.charCodeAt(0) - 0x40);
} else if (!shifted && !capslocked &&
} else if (!shifted && !capslocked &&
key >= 'A' && key <= 'Z') {
io.keyDown(key.charCodeAt(0) + 0x20);
} else {
@ -333,43 +333,43 @@ function KeyBoard(io) {
}
for (y = 0; y < 5; y++) {
row = $("<div class='row row" + y + "e'/>");
row = $('<div class="row row' + y + 'e"/>');
kb.append(row);
for (x = 0; x < keys[0][y].length; x++) {
key1 = keys[0][y][x];
key2 = keys[1][y][x];
label = $("<div />");
label = $('<div />');
label1 = buildLabel(key1);
label2 = buildLabel(key2);
key = $("<div class='key'>");
key.addClass("key-" + key1.replace(/[&#;]/g,""));
key = $('<div class="key">');
key.addClass('key-' + key1.replace(/[&#;]/g,''));
if (key1.length > 1) {
if (key1 == "LOCK")
key.addClass("vcenter2");
if (key1 == 'LOCK')
key.addClass('vcenter2');
else
key.addClass("vcenter");
key.addClass('vcenter');
}
if (key1 != key2) {
key.addClass("key-" + key2.replace(/[&;]/g,""));
key.addClass('key-' + key2.replace(/[&;]/g,''));
label.append(label2);
label.append("<br/>");
label.append('<br/>');
}
if (key1 == "LOCK")
key.addClass("active");
if (key1 == 'LOCK')
key.addClass('active');
label.append(label1);
key.append(label);
key.data({"key1": key1, "key2": key2});
key.data({'key1': key1, 'key2': key2});
if (window.ontouchstart === undefined) {
key.bind("mousedown", _mousedown);
key.bind("mouseup mouseout", _mouseup);
key.bind('mousedown', _mousedown);
key.bind('mouseup mouseout', _mouseup);
} else {
key.bind("touchstart", _mousedown);
key.bind("touchend touchleave", _mouseup);
key.bind('touchstart', _mousedown);
key.bind('touchend touchleave', _mouseup);
}
row.append(key);
@ -380,4 +380,3 @@ function KeyBoard(io) {
}
};
}

View File

@ -1,4 +1,3 @@
/*jshint browser:true */
/*exported Printer */
function Printer() {
@ -6,21 +5,20 @@ function Printer() {
return {
putChar: function(val) {
if (!_printer || _printer.closed) {
_printer = window.open("", "_blank","toolbar=0,location=0");
_printer.document.title = "Printer";
_printer.document.write("<div style='font: 12px courier'>");
_printer.document.write("<span>");
_printer = window.open('', '_blank','toolbar=0,location=0');
_printer.document.title = 'Printer';
_printer.document.write('<div style="font: 12px courier">');
_printer.document.write('<span>');
window.focus();
}
var c = String.fromCharCode(val & 0x7f);
if (c == '\r') {
_printer.document.write("<br /></span>");
_printer.document.write('<br /></span>');
} else if (c == ' ') {
_printer.document.write("&nbsp;");
_printer.document.write('&nbsp;');
} else {
_printer.document.write(c);
}
}
};
}

View File

@ -1,5 +1,4 @@
/* -*- mode: JavaScript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
/* Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@ -10,8 +9,10 @@
* implied warranty.
*/
/*jshint rhino:true, browser: true, devel: true */
/*exported allocMem, allocMemPages, bytify, debug, toHex, toBinary, extend, gup, hup, each */
/*eslint no-console: 0*/
/*exported allocMemPages, bytify, debug, each extend, gup, hup, toBinary, toHex
*/
/*global Uint8Array: false */
if (!Date.now) {
Date.now = function now() {
@ -19,8 +20,8 @@ if (!Date.now) {
};
}
var hex_digits = "0123456789ABCDEF";
var bin_digits = "01";
var hex_digits = '0123456789ABCDEF';
var bin_digits = '01';
function allocMem(size) {
var result;
@ -46,16 +47,14 @@ function bytify(ary) {
function extend(ary1, ary2) {
ary2.forEach(function(val) {
ary1.push(val);
ary1.push(val);
});
return ary1;
}
function debug(msg) {
if (typeof(console) != 'undefined' && 'log' in console) {
console.log(msg);
} else if (typeof(environment) == 'object') { // rhino shell
print(msg);
function debug() {
if (typeof console != 'undefined' && 'log' in console) {
console.log.apply(console, arguments);
}
}
@ -63,7 +62,7 @@ function toHex(v, n) {
if (!n) {
n = v < 256 ? 2 : 4;
}
var result = "";
var result = '';
for (var idx = 0; idx < n; idx++) {
result = hex_digits[v & 0x0f] + result;
v >>= 4;
@ -72,7 +71,7 @@ function toHex(v, n) {
}
function toBinary(v) {
var result = "";
var result = '';
for (var idx = 0; idx < 8; idx++) {
result = bin_digits[v & 0x01] + result;
v >>= 1;
@ -83,25 +82,25 @@ function toBinary(v) {
// From http://www.netlobo.com/url_query_string_javascript.html
function gup( name )
{
name = name.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( !results )
return "";
else
return results[1];
}
function hup() {
var regex = new RegExp("#(.*)");
var results = regex.exec(window.location.hash);
if ( !results )
return "";
name = name.replace(/[\[]/,'\\[').replace(/[\]]/,'\\]');
var regexS = '[\\?&]'+name+'=([^&#]*)';
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( !results )
return '';
else
return results[1];
}
function hup() {
var regex = new RegExp('#(.*)');
var results = regex.exec(window.location.hash);
if ( !results )
return '';
else
return results[1];
}
function keys(obj) {
var result = [];
for (var key in obj) {

View File

@ -1,5 +1,5 @@
#!/usr/bin/perl -w
# Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
# Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that

View File

@ -1,5 +1,5 @@
#!/usr/bin/env perl -w
# Copyright 2010-2013 Will Scullin <scullin@scullinsteel.com>
# Copyright 2010-2016 Will Scullin <scullin@scullinsteel.com>
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that