Added assembler check for string outside Data Segment.

This commit is contained in:
Anachronaut
2026-08-17 20:10:33 -04:00
parent 9e3425d34b
commit a842c884e8
7 changed files with 60 additions and 10 deletions
@@ -0,0 +1,19 @@
; A string written into the Program Segment.
;
; This used to assemble. The string contributed no bytes and no message: the second pass
; has a case for putting a string in the Data buffer and none for the Program buffer, so
; it fell through the switch and was gone. A program written this way would branch to a
; label that pointed at whatever followed instead.
;
; It is refused rather than emitted, because a string in Program Memory could not be read
; by the program holding it. No instruction on this machine reads Program Memory; only the
; memory controller can. Anybody writing this meant #Data.
#Program
start:
SETD.0 Greeting
HALT
Greeting:
"this is not where this goes"
+9 -4
View File
@@ -42,7 +42,7 @@
//
// The top kilobyte of Program Memory is reserved for vectors. Both tools have to
// agree on where it begins: the CPU starts execution through it, and the assembler
// has to refuse program text that would run into it.
// has to refuse a Program Segment that would run into it.
//
// Entries are two bytes each, most significant byte first, the same order the branch
// instructions and this file format already use.
@@ -88,9 +88,14 @@
#define VECTOR_FIRST_PINNED 16
#define VECTOR_FIRST_AUTO 64
// The first address the vector table occupies, and so the first address that program
// text may not use.
#define PROGRAM_TEXT_LIMIT SOFTWARE_VECTOR_BASE
// The first address the vector table occupies, and so the first address the Program
// Segment may not reach.
//
// The Segment rather than the code: instructions are most of what goes there, but not all
// of it. Literal bytes go there, a label named in the Program Segment puts its two byte
// address there, and #Align and #Reserve put runs of zeroes there. What the limit measures
// is how far all of that together has pushed the cursor.
#define PROGRAM_SEGMENT_LIMIT SOFTWARE_VECTOR_BASE
#define SPLITBIT_MAGIC "SPBT"
#define SPLITBIT_MAGIC_LENGTH 4
+22 -2
View File
@@ -330,9 +330,29 @@ int loadFile(intermediateElement **intermediateArray, char *fileName, int *inter
printf(" File: %s at line %d.\n", fileName, lineNumber);
exit(1);
}
// A string, which only the Data Segment can hold. Nothing below this line looks at
// strings, so without this they would fall past every check and out the bottom,
// and a string written anywhere else would assemble to nothing at all and say so
// to nobody.
} else if ((*intermediateArray)[*intermediateIndex].type == STRING) {
if (status == PROGRAM) {
fprintf(stderr, RED "Error: A string cannot go in the Program Segment.\n"
" Strings live in Data Memory, which is the only memory an instruction\n"
" can read. A string in Program Memory could not be reached even by the\n"
" program holding it, except through the memory controller.\n" RESET);
printf(" File: %s at line %d.\n", fileName, lineNumber);
printf(" The string: \"%s\"\n", (*intermediateArray)[*intermediateIndex].token);
printf(" Move it below a #Data line.\n");
exit(1);
}
if (status != DATA) {
fprintf(stderr, RED "Error: Attempting to write a string to nowhere!\n Did you forget to use the #Data keyword?\n" RESET);
printf(" File: %s at line %d.\n", fileName, lineNumber);
printf(" The string: \"%s\"\n", (*intermediateArray)[*intermediateIndex].token);
exit(1);
}
// Finally, check if it's a label or label definition.
// First, make sure it hasn't already been marked as a string literal.
} else if ((*intermediateArray)[*intermediateIndex].type != STRING) {
} else {
if (checkIfLabel(&(*intermediateArray)[*intermediateIndex])) {
if (status == NOWHERE) {
fprintf(stderr, RED "Error: Attempting to create or use a label nowhere!\n Did you forget to use the #Program or #Data keyword?\n" RESET);
+3 -3
View File
@@ -96,10 +96,10 @@ void populateLabelTable(intermediateElement *intermediateArray, int arraySize) {
if (debugSecondPass) printf("Token: %s with byte length %d to destination %d of type %d\n", intermediateArray[i].token ,intermediateArray[i].byteLength, intermediateArray[i].destination, intermediateArray[i].type);
}
if (programCount > PROGRAM_TEXT_LIMIT ) {
if (programCount > PROGRAM_SEGMENT_LIMIT ) {
fprintf(stderr, RED "Error: Program is too long to fit in Program Memory.\n"
" Program text may not run past 0x%04X, where the vector table begins.\n" RESET,
PROGRAM_TEXT_LIMIT - 1);
" The Program Segment may not run past 0x%04X, where the vector table begins.\n" RESET,
PROGRAM_SEGMENT_LIMIT - 1);
exit(1);
}
if (dataCount > 0xFFFF ) {
+2
View File
@@ -24,6 +24,8 @@ Any token beginning with a '0' is read as a numerical literal, so a malformed on
A string may be up to 255 characters. Each one is written down with a zero byte on the end, which is what lets a program find where it stops, and it means two strings written one after the other are not one longer string: there is a zero between them. A run of bytes longer than a string can hold has to be written as literals, or put there by the program itself while it runs.
**Strings belong in the Data Segment, and only there.** This is a Harvard machine: no instruction reads Program Memory, so a string put in the Program Segment could not be read by the program carrying it, and only the memory controller could reach it at all. The assembler refuses one rather than emitting bytes nothing can use. Single byte literals are a different matter and may go in either segment — a table of bytes a program branches through is a reasonable thing to want in Program Memory.
The one exception to the single byte rule is #Align and #Reserve, whose numbers are never emitted as bytes and may go up to 0xFFFF. See Moving The Cursor Along.
## Labels:
+1 -1
View File
@@ -50,7 +50,7 @@ The top kilobyte of Program Memory is reserved for vectors. Each entry is two by
| 0xFC00 | Software vectors 0 to 255 |
| 0xFE00 | Hardware vectors 0 to 255, one for each I/O port |
Program text may not run past 0xFBFF. The assembler refuses to assemble a program that would.
The Program Segment may not run past 0xFBFF. The assembler refuses to assemble a program that would.
The software vectors are given out like this:
+4
View File
@@ -277,6 +277,10 @@ diagDuplicateVector | testPrograms/diagnostics/duplicateVector.asm | xfail | -
# The two mistakes that pinning a number makes possible. Numbers the assembler hands out
# cannot collide; numbers a person writes down can, and can also be written outside the
# range set aside for them.
# A string in the Program Segment, which used to assemble to nothing at all and say so to
# nobody. Strings only have a case for the Data buffer, so one aimed anywhere else fell
# through and vanished.
diagStringInProgram | testPrograms/diagnostics/stringInProgram.asm | xfail | - | -
diagPinnedRange | testPrograms/diagnostics/pinnedVectorRange.asm | xfail | - | -
diagPinnedTaken | testPrograms/diagnostics/pinnedVectorTaken.asm | xfail | - | -
diagBareSWI | testPrograms/diagnostics/bareSWI.asm | xfail | - | -