// assembly.h // These are functions useful for translating assembly mnemonics to hex and vice-versa for the SplitBit CPU. // Written by Anachronaut // 10/18/2024 #include #ifndef ASSEMBLY_H #define ASSEMBLY_H // ---- The SplitBit binary format ---- // // A binary starts with a file header, then the Program Segment, then the Data // Segment. All multi byte numbers are stored most significant byte first. // // Offset Size Field // 0 4 "SPBT", so a file that is not a SplitBit binary is spotted at once // 4 1 Format version // 5 4 Required feature flags // 9 3 "PRG" // 12 2 Program Segment length // 14 N Program Segment // .. 3 "DAT" // .. 2 Data Segment length // .. M Data Segment // .. 3 "VEC", optional // .. 2 Vector Segment length, in bytes // .. K Vector Segment, four bytes per entry // // The Vector Segment is optional and comes last, so a binary written before it existed // 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, // 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. // // The feature flags are how a binary says it needs something the base machine does // not provide, so that an emulator which cannot provide it refuses to run the binary // 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. // ---- The vector table ---- // // 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. // // Entries are two bytes each, most significant byte first, the same order the branch // instructions and this file format already use. // // 0xFC00 Software vectors 0 to 255 // 0xFE00 Hardware vectors 0 to 255, one for each I/O port // // Software vectors 0 and 1 are start addresses rather than handlers. Vector 0 is // where the machine begins at power on and vector 1 is a warm restart, so a zero in // either of them is not "nothing installed" but the address 0x0000, which is where a // program carrying no vector table of its own begins. A zero in any other entry does // mean no handler is installed, and dispatching through one is a fault. #define SOFTWARE_VECTOR_BASE 0xFC00 #define HARDWARE_VECTOR_BASE 0xFE00 #define VECTOR_ENTRY_BYTES 2 #define VECTOR_BOOT 0 #define VECTOR_SOFT_RESET 1 #define VECTOR_INVALID_OPCODE 2 // Vectors 3 to 15 are held back for faults that do not exist yet, so that each cause // can have an entry of its own rather than sharing one and needing a cause register to // tell them apart. Everything from 16 up belongs to programs. #define VECTOR_FIRST_FREE 16 // 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 #define SPLITBIT_MAGIC "SPBT" #define SPLITBIT_MAGIC_LENGTH 4 #define SPLITBIT_FORMAT_VERSION 1 #define SPLITBIT_FLAGS_LENGTH 4 #define SEGMENT_MARKER_LENGTH 3 #define SEGMENT_LENGTH_BYTES 2 // Where a vector sits, and where its handler is. #define VECTOR_ENTRY_FILE_BYTES 4 // Everything the format costs a file, on top of the two segments themselves. #define SPLITBIT_HEADER_BYTES (SPLITBIT_MAGIC_LENGTH + 1 + SPLITBIT_FLAGS_LENGTH \ + 2 * (SEGMENT_MARKER_LENGTH + SEGMENT_LENGTH_BYTES)) // Features this build of the emulator can provide. A binary asking for anything // outside this set is refused. #define SPLITBIT_FEATURES_SUPPORTED 0x00000000u // Features the assembler currently needs to ask for. Nothing, so far. #define SPLITBIT_FEATURES_REQUIRED 0x00000000u const char* getMnemonic(uint8_t opcode); uint8_t getOpcode(char* mnemonic); // How many Data Pointer selector bytes follow the given opcode. Never more than two. #define MAX_DATA_POINTER_OPERANDS 2 int dataPointerOperands(uint8_t opcode); #endif // CPU_H