Say "boot image" where that is what is meant
"Binary" was doing three jobs. It meant an SPBT file that the machine starts from; it meant whatever the assembler happened to produce, which is now either that or a loadable program; and it meant a compiled host tool. A word that means three things means none of them, and the first of the three has a name already - this project has been calling them boot images for a while and the manuals had not caught up. Where it means an SPBT file -> boot image Where it means either output -> output Where it means a host executable -> left alone Where it means base two -> left alone The user facing messages move with it: Error: No boot image specified. Usage: ./SplitBit [OPTIONS] <boot image> Error: This is not a SplitBit boot image. Error: This boot image is in format version 2, and this emulator reads 1. Successfully wrote SplitBit boot image to "hello.bin". The assembler's own help was the interesting case. Its -o writes either format, so "the binary" there was never right - it is "the output" now, and the message that names the format is the one that says which it wrote. No recorded output contained the word, so nothing needed re-blessing. Checked before starting rather than after. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
306b4dce92
commit
b6004bdcde
@@ -6,7 +6,8 @@
|
|||||||
; Loading and running are separate commands in this shell, so the file to assemble is the
|
; Loading and running are separate commands in this shell, so the file to assemble is the
|
||||||
; argument to run rather than a second name after the program's.
|
; argument to run rather than a second name after the program's.
|
||||||
;
|
;
|
||||||
; Reads assembly source off the disk and writes a binary back to it, with no host involved
|
; Reads assembly source off the disk and writes a boot image or a loadable program back to it,
|
||||||
|
; with no host involved
|
||||||
; anywhere. The output has to be byte for byte what the C assembler produces from the same
|
; anywhere. The output has to be byte for byte what the C assembler produces from the same
|
||||||
; source, which is the only honest test of it and the one the suite runs.
|
; source, which is the only honest test of it and the one the suite runs.
|
||||||
;
|
;
|
||||||
@@ -2046,7 +2047,7 @@ ImgHold:
|
|||||||
DropWalk:
|
DropWalk:
|
||||||
0x00 0x00
|
0x00 0x00
|
||||||
|
|
||||||
; How big a binary this can build. Everything the assembler makes has to fit here at once,
|
; How big an output file this can build. Everything the assembler makes has to fit here at once,
|
||||||
; because a file is written in one call and there is nowhere to put half of one. CosmOS
|
; because a file is written in one call and there is nowhere to put half of one. CosmOS
|
||||||
; itself comes to 9,564 bytes.
|
; itself comes to 9,564 bytes.
|
||||||
ImgRoom:
|
ImgRoom:
|
||||||
@@ -2152,7 +2153,7 @@ BasesText:
|
|||||||
at zero, on top of whatever is there. Give both a #Base, or neither.
|
at zero, on top of whatever is there. Give both a #Base, or neither.
|
||||||
"
|
"
|
||||||
TooBigText:
|
TooBigText:
|
||||||
"the binary would be bigger than this assembler has room to build
|
"the output would be bigger than this assembler has room to build
|
||||||
"
|
"
|
||||||
NoWriteText:
|
NoWriteText:
|
||||||
"it would not write "
|
"it would not write "
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
;
|
;
|
||||||
; 0x8000 3072 the label index, 768 entries of four
|
; 0x8000 3072 the label index, 768 entries of four
|
||||||
; 0x8C00 8192 the label names, packed end to end
|
; 0x8C00 8192 the label names, packed end to end
|
||||||
; 0xAC00 13312 the binary being built
|
; 0xAC00 13312 the output file being built
|
||||||
; 0xE000 1792 the vector names, 64 entries of twenty eight
|
; 0xE000 1792 the vector names, 64 entries of twenty eight
|
||||||
; 0xE700 1758 the reader's stack, six levels of 293
|
; 0xE700 1758 the reader's stack, six levels of 293
|
||||||
; 0xEE00 368 which files have been included, sixteen names of 23
|
; 0xEE00 368 which files have been included, sixteen names of 23
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
SplitBit is an 8 bit computer that does not exist: a CPU with its own instruction set, split Program and Data memories, an interrupt and vector system, a bus that programs can enumerate, a memory controller that can write code into memory, and a disk. This repository is a C implementation of the machine, an assembler for it, a tool for its disks, and the software that runs on it, which now includes an operating system and an assembler written in SplitBit's own assembly language.
|
SplitBit is an 8 bit computer that does not exist: a CPU with its own instruction set, split Program and Data memories, an interrupt and vector system, a bus that programs can enumerate, a memory controller that can write code into memory, and a disk. This repository is a C implementation of the machine, an assembler for it, a tool for its disks, and the software that runs on it, which now includes an operating system and an assembler written in SplitBit's own assembly language.
|
||||||
|
|
||||||
**SplitBit assembles SplitBit.** `Programs/CosmOS/Assembler/` runs on the machine, reads source off a SplitBit disk, and writes a binary back to it with no host involved. It builds the operating system it is running under, and it builds itself, both byte for byte identical to what the C assembler produces from the same source. The test suite then boots the CosmOS that CosmOS built and has *that* one assemble CosmOS again, and the second generation is identical to the first, so the machinery has been through itself. After that the host is a convenience rather than a necessity.
|
**SplitBit assembles SplitBit.** `Programs/CosmOS/Assembler/` runs on the machine, reads source off a SplitBit disk, and writes a boot image or a loadable program back to it with no host involved. It builds the operating system it is running under, and it builds itself, both byte for byte identical to what the C assembler produces from the same source. The test suite then boots the CosmOS that CosmOS built and has *that* one assemble CosmOS again, and the second generation is identical to the first, so the machinery has been through itself. After that the host is a convenience rather than a necessity.
|
||||||
|
|
||||||
```
|
```
|
||||||
> load Asm.sbx
|
> load Asm.sbx
|
||||||
@@ -74,7 +74,7 @@ Then `dir` to see what is there, `load Snake.sbx` and `run` to play something, o
|
|||||||
## Running Programs: SplitBit
|
## Running Programs: SplitBit
|
||||||
|
|
||||||
```
|
```
|
||||||
./SplitBit [options] [binary file]
|
./SplitBit [options] [boot image]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | What it does |
|
| Option | What it does |
|
||||||
@@ -96,12 +96,12 @@ If the CPU reads a byte that is not an instruction, it goes to the fault handler
|
|||||||
|
|
||||||
| Option | What it does |
|
| Option | What it does |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `-o <file>` | Write the binary to this path. |
|
| `-o <file>` | Write the output to this path. |
|
||||||
| `-I <dir>` | Look in this directory for included files. May be given more than once. |
|
| `-I <dir>` | Look in this directory for included files. May be given more than once. |
|
||||||
| `-M <file>` | Write out which source files the binary depends on, as a make rule. |
|
| `-M <file>` | Write out which source files the output depends on, as a make rule. |
|
||||||
| `-h`, `--help` | Show help and usage information. |
|
| `-h`, `--help` | Show help and usage information. |
|
||||||
|
|
||||||
Without `-o` the binary takes the source file's name with a `.bin` extension, in the directory you called the assembler from. Included files are looked for beside the file that includes them, and then along the directories given with `-I`.
|
Without `-o` the output takes the source file's name with a `.bin` extension, in the directory you called the assembler from. Included files are looked for beside the file that includes them, and then along the directories given with `-I`.
|
||||||
|
|
||||||
## Managing Disks: SplitDisk
|
## Managing Disks: SplitDisk
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ Files are laid down contiguously, so a disk can have free blocks without having
|
|||||||
|
|
||||||
## Building Programs With Make:
|
## Building Programs With Make:
|
||||||
|
|
||||||
The assembler is built to work with make. `-o` puts the binary where the build system wants it, and `-M` writes out which libraries went into it, so that editing a library reassembles everything that includes it.
|
The assembler is built to work with make. `-o` puts the output where the build system wants it, and `-M` writes out which libraries went into it, so that editing a library reassembles everything that includes it.
|
||||||
|
|
||||||
`Programs/makefile` does this for the programs in this repository:
|
`Programs/makefile` does this for the programs in this repository:
|
||||||
|
|
||||||
|
|||||||
@@ -91,13 +91,13 @@ void printUsage(const char *programName) {
|
|||||||
printf("Usage: %s [OPTIONS] <sourcefile>\n", programName);
|
printf("Usage: %s [OPTIONS] <sourcefile>\n", programName);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -o <file> Write the binary to this path instead of alongside the source.\n");
|
printf(" -o <file> Write the output to this path instead of alongside the source.\n");
|
||||||
printf(" -I <dir> Look in this directory for included files. May be given more than once.\n");
|
printf(" -I <dir> Look in this directory for included files. May be given more than once.\n");
|
||||||
printf(" -M <file> Write the source files this binary depends on, as a make rule.\n");
|
printf(" -M <file> Write the source files this output depends on, as a make rule.\n");
|
||||||
printf(" -h, --help Display this help message.\n");
|
printf(" -h, --help Display this help message.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes a make rule naming every source file that went into the binary, so that a
|
// Writes a make rule naming every source file that went into the output, so that a
|
||||||
// build system knows to reassemble when any of them changes. The empty rules after it
|
// build system knows to reassemble when any of them changes. The empty rules after it
|
||||||
// are so that deleting a library does not leave make with a prerequisite it cannot
|
// are so that deleting a library does not leave make with a prerequisite it cannot
|
||||||
// build; without them the build stops instead of just reassembling.
|
// build; without them the build stops instead of just reassembling.
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
#ifndef ASSEMBLY_H
|
#ifndef ASSEMBLY_H
|
||||||
#define ASSEMBLY_H
|
#define ASSEMBLY_H
|
||||||
|
|
||||||
// ---- The SplitBit binary format ----
|
// ---- The SplitBit boot image format ----
|
||||||
//
|
//
|
||||||
// A binary starts with a file header, then the Program Segment, then the Data
|
// A boot image starts with a file header, then the Program Segment, then the Data
|
||||||
// Segment. All multi byte numbers are stored most significant byte first.
|
// Segment. All multi byte numbers are stored most significant byte first.
|
||||||
//
|
//
|
||||||
// Offset Size Field
|
// Offset Size Field
|
||||||
// 0 4 "SPBT", so a file that is not a SplitBit binary is spotted at once
|
// 0 4 "SPBT", so a file that is not a boot image is spotted at once
|
||||||
// 4 1 Format version
|
// 4 1 Format version
|
||||||
// 5 4 Required feature flags
|
// 5 4 Required feature flags
|
||||||
// 9 3 "PRG"
|
// 9 3 "PRG"
|
||||||
@@ -27,14 +27,14 @@
|
|||||||
// .. 2 Vector Segment length, in bytes
|
// .. 2 Vector Segment length, in bytes
|
||||||
// .. K Vector Segment, four bytes per entry
|
// .. K Vector Segment, four bytes per entry
|
||||||
//
|
//
|
||||||
// The Vector Segment is optional and comes last, so a binary written before it existed
|
// The Vector Segment is optional and comes last, so an image written before it existed
|
||||||
// simply ends after its Data Segment and still loads. Each entry is two bytes saying
|
// simply ends after its Data Segment and still loads. Each entry is two bytes saying
|
||||||
// where in Program Memory the vector sits, then two bytes saying where its handler is,
|
// where in Program Memory the vector sits, then two bytes saying where its handler is,
|
||||||
// most significant byte first. It is a list rather than an image of the table, so a
|
// most significant byte first. It is a list rather than an image of the table, so a
|
||||||
// program with three handlers costs twelve bytes instead of a padded kilobyte.
|
// program with three handlers costs twelve bytes instead of a padded kilobyte.
|
||||||
//
|
//
|
||||||
// The feature flags are how a binary says it needs something the base machine does
|
// The feature flags are how a boot image says it needs something the base machine does
|
||||||
// not provide, so that an emulator which cannot provide it refuses to run the binary
|
// not provide, so that an emulator which cannot provide it refuses to run the image
|
||||||
// rather than quietly doing the wrong thing. No features are defined yet; the field
|
// rather than quietly doing the wrong thing. No features are defined yet; the field
|
||||||
// is here so that adding one later does not need another format version.
|
// is here so that adding one later does not need another format version.
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
#define SPLITBIT_HEADER_BYTES (SPLITBIT_MAGIC_LENGTH + 1 + SPLITBIT_FLAGS_LENGTH \
|
#define SPLITBIT_HEADER_BYTES (SPLITBIT_MAGIC_LENGTH + 1 + SPLITBIT_FLAGS_LENGTH \
|
||||||
+ 2 * (SEGMENT_MARKER_LENGTH + SEGMENT_LENGTH_BYTES))
|
+ 2 * (SEGMENT_MARKER_LENGTH + SEGMENT_LENGTH_BYTES))
|
||||||
|
|
||||||
// Features this build of the emulator can provide. A binary asking for anything
|
// Features this build of the emulator can provide. An image asking for anything
|
||||||
// outside this set is refused.
|
// outside this set is refused.
|
||||||
#define SPLITBIT_FEATURES_SUPPORTED 0x00000000u
|
#define SPLITBIT_FEATURES_SUPPORTED 0x00000000u
|
||||||
|
|
||||||
|
|||||||
@@ -653,7 +653,7 @@ void writeOutputFile(const char *outputFileName, uint8_t *Program, int programCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the file header: the magic, the format version, and the features this
|
// Write the file header: the magic, the format version, and the features this
|
||||||
// binary needs from the machine. An emulator that cannot provide one of those
|
// boot image needs from the machine. An emulator that cannot provide one of those
|
||||||
// features refuses the file rather than running it and going quietly wrong.
|
// features refuses the file rather than running it and going quietly wrong.
|
||||||
fwrite(SPLITBIT_MAGIC, sizeof(char), SPLITBIT_MAGIC_LENGTH, outputFile);
|
fwrite(SPLITBIT_MAGIC, sizeof(char), SPLITBIT_MAGIC_LENGTH, outputFile);
|
||||||
fputc(SPLITBIT_FORMAT_VERSION, outputFile);
|
fputc(SPLITBIT_FORMAT_VERSION, outputFile);
|
||||||
@@ -703,7 +703,7 @@ void writeOutputFile(const char *outputFileName, uint8_t *Program, int programCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The Vector Segment, only if the program named any. Leaving it out entirely is
|
// The Vector Segment, only if the program named any. Leaving it out entirely is
|
||||||
// what lets a binary written before vectors existed still load: the reader treats
|
// what lets an image written before vectors existed still load: the reader treats
|
||||||
// the end of the file as an empty table rather than a missing one.
|
// the end of the file as an empty table rather than a missing one.
|
||||||
int installed = 0;
|
int installed = 0;
|
||||||
for (int i = 0; i < vectorArrayCount; i++) {
|
for (int i = 0; i < vectorArrayCount; i++) {
|
||||||
@@ -730,7 +730,7 @@ void writeOutputFile(const char *outputFileName, uint8_t *Program, int programCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose(outputFile);
|
fclose(outputFile);
|
||||||
printf("Successfully wrote SplitBit binary to \"%s\".\n", outputFileName);
|
printf("Successfully wrote SplitBit boot image to \"%s\".\n", outputFileName);
|
||||||
printf(GREEN " Program Segment size: %d bytes.\n Data Segment size: %d bytes.\n" RESET, programCount, dataCount);
|
printf(GREEN " Program Segment size: %d bytes.\n Data Segment size: %d bytes.\n" RESET, programCount, dataCount);
|
||||||
if (installed > 0) {
|
if (installed > 0) {
|
||||||
printf(GREEN " Vectors: %d.\n" RESET, installed);
|
printf(GREEN " Vectors: %d.\n" RESET, installed);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// has to change there in the same breath.
|
// has to change there in the same breath.
|
||||||
//
|
//
|
||||||
// All multi byte numbers are most significant byte first, the same as every other number
|
// All multi byte numbers are most significant byte first, the same as every other number
|
||||||
// SplitBit stores: addresses, the SPBT binary header, and the vector table.
|
// SplitBit stores: addresses, the SPBT boot image header, and the vector table.
|
||||||
//
|
//
|
||||||
// Written by Anachronaut
|
// Written by Anachronaut
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// 10/16/2024
|
// 10/16/2024
|
||||||
|
|
||||||
#include "bootstrap.h"
|
#include "bootstrap.h"
|
||||||
#include "../Assembler/assembly.h" // For the binary format, which both tools share.
|
#include "../Assembler/assembly.h" // For the boot image format, which both tools share.
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -39,14 +39,14 @@ static uint8_t readMarker(FILE *file, const char *expected, int length, char *fo
|
|||||||
return strncmp(found, expected, length) != 0;
|
return strncmp(found, expected, length) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads the file header: the magic, the format version, and the features the binary
|
// Reads the file header: the magic, the format version, and the features the boot image
|
||||||
// says it needs from the machine.
|
// says it needs from the machine.
|
||||||
static uint8_t readFileHeader(FILE *file) {
|
static uint8_t readFileHeader(FILE *file) {
|
||||||
char magic[SPLITBIT_MAGIC_LENGTH + 1];
|
char magic[SPLITBIT_MAGIC_LENGTH + 1];
|
||||||
if (readMarker(file, SPLITBIT_MAGIC, SPLITBIT_MAGIC_LENGTH, magic)) {
|
if (readMarker(file, SPLITBIT_MAGIC, SPLITBIT_MAGIC_LENGTH, magic)) {
|
||||||
fprintf(stderr, "Error: This is not a SplitBit binary.\n");
|
fprintf(stderr, "Error: This is not a SplitBit boot image.\n");
|
||||||
if (strncmp(magic, "PRG", 3) == 0) {
|
if (strncmp(magic, "PRG", 3) == 0) {
|
||||||
fprintf(stderr, " It looks like a binary from before the format carried a version.\n Reassemble it and try again.\n");
|
fprintf(stderr, " It looks like a boot image from before the format carried a version.\n Reassemble it and try again.\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, " Expected the file to begin with \"%s\", found \"%s\".\n", SPLITBIT_MAGIC, magic);
|
fprintf(stderr, " Expected the file to begin with \"%s\", found \"%s\".\n", SPLITBIT_MAGIC, magic);
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ static uint8_t readFileHeader(FILE *file) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (version != SPLITBIT_FORMAT_VERSION) {
|
if (version != SPLITBIT_FORMAT_VERSION) {
|
||||||
fprintf(stderr, "Error: This binary is in format version %u, and this emulator reads version %u.\n", version, SPLITBIT_FORMAT_VERSION);
|
fprintf(stderr, "Error: This boot image is in format version %u, and this emulator reads version %u.\n", version, SPLITBIT_FORMAT_VERSION);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ static uint8_t readFileHeader(FILE *file) {
|
|||||||
}
|
}
|
||||||
uint32_t missing = required & ~(uint32_t)SPLITBIT_FEATURES_SUPPORTED;
|
uint32_t missing = required & ~(uint32_t)SPLITBIT_FEATURES_SUPPORTED;
|
||||||
if (missing) {
|
if (missing) {
|
||||||
fprintf(stderr, "Error: This binary was built for a machine this emulator cannot provide.\n");
|
fprintf(stderr, "Error: This boot image was built for a machine this emulator cannot provide.\n");
|
||||||
fprintf(stderr, " It asks for feature bits 0x%08X, which are not implemented here.\n", missing);
|
fprintf(stderr, " It asks for feature bits 0x%08X, which are not implemented here.\n", missing);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ static uint8_t readVectorSegment(FILE *file, uint8_t *Program) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (slot < SOFTWARE_VECTOR_BASE) {
|
if (slot < SOFTWARE_VECTOR_BASE) {
|
||||||
fprintf(stderr, "Error: This binary puts a vector at 0x%04X, which is below the vector table.\n", slot);
|
fprintf(stderr, "Error: This boot image puts a vector at 0x%04X, which is below the vector table.\n", slot);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Program[slot] = (handler >> 8) & 0xFF;
|
Program[slot] = (handler >> 8) & 0xFF;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
uint16_t shiftRegister;
|
uint16_t shiftRegister;
|
||||||
|
|
||||||
// Reads one entry out of a vector table. Most significant byte first, matching the
|
// Reads one entry out of a vector table. Most significant byte first, matching the
|
||||||
// branch instructions and the binary format.
|
// branch instructions and both file formats.
|
||||||
static uint16_t readVector(const uint8_t *programMemory, uint16_t base, uint8_t index) {
|
static uint16_t readVector(const uint8_t *programMemory, uint16_t base, uint8_t index) {
|
||||||
uint16_t address = base + (uint16_t)index * VECTOR_ENTRY_BYTES;
|
uint16_t address = base + (uint16_t)index * VECTOR_ENTRY_BYTES;
|
||||||
return ((uint16_t)programMemory[address] << 8) | (uint16_t)programMemory[address + 1];
|
return ((uint16_t)programMemory[address] << 8) | (uint16_t)programMemory[address + 1];
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ int main (int argc, char *argv[]) {
|
|||||||
programFile = argv[optind];
|
programFile = argv[optind];
|
||||||
optind++;
|
optind++;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Error: No binary file specified.\n");
|
fprintf(stderr, "Error: No boot image specified.\n");
|
||||||
printHelp(argv[0]);
|
printHelp(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "../Assembler/assembly.h"
|
#include "../Assembler/assembly.h"
|
||||||
|
|
||||||
void printHelp(const char *programName) {
|
void printHelp(const char *programName) {
|
||||||
printf("Usage: %s [OPTIONS] <binaryfile>\n", programName);
|
printf("Usage: %s [OPTIONS] <boot image>\n", programName);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -d, --debug Enable debug mode.\n");
|
printf(" -d, --debug Enable debug mode.\n");
|
||||||
|
|||||||
@@ -417,16 +417,16 @@ Assembler [options] <sourcefile>
|
|||||||
|
|
||||||
| Option | Meaning |
|
| Option | Meaning |
|
||||||
| -- | -- |
|
| -- | -- |
|
||||||
| -o, --output \<file\> | Write the binary to this path. Without it, the binary is named after the source file, with a .bin extension, in the directory the assembler was run from. |
|
| -o, --output \<file\> | Write the output to this path. Without it, the output is named after the source file, with a .bin extension, in the directory the assembler was run from. |
|
||||||
| -I, --include \<dir\> | Look in this directory for included files. May be given more than once, and the directories are searched in the order given. |
|
| -I, --include \<dir\> | Look in this directory for included files. May be given more than once, and the directories are searched in the order given. |
|
||||||
| -M, --depend \<file\> | Write out which source files went into the binary, as a make rule. |
|
| -M, --depend \<file\> | Write out which source files went into the output, as a make rule. |
|
||||||
| -h, --help | Print the options and stop. |
|
| -h, --help | Print the options and stop. |
|
||||||
|
|
||||||
The assembler stops at the first error, says which file and line it was in, and exits without writing a binary.
|
The assembler stops at the first error, says which file and line it was in, and exits without writing anything.
|
||||||
|
|
||||||
## Building With Make:
|
## Building With Make:
|
||||||
|
|
||||||
The -o and -M options are there so that the assembler fits into a build system. -o puts the binary wherever the build wants it, and -M writes down which libraries went into it, so that editing a library reassembles every program that includes it.
|
The -o and -M options are there so that the assembler fits into a build system. -o puts the output wherever the build wants it, and -M writes down which libraries went into it, so that editing a library reassembles every program that includes it.
|
||||||
|
|
||||||
```
|
```
|
||||||
$(BUILD)/%.bin: %.asm
|
$(BUILD)/%.bin: %.asm
|
||||||
@@ -589,7 +589,7 @@ wrote hello.bin: program 17, data 14, labels 2
|
|||||||
|
|
||||||
Loading and running are separate commands in CosmOS, so the source file is the argument to `run`.
|
Loading and running are separate commands in CosmOS, so the source file is the argument to `run`.
|
||||||
|
|
||||||
**Its output must be byte for byte what the host assembler produces from the same source**, and `Tests/native.sh` checks exactly that: it assembles `Programs/Examples/hello.asm` both ways and compares the files, then runs the one the machine built. This is the discipline SplitDisk and `sbfs.asm` already work under - two implementations of one written specification, each one checking the other. "It ran" is not good enough for an assembler, because a binary with a label one byte out runs right up until it jumps into the middle of an instruction.
|
**Its output must be byte for byte what the host assembler produces from the same source**, and `Tests/native.sh` checks exactly that: it assembles `Programs/Examples/hello.asm` both ways and compares the files, then runs the one the machine built. This is the discipline SplitDisk and `sbfs.asm` already work under - two implementations of one written specification, each one checking the other. "It ran" is not good enough for an assembler, because a file with a label one byte out runs right up until it jumps into the middle of an instruction.
|
||||||
|
|
||||||
### How It Differs Inside:
|
### How It Differs Inside:
|
||||||
|
|
||||||
@@ -649,7 +649,7 @@ wrote Asm.sbx: program 7533, data 4099, labels 555
|
|||||||
|
|
||||||
Both come out **byte for byte identical** to what the host assembler builds from the same source. `make run-cosmos` puts every source file on the disk, so this can be done rather than read about.
|
Both come out **byte for byte identical** to what the host assembler builds from the same source. `make run-cosmos` puts every source file on the disk, so this can be done rather than read about.
|
||||||
|
|
||||||
**The check that matters most is the third one.** A binary that matches could still have been built by an assembler wrong in some way this particular source happens not to exercise. So `Tests/native.sh` boots the CosmOS that CosmOS built and has *that* assemble CosmOS again - and the second generation is identical to the first, down to the cycle count. It is a fixed point, which means the machinery has been through itself.
|
**The check that matters most is the third one.** A file that matches could still have been built by an assembler wrong in some way this particular source happens not to exercise. So `Tests/native.sh` boots the CosmOS that CosmOS built and has *that* assemble CosmOS again - and the second generation is identical to the first, down to the cycle count. It is a fixed point, which means the machinery has been through itself.
|
||||||
|
|
||||||
After that the host is a convenience rather than a necessity.
|
After that the host is a convenience rather than a necessity.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user