Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 8a5cba3340c550a0c5828d49663406cb02061461 0 parents
@tadpol authored
2  .gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+*.swp
17 README.markdown
@@ -0,0 +1,17 @@
+
+Avrian Jump
+===========
+
+A very simple ladder language for programming ATMega168s.
+
+This ladder language is not based on any other, and is mostly setup to be simple to use on a
+touch device with HTML elements. It also condenses down into an ASCII format that for most
+things will fit into a tweet.
+
+This started out as a desire to be able to program an Arduino from an iOS device.
+Given that recreating the Arduino IDE in HTML seemed like too much work, the project was
+reduced into something much simpler. Mainly, a simple ladder language, and the Audioino
+bootloader. That still left the need for an assembler, which while still a fair amount of
+work, seemed a lot more managable.
+
+
5 TODO
@@ -0,0 +1,5 @@
+
+- PWM outputs are NOPs, need to write them
+- Put Audioino bootloader onto a device and check that the wav from the web page will load.
+- Figure out HTML5 local storage and do save/load of ladders. (might skip for v1)
+
241 assemble/asmToAudio.js
@@ -0,0 +1,241 @@
+/**
+ * Take an array of data and turn it into an encoded audio data.
+ *
+ * Designed for the Audioino boot loader.
+ * See: http://www.hobby-roboter.de/forum/viewtopic.php?f=4&t=128&p=531
+ *
+ *
+ * Copyright (c) 2012 Michael Conrad Tadpol Tilstra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+(function(tadAvrAsm, undefined ) {
+
+ /**
+ * Converts an array of program data into a manchester encoded signal array.
+ */
+
+ function numsToSignal(hexes) {
+ /* The format that the Audioino boot loader expects seems to be as follows:
+ * The wave data is broken into frames.
+ * Each Frame is Frame header, followed by data, followed by silence.
+ * There are two kinds of Frames: A Page Frame, and a Run Frame.
+ * - The Run Frame leaves the boot loader and runs the application.
+ * - A Page Frame loads a page of data to be burned to flash.
+ *
+ * A Frame header is 5 bytes: Command, Page Index (2bytes), CRC (2bytes)
+ *
+ * Then the whole frame is Manchester Encoded with a sync sequence and a start bit.
+ */
+
+ /* Some private functions for this */
+
+ /**
+ * Append a block of silence
+ * At 44100, this is about 1/100th of a second.
+ */
+ function appendSilence(signal) {
+ for(var i=0; i < 441; i++) {
+ signal.push(0);
+ }
+ }
+
+ /**
+ * Appends a single Manchester encoded bit onto signal.
+ */
+ function encodeEdge(edge, signal) {
+ var val = edge?-1:1;
+ signal.push( -val );
+ signal.push( -val );
+ signal.push( val );
+ signal.push( val );
+ }
+
+ /**
+ * Encodes by Manchester and appends a frame to signal.
+ * Also adds a Start Sequence an Start bit for synchronising.
+ */
+ function encodeFrame(frame, signal) {
+ var i;
+
+ /* Generate Start sequence */
+ for(i=0; i < 40; i++) {
+ encodeEdge(false, signal);
+ }
+
+ /* Generate start pulse */
+ encodeEdge(true, signal);
+
+ var d;
+ for(i=0; i < frame.length; i++) {
+ if( !(i in frame) || typeof frame[i] == 'undefined') {
+ d = 0;
+ } else {
+ d = frame[i];
+ }
+ for(var j=0; j < 8; j++) {
+ encodeEdge( ((d&0x80)!=0), signal);
+ d = d << 1;
+ }
+ }
+
+ }
+
+ var signal = new Array();
+
+ /* Convert data into Page Frames */
+ for(var i=0; i < hexes.length;) {
+ /* Skip over gaps. ?better way to do this? */
+ if( !(i in hexes) ) {
+ continue;
+ }
+
+ var pageIdx = i >> 7; /* Convert byte location to page index. */
+ var frame = new Array();
+ frame.push(2); // Program Page Command
+ frame.push(pageIdx&0xff); // Page Index Lo.
+ frame.push((pageIdx>>8)&0xff); // Page Index Hi.
+ /* Not a true CRC. Is actually a Magic Number. Always 0x55AA */
+ frame.push(0xaa); // CRC Lo.
+ frame.push(0x55); // CRC Hi.
+ for(var j=0; j < 128 ; j++, i++ ) {
+ if( i in hexes ) {
+ frame.push( hexes[i] );
+ } else {
+ frame.push( 0xff );
+ }
+ }
+ encodeFrame(frame, signal);
+ appendSilence(signal);
+
+ }
+
+ /* Append a Run Frame */
+ var frame = new Array();
+ frame.push(3); // Run Command
+ frame.push(0); // Page Index Lo.
+ frame.push(0); // Page Index Hi.
+ /* Not a true CRC. Is actually a Magic Number. Always is 0x55AA */
+ frame.push(0xaa); // CRC Lo.
+ frame.push(0x55); // CRC Hi.
+ for(var j=0; j < 128; j++) {
+ frame.push(0);
+ }
+ encodeFrame(frame, signal);
+
+ return signal;
+ }
+
+ /**
+ * Convert array into WAV data
+ *
+ * Assumes array is of values: -1,0,1
+ *
+ * Based on code from sk89q
+ * See: http://www.sk89q.com/2008/11/dynamically-generating-a-wav-in-javascript/
+ */
+ function signalToWave(signal) {
+ var channels = 2;
+ var sampleRate = 44100;
+ var bitsPerSample = 16;
+
+ function packLE16(arg) {return String.fromCharCode(arg & 255, (arg >> 8) & 255);}
+ function packLE32(arg) {
+ return String.fromCharCode(arg & 255, (arg >> 8) & 255, (arg >> 16) & 255, (arg >> 24) & 255);
+ }
+
+ var data = new Array();
+ for(var i=0; i < signal.length; i++) {
+ var v = signal[i] * 32767;
+ /* push twice, once for each channel */
+ data.push( packLE16(v) );
+ data.push( packLE16(v) );
+ }
+
+ // Format sub-chunk
+ var chunk1 = [
+ "fmt ", // Sub-chunk identifier
+ packLE32(16), // Chunk length
+ packLE16(1), // Audio format (1 is linear quantization)
+ packLE16(channels),
+ packLE32(sampleRate),
+ packLE32(sampleRate * channels * bitsPerSample / 8), // Byte rate
+ packLE16(channels * bitsPerSample / 8),
+ packLE16(bitsPerSample)
+ ].join('');
+
+ // Data sub-chunk (contains the sound)
+ var chunk2 = [
+ "data", // Sub-chunk identifier
+ packLE32(signal.length * channels * bitsPerSample / 8), // Chunk length
+ data
+ ].join('');
+
+ // Header
+ var header = [
+ "RIFF",
+ packLE32(4 + (8 + chunk1.length) + (8 + chunk2.length)), // Length
+ "WAVE"
+ ].join('');
+
+ var wave = [header, chunk1, chunk2].join('');
+ return wave;
+ }
+
+ /**
+ * Convert the hexes array into one of numbers.
+ */
+ function hexesToNums(hexes) {
+ var da = [];
+ var spl = /(..)(..)/;
+ var md;
+ for(var i=0; i < hexes.length; i+=2) {
+ /* skip over gaps */
+ if( !(i in hexes) ) {
+ continue;
+ }
+ md = hexes[i].match(spl);
+ if(md == null) throw ("Not a string in hexes! at " + i);
+ /* push right side first for little Endian */
+ da[i] = parseInt(md[2], 16);
+ da[i+1] = parseInt(md[1], 16);
+ }
+ return da;
+ }
+
+ /**
+ * Add a new output mode.
+ */
+ tadAvrAsm.outModes.audioino = function(state) {
+ var da = hexesToNums(state.bytes);
+ var sig = numsToSignal(da);
+ var wav = signalToWave(sig);
+ return wav;
+ }
+
+ /**
+ * Convert wave to base64 and twist into an URI, then play.
+ */
+ tadAvrAsm.playWaveData = function(wave) {
+ var dataURI = "data:audio/wav;base64," + escape(btoa(wave));
+ var audio = new Audio(dataURI);
+ audio.play();
+ }
+
+}( window.tadAvrAsm = window.tadAvrAsm || {} ));
+
+/* vim: set cin sw=4 ts=4 noet : */
1,043 assemble/avrasm.js
@@ -0,0 +1,1043 @@
+/**
+ * Assemble AVR mnemonics into an S19 string.
+ *
+ * This was written with http://www.atmel.com/atmel/acrobat/doc0856.pdf
+ * It is a bit short of features often found in an assembler, but there is enough here to build
+ * simple programs and run them.
+ *
+ * It would be nice someday to add device support, just to give errors on unsupported
+ * instructions. Macros would be nice too.
+ *
+ *
+ * Copyright (c) 2012 Michael Conrad Tadpol Tilstra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+(function(tadAvrAsm, undefined ) {
+ /**
+ * Get a destination register index from a string and shift it to where it
+ * is most commonly found.
+ * Also, make sure it is within the valid range.
+ */
+ function destRindex(r, min, max) {
+ min = (typeof min == 'undefined')?0:min;
+ max = (typeof max == 'undefined')?31:max;
+ var d = r.match(/[Rr](\d{1,2})/);
+ if(!d) throw("Not a register: " + r);
+ d = parseInt(d[1]);
+ if( d < min || d > max) throw ("Rd out of range: " + min + "<>" + max);
+ return (d & 0x1f) << 4
+ }
+
+ /**
+ * Get a source register index from a string and shift it to where it is
+ * most commonly found.
+ * Also, make sure it is within the valid range.
+ */
+ function srcRindex(r, min, max) {
+ min = (typeof min == 'undefined')?0:min;
+ max = (typeof max == 'undefined')?31:max;
+ var d = r.match(/[Rr](\d{1,2})/);
+ if(!d) throw("Not a register: " + r);
+ d = parseInt(d[1]);
+ if( d < min || d > max) throw ("Rd out of range: " + min + "<>" + max);
+ var s = (d & 0xf);
+ s |= ((d>>4) & 1) << 9;
+ return s;
+ }
+
+ /**
+ * Get a constant value and check that it is in range.
+ */
+ function constValue(r, min, max) {
+ min = (typeof min == 'undefined')?0:min;
+ max = (typeof max == 'undefined')?255:max;
+ var d = parseInt(r);
+ if( isNaN(d) ) throw "constant is not a number.";
+ if( d < min || d > max) throw ("[Ks] out of range: " + min + "<>" + max);
+ return d;
+ }
+
+ /*
+ * Fit a twos-complement number into the specific bit count
+ */
+ function fitTwoC(r, bits) {
+ if(bits < 2) throw "Need atleast 2 bits to be signed.";
+ if(bits > 16) throw "fitTwoC only works on 16bit numbers for now.";
+ if(Math.abs(r) > Math.pow(2, bits-1)) throw ("Not enough bits for number. (" + r + ", " + bits + ")");
+ if( r < 0) {
+ r = 0xffff + r + 1;
+ }
+ var mask = 0xffff >> (16 - bits);
+ return r & mask;
+ }
+
+ /**
+ * Determin if input is an address or label and lookup if required.
+ * If label that doesn't exist, return NaN.
+ * If offset is not 0, convert from absolute address to relative.
+ */
+ function constOrLabel(c, labels, offset) {
+ offset = (typeof offset == 'undefined')?0:offset;
+ if( typeof c == 'string' ) {
+ var d = parseInt(c);
+ if( isNaN(d) ) {
+ if( c in labels ) {
+ d = labels[c] - offset;
+ d = d >> 1; /* convert bytes into words. */
+ } else {
+ return NaN;
+ }
+ }
+ c = d;
+ }
+ return c;
+ }
+
+ /**
+ * Convert number to hex and left pad it
+ */
+ function zeroPad(r, len) {
+ len = (typeof len == 'undefined')?4:len; // default to words.
+ r = Number(r).toString(16);
+ var base = Array(len+1).join('0');
+ var t = base.substr(0, len - r.length) + r;
+ return t;
+ }
+
+ /**
+ * Get an Indirect Address Register and shift it to where it is commonly found.
+ */
+ function stldXYZ(xyz) {
+ switch(xyz) {
+ case 'X':
+ return 0x900c;
+ case 'X+':
+ return 0x900d;
+ case '-X':
+ return 0x900e;
+ case 'Y':
+ return 0x8008;
+ case 'Y+':
+ return 0x9009;
+ case '-Y':
+ return 0x900a;
+ case 'Z':
+ return 0x8000;
+ case 'Z+':
+ return 0x9001;
+ case '-Z':
+ return 0x9002;
+ default:
+ throw "Not -?[XYZ]\\+?";
+ }
+ }
+
+ /**
+ * Get an Indirect Address Register with displacement and shift it to where it is commonly found.
+ */
+ function stldYZq(yzq) {
+ var d = yzq.match(/([YZ])\+(\d+)/);
+ var r = 0x8000;
+ switch(d[1]) {
+ case 'Y':
+ r |= 0x8;
+ break;
+ case 'Z':
+ /* r|= 0; */
+ break;
+ default:
+ throw "Not Y or Z with q";
+ }
+ var q = parseInt(d[2]);
+ if( q < 0 || q > 64 ) throw "q is out of range";
+ r |= ((q & 0x20) << 8) | ((q & 0x18) << 7) | (q & 0x7);
+ return r;
+ }
+
+ /**
+ * Table of Mnemonics that can be assembled.
+ */
+ var OPTABLE = {
+ /* Mnemonic: linecompiler */
+ "ADD": function(a,b) {
+ var r = 0x0c00 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "ADC": function(a,b) {
+ var r = 0x1c00 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "ADIW": function(a,b) {
+ var r = 0x9600;
+ var dm = a.match(/[Rr](24|26|28|30)/);
+ if( !dm ) throw "Rd must be 24, 26, 28, or 30";
+ var d = parseInt(dm[1]);
+ d = (d - 24) / 2;
+ r |= (d & 0x3) << 4;
+ var k = constValue(b, 0, 63);
+ r |= ((k & 0x30) << 2) | (k & 0x0f);
+ return zeroPad(r);
+ },
+ "AND": function(a,b) {
+ var r = 0x2000 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "ANDI": function(a,b) {
+ var r = 0x7000 | (destRindex(a, 16, 31) & 0xf0);
+ var k = constValue(b);
+ r |= ((k & 0xf0) << 4) | (k & 0xf);
+ return zeroPad(r);
+ },
+ "ASR": function(a,b) {
+ var r = 0x9405 | destRindex(a);
+ return zeroPad(r);
+ },
+ "BCLR": function(a,b) {
+ var r = 0x9488;
+ var s = constValue(a, 0, 7);
+ r |= (s & 0x7) << 4;
+ return zeroPad(r);
+ },
+ "BLD": function(a,b) {
+ var r = 0xf800 | destRindex(a) | (constValue(b, 0, 7) & 0x7);
+ return zeroPad(r);
+ },
+ "BRBC": function(a, b, byteLoc, labels) {
+ var k = constOrLabel(b, labels, byteLoc + 2);
+ if( isNaN(k) ) {
+ return function(l) {return OPTABLE["BRBC"](a, b, byteLoc, l);};
+ }
+ var r = 0xf400 | constValue(a, 0, 7);
+ r |= (fitTwoC(constValue(k, -64, 63), 7) << 3);
+ return zeroPad(r);
+ },
+ "BRBS": function(a, b, byteLoc, labels) {
+ var k = constOrLabel(b, labels, byteLoc + 2);
+ if( isNaN(k) ) {
+ return function(l) {return OPTABLE["BRBS"](a, b, byteLoc, l);};
+ }
+ var r = 0xf000 | constValue(a, 0, 7);
+ r |= (fitTwoC(constValue(k, -64, 63), 7) << 3);
+ return zeroPad(r);
+ },
+ "BRCC": function(a,b, byteLoc, labels) {
+ return OPTABLE["BRBC"](0, a, byteLoc, labels);
+ },
+ "BRCS": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](0, a, byteLoc, labels);
+ },
+ "BREAK": function() {
+ return "9598";
+ },
+ "BREQ": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](1, a, byteLoc, labels);
+ },
+ "BRGE": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](4, a, byteLoc, labels);
+ },
+ "BRHC": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](5, a, byteLoc, labels);
+ },
+ "BRHS": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](5, a, byteLoc, labels);
+ },
+ "BRID": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](7, a, byteLoc, labels);
+ },
+ "BRIE": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](7, a, byteLoc, labels);
+ },
+ "BRLO": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](0, a, byteLoc, labels);
+ },
+ "BRLT": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](4, a, byteLoc, labels);
+ },
+ "BRMI": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](2, a, byteLoc, labels);
+ },
+ "BRNE": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](1, a, byteLoc, labels);
+ },
+ "BRPL": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](2, a, byteLoc, labels);
+ },
+ "BRSH": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](0, a, byteLoc, labels);
+ },
+ "BRTC": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](6, a, byteLoc, labels);
+ },
+ "BRTS": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](6, a, byteLoc, labels);
+ },
+ "BRVC": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBC"](3, a, byteLoc, labels);
+ },
+ "BRVS": function(a, b, byteLoc, labels) {
+ return OPTABLE["BRBS"](3, a, byteLoc, labels);
+ },
+ "BSET": function(a, b) {
+ var r = 0x9408;
+ var s = constValue(a, 0, 7);
+ r |= (s & 0x7) << 4;
+ return zeroPad(r);
+ },
+ "BST": function(a, b) {
+ var r = 0xfa00 | destRindex(a) | constValue(b, 0, 7);
+ return zeroPad(r);
+ },
+ "CALL": function(a, b, byteLoc, labels) {
+ var k = constOrLabel(a, labels);
+ if( isNaN(k) ) {
+ return [function(l) {return OPTABLE["CALL"](a, b, byteLoc, l);}, "xxxx"];
+ }
+ var r = 0x940e;
+ k = constValue(k, 0, 0x400000);
+ var lk = k & 0xffff;
+ var hk = (k >> 16) & 0x3f;
+ r |= ((hk & 0x3e) << 3) | (hk & 1);
+ return [zeroPad(r), zeroPad(lk)];
+ },
+ "CBI": function(a, b) {
+ var r = 0x9800 | (constValue(a, 0, 31) << 3) | constValue(b, 0, 7);
+ return zeroPad(r);
+ },
+ "CRB": function(a, b) {
+ var k = constValue(b);
+ return OPTABLE["ANDI"](a, (~k)&0xff );
+ },
+ "CLC" : function() {
+ return "9488";
+ },
+ "CLH" : function() {
+ return "94d8";
+ },
+ "CLI" : function() {
+ return "94f8";
+ },
+ "CLN" : function() {
+ return "94a8";
+ },
+ "CLR": function(a) {
+ return OPTABLE["EOR"](a, a);
+ },
+ "CLS" : function() {
+ return "94c8";
+ },
+ "CLT" : function() {
+ return "94e8";
+ },
+ "CLV" : function() {
+ return "94b8";
+ },
+ "CLZ" : function() {
+ return "9498";
+ },
+ "COM": function(a) {
+ var r = 0x9400 | destRindex(a);
+ return zeroPad(r);
+ },
+ "CP": function(a, b) {
+ var r = 0x1400 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "CPC": function(a, b) {
+ var r = 0x0400 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "CPI": function(a, b) {
+ var r = 0x3000 | (destRindex(a, 16, 31) & 0xf0);
+ var k = constValue(b);
+ r |= ((k & 0xf0) << 4) | (k & 0xf);
+ return zeroPad(r);
+ },
+ "CPSE": function(a, b) {
+ var r = 0x1000 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "DEC": function(a) {
+ var r = 0x940a | destRindex(a);
+ return zeroPad(r);
+ },
+ "DES": function(a) {
+ var r = 0x940b | (constValue(a, 0, 15) << 4);
+ return zeroPad(r);
+ },
+ "EICALL": function() {
+ return "9519";
+ },
+ "EIJMP": function() {
+ return "9419";
+ },
+ "ELPM": function(a, b) {
+ if( typeof a == 'undefined' || a == '' ) {
+ return "95d8";
+ } else {
+ var r = 0x9000 | destRindex(a);
+ switch(b) {
+ case 'Z':
+ r |= 6;
+ break;
+ case 'Z+':
+ r |= 7;
+ break;
+ default:
+ throw "Bad operand";
+ }
+ return zeroPad(r);
+ }
+ },
+ "EOR": function(a, b) {
+ var r = 0x2400 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "FMUL": function(a, b) {
+ var r = 0x0308 | (destRindex(a, 16, 23) & 0x70) | (srcRindex(b, 16, 23) & 0x7);
+ return zeroPad(r);
+ },
+ "FMULS": function(a, b) {
+ var r = 0x0380 | (destRindex(a, 16, 23) & 0x70) | (srcRindex(b, 16, 23) & 0x7);
+ return zeroPad(r);
+ },
+ "FMULSU": function(a, b) {
+ var r = 0x0388 | (destRindex(a, 16, 23) & 0x70) | (srcRindex(b, 16, 23) & 0x7);
+ return zeroPad(r);
+ },
+ "ICALL": function() {
+ return "9509";
+ },
+ "IJMP": function() {
+ return "9409";
+ },
+ "IN": function(a, b) {
+ var r = 0xb000 | destRindex(a);
+ var A = constValue(b, 0, 63);
+ r |= ((A & 0x30) << 5) | ( A & 0x0f);
+ return zeroPad(r);
+ },
+ "INC": function(a) {
+ var r = 0x9403 | destRindex(a);
+ return zeroPad(r);
+ },
+ "JMP": function(a, b, byteLoc, labels) {
+ var k = constOrLabel(a, labels);
+ if( isNaN(k) ) {
+ return [function(l) {return OPTABLE["JMP"](a, b, byteLoc, l);}, "xxxx"];
+ }
+ var r = 0x940c;
+ k = constValue(k, 0, 0x400000);
+ var lk = k & 0xffff;
+ var hk = (k >> 16) & 0x3f;
+ r |= ((hk & 0x3e) << 3) | (hk & 1);
+ return [zeroPad(r), zeroPad(lk)];
+ },
+ "LAC": function(a, b) {
+ if(a != 'Z') throw "First Operand is not Z";
+ var r = 0x9206 | destRindex(b);
+ return zeroPad(r);
+ },
+ "LAS": function(a, b) {
+ if(a != 'Z') throw "First Operand is not Z";
+ var r = 0x9205 | destRindex(b);
+ return zeroPad(r);
+ },
+ "LAT": function(a, b) {
+ if(a != 'Z') throw "First Operand is not Z";
+ var r = 0x9207 | destRindex(b);
+ return zeroPad(r);
+ },
+ "LD": function(a, b) {
+ var r = 0x0000 | destRindex(a) | stldXYZ(b);
+ return zeroPad(r);
+ },
+ "LDD": function(a, b) {
+ var r = 0x0000 | destRindex(a) | stldYZq(b);
+ return zeroPad(r);
+ },
+ "LDI": function(a,b) {
+ var r = 0xe000 | (destRindex(a, 16, 31) & 0xf0);
+ var k = constValue(b);
+ r |= ((k & 0xf0) << 4) | (k & 0xf);
+ return zeroPad(r);
+ },
+ "LDS": function(a, b) {
+ var k = constValue(b, 0, 65535);
+ var r = 0x9000 | destRindex(a);
+ return [zeroPad(r), zeroPad(k)];
+ },
+ "LPM": function(a, b) {
+ if( typeof a == 'undefined' || a == '' ) {
+ return "95c8";
+ } else {
+ var r = 0x9000 | destRindex(a);
+ switch(b) {
+ case 'Z':
+ r |= 4;
+ break;
+ case 'Z+':
+ r |= 5;
+ break;
+ default:
+ throw "Bad operand";
+ }
+ return zeroPad(r);
+ }
+ },
+ "LSL": function(a) {
+ return OPTABLE["ADD"](a, a);
+ },
+ "LSR": function(a) {
+ var r = 0x9406 | destRindex(a);
+ return zeroPad(r);
+ },
+ "MOV": function(a, b) {
+ var r = 0x2c00 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "MOVW": function(a, b) {
+ /* use destRindex on both here for simpler shifting */
+ var r = 0x0100 | ((destRindex(a) >> 1) & 0xf0) | ((destRindex(b) >> 5) & 0xf);
+ return zeroPad(r);
+ },
+ "MUL": function(a, b) {
+ var r = 0x9c00 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "MULS": function(a, b) {
+ var r = 0x0200 | (destRindex(a, 16, 31) & 0xf0) | (srcRindex(b, 16, 31) & 0xf);
+ return zeroPad(r);
+ },
+ "MULSU": function(a, b) {
+ var r = 0x0300 | (destRindex(a, 16, 23) & 0x70) | (srcRindex(b, 16, 23) & 0x7);
+ return zeroPad(r);
+ },
+ "NEG": function(a) {
+ var r = 0x9401 | destRindex(a);
+ return zeroPad(r);
+ },
+ "NOP": function() {
+ return "0000";
+ },
+ "OR": function(a, b) {
+ var r = 0x2800 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "ORI": function(a, b) {
+ var r = 0x6000 | (destRindex(a, 16, 31) & 0xf0);
+ var k = constValue(b);
+ r |= ((k & 0xf0) << 4) | (k & 0xf);
+ return zeroPad(r);
+ },
+ "OUT": function(a, b) {
+ var r = 0xb800 | destRindex(b);
+ var A = constValue(a, 0, 63);
+ r |= ((A & 0x30) << 5) | ( A & 0x0f);
+ return zeroPad(r);
+ },
+ "POP": function(a) {
+ var r = 0x900f | destRindex(a);
+ return zeroPad(r);
+ },
+ "PUSH": function(a) {
+ var r = 0x920f | destRindex(a);
+ return zeroPad(r);
+ },
+ "RCALL": function(a, b, byteLoc, labels) {
+ var k = constOrLabel(a, labels, byteLoc + 2);
+ if( isNaN(k) ) {
+ return function(l) {return OPTABLE["RCALL"](a, b, byteLoc, l);};
+ }
+ var r = 0xd000 | fitTwoC(constValue(k, -2048, 2048), 12);
+ return zeroPad(r);
+ },
+ "RET": function() {
+ return "9508";
+ },
+ "RETI": function() {
+ return "9518";
+ },
+ "RJMP": function(a, b, byteLoc, labels) {
+ var k = constOrLabel(a, labels, byteLoc + 2);
+ if( isNaN(k) ) {
+ return function(l) {return OPTABLE["RJMP"](a, b, byteLoc, l);};
+ }
+ var r = 0xc000 | fitTwoC(constValue(k, -2048, 2048), 12);
+ return zeroPad(r);
+ },
+ "ROL": function(a) {
+ return OPTABLE["ADC"](a, a);
+ },
+ "ROR": function(a) {
+ var r = 0x9407 | destRindex(a);
+ return zeroPad(r);
+ },
+ "SBC": function(a,b) {
+ var r = 0x0800 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "SBCI": function(a, b) {
+ var r = 0x4000 | (destRindex(a, 16, 31) & 0xf0);
+ var k = constValue(b);
+ r |= ((k & 0xf0) << 4) | (k & 0x0f);
+ return zeroPad(r);
+ },
+ "SBI": function(a, b) {
+ var r = 0x9a00 | (constValue(a, 0, 31) << 3) | constValue(b, 0, 7);
+ return zeroPad(r);
+ },
+ "SBIC": function(a, b) {
+ var r = 0x9900 | (constValue(a, 0, 31) << 3) | constValue(b, 0, 7);
+ return zeroPad(r);
+ },
+ "SBIS": function(a, b) {
+ var r = 0x9b00 | (constValue(a, 0, 31) << 3) | constValue(b, 0, 7);
+ return zeroPad(r);
+ },
+ "SBIW": function(a, b) {
+ var r = 0x9700;
+ var dm = a.match(/[Rr](24|26|28|30)/);
+ if( !dm ) throw "Rd must be 24, 26, 28, or 30";
+ var d = parseInt(dm[1]);
+ d = (d - 24) / 2;
+ r |= (d & 0x3) << 4;
+ var k = constValue(b, 0, 63);
+ r |= ((k & 0x30) << 2) | (k & 0x0f);
+ return zeroPad(r);
+ },
+ "SBR": function(a, b) {
+ var r = 0x6000 | (destRindex(a, 16, 31) & 0xf0);
+ var k = constValue(b);
+ r |= ((k & 0xf0) << 4) | (k & 0x0f);
+ return zeroPad(r);
+ },
+ "SBRC": function(a, b) {
+ var r = 0xfc00 | destRindex(a) | constValue(b, 0, 7);
+ return zeroPad(r);
+ },
+ "SBRS": function(a, b) {
+ var r = 0xfe00 | destRindex(a) | constValue(b, 0, 7);
+ return zeroPad(r);
+ },
+ "SEC": function() {
+ return OPTABLE["SEflag"](0);
+ },
+ "SEflag": function(a) { /* set flag a */
+ var r = 0x9408 | (constValue(a, 0, 7) << 4);
+ return zeroPad(r);
+ },
+ "SEH": function() {
+ return OPTABLE["SEflag"](5);
+ },
+ "SEI": function() {
+ return OPTABLE["SEflag"](7);
+ },
+ "SEN": function() {
+ return OPTABLE["SEflag"](2);
+ },
+ "SER": function(a) {
+ var r = 0xef0f | (destRindex(a, 16, 31) & 0xf0);
+ return zeroPad(r);
+ },
+ "SES": function() {
+ return OPTABLE["SEflag"](4);
+ },
+ "SET": function() {
+ return OPTABLE["SEflag"](6);
+ },
+ "SEV": function() {
+ return OPTABLE["SEflag"](3);
+ },
+ "SEZ": function() {
+ return OPTABLE["SEflag"](1);
+ },
+ "SLEEP": function() {
+ return "9588";
+ },
+ "SPM": function(a) {
+ if( typeof a == 'undefined' || a == '' ) {
+ return "95e8";
+ } else {
+ if( a != 'Z+' ) throw "Bad param to SPM";
+ return "95f8";
+ }
+ },
+ "ST": function(a, b) {
+ var r = 0x0200 | destRindex(b) | stldXYZ(a);
+ return zeroPad(r);
+ },
+ "STD": function(a, b) {
+ var r = 0x0200 | destRindex(b) | stldYZq(a);
+ return zeroPad(r);
+ },
+ "STS": function(a, b) {
+ var k = constValue(a, 0, 65535);
+ var r = 0x9200 | destRindex(b);
+ return [zeroPad(r), zeroPad(k)];
+ },
+ "SUB": function(a, b) {
+ var r = 0x1800 | destRindex(a) | srcRindex(b);
+ return zeroPad(r);
+ },
+ "SUBI": function(a, b) {
+ var r = 0x5000 | (destRindex(a, 16, 31) & 0xf0);
+ var k = constValue(b);
+ r |= ((k & 0xf0) << 4) | (k & 0xf);
+ return zeroPad(r);
+ },
+ "SWAP": function(a) {
+ var r = 0x9402 | destRindex(a);
+ return zeroPad(r);
+ },
+ "TST": function(a) {
+ return OPTABLE["AND"](a, a);
+ },
+ "WDR": function() {
+ return "95a8";
+ },
+ "XCH": function(a, b) {
+ var r = 0x9204 | destRindex(b);
+ if( a != 'Z' ) throw "Bad param, not Z";
+ return zeroPad(r);
+ }
+ }
+
+ function passone(inputdata) {
+ var lines = inputdata.split("\n");
+ var commentReg = /[#;].*$/;
+ var labelReg = /^(\w+):/;
+ var codeReg = /^\s*(\w+)(?:\s+([^,]+)(?:,\s*(\S+))?)?\s*$/;
+ var lt;
+ var res;
+ var rets;
+ var mnemonic;
+
+ var byteOffset = 0;
+ var lableTable = {};
+ var replacements = {};
+ var errorTable = new Array();
+ var lineTable = new Array();
+
+ for(var idx = 0; idx < lines.length; idx++) {
+ res = lines[idx].trim();
+ if( res.length == 0 ) continue;
+ lt = {'line': idx+1, 'text': res, 'bytes':[], 'byteOffset':0};
+ res = res.replace(commentReg, "").trim(); /* strip off comments. */
+ if( res.length == 0 ) continue;
+ /* check for a label */
+ rets = res.match(labelReg);
+ if( rets ) {
+ lableTable[ rets[1] ] = byteOffset;
+ res = res.replace(labelReg, '').trim(); /* strip out label. */
+ }
+ if( res.length == 0 ) continue;
+ /* Check for a mnemonic line */
+ res = res.match(codeReg);
+ try {
+ if( res == null ) {
+ throw("doesn't match as code!");
+ }
+
+ if( ! res[1] ) {
+ throw "Empty mnemonic field!";
+ }
+
+ /* do opcode */
+ mnemonic = res[1].toUpperCase().trim();
+ /* This switch is ok for just these three.
+ * If ever to add more, then need to figure out how to merge all of the
+ * mnemonics into the OPTABLE. (or build a seperate internal op table)
+ */
+ switch(mnemonic) {
+ case '_REPLACE':
+ replacements[ res[2] ] = res[3];
+ continue;
+ case '_LOC':
+ var num = parseInt(res[2]);
+ if(isNaN(num)) {
+ throw "Location is not a number.";
+ }
+ if(num&0x1) {
+ throw "Location is odd";
+ }
+ byteOffset = num;
+ continue;
+ case '_IW':
+ var num = parseInt(res[2]);
+ if(isNaN(num)) {
+ throw "Immeadiate Word is not a number.";
+ }
+ lt.bytes = zeroPad(num);
+ lt.byteOffset = byteOffset;
+ byteOffset += 2;
+ continue;
+ }
+
+ if( ! (mnemonic in OPTABLE) ) {
+ throw "No such mnemonic: " + mnemonic;
+ }
+
+ /* do replacements on parameters. */
+ if( res[2] in replacements ) {
+ res[2] = replacements[res[2]];
+ }
+ if( res[3] in replacements ) {
+ res[3] = replacements[res[3]];
+ }
+
+ rets = OPTABLE[mnemonic]( res[2], res[3], byteOffset, lableTable );
+ lt.byteOffset = byteOffset;
+ switch(typeof rets) {
+ case 'function':
+ case 'string':
+ byteOffset += 2;
+ break;
+ case 'object': /* assumed as an array. */
+ byteOffset += rets.length * 2;
+ break;
+ default:
+ throw "unknown return type from optable.";
+ }
+ lt.bytes = rets;
+ lineTable.push(lt);
+ } catch (err) {
+ errorTable.push( "Line " + idx + ": " + err );
+ }
+
+ }
+
+ return {
+ "labels": lableTable,
+ "errors": errorTable,
+ 'lines':lineTable
+ };
+ }
+
+ /**
+ * Handle any forward referenced labels that were deferred in passone.
+ */
+ function passtwo(lineTable, labels) {
+ var errorTable = new Array();
+ var resultTable = new Array();
+ var rets;
+ for(var idx=0; idx < lineTable.length; idx++) {
+ try {
+ /* Look for functions left over from passone. */
+ if( typeof lineTable[idx].bytes == 'function' ) {
+ lineTable[idx].bytes = lineTable[idx].bytes(labels);
+ }
+ if( typeof lineTable[idx].bytes == 'object' &&
+ lineTable[idx].bytes.length >= 1 &&
+ typeof lineTable[idx].bytes[0] == 'function' ) { /* a bit gross. FIXME */
+ lineTable[idx].bytes = lineTable[idx].bytes[0](labels);
+ }
+
+ /* copy bytes out of linetable into the results. */
+ switch( typeof lineTable[idx].bytes ) {
+ case 'string':
+ resultTable[ lineTable[idx].byteOffset ] = lineTable[idx].bytes;
+ break;
+ case 'object': /* also array. */
+ if( lineTable[idx].bytes.length < 1 ) {
+ throw "Empty array in lineTable."
+ }
+ var bi = lineTable[idx].byteOffset;
+ for(var j=0; j < lineTable[idx].bytes.length; j++, bi+=2) {
+ if( typeof lineTable[idx].bytes[j] != 'string' ) {
+ throw "Not an array of strings.";
+ }
+ resultTable[ bi ] = lineTable[idx].bytes[j];
+ }
+ break;
+ default:
+ throw "unknown return type from optable.";
+ }
+ } catch(err) {
+ errorTable.push( "Line: " + lineTable[idx].line + ": " + err );
+ }
+ }
+ return { "errors": errorTable, "bytes":resultTable, 'lines': lineTable};
+ }
+
+ /**
+ * Convert array of 8bit hex strings into S19 data.
+ */
+ function hexesToS19(hexes) {
+ var ret = new Array();
+
+ ret.push("S0030000FC\n");
+
+ var len;
+ var checksum;
+ for(var iidx=0; iidx < hexes.length; ) {
+ /* Skip over gaps. ?better way to do this? */
+ if( !(iidx in hexes) ) {
+ iidx++;
+ continue;
+ }
+
+ /* 1 for checksum, 4 for address */
+ len = (hexes.length - iidx) + 5;
+ if(len > 33)
+ len = 33;
+
+ ret.push('S3');
+ ret.push( zeroPad(len, 2) );
+ ret.push( zeroPad(iidx, 8) );
+ checksum = len;
+
+ checksum = (((iidx >> 24) & 0xff) + checksum) & 0xff;
+ checksum = (((iidx >> 16) & 0xff) + checksum) & 0xff;
+ checksum = (((iidx >> 8) & 0xff) + checksum) & 0xff;
+ checksum = ((iidx & 0xff) + checksum) & 0xff;
+ len -= 5; /* 1 for checksum, 4 for address */
+
+ for(;len > 0 && iidx < hexes.length; iidx++, len--) {
+ if( !(iidx in hexes) ) break; /* if we hit a gap, stop this line */
+ ret.push( hexes[iidx] );
+ checksum = (parseInt(hexes[iidx], 16) + checksum) & 0xff;
+ }
+ ret.push( zeroPad((~checksum)&0xff, 2) );
+ ret.push("\n");
+ }
+
+ /* S19 end */
+ ret.push("S9030000FC\n");
+
+ return ret.join('');
+ }
+
+ /**
+ * Covert gappy array of 16bits to less gappy array of 8bits.
+ *
+ * Large gaps are still present.
+ *
+ * Likely the wrong way to do things.
+ */
+ function hexesToEights(hexes) {
+ var ret = new Array();
+ var spl = /(..)(..)/;
+ var md;
+ for(var i=0; i < hexes.length; i+=2) {
+ /* skip over gaps */
+ if( !(i in hexes) ) {
+ continue;
+ }
+ md = hexes[i].match(spl);
+ if(md == null) throw ("Not a string in hexes! at " + i);
+ /* push right side first for little Endian */
+ ret[i] = md[2];
+ ret[i+1] = md[1];
+ }
+ return ret;
+ }
+
+ /**
+ * Given a string that is the hex of a uint16, swap the bytes.
+ *
+ * That is, change ABCD into CDAB
+ */
+ function stringByteSwap(str) {
+ var m = str.match(/(..)(..)/);
+ if(!m) throw "Cannot swap this.";
+ return m[2] + m[1];
+ }
+
+ /**
+ * Dump out the assembed data with line numbers and what was assemebled at each line.
+ *
+ * This output is very similar to what 'gcc-avr-as -mall-opcodes -al' produces.
+ * The intent is that we can validate this assemble against gcc-avr-as with a diff tool.
+ * See also the buildCompareTable.sh script.
+ */
+ function toListing(lt) {
+ output = new Array();
+ for(var idx=0;idx < lt.length; idx++) {
+ var s = new Array();
+ var pad=' ';
+ var l = lt[idx].line.toString();
+ s.push( pad.substr(0, 4 - l.length) + l );
+ s.push(" ");
+ s.push( zeroPad(lt[idx].byteOffset) );
+ s.push(" ");
+ switch( typeof lt[idx].bytes ) {
+ case 'string':
+ s.push( stringByteSwap(lt[idx].bytes).toUpperCase() );
+ s.push(' ');
+ break;
+ case 'object':
+ for(var j=0;j < lt[idx].bytes.length; j++) {
+ s.push( stringByteSwap(lt[idx].bytes[j]).toUpperCase() );
+ s.push(' ');
+ }
+ break;
+ default:
+ throw ("Bogus byte type from line: " + lt[idx].line);
+ }
+ s.push( "\t");
+ s.push( lt[idx].text.replace(/\t/g,' ').replace(/,\s+/,',') );
+ output.push(s.join(''));
+ }
+ return output.join("\n");
+ }
+
+ tadAvrAsm.outModes = {};
+ tadAvrAsm.outModes.s19 = function(state) {
+ return hexesToS19( hexesToEights( state.bytes ) );
+ }
+ tadAvrAsm.outModes.list = function(state) {
+ return toListing(state.lines);
+ }
+
+ /**
+ * The assembler.
+ */
+ tadAvrAsm.assemble = function(input, options) {
+ try {
+ var mid = passone(input);
+ if( mid.errors.length > 0 ) {
+ return {"errors": mid.errors};
+ }
+ var end = passtwo(mid.lines, mid.labels);
+ if( end.errors.length > 0 ) {
+ return {"errors": end.errors};
+ }
+ mid=null;
+
+ var output;
+ if( typeof options == 'undefined' ) {
+ options = {};
+ options['outmode'] = 's19';
+ }
+ if( ! ('outmode' in options) ) {
+ options['outmode'] = 's19';
+ }
+ if( options.outmode in tadAvrAsm.outModes ) {
+ output = tadAvrAsm.outModes[options.outmode](end);
+ } else {
+ output = tadAvrAsm.outModes.s19(end);
+ }
+
+ return {"data":output};
+ } catch(err) {
+ return {"errors":[err]};
+ }
+ }
+
+}( window.tadAvrAsm = window.tadAvrAsm || {} ));
+
+/* vim: set cin sw=4 ts=4 noet : */
25 assemble/buildCompareTable.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+gas=avr-as
+# gas is doing something to constant values in the branches.
+# I'm done trying to figure out what; so ignoring the branching in this test.
+mlst=mnemoniclist-nobranching.S
+opcs=machineList.text
+
+tlst=`mktemp gaslXXXXXX`
+blst=`mktemp bytesXXXXXX`
+
+
+# build the listing.
+cat $mlst | $gas -mall-opcodes -al=$tlst
+rm -f a.out
+
+# Clean up so we can diff it with our output
+cat $tlst | sed -E -e '/^$/d' -e '/GAS LISTING/d' -e 's/[[:space:]]*$//' -e '/^[[:space:]]*[[:digit:]]+$/d' > $blst
+
+#
+
+rm -f $tlst
+
+mv $blst $opcs
+
161 assemble/jsdiff.js
@@ -0,0 +1,161 @@
+/*
+ * Javascript Diff Algorithm
+ * By John Resig (http://ejohn.org/)
+ * Modified by Chu Alan "sprite"
+ *
+ * Released under the MIT license.
+ *
+ * More Info:
+ * http://ejohn.org/projects/javascript-diff-algorithm/
+ */
+
+function escape(s) {
+ var n = s;
+ n = n.replace(/&/g, "&amp;");
+ n = n.replace(/</g, "&lt;");
+ n = n.replace(/>/g, "&gt;");
+ n = n.replace(/"/g, "&quot;");
+
+ return n;
+}
+
+function diffString( o, n ) {
+ o = o.replace(/\s+$/, '');
+ n = n.replace(/\s+$/, '');
+
+ var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
+ var str = "";
+
+ var oSpace = o.match(/\s+/g);
+ if (oSpace == null) {
+ oSpace = ["\n"];
+ } else {
+ oSpace.push("\n");
+ }
+ var nSpace = n.match(/\s+/g);
+ if (nSpace == null) {
+ nSpace = ["\n"];
+ } else {
+ nSpace.push("\n");
+ }
+
+ if (out.n.length == 0) {
+ for (var i = 0; i < out.o.length; i++) {
+ str += '<del>' + escape(out.o[i]) + oSpace[i] + "</del>";
+ }
+ } else {
+ if (out.n[0].text == null) {
+ for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
+ str += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
+ }
+ }
+
+ for ( var i = 0; i < out.n.length; i++ ) {
+ if (out.n[i].text == null) {
+ str += '<ins>' + escape(out.n[i]) + nSpace[i] + "</ins>";
+ } else {
+ var pre = "";
+
+ for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
+ pre += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
+ }
+ str += " " + out.n[i].text + nSpace[i] + pre;
+ }
+ }
+ }
+
+ return str;
+}
+
+function randomColor() {
+ return "rgb(" + (Math.random() * 100) + "%, " +
+ (Math.random() * 100) + "%, " +
+ (Math.random() * 100) + "%)";
+}
+function diffString2( o, n ) {
+ o = o.replace(/\s+$/, '');
+ n = n.replace(/\s+$/, '');
+
+ var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
+
+ var oSpace = o.match(/\s+/g);
+ if (oSpace == null) {
+ oSpace = ["\n"];
+ } else {
+ oSpace.push("\n");
+ }
+ var nSpace = n.match(/\s+/g);
+ if (nSpace == null) {
+ nSpace = ["\n"];
+ } else {
+ nSpace.push("\n");
+ }
+
+ var os = "";
+ var colors = new Array();
+ for (var i = 0; i < out.o.length; i++) {
+ colors[i] = randomColor();
+
+ if (out.o[i].text != null) {
+ os += '<span style="background-color: ' +colors[i]+ '">' +
+ escape(out.o[i].text) + oSpace[i] + "</span>";
+ } else {
+ os += "<del>" + escape(out.o[i]) + oSpace[i] + "</del>";
+ }
+ }
+
+ var ns = "";
+ for (var i = 0; i < out.n.length; i++) {
+ if (out.n[i].text != null) {
+ ns += '<span style="background-color: ' +colors[out.n[i].row]+ '">' +
+ escape(out.n[i].text) + nSpace[i] + "</span>";
+ } else {
+ ns += "<ins>" + escape(out.n[i]) + nSpace[i] + "</ins>";
+ }
+ }
+
+ return { o : os , n : ns };
+}
+
+function diff( o, n ) {
+ var ns = new Object();
+ var os = new Object();
+
+ for ( var i = 0; i < n.length; i++ ) {
+ if ( ns[ n[i] ] == null )
+ ns[ n[i] ] = { rows: new Array(), o: null };
+ ns[ n[i] ].rows.push( i );
+ }
+
+ for ( var i = 0; i < o.length; i++ ) {
+ if ( os[ o[i] ] == null )
+ os[ o[i] ] = { rows: new Array(), n: null };
+ os[ o[i] ].rows.push( i );
+ }
+
+ for ( var i in ns ) {
+ if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) {
+ n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] };
+ o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] };
+ }
+ }
+
+ for ( var i = 0; i < n.length - 1; i++ ) {
+ if ( n[i].text != null && n[i+1].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
+ n[i+1] == o[ n[i].row + 1 ] ) {
+ n[i+1] = { text: n[i+1], row: n[i].row + 1 };
+ o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 };
+ }
+ }
+
+ for ( var i = n.length - 1; i > 0; i-- ) {
+ if ( n[i].text != null && n[i-1].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
+ n[i-1] == o[ n[i].row - 1 ] ) {
+ n[i-1] = { text: n[i-1], row: n[i].row - 1 };
+ o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 };
+ }
+ }
+
+ return { o: o, n: n };
+}
+
439 assemble/mnemoniclist-nobranching.S
@@ -0,0 +1,439 @@
+ ADD r0,r1
+ ADD r15,r28
+ ADD r28,r31
+
+ ADC r0,r1
+ ADC r15,r28
+ ADC r28,r31
+
+ ADIW r24, 10
+ ADIW r26,44
+ ADIW r28,2
+ ADIW r30, 63
+
+ AND r0,r1
+ AND r15,r28
+ AND r28,r31
+
+ ANDI r16, 155
+ ANDI r25, 1
+ ANDI r31, 0xff
+
+ ASR r0
+ ASR r15
+ ASR r31
+
+ BCLR 0
+ BCLR 4
+ BCLR 7
+
+ BLD r0, 7
+ BLD r16, 4
+ BLD r31, 0
+
+# BRBC 0, -64
+# BRBC 4, 1
+# BRBC 7, 63
+#
+# BRBS 0, -64
+# BRBS 4, 1
+# BRBS 7, 63
+#
+# BRCC -64
+# BRCC -1
+# BRCC 63
+#
+# BRCS -64
+# BRCS -1
+# BRCS 63
+
+ BREAK
+
+# BREQ -64
+# BREQ 1
+# BREQ 63
+#
+# BRGE -64
+# BRGE 1
+# BRGE 63
+#
+# BRHC -64
+# BRHC 1
+# BRHC 63
+#
+# BRHS -64
+# BRHS 1
+# BRHS 63
+#
+# BRID -64
+# BRID 1
+# BRID 63
+#
+# BRIE -64
+# BRIE 1
+# BRIE 63
+#
+# BRLO -64
+# BRLO 1
+# BRLO 63
+#
+# BRLT -64
+# BRLT 1
+# BRLT 63
+#
+# BRMI -64
+# BRMI 1
+# BRMI 63
+#
+# BRNE -64
+# BRNE 1
+# BRNE 63
+#
+# BRPL -64
+# BRPL 1
+# BRPL 63
+#
+# BRSH -64
+# BRSH 1
+# BRSH 63
+#
+# BRTC -64
+# BRTC 1
+# BRTC 63
+#
+# BRTS -64
+# BRTS 1
+# BRTS 63
+#
+# BRVC -64
+# BRVC 1
+# BRVC 63
+#
+# BRVS -64
+# BRVS 1
+# BRVS 63
+
+ BSET 0
+ BSET 4
+ BSET 7
+
+ BST r0,7
+ BST r15,4
+ BST r31, 0
+
+# CALL 0
+# CALL 0x1FFFFF
+# CALL 0x3FFFFF
+
+ CBI 31,0
+ CBI 14,3
+ CBI 0,7
+
+# CRB r16, 255
+# CRB r21, 0xaa
+# CRB r31, 0
+
+ CLC
+ CLH
+ CLI
+ CLN
+
+ CLR r0
+ CLR r16
+ CLR r31
+
+ CLS
+ CLT
+ CLV
+ CLZ
+
+ COM r0
+ COM r15
+ COM r31
+
+ CP r0, r31
+ CP r15,r16
+ CP r31,r0
+
+ CPC r0,r31
+ CPC r15, r16
+ CPC r31, r0
+
+ CPI r16, 0xff
+ CPI r23, 0x55
+ CPI r31, 0
+
+ CPSE r0,r31
+ CPSE r15, r16
+ CPSE r31,r0
+
+ DEC r0
+ DEC r16
+ DEC r31
+
+ DES 0
+ DES 7
+ DES 15
+
+ EICALL
+ EIJMP
+
+ ELPM
+ ELPM r0, Z
+ ELPM r31, Z+
+
+ EOR r0, r31
+ EOR r16, r15
+ EOR r31,r0
+
+ FMUL r16,r23
+ FMUL r17,r19
+ FMUL r23,r16
+
+ FMULS r16,r23
+ FMULS r17,r19
+ FMULS r23,r16
+
+ FMULSU r16,r23
+ FMULSU r17,r19
+ FMULSU r23,r16
+
+ ICALL
+ IJMP
+
+ IN r0,63
+ IN r16,32
+ IN r31,0
+
+ INC r0
+ INC r15
+ INC r31
+
+# JMP 0
+# JMP 0x1FFFFF
+# JMP 0x3FFFFF
+
+# LAC Z,r0
+# LAC Z, r16
+# LAC Z, r31
+#
+# LAS Z,r0
+# LAS Z, r16
+# LAS Z, r31
+#
+# LAT Z,r0
+# LAT Z, r16
+# LAT Z, r31
+
+ LD R0,X
+ LD R15,X+
+ LD R31,-X
+
+ LD r0, Y
+ LD r16, Y+
+ LD r31, -Y
+
+ LD r0, Z
+ LD r15, Z+
+ LD r31, -Z
+
+ LDD R0, Y+63
+ LDD r31, Y+0
+
+ LDD R0, Z+63
+ LDD r31, Z+0
+
+ LDI r16,0xff
+ LDI r23,0xaa
+ LDI r31,0
+
+ LDS r0,65535
+ LDS r16,32767
+ LDS r31,0
+
+ LDS r16,127
+ LDS r23,64
+ LDS r31, 0
+
+ LPM
+ LPM R0,Z
+ LPM R31,Z+
+
+ LSL R0
+ LSL R15
+ LSL R31
+
+ LSR r0
+ LSR r16
+ LSR r31
+
+ MOV r0,r31
+ MOV r15,R16
+ MOV r31,R0
+
+ MOVW r0,r30
+ MOVW r14,R16
+ MOVW r30,r0
+
+ MUL r0,r31
+ MUL r15,r16
+ MUL r31,r0
+
+ MULS r16,r31
+ MULS r21,r26
+ MULS r31,r16
+
+ MULSU r16,r23
+ MULSU r18,r20
+ MULSU r23,r16
+
+ NEG r0
+ NEG r16
+ NEG r31
+
+ NOP
+
+ OR r0,r31
+ OR r16,r15
+ OR r31,r0
+
+ ORI r16,255
+ ORI r23,64
+ ORI r31,0
+
+ OUT 63,r0
+ OUT 32,r16
+ OUT 0,r31
+
+ POP r0
+ POP r16
+ POP r31
+
+ PUSH r0
+ PUSH r15
+ PUSH r31
+
+# RCALL -2048
+# RCALL 0
+# RCALL 2048
+
+ RET
+ RETI
+
+# RJMP -2048
+# RJMP 0
+# RJMP 2048
+
+ ROL r0
+ ROL r15
+ ROL r31
+
+ ROR r0
+ ROR r16
+ ROR r31
+
+ SBC r0,r31
+ SBC r15,r16
+ SBC r31,r0
+
+ SBCI r16,255
+ SBCI r23,63
+ SBCI r31,0
+
+ SBI 0, 7
+ SBI 16, 4
+ SBI 31, 0
+
+ SBIC 0, 7
+ SBIC 15, 4
+ SBIC 31, 0
+
+ SBIS 0, 7
+ SBIS 15, 4
+ SBIS 31, 0
+
+ SBIW r24,63
+ SBIW r26,45
+ SBIW r28,25
+ SBIW r30,0
+
+ SBR r16, 255
+ SBR r23, 64
+ SBR r31, 0
+
+ SBRC r0, 7
+ SBRC r15, 4
+ SBRC r31, 0
+
+ SBRS r0, 7
+ SBRS r15, 4
+ SBRS r31, 0
+
+ SEC
+ SEH
+ SEI
+ SEN
+
+ SER r16
+ SER r23
+ SER r31
+
+ SES
+ SET
+ SEV
+ SEZ
+ SLEEP
+
+ SPM
+ SPM Z+
+
+ ST X, r0
+ ST X+, r15
+ ST -X, r31
+
+ ST Y, r0
+ ST Y+, r15
+ ST -Y, r31
+
+ ST Z, R0
+ ST Z+, R15
+ ST -Z, R31
+
+ STD Y+0, R31
+ STD Y+63, r0
+
+ STD Z+0, R31
+ STD Z+63, r0
+
+ STS 0, r31
+ STS 32767, r15
+ STS 65535, r0
+
+ STS 0, r31
+ STS 63, r23
+ STS 127, r16
+
+ SUB r0, r31
+ SUB r15, r16
+ SUB r31, r0
+
+ SUBI r16, 255
+ SUBI r23, 127
+ SUBI r31, 0
+
+ SWAP r0
+ SWAP r15
+ SWAP r31
+
+ TST r0
+ TST r15
+ TST r31
+
+ WDR
+
+# XCH Z, r0
+# XCH Z, r16
+# XCH Z, r31
+#
+# vim: set noet ai cin sw=8 ts=8 :
+
438 assemble/mnemoniclist.S
@@ -0,0 +1,438 @@
+ ADD r0,r1
+ ADD r15,r28
+ ADD r28,r31
+
+ ADC r0,r1
+ ADC r15,r28
+ ADC r28,r31
+
+ ADIW r24, 10
+ ADIW r26,44
+ ADIW r28,2
+ ADIW r30, 63
+
+ AND r0,r1
+ AND r15,r28
+ AND r28,r31
+
+ ANDI r16, 155
+ ANDI r25, 1
+ ANDI r31, 0xff
+
+ ASR r0
+ ASR r15
+ ASR r31
+
+ BCLR 0
+ BCLR 4
+ BCLR 7
+
+ BLD r0, 7
+ BLD r16, 4
+ BLD r31, 0
+
+ BRBC 0, -64
+ BRBC 4, 1
+ BRBC 7, 63
+
+ BRBS 0, -64
+ BRBS 4, 1
+ BRBS 7, 63
+
+ BRCC -64
+ BRCC -1
+ BRCC 63
+
+ BRCS -64
+ BRCS -1
+ BRCS 63
+
+ BREAK
+
+ BREQ -64
+ BREQ 1
+ BREQ 63
+
+ BRGE -64
+ BRGE 1
+ BRGE 63
+
+ BRHC -64
+ BRHC 1
+ BRHC 63
+
+ BRHS -64
+ BRHS 1
+ BRHS 63
+
+ BRID -64
+ BRID 1
+ BRID 63
+
+ BRIE -64
+ BRIE 1
+ BRIE 63
+
+ BRLO -64
+ BRLO 1
+ BRLO 63
+
+ BRLT -64
+ BRLT 1
+ BRLT 63
+
+ BRMI -64
+ BRMI 1
+ BRMI 63
+
+ BRNE -64
+ BRNE 1
+ BRNE 63
+
+ BRPL -64
+ BRPL 1
+ BRPL 63
+
+ BRSH -64
+ BRSH 1
+ BRSH 63
+
+ BRTC -64
+ BRTC 1
+ BRTC 63
+
+ BRTS -64
+ BRTS 1
+ BRTS 63
+
+ BRVC -64
+ BRVC 1
+ BRVC 63
+
+ BRVS -64
+ BRVS 1
+ BRVS 63
+
+ BSET 0
+ BSET 4
+ BSET 7
+
+ BST r0,7
+ BST r15,4
+ BST r31, 0
+
+ CALL 0
+ CALL 0x1FFFFF
+ CALL 0x3FFFFF
+
+ CBI 31,0
+ CBI 14,3
+ CBI 0,7
+
+ CRB r16, 255
+ CRB r21, 0xaa
+ CRB r31, 0
+
+ CLC
+ CLH
+ CLI
+ CLN
+
+ CLR r0
+ CLR r16
+ CLR r31
+
+ CLS
+ CLT
+ CLV
+ CLZ
+
+ COM r0
+ COM r15
+ COM r31
+
+ CP r0, r31
+ CP r15,r16
+ CP r31,r0
+
+ CPC r0,r31
+ CPC r15, r16
+ CPC r31, r0
+
+ CPI r16, 0xff
+ CPI r23, 0x55
+ CPI r31, 0
+
+ CPSE r0,r31
+ CPSE r15, r16
+ CPSE r31,r0
+
+ DEC r0
+ DEC r16
+ DEC r31
+
+ DES 0
+ DES 7
+ DES 15
+
+ EICALL
+ EIJMP
+
+ ELPM
+ ELPM r0, Z
+ ELPM r31, Z+
+
+ EOR r0, r31
+ EOR r16, r15
+ EOR r31,r0
+
+ FMUL r16,r23
+ FMUL r17,r19
+ FMUL r23,r16
+
+ FMULS r16,r23
+ FMULS r17,r19
+ FMULS r23,r16
+
+ FMULSU r16,r23
+ FMULSU r17,r19
+ FMULSU r23,r16
+
+ ICALL
+ IJMP
+
+ IN r0,63
+ IN r16,32
+ IN r31,0
+
+ INC r0
+ INC r15
+ INC r31
+
+ JMP 0
+ JMP 0x1FFFFF
+ JMP 0x3FFFFF
+
+ LAC Z,r0
+ LAC Z, r16
+ LAC Z, r31
+
+ LAS Z,r0
+ LAS Z, r16
+ LAS Z, r31
+
+ LAT Z,r0
+ LAT Z, r16
+ LAT Z, r31
+
+ LD R0,X
+ LD R15,X+
+ LD R31,-X
+
+ LD r0, Y
+ LD r16, Y+
+ LD r31, -Y
+
+ LD r0, Z
+ LD r15, Z+
+ LD r31, -Z
+
+ LDD R0, Y+63
+ LDD r31, Y+0
+
+ LDD R0, Z+63
+ LDD r31, Z+0
+
+ LDI r16,0xff
+ LDI r23,0xaa
+ LDI r31,0
+
+ LDS r0,65535
+ LDS r16,32767
+ LDS r31,0
+
+ LDS r16,127
+ LDS r23,64
+ LDS r31, 0
+
+ LPM
+ LPM R0,Z
+ LPM R31,Z+
+
+ LSL R0
+ LSL R15
+ LSL R31
+
+ LSR r0
+ LSR r16
+ LSR r31
+
+ MOV r0,r31
+ MOV r15,R16
+ MOV r31,R0
+
+ MOVW r0,r30
+ MOVW r14,R16
+ MOVW r30,r0
+
+ MUL r0,r31
+ MUL r15,r16
+ MUL r31,r0
+
+ MULS r16,r31
+ MULS r21,r26
+ MULS r31,r16
+
+ MULSU r16,r23
+ MULSU r18,r20
+ MULSU r23,r16
+
+ NEG r0
+ NEG r16
+ NEG r31
+
+ NOP
+
+ OR r0,r31
+ OR r16,r15
+ OR r31,r0
+
+ ORI r16,255
+ ORI r23,64
+ ORI r31,0
+
+ OUT 63,r0
+ OUT 32,r16
+ OUT 0,r31
+
+ POP r0
+ POP r16
+ POP r31
+
+ PUSH r0
+ PUSH r15
+ PUSH r31
+
+ RCALL -2048
+ RCALL 0
+ RCALL 2048
+
+ RET
+ RETI
+
+ RJMP -2048
+ RJMP 0
+ RJMP 2048
+
+ ROL r0
+ ROL r15
+ ROL r31
+
+ ROR r0
+ ROR r16
+ ROR r31
+
+ SBC r0,r31
+ SBC r15,r16
+ SBC r31,r0
+
+ SBCI r16,255
+ SBCI r23,63
+ SBCI r31,0
+
+ SBI 0, 7
+ SBI 16, 4
+ SBI 31, 0
+
+ SBIC 0, 7
+ SBIC 15, 4
+ SBIC 31, 0
+
+ SBIS 0, 7
+ SBIS 15, 4
+ SBIS 31, 0
+
+ SBIW r24,63
+ SBIW r26,45
+ SBIW r28,25
+ SBIW r30,0
+
+ SBR r16, 255
+ SBR r23, 64
+ SBR r31, 0
+
+ SBRC r0, 7
+ SBRC r15, 4
+ SBRC r31, 0
+
+ SBRS r0, 7
+ SBRS r15, 4
+ SBRS r31, 0
+
+ SEC
+ SEH
+ SEI
+ SEN
+
+ SER r16
+ SER r23
+ SER r31
+
+ SES
+ SET
+ SEV
+ SEZ
+ SLEEP
+
+ SPM
+ SPM Z+
+
+ ST X, r0
+ ST X+, r15
+ ST -X, r31
+
+ ST Y, r0
+ ST Y+, r15
+ ST -Y, r31
+
+ ST Z, R0
+ ST Z+, R15
+ ST -Z, R31
+
+ STD Y+0, R31
+ STD Y+63, r0
+
+ STD Z+0, R31
+ STD Z+63, r0
+
+ STS 0, r31
+ STS 32767, r15
+ STS 65535, r0
+
+ STS 0, r31
+ STS 63, r23
+ STS 127, r16
+
+ SUB r0, r31
+ SUB r15, r16
+ SUB r31, r0
+
+ SUBI r16, 255
+ SUBI r23, 127
+ SUBI r31, 0
+
+ SWAP r0
+ SWAP r15
+ SWAP r31
+
+ TST r0
+ TST r15
+ TST r31
+
+ WDR
+
+ XCH Z, r0
+ XCH Z, r16
+ XCH Z, r31
+
+# vim: set noet ai cin sw=8 ts=8 :
634 assemble/simpletest.html
@@ -0,0 +1,634 @@
+<html>
+ <head>
+ <title>AVR Assembler test</title>
+ <script type="text/javascript" language="JavaScript" src="avrasm.js"></script>
+ <script type="text/javascript" language="JavaScript" src="asmToAudio.js"></script>
+ <script type="text/javascript" language="JavaScript">
+function doassemble(out) {
+ var ip = document.getElementById('input').value;
+
+ var ret = tadAvrAsm.assemble(ip, {'outmode':out});
+ if( "errors" in ret ) {
+ document.getElementById('output').value = ret.errors.join("\n");
+ } else {
+ document.getElementById('output').value = ret.data;
+ }
+
+}
+
+function loadtest(whi) {
+ var r = document.getElementById('test-' + whi).innerHTML;
+ document.getElementById('input').value = r;
+}
+ </script>
+ <style>
+ textarea {
+ font-family: monospace;
+ width: 50em;
+ height: 25em;
+ }
+ </style>
+ </head>
+ <body>
+ <table>
+ <tr><td>
+ <textarea id="input"></textarea>
+ </td><td>
+ <input type="button" value="Blink" onclick="javascript:loadtest('Blink')" /><br />
+ <input type="button" value="all" onclick="javascript:loadtest('allmnemonics')" /><br />
+ </td>
+ </tr>
+ </table>
+ <p>Assemble: <a href="#" onclick="javascript:doassemble('s19')">S19</a>
+ <a href="#" onclick="javascript:doassemble('list')">list</a>
+ <a href="#" onclick="javascript:doassemble('audioino')">audioino</a>
+ </p>
+ <textarea id="output"></textarea>
+
+ <!-- Blink on arduino -->
+ <pre id='test-Blink' style="visibility:hidden">
+ _replace DDRB, 0x04
+ _replace PORTB, 0x05
+ _replace LEDP, 5
+ _replace SPH, 0x3e
+ _replace SPL, 0x3d
+ _replace RAMEND_HI, 0x04
+ _replace RAMEND_LO, 0xff
+
+; Rest and Interrupt table for ATmega168
+ _loc 0
+ jmp RESET ; Reset Handler
+ jmp IgnoreINT ; IRQ0 Handler
+ jmp IgnoreINT ; IRQ1 Handler
+ jmp IgnoreINT ; PCINT0 Handler
+ jmp IgnoreINT ; PCINT1 Handler
+ jmp IgnoreINT ; PCINT2 Handler
+ jmp IgnoreINT ; Watchdog Timer
+ jmp IgnoreINT ; Timer2 Compare
+ jmp IgnoreINT ; Timer2 Compare
+ jmp IgnoreINT ; Timer2 Overflow Handler
+ jmp IgnoreINT ; Timer1 Capture Handler
+ jmp IgnoreINT ; Timer1 Compare A Handler
+ jmp IgnoreINT ; Timer1 Compare B Handler
+ jmp IgnoreINT ; Timer1 Overflow Handler
+ jmp IgnoreINT ; Timer0 Compare A Handler
+ jmp IgnoreINT ; Timer0 Compare B Handler
+ jmp IgnoreINT ; Timer0 Overflow Handler
+ jmp IgnoreINT ; SPI Transfer Complete Handler
+ jmp IgnoreINT ; USART, RX Complete Handler
+ jmp IgnoreINT ; USART, UDR Empty Handler
+ jmp IgnoreINT ; USART, TX Complete Handler
+ jmp IgnoreINT ; ADC Conversion Complete Handler
+ jmp IgnoreINT ; EEPROM Ready Handler
+ jmp IgnoreINT ; Analog Comparator Handler
+ jmp IgnoreINT ; 2-wire Serial Interface Handler
+ jmp IgnoreINT ; Store Program Memory Ready Handler
+
+IgnoreINT: reti
+
+longDelay: