added apple II display, sound; more tools; acme, plasm (PLASMA); platform switch
This commit is contained in:
parent
9391cafac6
commit
346bab90fd
57
index.html
57
index.html
|
@ -100,6 +100,7 @@ div.booklink {
|
|||
right: 0;
|
||||
padding: 6px;
|
||||
background-color: #ffffff;
|
||||
display:none;
|
||||
}
|
||||
div.twitbtn {
|
||||
position: fixed;
|
||||
|
@ -115,6 +116,48 @@ a.dropdown-toggle {
|
|||
color:#66ee66;
|
||||
padding:3px;
|
||||
}
|
||||
// http://stackoverflow.com/questions/18023493/bootstrap-3-dropdown-sub-menu-missing
|
||||
.dropdown-submenu {
|
||||
position:relative;
|
||||
}
|
||||
.dropdown-submenu>.dropdown-menu {
|
||||
top:0;
|
||||
left:100%;
|
||||
margin-top:-6px;
|
||||
margin-left:-1px;
|
||||
-webkit-border-radius:0 6px 6px 6px;
|
||||
-moz-border-radius:0 6px 6px 6px;
|
||||
border-radius:0 6px 6px 6px;
|
||||
}
|
||||
.dropdown-submenu:hover>.dropdown-menu {
|
||||
display:block;
|
||||
}
|
||||
.dropdown-submenu>a:after {
|
||||
display:block;
|
||||
content:" ";
|
||||
float:right;
|
||||
width:0;
|
||||
height:0;
|
||||
border-color:transparent;
|
||||
border-style:solid;
|
||||
border-width:5px 0 5px 5px;
|
||||
border-left-color:#cccccc;
|
||||
margin-top:5px;
|
||||
margin-right:-10px;
|
||||
}
|
||||
.dropdown-submenu:hover>a:after {
|
||||
border-left-color:#ffffff;
|
||||
}
|
||||
.dropdown-submenu.pull-left {
|
||||
float:none;
|
||||
}
|
||||
.dropdown-submenu.pull-left>.dropdown-menu {
|
||||
left:-100%;
|
||||
margin-left:10px;
|
||||
-webkit-border-radius:6px 0 6px 6px;
|
||||
-moz-border-radius:6px 0 6px 6px;
|
||||
border-radius:6px 0 6px 6px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -130,6 +173,14 @@ a.dropdown-toggle {
|
|||
<li><a class="dropdown-item" href="#" id="item_new_file">New File...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_share_file">Share File...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_reset_file">Reset to Original...</a></li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Platform</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="?platform=vcs" id="item_platform_vcs">Atari VCS</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=apple2" id="item_platform_apple2">Apple ][</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=atarivec" id="item_platform_atarivec">Asteroids</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<select id="preset_select" name="">
|
||||
|
@ -155,7 +206,7 @@ a.dropdown-toggle {
|
|||
<div class="twitbtn">
|
||||
<a href="https://twitter.com/8bitworkshop" class="twitter-follow-button" data-show-count="false">Follow @8bitworkshop</a><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
</div>
|
||||
<div class="booklink">
|
||||
<div class="booklink" id="booklink_vcs">
|
||||
<!--
|
||||
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0"
|
||||
src="http://ws-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&OneJS=1&Operation=GetAdHtml&MarketPlace=US&source=ac&ref=tf_til&ad_type=product_link&tracking_id=pzp-20&marketplace=amazon®ion=US&placement=B01N4DSRIZ&asins=B01N4DSRIZ&linkId=67b114b83ce0b13ceaf715ee86833626&show_border=true&link_opens_in_new_window=false&price_color=333333&title_color=0066c0&bg_color=7d6d6d">
|
||||
|
@ -172,8 +223,8 @@ a.dropdown-toggle {
|
|||
<script src="jquery/jquery-2.2.3.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap-tour.min.css">
|
||||
<script src="bootstrap/js/bootstrap.min.js"></script>
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap-tour.min.css">
|
||||
<script src="bootstrap/js/bootstrap-tour.min.js"></script>
|
||||
|
||||
<script src="codemirror/lib/codemirror.js"></script>
|
||||
|
@ -188,6 +239,7 @@ a.dropdown-toggle {
|
|||
|
||||
<script src="javatari.js/release/javatari/javatari.js"></script>
|
||||
<script src="src/emu.js"></script>
|
||||
<script src="src/util.js"></script>
|
||||
<script src="src/platform/vcs.js"></script>
|
||||
<script src="src/platform/apple2.js"></script>
|
||||
<script src="src/platform/atarivec.js"></script>
|
||||
|
@ -202,6 +254,5 @@ a.dropdown-toggle {
|
|||
|
||||
ga('create', 'UA-54497476-9', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
153
src/emu.js
153
src/emu.js
|
@ -2,28 +2,33 @@
|
|||
|
||||
// Emulator classes
|
||||
|
||||
function __createCanvas(mainElement, width, height) {
|
||||
// TODO
|
||||
var fsElement = document.createElement('div');
|
||||
fsElement.style.position = "relative";
|
||||
fsElement.style.padding = "20px";
|
||||
fsElement.style.overflow = "hidden";
|
||||
fsElement.style.background = "black";
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
canvas.style.width = "100%";
|
||||
canvas.style.height = "100%";
|
||||
canvas.tabIndex = "-1"; // Make it focusable
|
||||
|
||||
fsElement.appendChild(canvas);
|
||||
mainElement.appendChild(fsElement);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
var RasterVideo = function(mainElement, width, height, options) {
|
||||
var self = this;
|
||||
var canvas, ctx;
|
||||
var imageData, buf8, datau32;
|
||||
|
||||
this.start = function() {
|
||||
// TODO
|
||||
fsElement = document.createElement('div');
|
||||
fsElement.style.position = "relative";
|
||||
fsElement.style.padding = "50px";
|
||||
//fsElement.style.width = "100%";
|
||||
//fsElement.style.height = "100%";
|
||||
fsElement.style.overflow = "hidden";
|
||||
fsElement.style.background = "black";
|
||||
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
fsElement.appendChild(canvas);
|
||||
mainElement.appendChild(fsElement);
|
||||
|
||||
canvas = __createCanvas(mainElement, width, height);
|
||||
ctx = canvas.getContext('2d');
|
||||
imageData = ctx.createImageData(width, height);
|
||||
var buf = new ArrayBuffer(imageData.data.length);
|
||||
|
@ -93,23 +98,7 @@ var VectorVideo = function(mainElement, width, height) {
|
|||
var jitter = 1.0;
|
||||
|
||||
this.start = function() {
|
||||
// TODO
|
||||
var fsElement = document.createElement('div');
|
||||
fsElement.style.position = "relative";
|
||||
fsElement.style.padding = "20px";
|
||||
fsElement.style.overflow = "hidden";
|
||||
fsElement.style.background = "black";
|
||||
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
canvas.style.width = "100%";
|
||||
canvas.style.height = "100%";
|
||||
canvas.tabIndex = "-1"; // Make it focusable
|
||||
|
||||
fsElement.appendChild(canvas);
|
||||
mainElement.appendChild(fsElement);
|
||||
|
||||
canvas = __createCanvas(mainElement, width, height);
|
||||
ctx = canvas.getContext('2d');
|
||||
}
|
||||
|
||||
|
@ -152,10 +141,6 @@ var VectorVideo = function(mainElement, width, height) {
|
|||
}
|
||||
}
|
||||
|
||||
var SampleAudio = function(clockfreq) {
|
||||
|
||||
}
|
||||
|
||||
var RAM = function(size) {
|
||||
var memArray = new ArrayBuffer(size);
|
||||
this.mem = new Uint8Array(memArray);
|
||||
|
@ -197,3 +182,97 @@ var AnimationTimer = function(frequencyHz, callback) {
|
|||
}
|
||||
|
||||
//
|
||||
|
||||
var SampleAudio = function(clockfreq) {
|
||||
var self = this;
|
||||
var sfrac, sinc, accum;
|
||||
var buffer, bufpos, bufferlist;
|
||||
|
||||
function mix(ape) {
|
||||
var buflen=ape.outputBuffer.length;
|
||||
var lbuf = ape.outputBuffer.getChannelData(0);
|
||||
//var rbuf = ape.outputBuffer.getChannelData(1);
|
||||
var m = this.module;
|
||||
if (!m) m = ape.srcElement.module;
|
||||
if (!m) return;
|
||||
|
||||
var buf = bufferlist[1];
|
||||
for (var i=0; i<lbuf.length; i++) {
|
||||
lbuf[i] = buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
function createContext() {
|
||||
if ( typeof AudioContext !== 'undefined') {
|
||||
self.context = new AudioContext();
|
||||
} else {
|
||||
self.context = new webkitAudioContext();
|
||||
}
|
||||
self.sr=self.context.sampleRate;
|
||||
self.bufferlen=(self.sr > 44100) ? 4096 : 2048;
|
||||
|
||||
// Amiga 500 fixed filter at 6kHz. WebAudio lowpass is 12dB/oct, whereas
|
||||
// older Amigas had a 6dB/oct filter at 4900Hz.
|
||||
self.filterNode=self.context.createBiquadFilter();
|
||||
if (self.amiga500) {
|
||||
self.filterNode.frequency.value=6000;
|
||||
} else {
|
||||
self.filterNode.frequency.value=28867;
|
||||
}
|
||||
|
||||
// "LED filter" at 3275kHz - off by default
|
||||
self.lowpassNode=self.context.createBiquadFilter();
|
||||
self.lowpassNode.frequency.value=28867;
|
||||
self.filter=false;
|
||||
|
||||
// mixer
|
||||
if ( typeof self.context.createScriptProcessor === 'function') {
|
||||
self.mixerNode=self.context.createScriptProcessor(self.bufferlen, 1, 1);
|
||||
} else {
|
||||
self.mixerNode=self.context.createJavaScriptNode(self.bufferlen, 1, 1);
|
||||
}
|
||||
|
||||
self.mixerNode.module=self;
|
||||
self.mixerNode.onaudioprocess=mix;
|
||||
|
||||
// compressor for a bit of volume boost, helps with multich tunes
|
||||
self.compressorNode=self.context.createDynamicsCompressor();
|
||||
|
||||
// patch up some cables :)
|
||||
self.mixerNode.connect(self.filterNode);
|
||||
self.filterNode.connect(self.lowpassNode);
|
||||
self.lowpassNode.connect(self.compressorNode);
|
||||
self.compressorNode.connect(self.context.destination);
|
||||
}
|
||||
|
||||
this.start = function() {
|
||||
if (!this.context) createContext();
|
||||
sinc = this.sr * 1.0 / clockfreq;
|
||||
sfrac = 0;
|
||||
accum = 0;
|
||||
bufpos = 0;
|
||||
bufferlist = [];
|
||||
for (var i=0; i<2; i++) {
|
||||
var arrbuf = new ArrayBuffer(self.bufferlen*4);
|
||||
bufferlist[i] = new Float32Array(arrbuf);
|
||||
}
|
||||
buffer = bufferlist[0];
|
||||
}
|
||||
|
||||
this.feedSample = function(value, count) {
|
||||
while (count-- > 0) {
|
||||
accum += value;
|
||||
sfrac += sinc;
|
||||
if (sfrac >= 1) {
|
||||
buffer[bufpos++] = accum / sfrac;
|
||||
sfrac -= 1;
|
||||
accum = 0;
|
||||
if (bufpos >= buffer.length) {
|
||||
bufpos = 0;
|
||||
bufferlist[0] = bufferlist[1];
|
||||
bufferlist[1] = buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,33 +3,106 @@
|
|||
var APPLE2_PRESETS = [
|
||||
];
|
||||
|
||||
var GR_TXMODE = 1;
|
||||
var GR_MIXMODE = 2;
|
||||
var GR_PAGE1 = 4;
|
||||
var GR_HIRES = 8;
|
||||
|
||||
var Apple2Platform = function(mainElement) {
|
||||
var self = this;
|
||||
var cpuFrequency = 1.023;
|
||||
var cpuFrequency = 1023000;
|
||||
var cpuCyclesPerLine = 65;
|
||||
var cpu, ram, rom, bus;
|
||||
var video, audio, timer;
|
||||
var video, ap2disp, audio, timer;
|
||||
var grdirty = [];
|
||||
var grswitch = GR_TXMODE;
|
||||
var kbdlatch = 0;
|
||||
var soundstate = 0;
|
||||
var PGM_BASE = 0x6000;
|
||||
|
||||
this.getPresets = function() {
|
||||
return APPLE2_PRESETS;
|
||||
}
|
||||
|
||||
function noise() {
|
||||
return (Math.random() * 256) & 0xff;
|
||||
}
|
||||
|
||||
this.start = function() {
|
||||
cpu = new jt.M6502();
|
||||
ram = new RAM(0xc000);
|
||||
//rom = new lzgmini().decode(APPLEIIGO_LZG).slice(0,12288);
|
||||
rom = new lzgmini().decode(APPLEIIGO_LZG).slice(0,12288);
|
||||
// bus
|
||||
bus = {
|
||||
read: function(address) {
|
||||
address &= 0xffff;
|
||||
if (address >= 0xd000 && address <= 0xffff) {
|
||||
return rom[address - 0xd000];
|
||||
} else if (address < 0xc000) {
|
||||
return ram.mem[address];
|
||||
} else if (address < 0xc100) {
|
||||
var slot = (address >> 4) & 0x0f;
|
||||
switch (slot)
|
||||
{
|
||||
case 0:
|
||||
return kbdlatch;
|
||||
case 1:
|
||||
kbdlatch &= 0x7f;
|
||||
break;
|
||||
case 3:
|
||||
soundstate = soundstate ^ 1;
|
||||
break;
|
||||
case 5:
|
||||
if ((address & 0x0f) < 8) {
|
||||
// graphics
|
||||
if ((address & 1) != 0)
|
||||
grswitch |= 1 << ((address >> 1) & 0x07);
|
||||
else
|
||||
grswitch &= ~(1 << ((address >> 1) & 0x07));
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
// tapein, joystick, buttons
|
||||
switch (address & 7) {
|
||||
// buttons (off)
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return noise() & 0x7f;
|
||||
// joystick
|
||||
case 4:
|
||||
case 5:
|
||||
return noise() | 0x80;
|
||||
default:
|
||||
return noise();
|
||||
}
|
||||
case 7:
|
||||
// joy reset
|
||||
if (address == 0xc070)
|
||||
return noise() | 0x80;
|
||||
case 8:
|
||||
return doLanguageCardIO(address, value);
|
||||
case 9: case 10: case 11: case 12: case 13: case 14: case 15:
|
||||
return slots[slot-8].doIO(address, value);
|
||||
}
|
||||
} else {
|
||||
switch (address) {
|
||||
// JMP $c600
|
||||
case 0xc600: return 0x4c;
|
||||
case 0xc601: return PGM_BASE&0xff;
|
||||
case 0xc602: return (PGM_BASE>>8)&0xff;
|
||||
default: return noise();
|
||||
}
|
||||
}
|
||||
return noise();
|
||||
},
|
||||
write: function(address, val) {
|
||||
address &= 0xffff;
|
||||
if (address < 0xc000) {
|
||||
ram.mem[address] = val;
|
||||
grdirty[address>>7] = 1;
|
||||
} else if (address < 0xc100) {
|
||||
this.read(address); // strobe address
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -38,34 +111,28 @@ var Apple2Platform = function(mainElement) {
|
|||
video = new RasterVideo(mainElement,280,192);
|
||||
audio = new SampleAudio(cpuFrequency);
|
||||
video.start();
|
||||
audio.start();
|
||||
var idata = video.getFrameData();
|
||||
var grparams = {dirty:grdirty, grswitch:grswitch, mem:ram.mem};
|
||||
ap2disp = new Apple2Display(idata, grparams);
|
||||
var colors = [0xffff0000, 0xff00ff00];
|
||||
timer = new AnimationTimer(60, function() {
|
||||
// 262.5 scanlines per frame
|
||||
var iaddr = 0x2000;
|
||||
var iofs = 0;
|
||||
breakClock = -1;
|
||||
clock = 0;
|
||||
var clock = 0;
|
||||
for (var sl=0; sl<262; sl++) {
|
||||
for (var i=0; i<cpuCyclesPerLine; i++) {
|
||||
if (debugCondition && breakClock < 0 && debugCondition()) { breakClock = clock; }
|
||||
clock++;
|
||||
cpu.clockPulse();
|
||||
// TODO: audio
|
||||
}
|
||||
if (sl < 192) {
|
||||
for (var xo=0; xo<35; xo++) {
|
||||
var b = ram.mem[iaddr++];
|
||||
idata[iofs++] = colors[(b>>0)&1];
|
||||
idata[iofs++] = colors[(b>>1)&1];
|
||||
idata[iofs++] = colors[(b>>2)&1];
|
||||
idata[iofs++] = colors[(b>>3)&1];
|
||||
idata[iofs++] = colors[(b>>4)&1];
|
||||
idata[iofs++] = colors[(b>>5)&1];
|
||||
idata[iofs++] = colors[(b>>6)&1];
|
||||
}
|
||||
audio.feedSample(soundstate, 1);
|
||||
}
|
||||
}
|
||||
grparams.dirty = grdirty;
|
||||
grparams.grswitch = grswitch;
|
||||
ap2disp.updateScreen();
|
||||
video.updateFrame();
|
||||
});
|
||||
}
|
||||
|
@ -75,15 +142,20 @@ var Apple2Platform = function(mainElement) {
|
|||
}
|
||||
|
||||
this.loadROM = function(title, data) {
|
||||
this.reset();
|
||||
for (var i=0; i<data.length; i++) {
|
||||
ram.mem[i+PGM_BASE] = data[i];
|
||||
}
|
||||
/*
|
||||
if(data.length != 0x3000) {
|
||||
throw "ROM length must be == 0x3000";
|
||||
}
|
||||
rom = data;
|
||||
this.reset();
|
||||
*/
|
||||
}
|
||||
|
||||
this.getRasterPosition = function() {
|
||||
return {x:xpos, y:ypos};
|
||||
return {x:0, y:0};
|
||||
}
|
||||
|
||||
this.isRunning = function() {
|
||||
|
@ -188,8 +260,587 @@ var Apple2Platform = function(mainElement) {
|
|||
b:ram.mem.slice(0),
|
||||
};
|
||||
}
|
||||
this.getRAMForState = function(state) {
|
||||
return ram.mem;
|
||||
}
|
||||
};
|
||||
|
||||
var Apple2Display = function(pixels, apple) {
|
||||
var XSIZE = 280;
|
||||
var YSIZE = 192;
|
||||
var PIXELON = 0xffffffff;
|
||||
var PIXELOFF = 0xff000000;
|
||||
|
||||
var oldgrmode = -1;
|
||||
var textbuf = [];
|
||||
|
||||
var flashInterval = 500;
|
||||
|
||||
var loresColor = [
|
||||
(0xff000000), (0xffff00ff), (0xff00007f), (0xff7f007f),
|
||||
(0xff007f00), (0xff7f7f7f), (0xff0000bf), (0xff0000ff),
|
||||
(0xffbf7f00), (0xffffbf00), (0xffbfbfbf), (0xffff7f7f),
|
||||
(0xff00ff00), (0xffffff00), (0xff00bf7f), (0xffffffff),
|
||||
];
|
||||
|
||||
var text_lut = [
|
||||
0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380,
|
||||
0x028, 0x0a8, 0x128, 0x1a8, 0x228, 0x2a8, 0x328, 0x3a8,
|
||||
0x050, 0x0d0, 0x150, 0x1d0, 0x250, 0x2d0, 0x350, 0x3d0
|
||||
];
|
||||
|
||||
var hires_lut = [
|
||||
0x0000, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00,
|
||||
0x0080, 0x0480, 0x0880, 0x0c80, 0x1080, 0x1480, 0x1880, 0x1c80,
|
||||
0x0100, 0x0500, 0x0900, 0x0d00, 0x1100, 0x1500, 0x1900, 0x1d00,
|
||||
0x0180, 0x0580, 0x0980, 0x0d80, 0x1180, 0x1580, 0x1980, 0x1d80,
|
||||
0x0200, 0x0600, 0x0a00, 0x0e00, 0x1200, 0x1600, 0x1a00, 0x1e00,
|
||||
0x0280, 0x0680, 0x0a80, 0x0e80, 0x1280, 0x1680, 0x1a80, 0x1e80,
|
||||
0x0300, 0x0700, 0x0b00, 0x0f00, 0x1300, 0x1700, 0x1b00, 0x1f00,
|
||||
0x0380, 0x0780, 0x0b80, 0x0f80, 0x1380, 0x1780, 0x1b80, 0x1f80,
|
||||
0x0028, 0x0428, 0x0828, 0x0c28, 0x1028, 0x1428, 0x1828, 0x1c28,
|
||||
0x00a8, 0x04a8, 0x08a8, 0x0ca8, 0x10a8, 0x14a8, 0x18a8, 0x1ca8,
|
||||
0x0128, 0x0528, 0x0928, 0x0d28, 0x1128, 0x1528, 0x1928, 0x1d28,
|
||||
0x01a8, 0x05a8, 0x09a8, 0x0da8, 0x11a8, 0x15a8, 0x19a8, 0x1da8,
|
||||
0x0228, 0x0628, 0x0a28, 0x0e28, 0x1228, 0x1628, 0x1a28, 0x1e28,
|
||||
0x02a8, 0x06a8, 0x0aa8, 0x0ea8, 0x12a8, 0x16a8, 0x1aa8, 0x1ea8,
|
||||
0x0328, 0x0728, 0x0b28, 0x0f28, 0x1328, 0x1728, 0x1b28, 0x1f28,
|
||||
0x03a8, 0x07a8, 0x0ba8, 0x0fa8, 0x13a8, 0x17a8, 0x1ba8, 0x1fa8,
|
||||
0x0050, 0x0450, 0x0850, 0x0c50, 0x1050, 0x1450, 0x1850, 0x1c50,
|
||||
0x00d0, 0x04d0, 0x08d0, 0x0cd0, 0x10d0, 0x14d0, 0x18d0, 0x1cd0,
|
||||
0x0150, 0x0550, 0x0950, 0x0d50, 0x1150, 0x1550, 0x1950, 0x1d50,
|
||||
0x01d0, 0x05d0, 0x09d0, 0x0dd0, 0x11d0, 0x15d0, 0x19d0, 0x1dd0,
|
||||
0x0250, 0x0650, 0x0a50, 0x0e50, 0x1250, 0x1650, 0x1a50, 0x1e50,
|
||||
0x02d0, 0x06d0, 0x0ad0, 0x0ed0, 0x12d0, 0x16d0, 0x1ad0, 0x1ed0,
|
||||
0x0350, 0x0750, 0x0b50, 0x0f50, 0x1350, 0x1750, 0x1b50, 0x1f50,
|
||||
0x03d0, 0x07d0, 0x0bd0, 0x0fd0, 0x13d0, 0x17d0, 0x1bd0, 0x1fd0
|
||||
];
|
||||
|
||||
var colors_lut;
|
||||
|
||||
/**
|
||||
* This function makes the color lookup table for hires mode.
|
||||
* We make a table of 1024 * 2 * 7 entries.
|
||||
* Why? Because we assume each color byte has 10 bits
|
||||
* (8 real bits + 1 on each side) and we need different colors
|
||||
* for odd and even addresses (2) and each byte displays 7 pixels.
|
||||
*/
|
||||
{
|
||||
colors_lut = []; //new int[256*4*2*7];
|
||||
var i,j;
|
||||
var c1,c2,c3 = 15;
|
||||
var base = 0;
|
||||
|
||||
// go thru odd and even
|
||||
for (j=0; j<2; j++)
|
||||
{
|
||||
// go thru 1024 values
|
||||
for (var b1=0; b1<1024; b1++)
|
||||
{
|
||||
// see if the hi bit is set
|
||||
if ((b1 & 0x80) == 0)
|
||||
{
|
||||
c1 = 1; c2 = 12; // red & green
|
||||
} else
|
||||
{
|
||||
c1 = 7; c2 = 9; // blue & orange
|
||||
}
|
||||
// make a value consisting of:
|
||||
// the 8th bit, then bits 0-7, then the 9th bit
|
||||
var b = ((b1 & 0x100) >> 8) | ((b1 & 0x7f) << 1) |
|
||||
((b1 & 0x200) >> 1);
|
||||
// go through each pixel
|
||||
for (i=0; i<7; i++)
|
||||
{
|
||||
var c;
|
||||
// is this pixel lit?
|
||||
if (((2<<i)&b) != 0)
|
||||
{
|
||||
// are there pixels lit on both sides of this one?
|
||||
if (((7<<i)&b) == (7<<i))
|
||||
// yes, make it white
|
||||
c = 15;
|
||||
else
|
||||
// no, choose color based on odd/even byte
|
||||
// and odd/even pixel column
|
||||
c = ((((j ^ i) & 1) == 0) ? c1 : c2);
|
||||
} else
|
||||
{
|
||||
// are there pixels lit in the previous & next
|
||||
// column but none in this?
|
||||
if (((5<<i)&b) == (5<<i))
|
||||
// color this pixel
|
||||
c = ((((j ^ i) & 1) != 0) ? c1 : c2);
|
||||
else
|
||||
c = 0;
|
||||
}
|
||||
colors_lut[base] = loresColor[c];
|
||||
base++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawLoresChar(x, y, b)
|
||||
{
|
||||
var i,base,adr,c;
|
||||
base = (y<<3)*XSIZE + x*7; //(x<<2) + (x<<1) + x
|
||||
c = loresColor[b & 0x0f];
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
pixels[base] =
|
||||
pixels[base+1] =
|
||||
pixels[base+2] =
|
||||
pixels[base+3] =
|
||||
pixels[base+4] =
|
||||
pixels[base+5] =
|
||||
pixels[base+6] = c;
|
||||
base += XSIZE;
|
||||
}
|
||||
c = loresColor[b >> 4];
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
pixels[base] =
|
||||
pixels[base+1] =
|
||||
pixels[base+2] =
|
||||
pixels[base+3] =
|
||||
pixels[base+4] =
|
||||
pixels[base+5] =
|
||||
pixels[base+6] = c;
|
||||
base += XSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
function drawTextChar(x, y, b, invert)
|
||||
{
|
||||
var base = (y<<3)*XSIZE + x*7; // (x<<2) + (x<<1) + x
|
||||
var on,off;
|
||||
if (invert)
|
||||
{
|
||||
on = PIXELOFF;
|
||||
off = PIXELON;
|
||||
} else
|
||||
{
|
||||
on = PIXELON;
|
||||
off = PIXELOFF;
|
||||
}
|
||||
|
||||
for (var yy=0; yy<8; yy++)
|
||||
{
|
||||
var chr = apple2_charset[(b<<3)+yy];
|
||||
pixels[base] = ((chr & 64) > 0)?on:off;
|
||||
pixels[base+1] = ((chr & 32) > 0)?on:off;
|
||||
pixels[base+2] = ((chr & 16) > 0)?on:off;
|
||||
pixels[base+3] = ((chr & 8) > 0)?on:off;
|
||||
pixels[base+4] = ((chr & 4) > 0)?on:off;
|
||||
pixels[base+5] = ((chr & 2) > 0)?on:off;
|
||||
pixels[base+6] = ((chr & 1) > 0)?on:off;
|
||||
base += XSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
function drawHiresLines(y, maxy)
|
||||
{
|
||||
var yb = y*XSIZE;
|
||||
for (; y < maxy; y++)
|
||||
{
|
||||
var base = hires_lut[y] + (((apple.grswitch & GR_PAGE1) != 0) ? 0x4000 : 0x2000);
|
||||
if (!apple.dirty[base >> 7])
|
||||
{
|
||||
yb += XSIZE;
|
||||
continue;
|
||||
}
|
||||
var c1, c2;
|
||||
var b = 0;
|
||||
var b1 = apple.mem[base] & 0xff;
|
||||
for (var x1=0; x1<20; x1++)
|
||||
{
|
||||
var b2 = apple.mem[base+1] & 0xff;
|
||||
var b3 = apple.mem[base+2] & 0xff;
|
||||
var d1 = (((b&0x40)<<2) | b1 | b2<<9) & 0x3ff;
|
||||
for (var i=0; i<7; i++)
|
||||
pixels[yb+i] = colors_lut[d1*7+i];
|
||||
var d2 = (((b1&0x40)<<2) | b2 | b3<<9) & 0x3ff;
|
||||
for (var i=0; i<7; i++)
|
||||
pixels[yb+7+i] = colors_lut[d1*7+7168+i];
|
||||
yb += 14;
|
||||
base += 2;
|
||||
b = b2;
|
||||
b1 = b3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawLoresLine(y)
|
||||
{
|
||||
// get the base address of this line
|
||||
var base = text_lut[y] +
|
||||
(((apple.grswitch & GR_PAGE1) != 0) ? 0x800 : 0x400);
|
||||
// if (!dirty[base >> 7])
|
||||
// return;
|
||||
for (var x=0; x<40; x++)
|
||||
{
|
||||
var b = apple.mem[base+x] & 0xff;
|
||||
// if the char. changed, draw it
|
||||
if (b != textbuf[y*40+x])
|
||||
{
|
||||
drawLoresChar(x, y, b);
|
||||
textbuf[y*40+x] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawTextLine(y, flash)
|
||||
{
|
||||
// get the base address of this line
|
||||
var base = text_lut[y] +
|
||||
(((apple.grswitch & GR_PAGE1) != 0) ? 0x800 : 0x400);
|
||||
// if (!dirty[base >> 7])
|
||||
// return;
|
||||
for (var x=0; x<40; x++)
|
||||
{
|
||||
var b = apple.mem[base+x] & 0xff;
|
||||
var invert;
|
||||
// invert flash characters 1/2 of the time
|
||||
if (b >= 0x80)
|
||||
{
|
||||
invert = false;
|
||||
} else if (b >= 0x40)
|
||||
{
|
||||
invert = flash;
|
||||
if (flash)
|
||||
b -= 0x40;
|
||||
else
|
||||
b += 0x40;
|
||||
} else
|
||||
invert = true;
|
||||
// if the char. changed, draw it
|
||||
if (b != textbuf[y*40+x])
|
||||
{
|
||||
drawTextChar(x, y, b & 0x7f, invert);
|
||||
textbuf[y*40+x] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.updateScreen = function(totalrepaint)
|
||||
{
|
||||
var y;
|
||||
var flash = (new Date().getTime() % (flashInterval<<1)) > flashInterval;
|
||||
|
||||
// if graphics mode changed, repaint whole screen
|
||||
if (apple.grswitch != oldgrmode)
|
||||
{
|
||||
oldgrmode = apple.grswitch;
|
||||
totalrepaint = true;
|
||||
}
|
||||
if (totalrepaint)
|
||||
{
|
||||
// clear textbuf if in text mode
|
||||
if ((apple.grswitch & GR_TXMODE) != 0 || (apple.grswitch & GR_MIXMODE) != 0)
|
||||
{
|
||||
for (y=0; y<24; y++)
|
||||
for (var x=0; x<40; x++)
|
||||
textbuf[y*40+x] = -1;
|
||||
}
|
||||
for (var i=0; i<384; i++)
|
||||
apple.dirty[i] = true;
|
||||
}
|
||||
|
||||
// first, draw top part of window
|
||||
if ((apple.grswitch & GR_TXMODE) != 0)
|
||||
{
|
||||
for (y=0; y<20; y++)
|
||||
drawTextLine(y, flash);
|
||||
} else
|
||||
{
|
||||
if ((apple.grswitch & GR_HIRES) != 0)
|
||||
drawHiresLines(0, 160);
|
||||
else
|
||||
for (y=0; y<20; y++)
|
||||
drawLoresLine(y);
|
||||
}
|
||||
|
||||
// now do mixed part of window
|
||||
if ((apple.grswitch & GR_TXMODE) != 0 || (apple.grswitch & GR_MIXMODE) != 0)
|
||||
{
|
||||
for (y=20; y<24; y++)
|
||||
drawTextLine(y, flash);
|
||||
} else
|
||||
{
|
||||
if ((apple.grswitch & GR_HIRES) != 0)
|
||||
drawHiresLines(160, 192);
|
||||
else
|
||||
for (y=20; y<24; y++)
|
||||
drawLoresLine(y);
|
||||
}
|
||||
for (var i=0; i<384; i++)
|
||||
apple.dirty[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*exported apple2_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
|
||||
];
|
||||
|
||||
// public domain ROM
|
||||
var APPLEIIGO_LZG = [
|
||||
76,90,71,0,0,48,0,0,0,5,159,47,60,46,159,1,21,25,30,52,65,80,80,76,69,73,73,71,79,32,82,79,
|
||||
77,49,46,48,0,52,31,52,31,52,31,52,31,52,31,52,31,52,31,52,31,52,28,52,6,32,0,224,25,30,67,52,
|
||||
|
|
69
src/ui.js
69
src/ui.js
|
@ -1,5 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
var FileStore = function(storage, prefix) {
|
||||
var self = this;
|
||||
this.saveFile = function(name, text) {
|
||||
storage.setItem(prefix + name, text);
|
||||
}
|
||||
this.loadFile = function(name) {
|
||||
return storage.getItem(prefix + name) || storage.getItem(name);
|
||||
}
|
||||
this.getFiles = function(prefix2) {
|
||||
var files = [];
|
||||
for (var i = 0; i < storage.length; i++) {
|
||||
var key = storage.key(i);
|
||||
if (key.startsWith(prefix + prefix2)) {
|
||||
var name = key.substring(prefix.length + prefix2.length);
|
||||
files.push(name);
|
||||
}
|
||||
else if (key.startsWith(prefix2)) {
|
||||
var name = key.substring(prefix2.length);
|
||||
files.push(name);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
this.deleteFile = function(name) {
|
||||
storage.removeItem(name);
|
||||
storage.removeItem('local/' + name);
|
||||
}
|
||||
}
|
||||
|
||||
// 8bitworkshop IDE user interface
|
||||
|
||||
var worker = new Worker("./src/worker/workermain.js");
|
||||
|
@ -9,6 +38,7 @@ var current_preset_id = null;
|
|||
var offset2line = null;
|
||||
var line2offset = null;
|
||||
var trace_pending_at_pc;
|
||||
var store;
|
||||
|
||||
var PRESETS, platform, platform_id;
|
||||
|
||||
|
@ -40,7 +70,7 @@ function setLastPreset(id) {
|
|||
|
||||
function updatePreset(current_preset_id, text) {
|
||||
if (text.trim().length) {
|
||||
localStorage.setItem(current_preset_id, text);
|
||||
store.saveFile(current_preset_id, text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +83,7 @@ function loadCode(text) {
|
|||
function loadFile(fileid, filename, index) {
|
||||
current_preset_id = fileid;
|
||||
current_preset_index = index;
|
||||
var text = localStorage.getItem(fileid) || localStorage.getItem(fileid.replace(platform_id+"/","")) || "";
|
||||
var text = store.loadFile(fileid)|| "";
|
||||
if (text) {
|
||||
loadCode(text);
|
||||
setLastPreset(fileid);
|
||||
|
@ -107,6 +137,7 @@ function gotoPresetNamed(id) {
|
|||
updateSelector();
|
||||
}
|
||||
} else {
|
||||
qs['platform'] = platform_id;
|
||||
qs['file'] = id;
|
||||
window.location = "?" + $.param(qs);
|
||||
}
|
||||
|
@ -118,7 +149,7 @@ function _createNewFile(e) {
|
|||
if (filename.indexOf(".") < 0) {
|
||||
filename += ".a";
|
||||
}
|
||||
qs['file'] = "local/" + platform_id + "/" + filename;
|
||||
qs['file'] = "local/" + filename;
|
||||
window.location = "?" + $.param(qs);
|
||||
}
|
||||
return true;
|
||||
|
@ -172,23 +203,21 @@ function populateExamples(sel) {
|
|||
|
||||
function populateLocalFiles(sel) {
|
||||
sel.append($("<option />").text("------- Local Files -------"));
|
||||
for (var i = 0; i < localStorage.length; i++) {
|
||||
var key = localStorage.key(i);
|
||||
if (key.startsWith("local/")) {
|
||||
var name = key.substring(6);
|
||||
sel.append($("<option />").val("local/"+name).text(name).attr('selected',key==current_preset_id));
|
||||
}
|
||||
var filenames = store.getFiles("local/");
|
||||
for (var i = 0; i < filenames.length; i++) {
|
||||
var name = filenames[i];
|
||||
var key = "local/" + name;
|
||||
sel.append($("<option />").val(key).text(name).attr('selected',key==current_preset_id));
|
||||
}
|
||||
}
|
||||
|
||||
function populateSharedFiles(sel) {
|
||||
sel.append($("<option />").text("--------- Shared ---------"));
|
||||
for (var i = 0; i < localStorage.length; i++) {
|
||||
var key = localStorage.key(i);
|
||||
if (key.startsWith("shared/")) {
|
||||
var name = key.substring(6);
|
||||
sel.append($("<option />").val("shared/"+name).text(name).attr('selected',key==current_preset_id));
|
||||
}
|
||||
var filenames = store.getFiles("shared/");
|
||||
for (var i = 0; i < filenames.length; i++) {
|
||||
var name = filenames[i];
|
||||
var key = "shared/" + name;
|
||||
sel.append($("<option />").val(key).text(name).attr('selected',key==current_preset_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +239,10 @@ function updateSelector() {
|
|||
}
|
||||
|
||||
function setCode(text) {
|
||||
worker.postMessage({code:text});
|
||||
if (current_preset_id.endsWith(".pla"))
|
||||
worker.postMessage({code:text, tool:'plasm'});
|
||||
else
|
||||
worker.postMessage({code:text, tool:'dasm'});
|
||||
}
|
||||
|
||||
function arrayCompare(a,b) {
|
||||
|
@ -738,6 +770,7 @@ try {
|
|||
// load and start platform object
|
||||
if (platform_id == 'vcs') {
|
||||
platform = new VCSPlatform();
|
||||
$("#booklink_vcs").show();
|
||||
} else if (platform_id == 'apple2') {
|
||||
platform = new Apple2Platform($("#emulator")[0]);
|
||||
} else if (platform_id == 'atarivec') {
|
||||
|
@ -745,12 +778,12 @@ try {
|
|||
} else {
|
||||
alert("Platform " + platform_id + " not recognized");
|
||||
}
|
||||
store = new FileStore(localStorage, platform_id + '/');
|
||||
PRESETS = platform.getPresets();
|
||||
platform.start();
|
||||
// reset file?
|
||||
if (qs['file'] && qs['reset']) {
|
||||
localStorage.removeItem(qs['file']);
|
||||
localStorage.removeItem('local/' + qs['file']);
|
||||
store.deleteFile(qs['file']);
|
||||
qs['reset'] = '';
|
||||
window.location = "?" + $.param(qs);
|
||||
} else if (qs['file']) {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
// set up require.js for worker
|
||||
importScripts("../../js/dasm.js");
|
||||
importScripts("../../js/acme.js");
|
||||
importScripts("../../js/plasm.js");
|
||||
|
||||
// shim out window and document objects
|
||||
// https://github.com/mbostock/d3/issues/1053
|
||||
|
@ -19,11 +21,11 @@ var document = noop();
|
|||
document.documentElement = noop();
|
||||
document.documentElement.style = noop();
|
||||
|
||||
var MAIN_FILENAME = "main.a";
|
||||
var PREAMBLE = "\tprocessor 6502\n";
|
||||
var PREAMBLE_LINES = 1;
|
||||
var DASM_MAIN_FILENAME = "main.a";
|
||||
var DASM_PREAMBLE = "\tprocessor 6502\n";
|
||||
var DASM_PREAMBLE_LINES = 1;
|
||||
|
||||
function parseListing(code, unresolved) {
|
||||
function parseDASMListing(code, unresolved) {
|
||||
var errorMatch = /main.a [(](\d+)[)]: error: (.+)/;
|
||||
// 4 08ee a9 00 start lda #01workermain.js:23:5
|
||||
var lineMatch = /\s*(\d+)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f][0-9a-f ]+)\s+(.+)/;
|
||||
|
@ -34,13 +36,13 @@ function parseListing(code, unresolved) {
|
|||
for (var line of code.split(/\r?\n/)) {
|
||||
var linem = lineMatch.exec(line);
|
||||
if (linem && linem[1]) {
|
||||
var linenum = parseInt(linem[1]) - PREAMBLE_LINES;
|
||||
var linenum = parseInt(linem[1]) - DASM_PREAMBLE_LINES;
|
||||
var filename = linem[2];
|
||||
var offset = parseInt(linem[3], 16);
|
||||
var insns = linem[4];
|
||||
var restline = linem[5];
|
||||
// inside of main file?
|
||||
if (filename == MAIN_FILENAME) {
|
||||
if (filename == DASM_MAIN_FILENAME) {
|
||||
if (insns && !restline.match(equMatch)) {
|
||||
lines.push({
|
||||
line:linenum,
|
||||
|
@ -52,7 +54,7 @@ function parseListing(code, unresolved) {
|
|||
lastline = linenum;
|
||||
} else {
|
||||
// inside of macro or include file
|
||||
if (linenum == -PREAMBLE_LINES) { // start of macro?
|
||||
if (linenum == -DASM_PREAMBLE_LINES) { // start of macro?
|
||||
lines.push({
|
||||
line:lastline+1,
|
||||
offset:offset,
|
||||
|
@ -83,7 +85,7 @@ function parseListing(code, unresolved) {
|
|||
return {lines:lines, errors:errors};
|
||||
}
|
||||
|
||||
function assemble(code) {
|
||||
function assembleDASM(code) {
|
||||
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/;
|
||||
var unresolved = {};
|
||||
function print_fn(s) {
|
||||
|
@ -97,23 +99,73 @@ function assemble(code) {
|
|||
print:print_fn
|
||||
});
|
||||
var FS = Module['FS'];
|
||||
FS.writeFile(MAIN_FILENAME, PREAMBLE + code);
|
||||
|
||||
Module.callMain([MAIN_FILENAME, "-v3", "-la.lst"]);
|
||||
|
||||
FS.writeFile(DASM_MAIN_FILENAME, DASM_PREAMBLE + code);
|
||||
Module.callMain([DASM_MAIN_FILENAME, "-v3", "-la.lst"]);
|
||||
var aout = FS.readFile("a.out");
|
||||
//console.log(aout);
|
||||
var alst = FS.readFile("a.lst", {'encoding':'utf8'});
|
||||
//console.log(alst);
|
||||
var listing = parseListing(alst, unresolved);
|
||||
var listing = parseDASMListing(alst, unresolved);
|
||||
return {exitstatus:Module.EXITSTATUS, output:aout, listing:listing};
|
||||
}
|
||||
|
||||
//assemblepgm("\tprocessor 6502\n\torg $800\n\tlda #0");
|
||||
function assembleACME(code) {
|
||||
var re_usl = /(\w+)\s+0000\s+[?][?][?][?]/;
|
||||
var unresolved = {};
|
||||
function print_fn(s) {
|
||||
var matches = re_usl.exec(s);
|
||||
if (matches) {
|
||||
unresolved[matches[1]] = 0;
|
||||
}
|
||||
}
|
||||
var Module = ACME({
|
||||
noInitialRun:true,
|
||||
print:print_fn
|
||||
});
|
||||
var FS = Module['FS'];
|
||||
FS.writeFile("main.a", code);
|
||||
Module.callMain(["-o", "a.out", "-r", "a.rpt", "-l", "a.sym", "--setpc", "24576", "main.a"]);
|
||||
var aout = FS.readFile("a.out");
|
||||
var alst = FS.readFile("a.rpt", {'encoding':'utf8'});
|
||||
var asym = FS.readFile("a.sym", {'encoding':'utf8'});
|
||||
console.log("acme", code.length, "->", aout.length);
|
||||
console.log(alst);
|
||||
console.log(asym);
|
||||
var listing = parseDASMListing(alst, unresolved);
|
||||
return {exitstatus:Module.EXITSTATUS, output:aout, listing:listing};
|
||||
}
|
||||
|
||||
function compilePLASMA(code) {
|
||||
function print_fn(s) { console.log(s); }
|
||||
var outstr = "";
|
||||
function out_fn(s) { outstr += s; outstr += "\n"; }
|
||||
var Module = PLASM({
|
||||
noInitialRun:true,
|
||||
noFSInit:true,
|
||||
print:out_fn
|
||||
});
|
||||
var FS = Module['FS'];
|
||||
var i = 0;
|
||||
var output = [];
|
||||
FS.init(
|
||||
function() { return i<code.length ? code.charCodeAt(i++) : null; }
|
||||
);
|
||||
FS.writeFile("main.pla", code);
|
||||
Module.callMain(["-A"]);
|
||||
console.log("plasm", code.length, "->", outstr.length);
|
||||
return assembleACME(outstr);
|
||||
}
|
||||
|
||||
var tools = {
|
||||
'dasm': assembleDASM,
|
||||
'plasm': compilePLASMA,
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
var code = e.data.code;
|
||||
var result = assemble(code);
|
||||
var toolfn = tools[e.data.tool];
|
||||
if (!toolfn) throw "no tool named " + e.data.tool;
|
||||
var result = toolfn(code);
|
||||
//console.log("RESULT", result);
|
||||
postMessage(result);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue