Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

по ВМСиС транслятор кода KR580

.htm
Скачиваний:
0
Добавлен:
01.04.2014
Размер:
51.16 Кб
Скачать
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Pretty i8080 Assembler</title>
<script type="text/javascript">
<!--
//
// Pretty i8080 Assembler
// 
// Send comments to svofski at gmail dit com 
// 
// Copyright (c) 2009 Viacheslav Slavinsky
// 
// 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.
//
//
// Translation help:
// Leonid Kirillov, Alexander Timoshenko, Upi Tamminen,
// Cristopher Green, Nard Awater, Ali Asadzadeh,
// Guillermo S. Romero, Anna Merkulova, Stephan Henningsen
// 
// Revison Log
// Rev.A: Initial release
// Rev.B: A lot of fixes to compile TINIDISK.ASM by Dr. Li-Chen Wang
// Rev.C: Performance optimizations and cleanup, labels->hash
// Rev.D: More syntax fixes; opera navigation and Back Button Toolbar
// Rev.E: Navigation to label references (backref menu)
//        Nice labels table
//        Some Opera-related fixes
// Rev.F: fixed '.' and semi-colon in db
//        tab scroll fixed
// Rev.G: $ can now work as hex prefix
// Rev.H: Fixed spaces in reg-reg, .binfile, .hexfile
//
// TODO: evaluation should ignore precedence, it's all left-to-right
//

// -- global DOM elements

var debug = false;

var inTheOpera = navigator.appName.indexOf('Opera') != -1;

var binFileName = 'test.bin';
var hexFileName = 'test.hex';
var objCopy = 'gobjcopy';
var postbuild = '';
var doHexDump = true;

// -- utility stuffs --
function fromBinary(val) {
    x = 0;
    n = 1;
    for (i = val.length - 1; i >= 0; i--) {
        if (val[i] == '1')
            x += n;
        else if (val[i] != '0') 
            return Number.NaN;
        n *= 2;
    }

    return new Number(x);
}

function char8(val) {
    if (val > 32 && val < 127) return String.fromCharCode(val);
    return '.';
}

function hex8(val) {
    if (val < 0 || val > 255)  return "??";

    var hexstr = "0123456789ABCDEF";
    return hexstr[(val & 0xf0) >> 4] + hexstr[val & 0x0f];
}

function hex16(val) {
	return hex8((val & 0xff00) >> 8) + hex8(val & 0x00ff);
}

function isValidIm16(s) {
	return s != null && s.length > 0;
}

function isValidIm8(s) {
	return s != null && s.length > 0;
}

function isWhitespace(c) {
    return c=='\t' || c == ' ';// this is too slow c.match(/\s/);
}

Array.prototype.indexOf = function (element) {
    for (var i = 0; i < this.length; i++) {
          if (this[i] == element) {
              return i;
          }
    }
    return -1;
};

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); };
String.prototype.endsWith = function(c) { return this[this.length-1] == c; };

// -- Assembler --

var ops0 = {
"nop": "00",
"hlt":	"76",
"ei":	"fb",
"di":	"f3",
"sphl":	"f9",
"xchg":	"eb",
"xthl":	"e3",
"daa":	"27",
"cma":	"2f",
"stc":	"37",
"cmc":	"3f",
"rlc":	"07",
"rrc":	"0f",
"ral":	"17",
"rar":	"1f",
"pchl":	"e9",
"ret":	"c9",
"rnz":	"c0",
"rz":	"c8",
"rnc":	"d0",
"rc":	"d8",
"rpo":	"e0",
"rpe":	"e8",
"rp":	"f0",
"rm":	"f8"
};

var opsIm16 = {
"lda":	"3a",
"sta":	"32",
"lhld":	"2a",
"shld":	"22",
"jmp":	"c3",
"jnz":	"c2",
"jz":	"ca",
"jnc":	"d2",
"jc":	"da",
"jpo":	"e2",
"jpe":	"ea",
"jp":	"f2",
"jm":	"fa",
"call":	"cd",
"cnz":	"c4",
"cz":	"cc",
"cnc":	"d4",
"cc":	"dc",
"cpo":	"e4",
"cpe":	"ec",
"cp":	"f4",
"cm":	"fc"
};

// lxi rp, im16
var opsRpIm16 = {
"lxi":	"01"	// 00rp0001, bc=00, de=01,hl=10, sp=11
};

// adi 33, out 10
var opsIm8 = {
"adi": 	"c6",
"aci": 	"ce",
"sui":	"d6",
"sbi":	"de",
"ani":	"e6",
"xri":	"ee",
"ori":	"f6",
"cpi":	"fe",
"in":	"0db",
"out": 	"d3"
};

var opsRegIm8 = {
"mvi": 	"06"
};

var opsRegReg = {
"mov": 	"40"
};

var opsReg = {
"add": "80", // regsrc
"adc": "88",
"sub": "90",
"sbb": "98",
"ana": "a0",
"xra": "a8",
"ora": "b0",
"cmp": "b8",

"inr": "04", // regdst (<<3)
"dcr": "05"
};

// these are the direct register ops, regdst
var opsRegDst = new Array("inr", "dcr");

var opsRp = {
"ldax": "0A", // rp << 4 (only B, D)
"stax": "02", // rp << 4 (only B, D)
"dad":  "09", // rp << 4
"inx":  "03", // rp << 4
"dcx":  "0b", // rp << 4
"push": "c5", // rp << 4
"pop":  "c1" // rp << 4
};


var LabelsCount = 0;
var labels = new Object();

var resolveTable = Array(); // label negative id, resolved address
var mem = Array();
var textlabels = Array();
var references = Array();
var errors = Array();

function clearLabels() {
    LabelsCount = 0;
    labels = new Object();
}

function resolveNumber(identifier) {
    if (identifier == undefined || identifier.length == 0) return;
    
    if ((identifier[0] == "'" || identifier[0] == "'")
        && identifier.length == 3) {
        return (0xff & identifier.charCodeAt(1));
    }

    if (identifier[0] == '$') {
        identifier = "0x" + identifier.substr(1, identifier.length-1);
    }

	if ("0123456789".indexOf(identifier[0]) != -1) {
        var test;
		test = new Number(identifier);
		if (!isNaN(test)) {
			return test;
		}

        var suffix = identifier[identifier.length-1].toLowerCase();
        switch (suffix) {
        case 'd':
            test = new Number(identifier.substr(0, identifier.length-1));
            if (!isNaN(test)) {
                return test;
            }
            break;
        case 'h':
			test = new Number("0x" + identifier.substr(0, identifier.length-1));
			if (!isNaN(test)) {
				return test;
			}
            break;
        case 'b':
			test = fromBinary(identifier.substr(0, identifier.length-1));
			if (!isNaN(test)) {
				return test;
			}
            break;
        case 'q':
            try {
                var oct = identifier.substr(0, identifier.length-1);
                for (var i = oct.length; --i >= 0;) {
                    if (oct[i] == '8' || oct[i] == '9') return -1;
                }
                return new Number(
                    eval('0' + identifier.substr(0, identifier.length-1)));
            } catch(err) {}
            break;
        }
	}
	return -1;
}

function referencesLabel(identifier, linenumber) {
    identifier = identifier.toLowerCase();
    if (references[linenumber] == undefined) {
        references[linenumber] = identifier;
    }
}

function markLabel(identifier, address, linenumber, override) {
    identifier = identifier.replace(/\$([0-9a-fA-F]+)/, '0x$1');
    identifier = identifier.replace(/(^|[^'])(\$|\.)/, ' '+address+' ');
	var number = resolveNumber(identifier.trim());
	if (number != -1) return number;
	
	if (linenumber == undefined) {
        LabelsCount++;
		address = -1 - LabelsCount;
	}

    identifier = identifier.toLowerCase();
	
	var found = labels[identifier];
    if (found != undefined) {
        if (address >= 0) {
            resolveTable[-found] = address;
        } else {
            address = found;
        }
    }

	if (!found || override) {
        labels[identifier] = address;
	}

    if (linenumber != undefined) {
        textlabels[linenumber] = identifier;
    }
	
	return address;
}

function setmem16(addr, immediate) {
	if (immediate >= 0) {
		mem[addr] = immediate & 0xff;
		mem[addr+1] = immediate >> 8;
	} else {
		mem[addr] = immediate;
		mem[addr+1] = immediate;
	}
}

function setmem8(addr, immediate) {
	mem[addr] = immediate < 0 ? immediate : immediate & 0xff;
}

function parseRegisterPair(s) {
    if (s != undefined) {
        s = s.split(';')[0].toLowerCase();
    	if (s == 'b' || s == 'bc') return 0;
    	if (s == 'd' || s == 'de') return 1;
     	if (s == 'h' || s == 'hl') return 2;
          	if (s == 'sp'|| s == 'psw' || s == 'a') return 3;
    }
	return -1;
}

// b=000, c=001, d=010, e=011, h=100, l=101, m=110, a=111
function parseRegister(s) {
    if (s == undefined) return -1;
    s = s.toLowerCase();
	return "bcdehlma".indexOf(s[0]);
}

function tokenDBDW(s, addr, len, linenumber) {
    var size = -1;

    if (s.length == 0) return 0;

    n = markLabel(s, addr);
    referencesLabel(s, linenumber);

    if (len == undefined) len = 1;

    if (len == 1 && n < 256) {
        setmem8(addr, n);
        size = 1;
    } else if (len == 2 && n < 65536) {
        setmem16(addr, n); 
        size = 2;
    }

    return size;
}

function tokenString(s, addr, linenumber) {
    for (var i = 0; i < s.length; i++) {
        setmem8(addr+i, s.charCodeAt(i));
    }
    return s.length;
}

function parseDeclDB(args, addr, linenumber, dw) {
    var text = args.slice(1).join(' ');
    var arg = "";
    var mode = 0;
    var cork = false;
    var nbytes = 0;

    for (var i = 0; i < text.length; i++) {
        switch (mode) {
        case 0:
            if (text[i] == '"' || text[i] == "'") {
                mode = 1; cork = text[i];
                break;
            } else if (text[i] == ',') {
                var len = tokenDBDW(arg, addr+nbytes, dw, linenumber);
                if (len < 0) {
                    return -1;
                }
                nbytes += len;
                arg = "";
            } else if (text[i] == ';') {
                i = text.length;
                break;
            } else {
                arg += text[i];
            }
            break;
        case 1:
            if (text[i] != cork) {
                arg += text[i]; 
            } else {
                cork = false;
                mode = 0;
                len = tokenString(arg, addr+nbytes, linenumber);
                if (len < 0) {
                    return -1;
                }
                nbytes += len;
                arg = "";
            }
            break; 
        }
    }
    if (mode == 1) return -1;    // unterminated string
    var len = tokenDBDW(arg, addr+nbytes, dw, linenumber);
    if (len < 0) return -1;
    nbytes += len;

    return nbytes;
}

function getExpr(arr) {
    var ex = arr.join(' ').trim();
    if (ex[0] == '"' || ex[0] == "'") {
        return ex;
    }
    return ex.split(';')[0];
}

function useExpr(s, addr, linenumber) {
    var expr = getExpr(s);
    if (expr == undefined || expr.trim().length == 0) return false;

    var immediate = markLabel(expr, addr);
    referencesLabel(expr, linenumber);
    return immediate;
}

function parseInstruction(s, addr, linenumber) {
    var parts = s.split(/\s+/);
		
	for (var i = 0; i < parts.length; i++) {
		if (parts[i][0] == ';') {
			parts.length = i;
			break;
		}
	}
    
    var labelTag;
    var immediate;

	for (;parts.length > 0;) {
		var opcs;
	    var mnemonic = parts[0].toLowerCase();

        if (mnemonic.length == 0) {
            parts = parts.slice(1);
            continue;
        }

		// no operands
		if ((opcs = ops0[mnemonic]) != undefined) {
			mem[addr] = new Number("0x" + opcs);
			return 1;
		}
		
		// immediate word
		if ((opcs = opsIm16[mnemonic]) != undefined) {
			mem[addr] = new Number("0x" + opcs);

            immediate = useExpr(parts.slice(1), addr, linenumber);
            //if (!immediate) return -3;

			setmem16(addr+1, immediate);
			return 3;
		}
		
		// register pair <- immediate
		if ((opcs = opsRpIm16[mnemonic]) != undefined) {
			subparts = parts.slice(1).join(" ").split(",");
			if (subparts.length < 2) return -3;
			rp = parseRegisterPair(subparts[0]);
			if (rp == -1) return -3;

			mem[addr] = (new Number("0x" + opcs)) | (rp << 4);

            immediate = useExpr(subparts.slice(1), addr, linenumber);

			setmem16(addr+1, immediate);
			return 3;
		}

		// immediate byte		
		if ((opcs = opsIm8[mnemonic]) != undefined) {
			mem[addr] = new Number("0x" + opcs);
            immediate = useExpr(parts.slice(1), addr, linenumber);
            //if (!immediate) return -2;
            setmem8(addr+1, immediate);
            return 2;
		}

		// single register, im8
		if ((opcs = opsRegIm8[mnemonic]) != undefined) {
			subparts = parts.slice(1).join(" ").split(",");
			if (subparts.length < 2) return -2;
			reg = parseRegister(subparts[0]);
			if (reg == -1) return -2;

			mem[addr] = new Number("0x" + opcs) | reg << 3;

            immediate = useExpr(subparts.slice(1), addr, linenumber);

            setmem8(addr+1, immediate);
			return 2;			
		}
				
		// dual register (mov)
		if ((opcs = opsRegReg[mnemonic]) != undefined) {
			subparts = parts.slice(1).join(" ").split(",");
			if (subparts.length < 2) return -1;
			reg1 = parseRegister(subparts[0].trim());
			reg2 = parseRegister(subparts[1].trim());
			if (reg1 == -1 || reg2 == -1) return -1;
			mem[addr] = new Number("0x" + opcs) | reg1 << 3 | reg2;
			return 1;
		}

		// single register
		if ((opcs = opsReg[mnemonic]) != undefined) {
			reg = parseRegister(parts[1]);
			if (reg == -1) return -1;
			
			if (opsRegDst.indexOf(mnemonic) != -1) {
				reg <<= 3;
			}
			
			mem[addr] = new Number("0x" + opcs) | reg;
			return 1;
		}
		
		// single register pair
		if ((opcs = opsRp[mnemonic]) != undefined) {
			rp = parseRegisterPair(parts[1]);
			if (rp == -1) return -1;
			mem[addr] = new Number("0x" + opcs) | rp << 4;
			return 1;
		}		
		
		// rst
		if (mnemonic == "rst") {
			n = resolveNumber(parts[1]);
			if (n >= 0 && n < 8) {
				mem[addr] = 0xC7 | n << 3;
				return 1;
			}
			return -1;
		}
		
		if (mnemonic == ".org" || mnemonic == "org") {
			n = resolveNumber(parts[1]);
			if (n >= 0) {
				return -100000-n;
			}
			return -1;
		}

        if (mnemonic == ".binfile") {
            if (parts[1] != undefined && parts[1].trim().length > 0) {
                binFileName = parts[1];
            }
            return -100000;
        }

        if (mnemonic == ".hexfile") {
            if (parts[1] != undefined && parts[1].trim().length > 0) {
                hexFileName = parts[1];
            }
            return -100000;
        }

        if (mnemonic == ".objcopy") {
           objCopy = parts.slice(1).join(' '); 
           return -100000;
        }

        if (mnemonic == ".postbuild") {
            postbuild = parts.slice(1).join(' ');
            return -100000;
        }

        if (mnemonic == ".nodump") {
            doHexDump = false;
            return -100000;
        }

        // assign immediate value to label
        if (mnemonic == ".equ" || mnemonic == "equ") {
            if (labelTag == undefined) return -1;
            var value = evaluateExpression(parts.slice(1).join(' '), addr);
            markLabel(labelTag, value, linenumber, true);
            return 0;
        }

        if (mnemonic == 'cpu' ||
            mnemonic == 'aseg' ||
            mnemonic == '.aseg') return 0;

        if (mnemonic == 'db' || mnemonic == '.db' || mnemonic == 'str') {
            return parseDeclDB(parts, addr, linenumber, 1);
        }
        if (mnemonic == 'dw' || mnemonic == '.dw') {
            return parseDeclDB(parts, addr, linenumber, 2);
        }
        if (mnemonic == 'ds' || mnemonic == '.ds') {
            var size = evaluateExpression(parts.slice(1).join(' '), addr);
            if (size >= 0) {
                for (var i = 0; i < size; i++) {
                    setmem8(addr+i, 0);
                }
                return size;
            }
            return -1;
        }
		
		if (parts[0][0] == ";") {
			return 0;
		}

        // nothing else works, it must be a label
        if (labelTag == undefined) {
            var splat = mnemonic.split(':');
            labelTag = splat[0];
            markLabel(labelTag, addr, linenumber);

            parts.splice(0, 1, splat.slice(1).join(':'));
            continue;
        }
		
        mem[addr] = -2;
		return -1; // error
	}
	
	return 0; // empty
}


// -- output --

function labelList() {
    labelList.s = "            ";
    labelList.f = function(label, addr) {
        var result = label.substring(0, labelList.s.length);
        if (result.length < labelList.s.length) {
            result += labelList.s.substring(result.length);
        }
        result += addr < 0 ? "????" : hex16(addr);
        return result;
    }

    var sorted = [];
    for (var i in labels) {
        sorted[sorted.length] = i;
    }
    sorted.sort();

    var result = "<pre>Labels:</pre>";
    result += '<div class="hordiv"></div>';
    result += '<pre>';
    var col = 1;
    for (var j = 0; j < sorted.length; j++) {
        var i = sorted[j];
        var label = labels[i];

        // hmm? 
        if (label == undefined) continue;
        if (i.length == 0) continue; // resolved expressions
        result += "<span class='" +
            (col%4 == 0 ? 't2' : 't1') +  
            "' onclick=\"return gotoLabel('"+i+"');\"";
        if (label < 0) result += ' style="background-color:pink;" ';
        result += ">";
        result += labelList.f(i,label);
        result += "</span>";
        if (col % 4 == 0) result += "<br/>";
        col++;
    }
    result += "</pre>";
    
    return result;
}

function dumpspan(org, mode) {
    var result = "";
    var nonempty = false;
    conv = mode ? char8 : hex8;
    for (var i = org; i < org+16; i++) {
        if (mem[i] != undefined) nonempty = true;
        if (mode == 1) {
            result += conv(mem[i]);
        } else {
            result += (i > org && i%8 == 0) ? "-" : " ";
            if (mem[i] == undefined) {
                result += '  ';
            }
            else if (mem[i] < 0) {
                result += '<span class="errorline">' + conv(mem[i]) + '</span>';
            } else {
                result += conv(mem[i]);
            }
        }
    }

    return nonempty ? result : false;
}

function dump() {
	var org;
	for (org = 0; org < mem.length && mem[org] == undefined; org++);
	
	if (org % 16 != 0) org = org - org % 16;
	
    var result = "<pre>Memory dump:</pre>";
    result += '<div class="hordiv"></div>';
    var lastempty;

    var printline = 0;

    for (i = org; i < mem.length; i += 16) {
        span = dumpspan(i, 0);
        if (span || !lastempty) {
		    result += '<pre ' + 'class="d' + (printline++%2) + '"';
            result += ">";
        }
        if (span) {
            result += hex16(i) + ": ";
            result += span;
            result += '  ';
            result += dumpspan(i, 1);
            result += "</pre><br/>";
            lastempty = false;
        } 
        if (!span && !lastempty) {
            result += " </pre><br/>";
            lastempty = true;
        }
    }

    return result;
}

function intelHex() {
    var i, j;
    var line = "";
    var r = "";
    var pureHex = "";
    r += "<pre>Intel HEX:</pre>";
    r += '<div class="hordiv"></div>';

    r += "<pre>";
    r += 'cat &gt;' + hexFileName + ' &lt;&lt;X<br/>';
    //r += 'ed<br>i<br>';
    for (i = 0; i < mem.length;) {
        for (j = i; j < mem.length && mem[j] == undefined; j++);
        i = j;
        if (i >= mem.length) break; 

        line = ":";

        cs = 0;

        rec = "";
        for (j = 0; j < 32 && mem[i+j] != undefined; j++) {
           if (mem[i+j] < 0) mem[i+j] = 0;
           rec += hex8(mem[i+j]); 
           cs += mem[i+j];
        }

        cs += j; line += hex8(j);   // byte count
        cs += (i>>8)&255; cs+=i&255; line += hex16(i);  // record address
        cs += 0; line += "00";      // record type 0, data
        line += rec;

        cs = 0xff&(-(cs&255));
        line += hex8(cs);
        pureHex += line + '|n';
        r += line + '<br/>';

        i += j;
    }
    r += ':00000001FF<br/>';
    pureHex += ':00000001FF\n';
    //r += '.<br>w ' + hexFileName +'<br>q<br>';
    r += 'X<br/>';
    r += objCopy + ' -I ihex ' + hexFileName + ' -O binary ' + 
        binFileName + '<br/>';
    if (postbuild.length > 0) {
        r += postbuild + '<br/>';
    }
    r += '</pre>';

    var formData = document.getElementById('hex');
    formData.value = pureHex;
    var formBinName = document.getElementById('formbinname');
    formBinName.value = binFileName;

    return r;
}

function getListHeight() {
    var listElement = document.getElementById('list');
    return inTheOpera ? 
        listElement.style.pixelHeight : listElement.offsetHeight;

}

function gotoLabel(label) {
    var sought = textlabels.indexOf(label.toLowerCase());
    var element = document.getElementById("label" + sought);
    if (element != undefined) {
        startHighlighting(sought, element);
        element = element.parentNode;
        var destination = element.offsetTop - getListHeight()/2;
        scrollTo(destination, true);
    }
    return false;
}

function getReferencedLabel(lineno) {
    var refto = references[lineno];
    if (refto != undefined) {
        var sought = textlabels.indexOf(refto.toLowerCase());
        return document.getElementById("label" + sought);
    }
    return undefined;
}

function getReferencingLines(lineno) {
    var refs = new Array();
    var fullrefs = new Array();
    var label = textlabels[lineno];
    if (label != undefined) {
        for(var i = 0; i < references.length; i++) {
            if (references[i] == label) {
                var element = document.getElementById("code" + i);
                refs[refs.length] = element;
                element = document.getElementById("l" + i);
                fullrefs[fullrefs.length] = element;
            }
        }
    }
    referencingLinesFull = fullrefs;
    return refs;
}

function getLabel(l) {
    return labels[l.toLowerCase()];
}

function listing(text,lengths,addresses) {
    var result = "";
    var addr = 0;
    for(var i = 0; i < text.length; i++) {
        var labeltext = "";
        var remainder = text[i];
        var parts = text[i].split(/[\:\s]/);
        if (parts.length > 1) {
            if (getLabel(parts[0]) != -1) {
                labeltext = parts[0];
                remainder = text[i].substring(labeltext.length);
            }
        }

        var id = "l" + i;
        var labelid = "label" + i;
        var remid = "code" + i;

        var hexes = "";
        var unresolved = false;
        var width = 0;

        var len = lengths[i] > 4 ? 4 : lengths[i];
        for (var b = 0; b < len; b++) {
            hexes += hex8(mem[addresses[i]+b]) + ' ';
            width += 3;
            if (mem[addresses[i]+b] < 0) unresolved = true;
        }
        for (b = 0; b < 16 - width; b++) { hexes += ' '; }

        result += '<pre id="' + id + '"' 
        //    +
        //    ' onmouseover="return mouseover('+i+');"' + 
        //    ' onmouseout="return mouseout('+i+');"';

        if (unresolved || errors[i] != undefined) {
            result += ' class="errorline" ';
        }

        result += 
            '>' + (lengths[i] > 0 ? hex16(addresses[i]) : "");
        result += '\t';

        result += hexes;

        if (labeltext.length > 0) {
            var t = '<span class="l" id="' + labelid + '"' +
            ' onmouseover="return mouseovel('+i+');"' + 
            ' onmouseout="return mouseout('+i+');"' +
            '>' + labeltext + '</span>';
            result += t;
        }
        for (b = 0; b < remainder.length && isWhitespace(remainder[b]); b++) {
            result += ' ';
        }
        remainder = remainder.substring(b);
        if (remainder.length > 0) {
            result += '<span id="' + remid + '"' +
            ' onmouseover="return mouseover('+i+');"' + 
            ' onmouseout="return mouseout('+i+');"' +
            '>' + remainder + '</span>';
        }

        // hacked this into displaying only first and last lines
        // of db thingies
        if (len < lengths[i]) {
            result += '<br/>\t.&nbsp;.&nbsp;.&nbsp;<br/>';
            for (var subline = 1; subline*4 < lengths[i]; subline++) {
                var subresult = '';
                subresult += hex16(addresses[i]+subline*4) + '\t';
                for (var sofs = 0; sofs < 4; sofs++) {
                    var adr = subline*4+sofs;
                    if (adr < lengths[i]) {
                        subresult += hex8(mem[addresses[i]+adr]) + ' ';
                    }
                }
                //result += "<br/>";
            }
            result += subresult + "<br/>";
        }
        result += '</pre>';

        addr += lengths[i];
    }

    result += labelList();

    result += "<div>&nbsp;</div>";
    
    if (doHexDump) {
        result += dump();
    }

    result += "<div>&nbsp;</div>";

    result += intelHex();

    result += "<div>&nbsp;</div>";

    return result;
}

function error(line, text) {
    errors[line] = text;
}

// last known source to compare against
var last_src = false;

// assembler main entry point
function assemble() {
    var src = document.getElementById('source').value;

    if (last_src == src) {
        return;
    } 

    var list = document.getElementById('list');
    var savedScroll = list.scrollTop;
    var lengths = Array();
    var addresses = Array();

    var inputlines = src.split('\n');
    
    var addr = 0;
    clearLabels();
    resolveTable.length = 0;
    mem.length = 0;
    list.innerHTML = '';
    backrefWindow = false;
    references.length = 0;
    textlabels.length = 0;
    errors.length = 0;
    doHexDump = true;
    postbuild = '';
    objCopy = 'gobjcopy';
    
    for (var line = 0; line < inputlines.length; line++) {
		var size = parseInstruction(inputlines[line].trim(), addr, line);
		if (size <= -100000) {
			addr = -size-100000;
			size = 0;
		} else if (size < 0) {
			error(line, "syntax error");
			size = -size;
		}
        lengths[line] = size;
        addresses[line] = addr;
		addr += size;
    }
    
    resolveLabelsTable();
    evaluateLabels();
    resolveLabelsInMem();
    
    list.innerHTML += listing(inputlines, lengths, addresses);

    list.scrollTop = savedScroll;

    updateSizes();

    last_src = src;

    autotranslate = false;
}

function evaluateExpression(input, addr) {
    var q;
    var originput = input;
    //console.log("input=" + input + " addr=" + addr);
    try {
        input = input.replace(/\$([0-9a-fA-F]+)/, '0x$1');
        input = input.replace(/(^|[^'])\$|\./gi, ' '+addr+' ');
        input = input.replace(/([\d\w]+)\s(shr|shl|and|or|xor)\s([\d\w]+)/gi,'($1 $2 $3)');
        input = input.replace(/\b(shl|shr|xor|or|and|[+\-*\/()])\b/gi,
            function(m) {
                switch (m) {
                case 'and':
                    return '&';
                case 'or':
                    return '|';
                case 'xor':
                    return '^';
                case 'shl':
                    return '<<';
                case 'shr':
                    return '>>';
                default:
                    return m;
                }
            });
        q = input.split(/<<|>>|[+\-*\/()\^\&]/);
    } catch (e) {
        return -1;
    }
    input = input;
    var expr = '';
    for (var ident = 0; ident < q.length; ident++) {
        var qident = q[ident].trim();
        if (-1 != resolveNumber(qident)) continue;
        var addr = labels[qident];//.indexOf(qident);
        if (addr != undefined) {
            //addr = labels[idx+1];
            if (addr >= 0) {
                expr += 'var _' + qident + '=' + addr +';\n';
                var rx = new RegExp('\\b'+qident+'\\b', 'gm');
                input = input.replace(rx, '_' + qident);
            } else {
                expr = false;
                break;
            }
        }
    }
    //console.log('0 input=',  input);
    //console.log('1 expr=', expr);
    expr += input.replace(/[0-9][0-9a-fA-F]*[hbqdHBQD]|'.'/g,
        function(m) {
            return resolveNumber(m);
        });
    //console.log('expr=', expr);
    try {
        return eval(expr.toLowerCase());
    } catch (err) {
        //console.log('expr was:',expr.toLowerCase(), originput);
        //console.log(err);
    }

    return -1;
}

function evaluateLabels() {
    for (var i in labels) {
        var label = labels[i];
        if (label < 0 && resolveTable[-label] == undefined) {
            var result = evaluateExpression(i,-1);
            if (result >= 0) {
                resolveTable[-label] = result;
                labels[i] = undefined;
            }
        } 
    }
}

function resolveLabelsInMem() {
    for (var i = 0; i < mem.length;) {
        var negativeId;
        if ((negativeId = mem[i]) < 0) {
            newvalue = resolveTable[-negativeId];

            if (newvalue != undefined) mem[i] = newvalue & 0xff;
            i++;
            if (mem[i] == negativeId) {
                if (newvalue != undefined) mem[i] = 0xff & (newvalue >> 8);
                i++;
            }
        } else {
            i++;
        }
    }
}
 
function resolveLabelsTable(nid) {   
   for (var i in labels) {
        var label = labels[i];
        if (label < 0) {
            var addr = resolveTable[-label];
            if (addr != undefined) {
                labels[i] = addr;
            }
        }
    }
}

// automatic assembler launcher

var autotranslate = false;

function keypress(e) {
    cock(1500);
}

function cock(timeout) {
    if (autotranslate) {
        clearTimeout(autotranslate);
    }
    autotranslate = setTimeout('assemble()', timeout);
}


function keydown(e) {
    if (e.keyCode == 9) {
        var obj = document.getElementById('source');
        var savedScroll = obj.scrollTop;
        /* Find the Start and End Position */
        var start = obj.selectionStart;
        var end   = obj.selectionEnd;

        /* Remember obj is a textarea or input field */
        obj.value = obj.value.substr(0, start)
               + "\t"
               + obj.value.substr(end, obj.value.length);
        obj.setSelectionRange(start+1,start+1);
        obj.scrollTop = savedScroll;

        return false;
    }
    return true;
}

scrollHistory = [];

function scrollMark(location) {
    scrollHistory[scrollHistory.length] = location;
    if (scrollHistory.length > 32) {
        scrollHistory = scrollHistory.slice(1);
    }
}

// gobak i sosak
function scrollBack() {
    if (scrollHistory.length == 0) return;

    var dest = scrollHistory[scrollHistory.length - 1];
    scrollHistory.length = scrollHistory.length - 1;

    var l = document.getElementById('list');
    l.scrollTop = dest;

    magicToolbar(0);
}

// -- Highlighting and navigation --

var highlightTimeout = false;
var highlightTimeout2 = false;
var highlightLabel = false;
var highlightLineNo = false;
var highlightLines = new Array();
var highlightArrow = false;
var highlightOrigin = false;
var highlightDir = false;
var highlightDelayed = false;

// backreferences window
var backrefTimeout = false;
var backrefWindow = false;
var backrefTop = 0, backrefLeft = 0;
var backrefLabel = "?";

var referencingLinesFull = [];

function startHighlighting(lineno, label) {
    if (highlightTimeout == false) {
         highlightLineNo = lineno;
         highlightOrigin = document.getElementById('code'+lineno);
         highlightTimeout = setTimeout('highlightStage1()', 500);
         if (label != undefined) {
            highlightLabel = label;
         } else {
            highlightLabel = false;
         }
    }
}

function scrollTo(n, dontdelay) {
    if (!dontdelay) {
        highlightDelayed = true;
    }
    var l = document.getElementById('list');
    scrollMark(l.scrollTop);

    l.scrollTop = n;

    if (highlightOrigin) {
        highlightOrigin.removeAttribute('onclick');
        highlightOrigin.style.cursor = null;
    }
    if (highlightArrow) {
        highlightOrigin.removeChild(highlightArrow);
    }
}

function highlightStage1() {
    //highlightLines = getReferencingLines(highlightLineNo);
    if (!highlightLabel) {
        highlightLabel = getReferencedLabel(highlightLineNo);
    }
    if (highlightLabel != undefined) {
        var listElement = document.getElementById('list');
        var scrollTop = listElement.scrollTop;
        var height = getListHeight();

        // highlightLabel would only have relative offsetTop in Opera
        var labelTop = highlightLabel.parentNode.offsetTop;
        var labelHeight = highlightLabel.offsetHeight;

        if (highlightArrow == false && (labelTop-labelHeight) <= scrollTop) {
            highlightArrow = document.createElement('span');
            highlightArrow.innerHTML = '&#x25b2;'; //uarr
            highlightDir = 'uarr';
        } else if (highlightArrow == false && labelTop > scrollTop+height) {
            highlightArrow = document.createElement('span');
            highlightArrow.innerHTML = '&#x25bc;'; //darr
            highlightDir = 'darr';
        }

        if (highlightArrow != false) {
            highlightArrow.className = highlightDir+1;

            highlightOrigin.insertBefore(highlightArrow, highlightOrigin.firstChild);
            highlightArrow.style.display='inline-block';
            highlightArrow.style.marginLeft ='-30px';
            highlightArrow.style.paddingLeft ='15px';
            highlightArrow.style.width = '15px';
            highlightArrow.style.backgroundColor = 'white';

            highlightOrigin.setAttribute('onclick', 
                'scrollTo('+(labelTop-height/2)+'); return false;');
            highlightOrigin.style.cursor = 'pointer';
        }

        highlightLabel.className = 'highlight1';
    } 
    //for (src = 0; src < highlightLines.length; src++) {
    //    highlightLines[src].className = 'srchl1';
    //}
    highlightTimeout = setTimeout('highlightStage2()', 50);
}

function highlightStage2() {
    if (highlightLabel != undefined) {
        highlightLabel.className = 'highlight2';
    }
    //for (src = 0; src < highlightLines.length; src++) {
    //    highlightLines[src].className = 'srchl2';
    //}
    if (highlightArrow != false) {
        highlightArrow.className = highlightDir + 2;
    }
    highlightTimeout = setTimeout('highlightStage3()', 100);
}

function highlightStage3() {
    if (highlightLabel != undefined) {
        highlightLabel.className = 'highlight3';
    }
    //for (src = 0; src < highlightLines.length; src++) {
    //    highlightLines[src].className = 'srchl3';
    //}
    if (highlightArrow != false) {
        highlightArrow.className = highlightDir + 3;
    }
}

function endHighlighting(lineno) {
    if (lineno == -2) {
         highlightTimeout2 = setTimeout('endHighlighting(-1)', 1000);
         highlightStage1();
         return;
    } else if (lineno == -1) {
        highlightDelayed = false;
        highlightTimeout2 = false;
    } else {
        if (highlightDelayed) {
            if (highlightTimeout2 == false) {
                highlightTimeout2 = setTimeout('endHighlighting(-2)', 350);
            }
            return;
        }
    }

    clearTimeout(highlightTimeout);
    highlightTimeout = false;
    if (highlightLabel != undefined) {
        highlightLabel.className = "highlight0";
        highlightLabel = undefined;
    }
    for (src = 0; src < highlightLines.length; src++) {
        highlightLines[src].className = null;//'srchl0';
    }
    highlightLines.length = 0;

    if (highlightArrow != false) {
        if (highlightArrow.parentNode != null) {
            highlightArrow.parentNode.removeChild(highlightArrow);
        }
        highlightArrow = false;
    }
    if (highlightOrigin) {
        highlightOrigin.removeAttribute('onclick');
        highlightOrigin.style.cursor = null;
    }
}

function formatBackrefText(element) {
    formatBackrefText.spaces = "         ";
    var adr = element.innerHTML.substr(0, 4);
    var label = "";
    var text = "";
    for (var i = 0; i < element.childNodes.length; i++) {
        var child = element.childNodes[i];
        if (child.id == undefined) continue;
        if (child.id.indexOf("label") == 0) {
            label = child.innerHTML;
        } else if (child.id.indexOf("code") == 0) {
            text = child.innerHTML;
        }
    }

    if (label.length < formatBackrefText.spaces.length) {
        label += formatBackrefText.spaces.substring(label.length);
    }

    return [adr,label,text].join(' ').replace(/ /g,'&nbsp;');
}

function showBackrefReturn(on) {
    var sosak = document.getElementById('backrefgoback');
    if (sosak != undefined) {
        sosak.style.display= on ? 'block' : 'none';
    }
    return false;
}

function backrefHintLine(n) {
    if (n == -1) {
        if (backrefHintLine.unhint != undefined) {
            backrefHintLine.unhint.className = null;
            backrefHintLine.unhint = undefined;
        }
        return;
    }
    backrefHintLine(-1);
    var line = document.getElementById(n);
    if (line != undefined) {
        backrefHintLine.unhint = line.childNodes[line.childNodes.length-1];
        backrefHintLine.unhint.className = 'srchl3';
    }
}

function startBackrefWindow(lineno) {
    if (lineno != -1) {
        highlightLines = getReferencingLines(lineno);
        highlightOrigin = document.getElementById('code'+lineno);
        backrefLabel = document.getElementById('label'+lineno);
        setTimeout('startBackrefWindow(-1)', 250);
        return;
    }
    if (backrefTimeout == false &&
        highlightLines.length > 0) {
        backrefTimeout = setTimeout('showBackref(0)', 500);
        backrefLeft = backrefLabel.offsetLeft;
        backrefTop = highlightOrigin.offsetTop;
        backrefTop += backrefLabel.offsetHeight;
        list = document.getElementById('list');
        if (!inTheOpera) {
            backrefTop -= document.getElementById('list').scrollTop;
        }
    }
}


function showBackref(n) {
    if (n == 0) {
        endHighlighting(0);
        var list = document.getElementById('list');
        var height = getListHeight();
        backrefTimeout = false;
        // start display
        if (!backrefWindow) {
            backrefWindow = document.createElement('div');
            backrefWindow.id = 'backrefpopup';
            backrefWindow.style.position = 'fixed';
            backrefWindow.setAttribute("onmouseover",
                "clearTimeout(backrefTimeout);backrefTimeout=false;return false;");
            backrefWindow.setAttribute("onmouseout",
                "showBackref(-1);return false;");
            document.getElementById('list').appendChild(backrefWindow);
        }
        backrefWindow.style.left = backrefLeft + 'px';
        backrefWindow.style.top = backrefTop + 'px';
        backrefWindow.style.display = 'block';

        backrefWindow.innerHTML = '';
        for (var src = 0; src < referencingLinesFull.length; src++) {
            var labelTop = referencingLinesFull[src].offsetTop;
            var text = formatBackrefText(referencingLinesFull[src]);
            var scrollTo = labelTop - backrefTop + 15;
                        
            backrefWindow.innerHTML += 
              '<div onclick="scrollTo('+scrollTo+');' +
              'backrefHintLine(\'' + referencingLinesFull[src].id +'\');' +
              'showBackrefReturn(1);' +
              'return false;"' +
              ' class="brmenuitem" ' +
              '>' +
              text + 
              '</div>';
        }
        // append return
        var returnTo = list.scrollTop;
        backrefWindow.innerHTML += 
              '<div id="backrefgoback" onclick="scrollTo(' +returnTo+ ');'+
                            'showBackref(-1);return false;"' +
              ' class="brmenuitem" ' +
              ' style="border-top:1px solid black;font-size:120%;">' +
              '&nbsp;&#x25c0;&nbsp;' + backrefLabel.innerHTML +
              '</div>';
        showBackrefReturn(0);
        backrefWindow.style.opacity = 0;
        showBackref.opacity = 0;
        showBackref(1);
    }

    if (n == 1) {
        if (backrefWindow.style.opacity == 0.9) {
            backrefTimeout = false;
        } else {
            showBackref.opacity += .3;
            backrefWindow.style.opacity = showBackref.opacity;
            setTimeout('showBackref(1);', 50);
        }
    }

    // start hiding
    if (n == -1) {
        clearTimeout(backrefTimeout);
        backrefTimeout = setTimeout('showBackref(-2)', 100);
        backrefHintLine(-1);
    }

    if (n == -2) {
        clearTimeout(backrefTimeout);
        backrefTimeout = false;
        if (backrefWindow != false) {
            backrefWindow.style.display = 'none';
        }
    }

    return false;
}

function mouseover(lineno) {
    startHighlighting(lineno);
    return false;
}

function mouseovel(lineno) {
    startBackrefWindow(lineno);
    return false;
}

function mouseout(lineno) {
    endHighlighting(lineno);
    showBackref(-1);
    return false;
}

function boo() {
    document.write('<h1>Unfortunately&#0133;</h1>');
    document.write('<p>The <b>Pretty i8080 Assembler</b> only works in Internet Browsers.</p>');
    document.write('<p>You\'re using Microsoft Internet Explorer, which was called an "internet browser" by mistake.</p>');
    document.write('<p>Please upgrade and come back with a Firefox, Iceweasel, Konqueror, Safari, Chrome or even Opera.</p>');
    document.write('<p>Or try b2m\'s <a href="http://bashkiria-2m.narod.ru/i8080.html">Good i8080 Assembler.</p>');
}

function loaded() {
    if (navigator.appName == 'Microsoft Internet Explorer' || 
        navigator.appVersion.indexOf('MSIE') != -1) {
        boo();
        return false;
    }

    i18n();

    updateSizes();

    cock(100);
}

function updateSizes() {
    height = window.innerHeight - 95;

    var ti = document.getElementById('source');
    ti.style.height = height + "px";
    var to = document.getElementById('list');
    to.style.height = height + "px";
}

// toolbar
var toolbarOpacity = 0;
var toolbarTimeout = false;

function magicToolbar(n) {
    var tulba = document.getElementById('toolbar');

    if (n == 0) {
        if (scrollHistory.length == 0) {
            // force hiding if no history
            n = 2;
        } else {
            tulba.style.cursor = 'pointer';
            clearTimeout(toolbarTimeout);
            toolbarTimeout = setTimeout('magicToolbar(1);', 100);
        }
    }

    if (n == 1) {
        toolbarOpacity += 0.2;
        tulba.style.opacity = toolbarOpacity;
        if (Math.abs(toolbarOpacity - 1.0) > 0.05) {
            clearTimeout(toolbarTimeout);
            toolbarTimeout = setTimeout('magicToolbar(1);', 50);
        }
    }

    if (n == 2) {
        tulba.style.cursor = 'default';
        if (toolbarOpacity > 0) {
            clearTimeout(toolbarTimeout);
            toolbarTimeout = setTimeout('magicToolbar(3);', 50);
        }
    }

    if (n == 3) {
        toolbarOpacity -= 0.4;
        if (toolbarOpacity < 0) toolbarOpacity = 0;
        tulba.style.opacity = toolbarOpacity;
        if (toolbarOpacity > 0) {
            clearTimeout(toolbarTimeout);
            toolbarTimeout = setTimeout('magicToolbar(3);', 50);
        }
    }
}

// -- i18n --
var languages = 
{
"en":["Pretty i8080 Assembler", "Make Beautiful Code"],
"se":["Fin i8080 assembler", "Översätt den snygga"],
"ru":["Прекрасный ассемблер КР580ВМ80А", "Транслировать прелесть"],
"uk":["Прекрасний асемблер КР580ВМ80А", "Транслювати принаду"],
"es":["Bonito ensamblador de i8080", "Crear código precioso"],
"nl":["Fraaie i8080 Assembler", "Vertaal dit juweel"],
"de":["Schöne i8080 Assembler","Übersetze diese Schatz"],
"fi":["Siev&auml; i8080 assembleri", "Tee kaunista koodia"],
"dk":["Smuk i8080 Assembler","Skriv pæn kode"],
"cz":["Dobrý i8080 Assembler","Kompilaci drahé"],
"tr":["Temiz montajcı kodu i8080","Güzel kodu yapmak"],
"ja":["美しい i8080アセンブラ","美しい コードをしよう"],
"he":["i8080 יופי של שפת סף","לקודד יופי של קידוד"],
// Persian translation by Ali Asadzadeh, thanks Ali!
"fa":["یک اسمبلر جالب برای i8080","کامپایل کردن این کد زیبا"]
};

function i18n() {
    var lang = navigator.language;
    if (lang != undefined) lang = lang.split('-')[0];

    explang = document.URL.split('?')[1];
    if (explang != undefined) lang = explang;

    messages = languages[lang];
    if (messages == undefined) messages = languages["en"];

    var m_header = messages[0];
    var m_button = messages[1];

    var header = document.getElementById('header');
    var baton = document.getElementById('baton');

    header.innerHTML = m_header;
    //baton.innerHTML = m_button;
    baton.value = m_button;

    if (lang == 'he' || lang == 'fa') {
        header.style.textAlign = 'right';
        baton.style.cssFloat = 'right';
        baton.style.clear = 'right';
        document.getElementById('buttbr').style.cssFloat = 'right';
        document.getElementById('ta').style.cssFloat = 'right';
        document.getElementById('list').style.cssFloat = 'left';
    }
}
-->
</script>

<style type="text/css" media="screen">
html { }
body {font-size:small; background-color: white; }
.hordiv { width:80%; text-align: left; border-bottom:2px solid black;}
.code { font-family: monospace; }
pre { margin-top:0ex; margin-bottom:0ex; }
.highlight0 { border:none; background-color: transparent; }
.highlight1 { background-color: wheat; border: 1px dotted red; margin:-1px -1px -1px -1px;}
.highlight2 { background-color: white; border: 2px solid red; margin:-2px -2px -2px -2px;}
.highlight3 { background-color: yellow; border: 1px solid pink; margin:-1px -1px -1px -1px;}

.srchl0 { border:none; background-color: transparent; }
.srchl1 { background-color: wheat; border: 1px dotted red; margin:-1px -1px -1px -1px;}
.srchl2 { background-color: white; border: 2px solid red; margin:-2px -2px -2px -2px;}
.srchl3 { background-color: yellow; border: 1px solid pink; margin:-1px -1px -1px -1px;}

.errorline { background-color: pink; }

.d1 { padding-right:0.5em; background-color: #f0f0f0; display:inline;}
.d0 { padding-right:0.5em; background-color: #e0ffff; display:inline;}

#header {
font-family:Gill Sans, Franklin Gothic Medium, sans-serif;
font-size:150%;
font-weight:bold;
background-color:maroon;
color:white;
padding:5px 5px 2px 5px;
border-bottom: 1px dotted darkgray;
user-select:none;
-moz-user-select: none;
-khtml-user-select: none;
}

#toolbar {
float:right;
font-family:Gill Sans, Franklin Gothic Medium, sans-serif;
font-size:150%;
font-weight:bold;
background:transparent;
color:white;
padding:5px 1em 2px 1em;
opacity:0;
user-select:none;
-moz-user-select: none;
-khtml-user-select: none;
}

#baton { 
cursor:pointer;
font-family:Gill Sans, Franklin Gothic Medium, sans-serif;
border: 1px solid black; display: inline-block;
font-weight:bold; 
font-variant: small-caps;
letter-spacing: 0.4ex;
padding-left:10px;
padding-right:10px;
padding-top:2px;
color: white;
background-color: black;
color: white;
background-color: black;
margin-top:0.65ex;
user-select:none;
-moz-user-select: none;
-khtml-user-select: none;
}

#textinput { 
overflow:hidden;
white-space:nowrap;}

#source {
font-family:monospace; font-size:100%;
margin:0px 0px 0px 0px;
padding:0px 0px 0px 5px;
width:100%;
border: 1px solid black;
border-top: 1px dotted darkgray;
}
#ta { 
display: inline-block; 
float:left;
width:39%;
direction:ltr;
}
#list {
direction:ltr;
float:right;
border: 1px solid black;
border-top: 1px dotted darkgray;
vertical-align:top; width:40em; 
padding-left:1ex;
overflow:scroll;
display:inline-block;
width:60%;
}
.uarr1 {
top:2px;
font-family:monospace; font-size:90%; font-weight:bold; position:relative;
color:#fff0f0;
opacity:0;
}
.uarr2{
top:1px;
font-family:monospace; font-size:90%; font-weight:bold; position:relative;
color:#ffa0a0;
opacity:0.4;
}
.uarr3 {
top:0px;
font-family:monospace; font-size:90%; font-weight:bold; position:relative;
color:#b00000;
opacity:0.8;
}
.darr1 {
font-family:monospace; font-size:90%; font-weight:bold; position:relative;
color:#fff0f0;
opacity:0;
}
.darr2{
font-family:monospace; font-size:90%; font-weight:bold; position:relative;
color:#ffa0a0;
opacity:0.4;
}
.darr3 {
font-family:monospace; font-size:90%; font-weight:bold; position:relative;
top:1px;
color:#b00000;
opacity:0.8;
}

#backrefpopup {
border:2px solid #ffff7d;
background:#ffff7d;
font-size:75%;
font-family:monospace;
opacity:0.9;
max-width:30em;
overflow:hidden;
}

.brmenuitem {
background:transparent;
cursor:pointer;
user-select:none;
-moz-user-select: none;
-khtml-user-select: none;
}
.brmenuitem:hover {
background:maroon;
color:white;
}

span.l {
cursor:default;
}

span.t1 {
padding-right:1em;padding-left:0.4em;
border-right:1px solid lightgray;
cursor:pointer;
}
span.t2 {
padding-right:1em;padding-left:0.4em;
cursor:pointer;
}
span.t1:hover { background:#ffff7d; }
span.t2:hover { background:#ffff7d; }

</style>

</head>
<body id='main' onload="loaded(); return false;" onresize="updateSizes(); return false;">

<div id="toolbar" 
onclick="scrollBack(); return false;"
onmouseover="magicToolbar(0); return false;"
onmouseout="magicToolbar(2); return false;"
>
&#x25c0;
</div>

<div id="header" 
onmouseover="magicToolbar(0); return false;"
onmouseout="magicToolbar(2); return false;"
>
Прекрасный ассемблер КР580ВМ80А
</div>
<div id="textinput">
<div id="list">…</div>
<div id="ta">
<textarea
onkeydown="return keydown(event);" 
onkeypress="keypress(event);return true;" id="source" rows="30">
        ; i8080 assembler code
        .hexfile test.hex
        .binfile test.bin
        .objcopy gobjcopy
        .postbuild echo "Hooray!"
        ;.nodump
bdos    equ 5
intv    equ 38h
        .org 100h
        jmp begin
        db 27
msg:
        db 'Assembled by Pretty i8080 Assembler',0dh,0ah,'$'
yeah:
        db 'Hoorj!',0dh,0ah,'$'
begin:
        lxi d, msg
        mvi c, 9
        call bdos
        call delay
        mvi c, 9
        lxi d, yeah
        call bdos
        ret

delay:
        mvi a, 33
        hlt
        dcr a
        jnz .-2
        ret
</textarea></div>
</div>
<div id="messagepane">
</div>
<br/>
<div id="buttbr" class="hordiv"></div>
<!--div id="baton" onclick="assemble(); return false;">Транслировать прелесть</div-->
<form action="hex2bin.cgi" method="post">
<input type="text" id="hex" name="hex" style="display:none;">
<input type="text" id="formbinname" name="formbinname" style="display:none;">
<input type="submit" id="baton" name="baton" value="Translate">
</form>
<!--div id="debug">idebug</div-->

</body>
</html>