Skip to content

Commit

Permalink
Forbid setting the program counter out of bounds of the current segme…
Browse files Browse the repository at this point in the history
…nt (#60)
  • Loading branch information
nurpax committed Feb 6, 2021
1 parent 9963c26 commit b4c7bf0
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 12 deletions.
15 changes: 9 additions & 6 deletions src/asm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ class Assembler {
private includeStack: string[] = [];

private lineLoc: SourceLoc;
private curSegment: Segment = new Segment(0, 0); // invalid, setup at start of pass
private curSegment: Segment = new Segment(0, 0, false); // invalid, setup at start of pass
private pass = 0;
needPass = false;
private scopes = new Scopes();
Expand Down Expand Up @@ -535,11 +535,11 @@ class Assembler {

// Empty segments list and append default
this.segments = [];
this.curSegment = this.newSegment('default', this.platform.defaultStartPC);
this.curSegment = this.newSegment('default', this.platform.defaultStartPC, undefined, true);
}

newSegment(name: string, startAddr: number, endAddr?: number): Segment {
const segment = new Segment(startAddr, endAddr);
newSegment(name: string, startAddr: number, endAddr: number | undefined, inferStart: boolean): Segment {
const segment = new Segment(startAddr, endAddr, inferStart);
this.segments.push([name, segment]);
return segment;
}
Expand Down Expand Up @@ -1015,7 +1015,10 @@ class Assembler {
if (!this.curSegment.empty() && this.curSegment.currentPC() > v) {
this.addError(`Cannot set program counter to a smaller value than current (current: $${toHex16(this.curSegment.currentPC())}, trying to set $${toHex16(v)})`, valueExpr.loc);
}
this.curSegment.setCurrentPC(v);
const err = this.curSegment.setCurrentPC(v);
if (err !== undefined) {
this.addError(err, valueExpr.loc);
}
}
}

Expand Down Expand Up @@ -1362,7 +1365,7 @@ class Assembler {
if (passErrors) {
return;
}
const segment = this.newSegment(name.name, start.value, end.value);
const segment = this.newSegment(name.name, start.value, end.value, false);
this.scopes.declareSegment(name.name, segment);
return;
}
Expand Down
41 changes: 35 additions & 6 deletions src/segment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,55 @@ type Block = { start: number, binary: number[] };
class Segment {
start: number;
end?: number;
inferStart: boolean; // allow 'start' to be set lazily (so the platform default can be overridden)
initialStart: number;
curBlock: Block;
blocks: Block[];

constructor(start: number, end?: number) {
constructor(start: number, end: number | undefined, inferStart: boolean) {
this.start = start;
this.end = end;
this.inferStart = inferStart;
this.blocks = [{
start: start,
start,
binary: []
}];
this.curBlock = this.blocks[0];
}

// Setting the current PC will start a new "memory block". A segment
// consists of multiple memory blocks.
setCurrentPC(pc: number) {
setCurrentPC(pc: number): string|undefined {
let err = undefined;
// Overriding default segment start for the 'default' segment?
if (this.inferStart && this.blocks.length === 1 && this.blocks[0].binary.length === 0) {
// This case is for the "default" segment where we just detect the
// first:
//
// * = some values
//
// and make that the segment 'start' address.
this.start = pc;
} else {
const endstr = this.end !== undefined ? `$${toHex16(this.end)}` : '';
const range = `Segment address range: $${toHex16(this.start)}-${endstr}`;
if (pc < this.start) {
err = `${range}. Cannot set program counter to a lower address $${toHex16(pc)}.`;
} else {
if (this.end !== undefined && pc > this.end) {
err = `${range}. Trying to set program counter to $${toHex16(pc)} -- it is past segment end ${endstr}.`;
} else {
this.start = pc;
}
}
}
const newBlock = {
start: pc,
binary: []
};
const idx = this.blocks.push(newBlock);
this.curBlock = this.blocks[idx-1];
return err;
}

empty(): boolean {
Expand All @@ -40,8 +67,10 @@ class Segment {
}

emit(byte: number): string|undefined {
if (this.end !== undefined && this.currentPC() > this.end) {
return `Segment overflow at $${toHex16(this.currentPC())}. Segment address range: $${toHex16(this.start)}-$${toHex16(this.end)}`;
if ((this.currentPC() < this.start) || (this.end !== undefined && this.currentPC() > this.end)) {
const endstr = this.end !== undefined ? `$${toHex16(this.end)}` : '';
const startstr = this.start !== undefined ? `$${toHex16(this.start)}` : '';
return `Segment overflow at $${toHex16(this.currentPC())}. Segment address range: ${startstr}-${endstr}`;
}
this.curBlock.binary.push(byte);
return undefined;
Expand All @@ -54,7 +83,7 @@ function compact(segments: [string, Segment][]): [string, Segment][] {
for (const [name,seg] of segments) {
const compactBlocks = seg.blocks.filter(b => b.binary.length !== 0);
if (compactBlocks.length !== 0) {
const newSeg = new Segment(seg.start, seg.end);
const newSeg = new Segment(seg.start, seg.end, seg.inferStart);
newSeg.blocks = compactBlocks;
newSeg.curBlock = compactBlocks[compactBlocks.length-1];
out.push([name, newSeg]);
Expand Down
1 change: 1 addition & 0 deletions test/errors/segment5_overflow.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/errors/segment5_overflow.input.asm:5:5: error: Segment address range: $1000-$1100. Cannot set program counter to a lower address $0900.
8 changes: 8 additions & 0 deletions test/errors/segment5_overflow.input.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

!segment code(start=$1000, end=$1100)

!segment code
* = $900 ; underflows start of segment
* = $1000
lda #0
lda #1
1 change: 1 addition & 0 deletions test/errors/segment6_overflow.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/errors/segment6_overflow.input.asm:5:5: error: Segment address range: $1000-$11ff. Trying to set program counter to $2000 -- it is past segment end $11ff.
8 changes: 8 additions & 0 deletions test/errors/segment6_overflow.input.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

!segment code(start=$1000, end=$11ff)

!segment code
* = $2000 ; can't set PC past the current segment
* = $1050
lda #0
lda #1

0 comments on commit b4c7bf0

Please sign in to comment.