Do some work on the CPU, assembler still needs update
This commit is contained in:
87
assembler/assembler.h
Normal file
87
assembler/assembler.h
Normal file
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Created by bruno on 1.2.2025.
|
||||
//
|
||||
|
||||
#ifndef RISCB_ASSEMBLER_H
|
||||
#define RISCB_ASSEMBLER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "../cpu/core.h"
|
||||
|
||||
//
|
||||
// Definitions used by the CPU and the assembler
|
||||
//
|
||||
|
||||
#define MAX_LINE_LENGTH 256
|
||||
#define MAX_LABELS 1024
|
||||
|
||||
//
|
||||
// Label table entry
|
||||
//
|
||||
typedef struct {
|
||||
char name[64];
|
||||
int address; // address (in the output machine code)
|
||||
} Label;
|
||||
|
||||
extern Label labels[MAX_LABELS];
|
||||
extern int labelCount;
|
||||
|
||||
//
|
||||
// Helper functions for string manipulation
|
||||
//
|
||||
void trim(char *s);
|
||||
|
||||
// Look up a label by name; returns -1 if not found.
|
||||
int lookupLabel(const char *name);
|
||||
|
||||
// Add a label to the table
|
||||
void addLabel(const char *name, int address);
|
||||
|
||||
//
|
||||
// Parse a register string (e.g., "R0", "R1", etc.) and return it's number.
|
||||
// Returns -1 on error.
|
||||
int parseRegister(const char *token);
|
||||
|
||||
// Parse an immediate value (supports decimal and 0x... hexadecimal)
|
||||
uint8_t parseImmediate(const char *token);
|
||||
|
||||
//
|
||||
// Map an instruction mnemonic (string) to its opcode value and expected operand types.
|
||||
// For simplicity, we will return the opcode value and then in our parser we’ll decide how many operands to expect.
|
||||
// (In a full assembler you might use a more sophisticated data structure.)
|
||||
//
|
||||
int getOpcode(char *mnemonic);
|
||||
|
||||
//
|
||||
// In this simple assembler, some instructions share a mnemonic, and we must choose the correct opcode
|
||||
// based on the type of the operand (register vs. immediate vs. memory).
|
||||
// The following helper functions decide that, given two operands (as strings).
|
||||
//
|
||||
// For example, "MOV Rn, 42" should choose MOV_RN_IMM, while "MOV Rn, Rm" should choose MOV_RN_RM.
|
||||
// We assume that memory addresses are written in square brackets, e.g. "[123]".
|
||||
//
|
||||
int resolveMOV(const char *dest, const char *src);
|
||||
|
||||
int resolveALU(int baseOpcode, const char *src);
|
||||
|
||||
//
|
||||
// The first pass scans the assembly source file to record all labels and their addresses.
|
||||
// The address is simply the offset into the output machine code buffer.
|
||||
// For this example, every instruction is assumed to have a fixed length (opcode plus operand bytes).
|
||||
//
|
||||
int firstPass(const char *source);
|
||||
|
||||
//
|
||||
// The second pass actually translates the assembly instructions to machine code.
|
||||
// The machine code is written into the provided buffer. (It must be large enough.)
|
||||
//
|
||||
int secondPass(const char *source, uint8_t *code);
|
||||
|
||||
void completePass(const char *input, CPU *cpu);
|
||||
|
||||
|
||||
#endif //RISCB_ASSEMBLER_H
|
Reference in New Issue
Block a user