Stage 0: the emulator carries the ROM, so a disk is enough
./SplitBit --disk system.img stage two CosmOS > No boot image named. The emulator shadows its built in stage one into Program Memory - boot vector included - and the CPU then does exactly what it has always done: reads the boot vector and starts where it points. NOTHING ABOUT THE CPU CHANGED to make a machine that starts itself, which is what picking shadowing over a mapped ROM bought. The ROM is generated from Programs/Boot/stage1.asm by the makefile rather than committed beside it, because a copy of a program kept next to the program is a copy that goes stale. That makes the assembler a real dependency of the emulator, which it always sort of was and now says so. od and awk rather than xxd, which is not everywhere, or python, which the README does not ask anybody to install in order to build this. loadROM is loadFile given bytes instead of a path: both go through one reader over an fmemopen stream, because a ROM is a boot image and there is no reason for the machine to have two ways of understanding one. Naming an image still works and is what every other test here does. That path is not a shortcut to apologise for - placing memory from outside is a real thing real machines allow, and it is a debugger. The help says so now. No image and no disk is the one case with nothing to run, and it says that rather than printing a usage message about a missing file. run.sh gained a "rom" mode which hands the emulator a disk and nothing else. The source column still names stage1.asm, because that is what is IN the ROM: assembling it there says the thing the emulator carries is a thing that still assembles.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include "bootstrap.h"
|
||||
#include "../Assembler/assembly.h" // For the boot image format, which both tools share.
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// Reads a number of the given width, most significant byte first.
|
||||
@@ -144,18 +145,46 @@ static uint8_t readVectorSegment(FILE *file, uint8_t *Program) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The Program Segment must come first, then the Data Segment. Short circuiting here means
|
||||
// there is one exit, and so only one place that has to close whatever it was reading.
|
||||
static uint8_t readImage(FILE *file, uint8_t *Program, uint8_t *Data) {
|
||||
return readFileHeader(file)
|
||||
|| readSegment(file, "PRG", Program)
|
||||
|| readSegment(file, "DAT", Data)
|
||||
|| readVectorSegment(file, Program);
|
||||
}
|
||||
|
||||
// ---- Waking up in ROM ----
|
||||
//
|
||||
// The same reader as a named file, given the bytes instead of a path, because a ROM is a
|
||||
// boot image and there is no reason for the machine to have two ways of understanding one.
|
||||
//
|
||||
// THIS IS SHADOWING, which is a real technique rather than a convenience: reset copies the
|
||||
// ROM into Program Memory, including its boot vector, and the CPU then does exactly what it
|
||||
// has always done - reads the boot vector and starts where it points. Nothing about the CPU
|
||||
// changes to make a machine that starts itself.
|
||||
//
|
||||
// And because it is a copy rather than a mapping, the bytes are ordinary Program Memory
|
||||
// once stage one has jumped away. The system may write over them; a reset puts them back.
|
||||
uint8_t loadROM(const unsigned char *bytes, unsigned long length,
|
||||
uint8_t *Program, uint8_t *Data) {
|
||||
FILE *file = fmemopen((void *)(uintptr_t)bytes, (size_t)length, "rb");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Error: Couldn't open the boot ROM.\n");
|
||||
return 1;
|
||||
}
|
||||
uint8_t failed = readImage(file, Program, Data);
|
||||
fclose(file);
|
||||
return failed;
|
||||
}
|
||||
|
||||
uint8_t loadFile(char *path, uint8_t *Program, uint8_t *Data) {
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Error: Couldn't open file: %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
// The Program Segment must come first, then the Data Segment. Short circuiting
|
||||
// here means there is one exit, and so only one place that has to close the file.
|
||||
uint8_t failed = readFileHeader(file)
|
||||
|| readSegment(file, "PRG", Program)
|
||||
|| readSegment(file, "DAT", Data)
|
||||
|| readVectorSegment(file, Program);
|
||||
uint8_t failed = readImage(file, Program, Data);
|
||||
fclose(file);
|
||||
return failed;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user