mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-06-08 23:29:42 +00:00
ecs: bin pack temp vars
This commit is contained in:
parent
bc7cd6f1a3
commit
5081307d81
|
@ -22,7 +22,7 @@ export interface Box {
|
||||||
|
|
||||||
export interface PlacedBox extends Box {
|
export interface PlacedBox extends Box {
|
||||||
bin: Bin;
|
bin: Bin;
|
||||||
parent: Box;
|
parents: Box[];
|
||||||
place: BoxPlacement;
|
place: BoxPlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,33 +30,22 @@ function boxesIntersect(a: Box, b: Box) : boolean {
|
||||||
return !(b.left >= a.right || b.right <= a.left || b.top >= a.bottom || b.bottom <= a.top);
|
return !(b.left >= a.right || b.right <= a.left || b.top >= a.bottom || b.bottom <= a.top);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBoxPlacements(b: PlacedBox) {
|
function boxesContain(a: Box, b: Box) : boolean {
|
||||||
let posns : BoxPlacement[];
|
return b.left >= a.left && b.top >= a.top && b.right <= a.right && b.bottom <= a.bottom;
|
||||||
let snugw = b.right - b.left == b.parent.right - b.parent.left;
|
|
||||||
let snugh = b.bottom - b.top == b.parent.bottom - b.parent.top;
|
|
||||||
if (snugw && snugh) {
|
|
||||||
posns = [BoxPlacement.TopLeft];
|
|
||||||
} else if (snugw && !snugh) {
|
|
||||||
posns = [BoxPlacement.TopLeft, BoxPlacement.BottomLeft];
|
|
||||||
} else if (!snugw && snugh) {
|
|
||||||
posns = [BoxPlacement.TopLeft, BoxPlacement.TopRight];
|
|
||||||
} else {
|
|
||||||
posns = [BoxPlacement.TopLeft, BoxPlacement.TopRight,
|
|
||||||
BoxPlacement.BottomLeft, BoxPlacement.BottomRight];
|
|
||||||
}
|
|
||||||
return posns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Bin {
|
export class Bin {
|
||||||
boxes: Box[] = [];
|
boxes: Box[] = [];
|
||||||
free: Box[] = [];
|
free: Box[] = [];
|
||||||
|
extents: Box = {left:0,top:0,right:0,bottom:0};
|
||||||
|
|
||||||
constructor(public readonly binbounds: Box) {
|
constructor(public readonly binbounds: Box) {
|
||||||
this.free.push(binbounds);
|
this.free.push(binbounds);
|
||||||
}
|
}
|
||||||
getBoxes(bounds: Box, limit: number) : Box[] {
|
getBoxes(bounds: Box, limit: number, boxes?: Box[]) : Box[] {
|
||||||
let result = [];
|
let result = [];
|
||||||
for (let box of this.boxes) {
|
if (!boxes) boxes = this.boxes;
|
||||||
|
for (let box of boxes) {
|
||||||
//console.log(bounds, box, boxesIntersect(bounds, box))
|
//console.log(bounds, box, boxesIntersect(bounds, box))
|
||||||
if (boxesIntersect(bounds, box)) {
|
if (boxesIntersect(bounds, box)) {
|
||||||
result.push(box);
|
result.push(box);
|
||||||
|
@ -66,7 +55,7 @@ export class Bin {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
fits(b: Box) {
|
fits(b: Box) {
|
||||||
if (!boxesIntersect(this.binbounds, b)) {
|
if (!boxesContain(this.binbounds, b)) {
|
||||||
if (debug) console.log('out of bounds!', b.left,b.top,b.right,b.bottom);
|
if (debug) console.log('out of bounds!', b.left,b.top,b.right,b.bottom);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -90,6 +79,7 @@ export class Bin {
|
||||||
let score = 1 / (1 + dx + dy);
|
let score = 1 / (1 + dx + dy);
|
||||||
if (score > bestscore) {
|
if (score > bestscore) {
|
||||||
best = f;
|
best = f;
|
||||||
|
if (score == 1) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,56 +98,51 @@ export class Bin {
|
||||||
let score = 1 / (1 + box.left + box.top);
|
let score = 1 / (1 + box.left + box.top);
|
||||||
if (score > bestscore) {
|
if (score > bestscore) {
|
||||||
best = f;
|
best = f;
|
||||||
|
if (score == 1) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
add(b: PlacedBox) {
|
add(b: PlacedBox) {
|
||||||
if (debug) console.log('added', b.left,b.top,b.right,b.bottom);
|
if (debug) console.log('add', b.left,b.top,b.right,b.bottom);
|
||||||
if (!this.fits(b)) {
|
if (!this.fits(b)) {
|
||||||
//console.log('collided with', this.getBoxes(b, 1));
|
//console.log('collided with', this.getBoxes(b, 1));
|
||||||
throw new Error(`bad fit ${b.left} ${b.top} ${b.right} ${b.bottom}`)
|
throw new Error(`bad fit ${b.left} ${b.top} ${b.right} ${b.bottom}`)
|
||||||
}
|
}
|
||||||
// add box to list
|
// add box to list
|
||||||
this.boxes.push(b);
|
this.boxes.push(b);
|
||||||
|
this.extents.right = Math.max(this.extents.right, b.right);
|
||||||
|
this.extents.bottom = Math.max(this.extents.bottom, b.bottom);
|
||||||
// delete bin
|
// delete bin
|
||||||
let i = this.free.indexOf(b.parent);
|
for (let p of b.parents) {
|
||||||
if (i < 0) throw new Error('cannot find parent');
|
let i = this.free.indexOf(p);
|
||||||
if (debug) console.log('removed',b.parent.left,b.parent.top,b.parent.right,b.parent.bottom);
|
if (i < 0) throw new Error('cannot find parent');
|
||||||
this.free.splice(i, 1);
|
if (debug) console.log('removed',p.left,p.top,p.right,p.bottom);
|
||||||
// split into new bins
|
this.free.splice(i, 1);
|
||||||
switch (b.place) {
|
// split into new bins
|
||||||
case BoxPlacement.TopLeft:
|
// make long columns
|
||||||
this.addFree( { top: b.top, left: b.right, bottom: b.bottom, right: b.parent.right } );
|
this.addFree(p.left, p.top, b.left, p.bottom);
|
||||||
this.addFree( { top: b.bottom, left: b.parent.left, bottom: b.parent.bottom, right: b.parent.right } );
|
this.addFree(b.right, p.top, p.right, p.bottom);
|
||||||
break;
|
// make top caps
|
||||||
case BoxPlacement.TopRight:
|
this.addFree(b.left, p.top, b.right, b.top);
|
||||||
this.addFree( { top: b.top, left: b.parent.left, bottom: b.bottom, right: b.left } );
|
this.addFree(b.left, b.bottom, b.right, p.bottom);
|
||||||
this.addFree( { top: b.bottom, left: b.parent.left, bottom: b.parent.bottom, right: b.parent.right } );
|
|
||||||
break;
|
|
||||||
case BoxPlacement.BottomLeft:
|
|
||||||
this.addFree( { top: b.parent.top, left: b.parent.left, bottom: b.top, right: b.parent.right } );
|
|
||||||
this.addFree( { top: b.top, left: b.right, bottom: b.parent.bottom, right: b.parent.right } );
|
|
||||||
break;
|
|
||||||
case BoxPlacement.BottomRight:
|
|
||||||
this.addFree( { top: b.parent.top, left: b.parent.left, bottom: b.top, right: b.parent.right } );
|
|
||||||
this.addFree( { top: b.top, left: b.parent.left, bottom: b.parent.bottom, right: b.left } );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addFree(b: Box) {
|
addFree(left: number, top: number, right: number, bottom: number) {
|
||||||
if (b.bottom > b.top && b.right > b.left) {
|
if (bottom > top && right > left) {
|
||||||
|
let b = { left, top, right, bottom };
|
||||||
if (debug) console.log('free',b.left,b.top,b.right,b.bottom);
|
if (debug) console.log('free',b.left,b.top,b.right,b.bottom);
|
||||||
this.free.push(b);
|
this.free.push(b);
|
||||||
}
|
}
|
||||||
// TODO: merge free boxes
|
// TODO: merge free boxes?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Packer {
|
export class Packer {
|
||||||
bins : Bin[] = [];
|
bins : Bin[] = [];
|
||||||
boxes : BoxConstraints[] = [];
|
boxes : BoxConstraints[] = [];
|
||||||
|
defaultPlacement : BoxPlacement = BoxPlacement.TopLeft; //TODO
|
||||||
|
|
||||||
pack() : boolean {
|
pack() : boolean {
|
||||||
for (let bc of this.boxes) {
|
for (let bc of this.boxes) {
|
||||||
|
@ -170,13 +155,15 @@ export class Packer {
|
||||||
}
|
}
|
||||||
bestPlacement(b: BoxConstraints) : PlacedBox | null {
|
bestPlacement(b: BoxConstraints) : PlacedBox | null {
|
||||||
for (let bin of this.bins) {
|
for (let bin of this.bins) {
|
||||||
let place : BoxPlacement = BoxPlacement.TopLeft; //TODO
|
|
||||||
let parent = bin.bestFit(b);
|
let parent = bin.bestFit(b);
|
||||||
|
let approx = false;
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
parent = bin.anyFit(b);
|
parent = bin.anyFit(b);
|
||||||
|
approx = true;
|
||||||
if (debug) console.log('anyfit',parent?.left,parent?.top);
|
if (debug) console.log('anyfit',parent?.left,parent?.top);
|
||||||
}
|
}
|
||||||
if (parent) {
|
if (parent) {
|
||||||
|
let place = this.defaultPlacement;
|
||||||
let box = {
|
let box = {
|
||||||
left: parent.left,
|
left: parent.left,
|
||||||
top: parent.top,
|
top: parent.top,
|
||||||
|
@ -191,16 +178,21 @@ export class Packer {
|
||||||
box.top = b.top;
|
box.top = b.top;
|
||||||
box.bottom = b.top + b.height;
|
box.bottom = b.top + b.height;
|
||||||
}
|
}
|
||||||
if (debug) console.log('place',box.left,box.top,box.right,box.bottom,parent?.left,parent?.top);
|
|
||||||
/*
|
|
||||||
if (place == BoxPlacement.BottomLeft || place == BoxPlacement.BottomRight) {
|
if (place == BoxPlacement.BottomLeft || place == BoxPlacement.BottomRight) {
|
||||||
box.top = parent.bottom - (box.bottom - box.top);
|
let h = box.bottom - box.top;
|
||||||
|
box.top = parent.bottom - h;
|
||||||
|
box.bottom = parent.bottom;
|
||||||
}
|
}
|
||||||
if (place == BoxPlacement.TopRight || place == BoxPlacement.BottomRight) {
|
if (place == BoxPlacement.TopRight || place == BoxPlacement.BottomRight) {
|
||||||
box.left = parent.right - (box.right - box.left);
|
let w = box.right - box.left;
|
||||||
|
box.left = parent.right - w;
|
||||||
|
box.right = parent.right;
|
||||||
}
|
}
|
||||||
*/
|
if (debug) console.log('place',box.left,box.top,box.right,box.bottom,parent?.left,parent?.top);
|
||||||
return { parent, place, bin, ...box };
|
let parents = [parent];
|
||||||
|
// if approx match, might overlap multiple free boxes
|
||||||
|
if (approx) parents = bin.getBoxes(box, 100, bin.free);
|
||||||
|
return { parents, place, bin, ...box };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (debug) console.log('cannot place!', b.left,b.top,b.width,b.height);
|
if (debug) console.log('cannot place!', b.left,b.top,b.width,b.height);
|
||||||
|
|
|
@ -226,10 +226,10 @@ export class ECSCompiler extends Tokenizer {
|
||||||
// TODO: unused events?
|
// TODO: unused events?
|
||||||
const event = this.expectIdent().str;
|
const event = this.expectIdent().str;
|
||||||
this.expectToken('do');
|
this.expectToken('do');
|
||||||
const all_modifiers = ['cyclecritical','asc','desc']; // TODO
|
|
||||||
const modifiers = this.parseModifiers(all_modifiers);
|
|
||||||
// TODO: include modifiers in error msg
|
// TODO: include modifiers in error msg
|
||||||
const select = this.expectTokens(SELECT_TYPE).str as SelectType; // TODO: type check?
|
const select = this.expectTokens(SELECT_TYPE).str as SelectType; // TODO: type check?
|
||||||
|
const all_modifiers = ['cyclecritical','asc','desc']; // TODO
|
||||||
|
const modifiers = this.parseModifiers(all_modifiers);
|
||||||
let query = undefined;
|
let query = undefined;
|
||||||
let join = undefined;
|
let join = undefined;
|
||||||
if (select == 'once') {
|
if (select == 'once') {
|
||||||
|
|
|
@ -339,6 +339,12 @@ export class Dialect_CA65 {
|
||||||
else return `.byte (${b.symbol} >> ${b.bitofs})` // TODO?
|
else return `.byte (${b.symbol} >> ${b.bitofs})` // TODO?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tempLabel(sys: System) {
|
||||||
|
return `${sys.name}__tmp`;
|
||||||
|
}
|
||||||
|
equate(symbol: string, value: string): string {
|
||||||
|
return `${symbol} = ${value}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: merge with Dialect?
|
// TODO: merge with Dialect?
|
||||||
|
@ -372,6 +378,7 @@ class CodeSegment {
|
||||||
|
|
||||||
class DataSegment {
|
class DataSegment {
|
||||||
symbols: { [sym: string]: number } = {};
|
symbols: { [sym: string]: number } = {};
|
||||||
|
equates: { [sym: string]: string } = {};
|
||||||
ofs2sym = new Map<number, string[]>();
|
ofs2sym = new Map<number, string[]>();
|
||||||
fieldranges: { [cfname: string]: FieldArray } = {};
|
fieldranges: { [cfname: string]: FieldArray } = {};
|
||||||
size: number = 0;
|
size: number = 0;
|
||||||
|
@ -397,6 +404,7 @@ class DataSegment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dump(file: SourceFileExport, dialect: Dialect_CA65) {
|
dump(file: SourceFileExport, dialect: Dialect_CA65) {
|
||||||
|
// TODO: fewer lines
|
||||||
for (let i = 0; i < this.size; i++) {
|
for (let i = 0; i < this.size; i++) {
|
||||||
let syms = this.ofs2sym.get(i);
|
let syms = this.ofs2sym.get(i);
|
||||||
if (syms) {
|
if (syms) {
|
||||||
|
@ -405,6 +413,9 @@ class DataSegment {
|
||||||
}
|
}
|
||||||
file.line(dialect.byte(this.initdata[i]));
|
file.line(dialect.byte(this.initdata[i]));
|
||||||
}
|
}
|
||||||
|
for (let [symbol,value] of Object.entries(this.equates)) {
|
||||||
|
file.line(dialect.equate(symbol, value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: move cfname functions in here too
|
// TODO: move cfname functions in here too
|
||||||
getFieldRange(component: ComponentType, fieldName: string) {
|
getFieldRange(component: ComponentType, fieldName: string) {
|
||||||
|
@ -699,7 +710,6 @@ class ActionEval {
|
||||||
if (tempinc < 0 || tempinc >= this.sys.tempbytes) throw new ECSError(`this system only has ${this.sys.tempbytes} locals`, this.action);
|
if (tempinc < 0 || tempinc >= this.sys.tempbytes) throw new ECSError(`this system only has ${this.sys.tempbytes} locals`, this.action);
|
||||||
this.scope.updateTempLiveness(this.sys);
|
this.scope.updateTempLiveness(this.sys);
|
||||||
return `${this.tmplabel}+${tempinc}`;
|
return `${this.tmplabel}+${tempinc}`;
|
||||||
//return `TEMP+${this.scope.tempOffset}+${tempinc}`;
|
|
||||||
}
|
}
|
||||||
__bss_init(args: string[]) {
|
__bss_init(args: string[]) {
|
||||||
return this.scope.allocateInitData(this.scope.bss);
|
return this.scope.allocateInitData(this.scope.bss);
|
||||||
|
@ -846,9 +856,6 @@ export class EntityScope implements SourceLocated {
|
||||||
code = new CodeSegment();
|
code = new CodeSegment();
|
||||||
componentsInScope = new Set();
|
componentsInScope = new Set();
|
||||||
eventSeq = 0;
|
eventSeq = 0;
|
||||||
tempOffset = 0;
|
|
||||||
tempSize = 0;
|
|
||||||
maxTempBytes = 0;
|
|
||||||
resources = new Set<string>();
|
resources = new Set<string>();
|
||||||
state = new ActionCPUState();
|
state = new ActionCPUState();
|
||||||
isDemo = false;
|
isDemo = false;
|
||||||
|
@ -1088,13 +1095,7 @@ export class EntityScope implements SourceLocated {
|
||||||
//s += `\n; event ${event}\n`;
|
//s += `\n; event ${event}\n`;
|
||||||
systems = systems.filter(s => this.systems.includes(s));
|
systems = systems.filter(s => this.systems.includes(s));
|
||||||
for (let sys of systems) {
|
for (let sys of systems) {
|
||||||
// TODO: does this work if multiple actions?
|
let tmplabel = this.dialect.tempLabel(sys);
|
||||||
// TODO: share storage
|
|
||||||
//if (sys.tempbytes) this.allocateTempBytes(sys.tempbytes);
|
|
||||||
let tmplabel = `${sys.name}_tmp`;
|
|
||||||
if (sys.tempbytes) this.bss.allocateBytes(tmplabel, sys.tempbytes);
|
|
||||||
//this.allocateTempBytes(1);
|
|
||||||
let numActions = 0;
|
|
||||||
for (let action of sys.actions) {
|
for (let action of sys.actions) {
|
||||||
if (action.event == event) {
|
if (action.event == event) {
|
||||||
// TODO: use Tokenizer so error msgs are better
|
// TODO: use Tokenizer so error msgs are better
|
||||||
|
@ -1108,19 +1109,11 @@ export class EntityScope implements SourceLocated {
|
||||||
// TODO: check that this happens once?
|
// TODO: check that this happens once?
|
||||||
codeeval.end();
|
codeeval.end();
|
||||||
this.getActionStats(action).callcount++;
|
this.getActionStats(action).callcount++;
|
||||||
numActions++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: if (sys.tempbytes && numActions) this.allocateTempBytes(-sys.tempbytes);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
allocateTempBytes(n: number) {
|
|
||||||
if (n > 0) this.tempOffset = this.tempSize;
|
|
||||||
this.tempSize += n;
|
|
||||||
this.maxTempBytes = Math.max(this.tempSize, this.maxTempBytes);
|
|
||||||
if (n < 0) this.tempOffset = this.tempSize;
|
|
||||||
}
|
|
||||||
getSystemStats(sys: System) : SystemStats {
|
getSystemStats(sys: System) : SystemStats {
|
||||||
let stats = this.sysstats.get(sys);
|
let stats = this.sysstats.get(sys);
|
||||||
if (!stats) {
|
if (!stats) {
|
||||||
|
@ -1151,10 +1144,11 @@ export class EntityScope implements SourceLocated {
|
||||||
this.resources.add(symbol);
|
this.resources.add(symbol);
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
allocateTempVars() {
|
private allocateTempVars() {
|
||||||
let pack = new Packer();
|
let pack = new Packer();
|
||||||
let maxTempBytes = 128; // TODO
|
let maxTempBytes = 128 - this.bss.size; // TODO: multiple data segs
|
||||||
pack.bins.push(new Bin({ left:0, top:0, bottom: this.eventSeq+1, right: maxTempBytes }));
|
let bssbin = new Bin({ left:0, top:0, bottom: this.eventSeq+1, right: maxTempBytes });
|
||||||
|
pack.bins.push(bssbin);
|
||||||
for (let sys of this.systems) {
|
for (let sys of this.systems) {
|
||||||
let stats = this.getSystemStats(sys);
|
let stats = this.getSystemStats(sys);
|
||||||
if (sys.tempbytes && stats.tempstartseq && stats.tempendseq) {
|
if (sys.tempbytes && stats.tempstartseq && stats.tempendseq) {
|
||||||
|
@ -1170,19 +1164,23 @@ export class EntityScope implements SourceLocated {
|
||||||
}
|
}
|
||||||
if (!pack.pack()) console.log('cannot pack temporary local vars'); // TODO
|
if (!pack.pack()) console.log('cannot pack temporary local vars'); // TODO
|
||||||
console.log('tempvars', pack);
|
console.log('tempvars', pack);
|
||||||
for (let b of pack.boxes) {
|
if (bssbin.extents.right > 0) {
|
||||||
console.log((b as any).sys.name, b.box);
|
this.bss.allocateBytes('TEMP', bssbin.extents.right);
|
||||||
|
for (let b of pack.boxes) {
|
||||||
|
let sys : System = (b as any).sys;
|
||||||
|
console.log(sys.name, b.box?.left);
|
||||||
|
this.bss.equates[this.dialect.tempLabel(sys)] = `TEMP+${b.box?.left}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
analyzeEntities() {
|
private analyzeEntities() {
|
||||||
this.buildSegments();
|
this.buildSegments();
|
||||||
this.allocateSegment(this.bss, false);
|
this.allocateSegment(this.bss, false);
|
||||||
this.allocateSegment(this.rodata, true);
|
this.allocateSegment(this.rodata, true);
|
||||||
this.allocateROData(this.rodata);
|
this.allocateROData(this.rodata);
|
||||||
}
|
}
|
||||||
generateCode() {
|
private generateCode() {
|
||||||
let isMainScope = this.parent == null;
|
let isMainScope = this.parent == null;
|
||||||
this.tempOffset = this.maxTempBytes = 0;
|
|
||||||
let start;
|
let start;
|
||||||
let initsys = this.em.getSystemByName('Init');
|
let initsys = this.em.getSystemByName('Init');
|
||||||
if (isMainScope && initsys) {
|
if (isMainScope && initsys) {
|
||||||
|
@ -1197,7 +1195,6 @@ export class EntityScope implements SourceLocated {
|
||||||
this.code.addCodeFragment(code);
|
this.code.addCodeFragment(code);
|
||||||
}
|
}
|
||||||
//this.showStats();
|
//this.showStats();
|
||||||
this.allocateTempVars();
|
|
||||||
}
|
}
|
||||||
showStats() {
|
showStats() {
|
||||||
for (let sys of this.systems) {
|
for (let sys of this.systems) {
|
||||||
|
@ -1207,16 +1204,10 @@ export class EntityScope implements SourceLocated {
|
||||||
console.log(action.event, this.getActionStats(action));
|
console.log(action.event, this.getActionStats(action));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dump(file: SourceFileExport) {
|
|
||||||
this.analyzeEntities();
|
|
||||||
this.generateCode();
|
|
||||||
this.dumpCodeTo(file);
|
|
||||||
}
|
|
||||||
private dumpCodeTo(file: SourceFileExport) {
|
private dumpCodeTo(file: SourceFileExport) {
|
||||||
let dialect = this.dialect;
|
let dialect = this.dialect;
|
||||||
file.line(dialect.startScope(this.name));
|
file.line(dialect.startScope(this.name));
|
||||||
file.line(dialect.segment(`${this.name}_DATA`, 'bss'));
|
file.line(dialect.segment(`${this.name}_DATA`, 'bss'));
|
||||||
if (this.maxTempBytes) this.bss.allocateBytes('TEMP', this.maxTempBytes);
|
|
||||||
this.bss.dump(file, dialect);
|
this.bss.dump(file, dialect);
|
||||||
file.line(dialect.segment(`${this.name}_RODATA`, 'rodata'));
|
file.line(dialect.segment(`${this.name}_RODATA`, 'rodata'));
|
||||||
this.rodata.dump(file, dialect);
|
this.rodata.dump(file, dialect);
|
||||||
|
@ -1229,6 +1220,12 @@ export class EntityScope implements SourceLocated {
|
||||||
}
|
}
|
||||||
file.line(dialect.endScope(this.name));
|
file.line(dialect.endScope(this.name));
|
||||||
}
|
}
|
||||||
|
dump(file: SourceFileExport) {
|
||||||
|
this.analyzeEntities();
|
||||||
|
this.generateCode();
|
||||||
|
this.allocateTempVars();
|
||||||
|
this.dumpCodeTo(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EntityManager {
|
export class EntityManager {
|
||||||
|
|
|
@ -284,8 +284,6 @@ function testECS() {
|
||||||
|
|
||||||
//console.log(em.archetypesMatching({ include:['xpos','ypos']})[0])
|
//console.log(em.archetypesMatching({ include:['xpos','ypos']})[0])
|
||||||
|
|
||||||
root.analyzeEntities();
|
|
||||||
root.generateCode();
|
|
||||||
let src = new SourceFileExport();
|
let src = new SourceFileExport();
|
||||||
root.dump(src);
|
root.dump(src);
|
||||||
//console.log(src.toString());
|
//console.log(src.toString());
|
||||||
|
@ -372,26 +370,28 @@ describe('Compiler', function() {
|
||||||
let testdir = './test/ecs/';
|
let testdir = './test/ecs/';
|
||||||
let files = readdirSync(testdir).filter(f => f.endsWith('.ecs'));
|
let files = readdirSync(testdir).filter(f => f.endsWith('.ecs'));
|
||||||
files.forEach((ecsfn) => {
|
files.forEach((ecsfn) => {
|
||||||
let goodfn = ecsfn.replace('.ecs','.txt')
|
let asmfn = ecsfn.replace('.ecs','.asm');
|
||||||
let srcpath = testdir + ecsfn;
|
let goodfn = ecsfn.replace('.ecs','.txt');
|
||||||
let destpath = testdir + goodfn;
|
let ecspath = testdir + ecsfn;
|
||||||
|
let goodpath = testdir + goodfn;
|
||||||
let dialect = new Dialect_CA65();
|
let dialect = new Dialect_CA65();
|
||||||
let em = new EntityManager(dialect);
|
let em = new EntityManager(dialect);
|
||||||
em.mainPath = srcpath;
|
em.mainPath = ecspath;
|
||||||
let compiler = new ECSCompiler(em);
|
let compiler = new ECSCompiler(em);
|
||||||
compiler.getImportFile = (path: string) => {
|
compiler.getImportFile = (path: string) => {
|
||||||
return readFileSync(testdir + path, 'utf-8');
|
return readFileSync(testdir + path, 'utf-8');
|
||||||
}
|
}
|
||||||
let code = readFileSync(srcpath, 'utf-8');
|
let code = readFileSync(ecspath, 'utf-8');
|
||||||
compiler.parseFile(code, srcpath);
|
compiler.parseFile(code, ecspath);
|
||||||
let out = new SourceFileExport();
|
let out = new SourceFileExport();
|
||||||
em.exportToFile(out);
|
em.exportToFile(out);
|
||||||
let outtxt = out.toString();
|
let outtxt = out.toString();
|
||||||
let goodtxt = readFileSync(destpath, 'utf-8');
|
let goodtxt = readFileSync(goodpath, 'utf-8');
|
||||||
if (outtxt.trim() != goodtxt.trim()) {
|
if (outtxt.trim() != goodtxt.trim()) {
|
||||||
writeFileSync('/tmp/' + goodfn, outtxt, 'utf-8');
|
let asmpath = '/tmp/' + asmfn;
|
||||||
console.log(spawnSync('/usr/bin/diff', [srcpath, destpath], {encoding:'utf-8'}).stdout);
|
writeFileSync(asmpath, outtxt, 'utf-8');
|
||||||
throw new Error(ecsfn + ' did not match test file');
|
console.log(spawnSync('/usr/bin/diff', [asmpath, goodpath], {encoding:'utf-8'}).stdout);
|
||||||
|
throw new Error(`files different; to fix: cp ${asmpath} ${goodpath}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -418,13 +418,30 @@ describe('Box Packer', function() {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('Should pack temp vars', function() {
|
it('Should pack top-aligned boxes', function() {
|
||||||
|
testPack(
|
||||||
|
[
|
||||||
|
new Bin({ left:0, top:0, right:10, bottom:10 })
|
||||||
|
], [
|
||||||
|
{ width: 5, height: 7, top: 0 },
|
||||||
|
{ width: 5, height: 7, top: 1 },
|
||||||
|
{ width: 5, height: 1 },
|
||||||
|
{ width: 5, height: 1 },
|
||||||
|
{ width: 5, height: 3 },
|
||||||
|
{ width: 5, height: 1 },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('Should pack top-aligned boxes', function() {
|
||||||
testPack(
|
testPack(
|
||||||
[
|
[
|
||||||
new Bin({ left:0, top:0, right:10, bottom:10 })
|
new Bin({ left:0, top:0, right:10, bottom:10 })
|
||||||
], [
|
], [
|
||||||
{ width: 3, height: 7, top: 0 },
|
{ width: 3, height: 7, top: 0 },
|
||||||
{ width: 3, height: 7, top: 1 },
|
{ width: 3, height: 7, top: 1 },
|
||||||
|
{ width: 3, height: 7, top: 2 },
|
||||||
|
{ width: 5, height: 1 },
|
||||||
|
{ width: 3, height: 1 },
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
PFColor_pfcolor_b0:
|
PFColor_pfcolor_b0:
|
||||||
.res 1
|
.res 1
|
||||||
.res 1
|
.res 1
|
||||||
Local_tmp:
|
TEMP:
|
||||||
.res 1
|
.res 1
|
||||||
|
Local__tmp = TEMP+0
|
||||||
.code
|
.code
|
||||||
KernelSection_lines_b0:
|
KernelSection_lines_b0:
|
||||||
.byte 2
|
.byte 2
|
||||||
|
@ -197,7 +198,7 @@ StaticKernel__kernel__7____exit:
|
||||||
|
|
||||||
;;; start action Local joybutton
|
;;; start action Local joybutton
|
||||||
|
|
||||||
inc Local_tmp+0
|
inc Local__tmp+0
|
||||||
inc PFColor_pfcolor_b0
|
inc PFColor_pfcolor_b0
|
||||||
|
|
||||||
;;; end action Local joybutton
|
;;; end action Local joybutton
|
||||||
|
|
Loading…
Reference in New Issue
Block a user