mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-01-13 06:29:57 +00:00
nanoasm: fixed multi-byte fixups
This commit is contained in:
parent
bf12984f26
commit
5109986557
@ -1,8 +1,14 @@
|
||||
|
||||
type Endian = 'big' | 'little';
|
||||
|
||||
type Symbol = {
|
||||
value: number
|
||||
}
|
||||
|
||||
type AssemblerVar = {
|
||||
bits : number,
|
||||
toks : string[],
|
||||
endian? : 'big' | 'little',
|
||||
endian? : Endian,
|
||||
iprel? : boolean,
|
||||
ipofs? : number,
|
||||
ipmul? : number,
|
||||
@ -38,6 +44,7 @@ type AssemblerFixup = {
|
||||
iprel:boolean,
|
||||
ipofs:number,
|
||||
ipmul:number,
|
||||
endian:Endian
|
||||
};
|
||||
|
||||
type AssemblerSpec = {
|
||||
@ -96,7 +103,7 @@ export class Assembler {
|
||||
ip = 0;
|
||||
origin = 0;
|
||||
linenum = 0;
|
||||
symbols : {[name:string] : {value:number}} = {};
|
||||
symbols : {[name:string] : Symbol} = {};
|
||||
errors : AssemblerError[] = [];
|
||||
outwords : number[] = [];
|
||||
asmlines : AssemblerLine[] = [];
|
||||
@ -152,7 +159,7 @@ export class Assembler {
|
||||
|
||||
preprocessRules() {
|
||||
if (this.spec.width) {
|
||||
this.width = this.spec.width|0;
|
||||
this.width = this.spec.width || 8;
|
||||
}
|
||||
for (var rule of this.spec.rules) {
|
||||
this.rule2regex(rule, this.spec.vars);
|
||||
@ -220,23 +227,17 @@ export class Assembler {
|
||||
return parseInt(s);
|
||||
}
|
||||
|
||||
changeEndian(endian: 'big'|'little', x: number, nbits: number) {
|
||||
if (endian == null || endian == 'big') {
|
||||
return x;
|
||||
} else if (endian == 'little') {
|
||||
var y = 0;
|
||||
while (nbits > 0) {
|
||||
var n = Math.min(nbits, this.width);
|
||||
var mask = (1 << n) - 1;
|
||||
y <<= n;
|
||||
y |= (x & mask);
|
||||
x >>>= n;
|
||||
nbits -= n;
|
||||
}
|
||||
return y;
|
||||
} else {
|
||||
this.fatal('Endian must be "big" or "little"');
|
||||
swapEndian(x: number, nbits: number) {
|
||||
var y = 0;
|
||||
while (nbits > 0) {
|
||||
var n = Math.min(nbits, this.width);
|
||||
var mask = (1 << n) - 1;
|
||||
y <<= n;
|
||||
y |= (x & mask);
|
||||
x >>>= n;
|
||||
nbits -= n;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
buildInstruction(rule:AssemblerRule, m:string[]) : AssemblerLineResult {
|
||||
@ -273,12 +274,12 @@ export class Assembler {
|
||||
} else {
|
||||
// otherwise, parse it as a constant
|
||||
x = this.parseConst(id, n);
|
||||
x = this.changeEndian(v.endian, x, v.bits);
|
||||
// is it a label? add fixup
|
||||
if (isNaN(x)) {
|
||||
this.fixups.push({
|
||||
sym:id, ofs:this.ip, size:v.bits, line:this.linenum,
|
||||
dstlen:n, dstofs:oplen, srcofs:shift,
|
||||
endian:v.endian,
|
||||
iprel:!!v.iprel, ipofs:(v.ipofs+0), ipmul:v.ipmul||1
|
||||
});
|
||||
x = 0;
|
||||
@ -288,6 +289,8 @@ export class Assembler {
|
||||
return {error:"Value " + x + " does not fit in " + v.bits + " bits"};
|
||||
}
|
||||
}
|
||||
// if little endian, we need to swap ordering
|
||||
if (v.endian == 'little') x = this.swapEndian(x, v.bits);
|
||||
// is it an array slice? slice the bits
|
||||
if (typeof b !== "number") {
|
||||
x = (x >>> shift) & ((1 << b.n)-1);
|
||||
@ -381,35 +384,49 @@ export class Assembler {
|
||||
this.warning(lastError ? lastError : ("Could not decode instruction: " + line));
|
||||
}
|
||||
|
||||
applyFixup(fix: AssemblerFixup, sym: Symbol) {
|
||||
var ofs = fix.ofs + Math.floor(fix.dstofs/this.width);
|
||||
var mask = ((1<<fix.size)-1);
|
||||
var value = this.parseConst(sym.value+"", fix.dstlen);
|
||||
if (fix.iprel)
|
||||
value = (value - fix.ofs) * fix.ipmul - fix.ipofs;
|
||||
if (fix.srcofs == 0 && (value > mask || value < -mask))
|
||||
this.warning("Symbol " + fix.sym + " (" + value + ") does not fit in " + fix.dstlen + " bits", fix.line);
|
||||
//console.log(hex(value,8), fix.srcofs, fix.dstofs, fix.dstlen);
|
||||
if (fix.srcofs > 0)
|
||||
value >>>= fix.srcofs;
|
||||
value &= (1 << fix.dstlen) - 1;
|
||||
// TODO: make it work for all widths
|
||||
if (this.width == 32) {
|
||||
var shift = 32 - fix.dstofs - fix.dstlen;
|
||||
value <<= shift;
|
||||
}
|
||||
// TODO: check range
|
||||
if (fix.size <= this.width) {
|
||||
this.outwords[ofs - this.origin] ^= value;
|
||||
} else {
|
||||
// swap if we want big endian (we'll apply in LSB first order)
|
||||
if (fix.endian == 'big') value = this.swapEndian(value, fix.size);
|
||||
// apply multi-byte fixup
|
||||
while (value) {
|
||||
if (value & this.outwords[ofs - this.origin]) {
|
||||
this.warning("Instruction bits overlapped: " + hex(this.outwords[ofs - this.origin],8), hex(value,8));
|
||||
} else {
|
||||
this.outwords[ofs - this.origin] ^= value & ((1<<this.width)-1);
|
||||
}
|
||||
value >>>= this.width;
|
||||
ofs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finish() : AssemblerState {
|
||||
// apply fixups
|
||||
for (var i=0; i<this.fixups.length; i++) {
|
||||
var fix = this.fixups[i];
|
||||
var sym = this.symbols[fix.sym];
|
||||
if (sym) {
|
||||
var ofs = fix.ofs + Math.floor(fix.dstofs/this.width);
|
||||
var mask = ((1<<fix.size)-1);
|
||||
var value = this.parseConst(sym.value+"", fix.dstlen);
|
||||
if (fix.iprel)
|
||||
value = (value - fix.ofs) * fix.ipmul - fix.ipofs;
|
||||
if (fix.srcofs == 0 && (value > mask || value < -mask))
|
||||
this.warning("Symbol " + fix.sym + " (" + value + ") does not fit in " + fix.dstlen + " bits", fix.line);
|
||||
//console.log(hex(value,8), fix.srcofs, fix.dstofs, fix.dstlen);
|
||||
if (fix.srcofs > 0)
|
||||
value >>>= fix.srcofs;
|
||||
value &= (1 << fix.dstlen) - 1;
|
||||
// TODO: make it work for all widths
|
||||
if (this.width == 32) {
|
||||
var shift = 32 - fix.dstofs - fix.dstlen;
|
||||
value <<= shift;
|
||||
//console.log(fix, shift, fix.dstlen, hex(value,8));
|
||||
}
|
||||
// TODO: check range
|
||||
// TODO: span multiple words?
|
||||
if (value & this.outwords[ofs - this.origin]) {
|
||||
//this.warning("Instruction bits overlapped: " + hex(this.outwords[ofs - this.origin],8), hex(value,8));
|
||||
}
|
||||
this.outwords[ofs - this.origin] ^= value; // TODO: << shift?
|
||||
this.applyFixup(fix, sym);
|
||||
} else {
|
||||
this.warning("Symbol '" + fix.sym + "' not found");
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ WaitVsync:
|
||||
//assert.equal(result, {});
|
||||
assert.equal(128, result.origin);
|
||||
assert.equal(152, result.ip);
|
||||
console.log(result);
|
||||
assert.deepEqual([], result.errors);
|
||||
assert.deepEqual({
|
||||
insns: "0B",
|
||||
line: 13,
|
||||
@ -215,7 +215,6 @@ WaitVsync:
|
||||
`;
|
||||
let asm = new assembler.Assembler(EXAMPLE_SPEC);
|
||||
let result = asm.assembleFile(source);
|
||||
console.log(result);
|
||||
assert.deepEqual(
|
||||
[ { msg: "Can't use 'c' here, only one of: a, b, ip, none", line: 2 } ],
|
||||
result.errors);
|
||||
@ -246,6 +245,7 @@ WaitVsync:
|
||||
`;
|
||||
let asm = new assembler.Assembler(femto16_spec);
|
||||
let result = asm.assembleFile(source);
|
||||
assert.deepEqual([], result.errors);
|
||||
assert.deepEqual(result.lines, [
|
||||
{ line: 5, offset: 32768, nbits: 32, insns: '1E58 6FFF' },
|
||||
{ line: 6, offset: 32770, nbits: 32, insns: '1B58 8006' },
|
||||
@ -289,6 +289,7 @@ WaitVsync:
|
||||
`;
|
||||
let asm = new assembler.Assembler(riscv_spec);
|
||||
let result = asm.assembleFile(source);
|
||||
assert.deepEqual([], result.errors);
|
||||
assert.deepEqual(result.lines, [
|
||||
{ line: 7, offset: 0, nbits: 32, insns: '002100B3' },
|
||||
{ line: 8, offset: 1, nbits: 32, insns: '402001B3' },
|
||||
@ -304,7 +305,7 @@ WaitVsync:
|
||||
]);
|
||||
});
|
||||
|
||||
it('Should assemble 16-bit constants', function() {
|
||||
it('Should assemble multiword little endian constants', function() {
|
||||
let source = `
|
||||
.arch Beaker8
|
||||
.org 0
|
||||
@ -326,10 +327,10 @@ init: call setTextMode
|
||||
setTextMode:
|
||||
send vdpReg0, $14
|
||||
const.w $2000 ;// length
|
||||
const.w.0 ;// address
|
||||
const.w.0 ;// address
|
||||
const.w init ;// symbol
|
||||
call clrVram
|
||||
ret
|
||||
|
||||
clrVram:
|
||||
send vdpReg1
|
||||
send vdpReg2
|
||||
@ -342,23 +343,24 @@ _loop:
|
||||
`;
|
||||
let asm = new assembler.Assembler(BEAKER8_SPEC);
|
||||
let result = asm.assembleFile(source);
|
||||
console.log(result.lines);
|
||||
assert.deepEqual([], result.errors);
|
||||
assert.deepEqual(result.lines, [
|
||||
{ line: 13, offset: 0, nbits: 8, insns: 'E4' },
|
||||
{ line: 14, offset: 1, nbits: 24, insns: 'E9 00 00' },
|
||||
{ line: 16, offset: 4, nbits: 24, insns: 'EB 00 00' },
|
||||
{ line: 14, offset: 1, nbits: 24, insns: 'E9 04 00' },
|
||||
{ line: 16, offset: 4, nbits: 24, insns: 'EB 08 00' },
|
||||
{ line: 17, offset: 7, nbits: 8, insns: 'E1' },
|
||||
{ line: 20, offset: 8, nbits: 32, insns: '06 40 29 40' },
|
||||
{ line: 21, offset: 12, nbits: 24, insns: '0E 00 20' },
|
||||
{ line: 22, offset: 15, nbits: 8, insns: '08' },
|
||||
{ line: 23, offset: 16, nbits: 24, insns: 'EB 00 00' },
|
||||
{ line: 24, offset: 19, nbits: 8, insns: 'F8' },
|
||||
{ line: 27, offset: 20, nbits: 16, insns: '29 41' },
|
||||
{ line: 28, offset: 22, nbits: 16, insns: '29 42' },
|
||||
{ line: 31, offset: 24, nbits: 8, insns: '00' },
|
||||
{ line: 32, offset: 25, nbits: 16, insns: '29 00' },
|
||||
{ line: 33, offset: 27, nbits: 8, insns: 'EF' },
|
||||
{ line: 34, offset: 28, nbits: 8, insns: 'F8' }
|
||||
{ line: 23, offset: 16, nbits: 24, insns: '0E 04 00' },
|
||||
{ line: 24, offset: 19, nbits: 24, insns: 'EB 17 00' },
|
||||
{ line: 25, offset: 22, nbits: 8, insns: 'F8' },
|
||||
{ line: 27, offset: 23, nbits: 16, insns: '29 41' },
|
||||
{ line: 28, offset: 25, nbits: 16, insns: '29 42' },
|
||||
{ line: 31, offset: 27, nbits: 8, insns: '00' },
|
||||
{ line: 32, offset: 28, nbits: 16, insns: '29 00' },
|
||||
{ line: 33, offset: 30, nbits: 8, insns: 'EF' },
|
||||
{ line: 34, offset: 31, nbits: 8, insns: 'F8' }
|
||||
]);
|
||||
})
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user