add assembler
This commit is contained in:
		
							parent
							
								
									05793ad4ae
								
							
						
					
					
						commit
						4f6520c470
					
				
							
								
								
									
										8
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								Makefile
									
									
									
									
									
								
							| @ -34,7 +34,7 @@ endif | |||||||
| 
 | 
 | ||||||
| HEADERS = $(shell find . -name *.h) | HEADERS = $(shell find . -name *.h) | ||||||
| 
 | 
 | ||||||
| ASM_SOURCES = $(shell find asm/ -name *.c) | ASM_SOURCES = $(shell find asm/ -name *.c -not -name main.c) | ||||||
| ASM_OBJECTS = $(patsubst %.c,build/%.o,$(ASM_SOURCES)) | ASM_OBJECTS = $(patsubst %.c,build/%.o,$(ASM_SOURCES)) | ||||||
| 
 | 
 | ||||||
| VM_SOURCES = $(shell find vm/ -name *.c) | VM_SOURCES = $(shell find vm/ -name *.c) | ||||||
| @ -43,7 +43,7 @@ VM_OBJECTS = $(patsubst %.c,build/%.o,$(VM_SOURCES)) | |||||||
| KERN_SOURCES = $(shell find kern/ -name *.c) | KERN_SOURCES = $(shell find kern/ -name *.c) | ||||||
| KERN_OBJECTS = $(patsubst %.c,build/%.o,$(KERN_SOURCES)) | KERN_OBJECTS = $(patsubst %.c,build/%.o,$(KERN_SOURCES)) | ||||||
| 
 | 
 | ||||||
| all: bin/vm bin/build_disk_image | all: bin/vm bin/build_disk_image bin/asm | ||||||
| 
 | 
 | ||||||
| bin/vm: $(VM_OBJECTS) $(ASM_OBJECTS) build/image | bin/vm: $(VM_OBJECTS) $(ASM_OBJECTS) build/image | ||||||
| 	@mkdir -p $(dir $@) | 	@mkdir -p $(dir $@) | ||||||
| @ -57,6 +57,10 @@ bin/build_disk_image: $(KERN_OBJECTS) $(ASM_OBJECTS) | |||||||
| 	@mkdir -p $(dir $@) | 	@mkdir -p $(dir $@) | ||||||
| 	$(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) | 	$(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) | ||||||
| 
 | 
 | ||||||
|  | bin/asm: $(ASM_OBJECTS) build/asm/main.o | ||||||
|  | 	@mkdir -p $(dir $@) | ||||||
|  | 	$(CC) $^ -o $@ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS) | ||||||
|  | 
 | ||||||
| build/%.o: %.c $(HEADERS) | build/%.o: %.c $(HEADERS) | ||||||
| 	@mkdir -p $(dir $@) | 	@mkdir -p $(dir $@) | ||||||
| 	$(CC) $< -c -o $@ $(C_FLAGS) $(OPTIMIZATION) $(F_FLAGS) | 	$(CC) $< -c -o $@ $(C_FLAGS) $(OPTIMIZATION) $(F_FLAGS) | ||||||
|  | |||||||
							
								
								
									
										874
									
								
								asm/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										874
									
								
								asm/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,874 @@ | |||||||
|  | #include "common/arch.h" | ||||||
|  | #include <assert.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | static inline bool str_includes(const char* str, char ch) | ||||||
|  | { | ||||||
|  |     for (size_t i = 0; str[i] != '\0'; ++i) { | ||||||
|  |         if (str[i] == ch) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline char* asm_strndup(const char* str, size_t len) | ||||||
|  | { | ||||||
|  |     char* val = calloc(len + 1, sizeof(char)); | ||||||
|  |     strncpy(val, str, len); | ||||||
|  |     return val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     size_t idx; | ||||||
|  |     int line; | ||||||
|  |     int col; | ||||||
|  | } Loc; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     TT_Err, | ||||||
|  |     TT_Eof, | ||||||
|  |     TT_Ident, | ||||||
|  |     TT_Int, | ||||||
|  |     TT_Binary, | ||||||
|  |     TT_Hex, | ||||||
|  |     TT_Newline = '\n', | ||||||
|  |     TT_DoubleLt, | ||||||
|  |     TT_DoubleGt, | ||||||
|  |     TT_Pipe = '|', | ||||||
|  |     TT_Hat = '^', | ||||||
|  |     TT_Ampersand = '&', | ||||||
|  |     TT_Plus = '+', | ||||||
|  |     TT_Minus = '-', | ||||||
|  |     TT_Asterisk = '*', | ||||||
|  |     TT_Slash = '/', | ||||||
|  |     TT_Percent = '%', | ||||||
|  |     TT_LParen = '(', | ||||||
|  |     TT_RParen = ')', | ||||||
|  |     TT_LBracket = '[', | ||||||
|  |     TT_RBracket = ']', | ||||||
|  |     TT_Dot = '.', | ||||||
|  |     TT_Comma = ',', | ||||||
|  |     TT_Colon = ':', | ||||||
|  |     TT_Exclamation = '!', | ||||||
|  | } TokTy; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     TokTy ty; | ||||||
|  |     Loc loc; | ||||||
|  |     size_t len; | ||||||
|  | } Tok; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     const char* filename; | ||||||
|  |     const char* text; | ||||||
|  |     size_t text_len; | ||||||
|  |     size_t idx; | ||||||
|  |     int line; | ||||||
|  |     int col; | ||||||
|  |     char ch; | ||||||
|  |     bool error_occured; | ||||||
|  | } Lexer; | ||||||
|  | 
 | ||||||
|  | void lexer_construct(Lexer* lexer, const char* filename, const char* text) | ||||||
|  | { | ||||||
|  |     *lexer = (Lexer) { | ||||||
|  |         .filename = filename, | ||||||
|  |         .text = text, | ||||||
|  |         .text_len = strlen(text), | ||||||
|  |         .idx = 0, | ||||||
|  |         .line = 1, | ||||||
|  |         .col = 1, | ||||||
|  |         .ch = text[0], | ||||||
|  |         .error_occured = false, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline bool lexer_done(const Lexer* lexer) | ||||||
|  | { | ||||||
|  |     return lexer->idx >= lexer->text_len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void lexer_step(Lexer* lexer) | ||||||
|  | { | ||||||
|  |     if (lexer_done(lexer)) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (lexer->ch == '\n') { | ||||||
|  |         lexer->line += 1; | ||||||
|  |         lexer->col = 1; | ||||||
|  |     } else { | ||||||
|  |         lexer->col += 1; | ||||||
|  |     } | ||||||
|  |     lexer->idx += 1; | ||||||
|  |     lexer->ch = lexer->text[lexer->idx]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline Loc lexer_loc(const Lexer* lexer) | ||||||
|  | { | ||||||
|  |     return (Loc) { .idx = lexer->idx, .line = lexer->line, .col = lexer->col }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline Tok lexer_tok(const Lexer* lexer, TokTy ty, Loc loc) | ||||||
|  | { | ||||||
|  |     return (Tok) { .ty = ty, .loc = loc, .len = lexer->idx - loc.idx }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void lexer_report(Lexer* lexer, const char* msg, Loc loc) | ||||||
|  | { | ||||||
|  |     lexer->error_occured = true; | ||||||
|  | 
 | ||||||
|  |     size_t line_start = loc.idx; | ||||||
|  |     while (line_start > 0 && lexer->text[line_start] != '\n') { | ||||||
|  |         line_start -= 1; | ||||||
|  |     } | ||||||
|  |     if (lexer->text[line_start] == '\n') { | ||||||
|  |         line_start += 1; | ||||||
|  |     } | ||||||
|  |     size_t line_end = loc.idx + 1; | ||||||
|  |     while (line_end < lexer->text_len && lexer->text[line_end] != '\n') { | ||||||
|  |         line_end += 1; | ||||||
|  |     } | ||||||
|  |     const char* line = &lexer->text[line_start]; | ||||||
|  |     int line_len = (int)line_end - (int)line_start; | ||||||
|  | 
 | ||||||
|  |     fprintf(stderr, | ||||||
|  |         "error: %s\n  --> %s:%d:%d\n     |\n%5d|%.*s\n     |%*c^\n", | ||||||
|  |         msg, | ||||||
|  |         lexer->filename, | ||||||
|  |         loc.line, | ||||||
|  |         loc.col, | ||||||
|  |         loc.line, | ||||||
|  |         line_len, | ||||||
|  |         line, | ||||||
|  |         loc.col - 2, | ||||||
|  |         ' '); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Tok lexer_next(Lexer* lexer) | ||||||
|  | { | ||||||
|  |     const char* ident_chars = "abcdefghijklmnopqrstuvwxyz" | ||||||
|  |                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"; | ||||||
|  |     const char* int_chars = "1234567890"; | ||||||
|  |     const char* hex_chars = "01234567889abcdefABCDEF"; | ||||||
|  | 
 | ||||||
|  |     Loc loc = lexer_loc(lexer); | ||||||
|  |     if (lexer_done(lexer)) { | ||||||
|  |         return lexer_tok(lexer, TT_Eof, loc); | ||||||
|  |     } | ||||||
|  |     if (lexer->ch == '\n') { | ||||||
|  |         lexer_step(lexer); | ||||||
|  |         return lexer_tok(lexer, '\n', loc); | ||||||
|  |     } else if (str_includes(" \t", lexer->ch)) { | ||||||
|  |         while (!lexer_done(lexer) && str_includes(" \t", lexer->ch)) { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |         } | ||||||
|  |         return lexer_next(lexer); | ||||||
|  |     } else if (str_includes(ident_chars, lexer->ch)) { | ||||||
|  |         while (!lexer_done(lexer) | ||||||
|  |             && (str_includes(ident_chars, lexer->ch) | ||||||
|  |                 || str_includes(int_chars, lexer->ch))) { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |         } | ||||||
|  |         return lexer_tok(lexer, TT_Ident, loc); | ||||||
|  |     } else if (str_includes(int_chars, lexer->ch) && lexer->ch != '0') { | ||||||
|  |         while (!lexer_done(lexer) && (str_includes(int_chars, lexer->ch))) { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |         } | ||||||
|  |         return lexer_tok(lexer, TT_Int, loc); | ||||||
|  |     } else if (lexer->ch == ';') { | ||||||
|  |         while (!lexer_done(lexer) && lexer->ch != '\n') { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |         } | ||||||
|  |         return lexer_next(lexer); | ||||||
|  |     } else if (lexer->ch == '0') { | ||||||
|  |         lexer_step(lexer); | ||||||
|  |         if (lexer->ch == 'b') { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |             if (lexer_done(lexer) || !str_includes("01", lexer->ch)) { | ||||||
|  |                 lexer_report(lexer, "malformed binary literal", loc); | ||||||
|  |                 return lexer_tok(lexer, TT_Err, loc); | ||||||
|  |             } | ||||||
|  |             while (!lexer_done(lexer) && str_includes("01", lexer->ch)) { | ||||||
|  |                 lexer_step(lexer); | ||||||
|  |             } | ||||||
|  |             return lexer_tok(lexer, TT_Binary, loc); | ||||||
|  |         } else if (lexer->ch == 'x') { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |             if (lexer_done(lexer) || !str_includes(hex_chars, lexer->ch)) { | ||||||
|  |                 lexer_report(lexer, "malformed hex literal", loc); | ||||||
|  |                 return lexer_tok(lexer, TT_Err, loc); | ||||||
|  |             } | ||||||
|  |             while (!lexer_done(lexer) && str_includes(hex_chars, lexer->ch)) { | ||||||
|  |                 lexer_step(lexer); | ||||||
|  |             } | ||||||
|  |             return lexer_tok(lexer, TT_Hex, loc); | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |             return lexer_tok(lexer, TT_Int, loc); | ||||||
|  |         } | ||||||
|  |     } else if (lexer->ch == '<') { | ||||||
|  |         lexer_step(lexer); | ||||||
|  |         if (!lexer_done(lexer) && lexer->ch == '<') { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |             return lexer_tok(lexer, TT_DoubleLt, loc); | ||||||
|  |         } else { | ||||||
|  |             lexer_report(lexer, "expected '<'", loc); | ||||||
|  |             return lexer_tok(lexer, TT_Err, loc); | ||||||
|  |         } | ||||||
|  |     } else if (lexer->ch == '>') { | ||||||
|  |         lexer_step(lexer); | ||||||
|  |         if (!lexer_done(lexer) && lexer->ch == '>') { | ||||||
|  |             lexer_step(lexer); | ||||||
|  |             return lexer_tok(lexer, TT_DoubleGt, loc); | ||||||
|  |         } else { | ||||||
|  |             lexer_report(lexer, "expected '>'", loc); | ||||||
|  |             return lexer_tok(lexer, TT_Err, loc); | ||||||
|  |         } | ||||||
|  |     } else if (str_includes("|^&+-*/%()[].,:!", lexer->ch)) { | ||||||
|  |         char ch = lexer->ch; | ||||||
|  |         lexer_step(lexer); | ||||||
|  |         return lexer_tok(lexer, (TokTy)ch, loc); | ||||||
|  |     } else { | ||||||
|  |         lexer_report(lexer, "illegal character '%c'", loc); | ||||||
|  |         lexer_step(lexer); | ||||||
|  |         return lexer_next(lexer); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // typedef enum {
 | ||||||
|  | //     M_err,
 | ||||||
|  | //     M_d8,
 | ||||||
|  | //     M_d16,
 | ||||||
|  | //     M_nop,
 | ||||||
|  | //     M_hlt,
 | ||||||
|  | //     M_jmp,
 | ||||||
|  | //     M_jmpf,
 | ||||||
|  | //     M_jnz,
 | ||||||
|  | //     M_cmp,
 | ||||||
|  | //     M_mov,
 | ||||||
|  | //     M_in,
 | ||||||
|  | //     M_out,
 | ||||||
|  | //     M_call,
 | ||||||
|  | //     M_callf,
 | ||||||
|  | //     M_ret,
 | ||||||
|  | //     M_retf,
 | ||||||
|  | //     M_lit,
 | ||||||
|  | //     M_int,
 | ||||||
|  | //     M_iret,
 | ||||||
|  | // } Mnemonic;
 | ||||||
|  | 
 | ||||||
|  | typedef struct PLabel PLabel; | ||||||
|  | 
 | ||||||
|  | struct PLabel { | ||||||
|  |     PLabel* next; | ||||||
|  |     char* ident; | ||||||
|  |     Loc loc; | ||||||
|  |     bool sub_label; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | PLabel* plabel_new(PLabel* next, char* ident, bool sub_label, Loc loc) | ||||||
|  | { | ||||||
|  |     PLabel* label = malloc(sizeof(PLabel)); | ||||||
|  |     *label = (PLabel) { next, ident, loc, sub_label }; | ||||||
|  |     return label; | ||||||
|  | } | ||||||
|  | void plabel_free(PLabel* label) | ||||||
|  | { | ||||||
|  |     if (!label) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     plabel_free(label->next); | ||||||
|  |     free(label->ident); | ||||||
|  |     free(label); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     PoTy_Reg, | ||||||
|  |     PoTy_Imm, | ||||||
|  |     PoTy_Ident, | ||||||
|  |     PoTy_SubLabel, | ||||||
|  |     PoTy_MemU8, | ||||||
|  |     PoTy_MemU16, | ||||||
|  |     PoTy_Not, | ||||||
|  |     PoTy_Negate, | ||||||
|  |     PoTy_Or, | ||||||
|  |     PoTy_Xor, | ||||||
|  |     PoTy_And, | ||||||
|  |     PoTy_Shl, | ||||||
|  |     PoTy_Shr, | ||||||
|  |     PoTy_Add, | ||||||
|  |     PoTy_Sub, | ||||||
|  |     PoTy_Mul, | ||||||
|  |     PoTy_Div, | ||||||
|  |     PoTy_Mod, | ||||||
|  | } POperandTy; | ||||||
|  | 
 | ||||||
|  | typedef struct POperand POperand; | ||||||
|  | 
 | ||||||
|  | struct POperand { | ||||||
|  |     POperandTy ty; | ||||||
|  |     Loc loc; | ||||||
|  |     union { | ||||||
|  |         Reg reg; | ||||||
|  |         uint16_t imm; | ||||||
|  |         char* ident; | ||||||
|  |         POperand* operand; | ||||||
|  |         struct { | ||||||
|  |             POperand* left; | ||||||
|  |             POperand* right; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | POperand* poperand_new_reg(Reg reg, Loc loc) | ||||||
|  | { | ||||||
|  |     POperand* operand = malloc(sizeof(POperand)); | ||||||
|  |     *operand = (POperand) { .ty = PoTy_Reg, .loc = loc, .reg = reg }; | ||||||
|  |     return operand; | ||||||
|  | } | ||||||
|  | POperand* poperand_new_imm(uint16_t imm, Loc loc) | ||||||
|  | { | ||||||
|  |     POperand* operand = malloc(sizeof(POperand)); | ||||||
|  |     *operand = (POperand) { .ty = PoTy_Imm, .loc = loc, .imm = imm }; | ||||||
|  |     return operand; | ||||||
|  | } | ||||||
|  | POperand* poperand_new_ident(POperandTy ty, char* ident, Loc loc) | ||||||
|  | { | ||||||
|  |     POperand* operand = malloc(sizeof(POperand)); | ||||||
|  |     *operand = (POperand) { .ty = ty, .loc = loc, .ident = ident }; | ||||||
|  |     return operand; | ||||||
|  | } | ||||||
|  | POperand* poperand_new_unary(POperandTy ty, POperand* inner, Loc loc) | ||||||
|  | { | ||||||
|  |     POperand* operand = malloc(sizeof(POperand)); | ||||||
|  |     *operand = (POperand) { .ty = ty, .loc = loc, .operand = inner }; | ||||||
|  |     return operand; | ||||||
|  | } | ||||||
|  | POperand* poperand_new_binary( | ||||||
|  |     POperandTy ty, POperand* left, POperand* right, Loc loc) | ||||||
|  | { | ||||||
|  |     POperand* operand = malloc(sizeof(POperand)); | ||||||
|  |     *operand | ||||||
|  |         = (POperand) { .ty = ty, .loc = loc, .left = left, .right = right }; | ||||||
|  |     return operand; | ||||||
|  | } | ||||||
|  | void poperand_free(POperand* operand) | ||||||
|  | { | ||||||
|  |     switch (operand->ty) { | ||||||
|  |         case PoTy_Reg: | ||||||
|  |         case PoTy_Imm: | ||||||
|  |             break; | ||||||
|  |         case PoTy_Ident: | ||||||
|  |         case PoTy_SubLabel: | ||||||
|  |             free(operand->ident); | ||||||
|  |             break; | ||||||
|  |         case PoTy_MemU8: | ||||||
|  |         case PoTy_MemU16: | ||||||
|  |         case PoTy_Not: | ||||||
|  |         case PoTy_Negate: | ||||||
|  |             poperand_free(operand->operand); | ||||||
|  |             break; | ||||||
|  |         case PoTy_Or: | ||||||
|  |         case PoTy_Xor: | ||||||
|  |         case PoTy_And: | ||||||
|  |         case PoTy_Shl: | ||||||
|  |         case PoTy_Shr: | ||||||
|  |         case PoTy_Add: | ||||||
|  |         case PoTy_Sub: | ||||||
|  |         case PoTy_Mul: | ||||||
|  |         case PoTy_Div: | ||||||
|  |         case PoTy_Mod: | ||||||
|  |             poperand_free(operand->left); | ||||||
|  |             poperand_free(operand->right); | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  |     free(operand); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     PLabel* labels; | ||||||
|  |     char* op; | ||||||
|  |     Loc loc; | ||||||
|  |     size_t ops_size; | ||||||
|  |     POperand* ops[]; | ||||||
|  | } PLine; | ||||||
|  | 
 | ||||||
|  | PLine* pline_new_0(char* op, PLabel* labels, Loc loc) | ||||||
|  | { | ||||||
|  |     PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 0); | ||||||
|  |     *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 0 }; | ||||||
|  |     return line; | ||||||
|  | } | ||||||
|  | PLine* pline_new_1(char* op, PLabel* labels, Loc loc, POperand* op0) | ||||||
|  | { | ||||||
|  |     PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 1); | ||||||
|  |     *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 1 }; | ||||||
|  |     line->ops[0] = op0; | ||||||
|  |     return line; | ||||||
|  | } | ||||||
|  | PLine* pline_new_2( | ||||||
|  |     char* op, PLabel* labels, Loc loc, POperand* op0, POperand* op1) | ||||||
|  | { | ||||||
|  |     PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 2); | ||||||
|  |     *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 2 }; | ||||||
|  |     line->ops[0] = op0; | ||||||
|  |     line->ops[1] = op1; | ||||||
|  |     return line; | ||||||
|  | } | ||||||
|  | PLine* pline_new_3(char* op, | ||||||
|  |     PLabel* labels, | ||||||
|  |     Loc loc, | ||||||
|  |     POperand* op0, | ||||||
|  |     POperand* op1, | ||||||
|  |     POperand* op2) | ||||||
|  | { | ||||||
|  |     PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * 3); | ||||||
|  |     *line = (PLine) { .labels = labels, .op = op, .loc = loc, .ops_size = 3 }; | ||||||
|  |     line->ops[0] = op0; | ||||||
|  |     line->ops[1] = op1; | ||||||
|  |     line->ops[2] = op2; | ||||||
|  |     return line; | ||||||
|  | } | ||||||
|  | void pline_free(PLine* pline) | ||||||
|  | { | ||||||
|  |     plabel_free(pline->labels); | ||||||
|  |     free(pline->op); | ||||||
|  |     for (size_t i = 0; i < pline->ops_size; ++i) { | ||||||
|  |         poperand_free(pline->ops[i]); | ||||||
|  |     } | ||||||
|  |     free(pline); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     Lexer lexer; | ||||||
|  |     Tok tok; | ||||||
|  |     Tok eaten; | ||||||
|  |     bool error_occured; | ||||||
|  | } Parser; | ||||||
|  | 
 | ||||||
|  | void parser_construct(Parser* parser, const char* filename, const char* text) | ||||||
|  | { | ||||||
|  |     Lexer lexer; | ||||||
|  |     lexer_construct(&lexer, filename, text); | ||||||
|  | 
 | ||||||
|  |     *parser = (Parser) { | ||||||
|  |         .lexer = lexer, | ||||||
|  |         .tok = lexer_next(&lexer), | ||||||
|  |         .eaten = (Tok) { 0 }, | ||||||
|  |         .error_occured = false, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool parser_done(const Parser* parser) | ||||||
|  | { | ||||||
|  |     return parser->tok.ty == TT_Eof; | ||||||
|  | } | ||||||
|  | bool parser_error_occured(const Parser* parser) | ||||||
|  | { | ||||||
|  |     return parser->error_occured || parser->lexer.error_occured; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void parser_step(Parser* parser) | ||||||
|  | { | ||||||
|  |     parser->tok = lexer_next(&parser->lexer); | ||||||
|  | } | ||||||
|  | static inline bool parser_test(const Parser* parser, TokTy ty) | ||||||
|  | { | ||||||
|  |     return parser->tok.ty == ty; | ||||||
|  | } | ||||||
|  | static inline bool parser_eat(Parser* parser, TokTy ty) | ||||||
|  | { | ||||||
|  |     if (parser_test(parser, ty)) { | ||||||
|  |         parser->eaten = parser->tok; | ||||||
|  |         parser_step(parser); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | static inline char* parser_ident_val(const Parser* parser, Tok tok) | ||||||
|  | { | ||||||
|  |     return asm_strndup(&parser->lexer.text[tok.loc.idx], tok.len); | ||||||
|  | } | ||||||
|  | static inline void parser_report(Parser* parser, const char* msg, Loc loc) | ||||||
|  | { | ||||||
|  |     parser->error_occured = true; | ||||||
|  | 
 | ||||||
|  |     size_t line_start = loc.idx; | ||||||
|  |     while (line_start > 0 && parser->lexer.text[line_start] != '\n') { | ||||||
|  |         line_start -= 1; | ||||||
|  |     } | ||||||
|  |     if (parser->lexer.text[line_start] == '\n') { | ||||||
|  |         line_start += 1; | ||||||
|  |     } | ||||||
|  |     size_t line_end = loc.idx + 1; | ||||||
|  |     while (line_end < parser->lexer.text_len | ||||||
|  |         && parser->lexer.text[line_end] != '\n') { | ||||||
|  |         line_end += 1; | ||||||
|  |     } | ||||||
|  |     const char* line = &parser->lexer.text[line_start]; | ||||||
|  |     int line_len = (int)line_end - (int)line_start; | ||||||
|  | 
 | ||||||
|  |     fprintf(stderr, | ||||||
|  |         "error: %s\n  --> %s:%d:%d\n     |\n%5d|%.*s\n     |%*c^\n", | ||||||
|  |         msg, | ||||||
|  |         parser->lexer.filename, | ||||||
|  |         loc.line, | ||||||
|  |         loc.col, | ||||||
|  |         loc.line, | ||||||
|  |         line_len, | ||||||
|  |         line, | ||||||
|  |         loc.col - 2, | ||||||
|  |         ' '); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void parser_skip_newlines(Parser* parser) | ||||||
|  | { | ||||||
|  |     while (parser_eat(parser, '\n')) { } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline PLabel* parser_parse_labels( | ||||||
|  |     Parser* parser, char** ident, Loc* ident_loc) | ||||||
|  | { | ||||||
|  |     *ident = NULL; | ||||||
|  |     PLabel* labels = NULL; | ||||||
|  |     while (parser->tok.ty != TT_Eof && *ident == NULL) { | ||||||
|  |         parser_skip_newlines(parser); | ||||||
|  |         Loc loc = parser->tok.loc; | ||||||
|  |         if (parser_eat(parser, '.')) { | ||||||
|  |             if (!parser_eat(parser, TT_Ident)) { | ||||||
|  |                 parser_report(parser, "expected identifier", parser->tok.loc); | ||||||
|  |                 plabel_free(labels); | ||||||
|  |                 return NULL; | ||||||
|  |             } | ||||||
|  |             char* label_ident = parser_ident_val(parser, parser->eaten); | ||||||
|  |             if (!parser_eat(parser, ':')) { | ||||||
|  |                 parser_report(parser, "expected ':'", parser->tok.loc); | ||||||
|  |                 plabel_free(labels); | ||||||
|  |                 free(label_ident); | ||||||
|  |                 return NULL; | ||||||
|  |             } | ||||||
|  |             labels = plabel_new(labels, label_ident, true, loc); | ||||||
|  |         } else if (parser_eat(parser, TT_Ident)) { | ||||||
|  |             *ident = parser_ident_val(parser, parser->eaten); | ||||||
|  |             *ident_loc = loc; | ||||||
|  |             if (!parser_eat(parser, ':')) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             labels = plabel_new(labels, *ident, false, loc); | ||||||
|  |             *ident = NULL; | ||||||
|  |         } else { | ||||||
|  |             parser_report( | ||||||
|  |                 parser, "expected identifier or ':'", parser->tok.loc); | ||||||
|  |             plabel_free(labels); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return labels; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const int parser_binary_prec = 6; | ||||||
|  | static inline POperand* parser_parse_operand_2(Parser* parser, int prec); | ||||||
|  | 
 | ||||||
|  | static inline POperand* parser_parse_operand_0(Parser* parser) | ||||||
|  | { | ||||||
|  |     Loc loc = parser->tok.loc; | ||||||
|  |     if (parser_eat(parser, TT_Ident)) { | ||||||
|  |         char* ident = parser_ident_val(parser, parser->eaten); | ||||||
|  |         const char* reg_key[10] = { | ||||||
|  |             "r0", "r1", "r2", "r3", "r4", "rbp", "rsp", "rfl", "rcs", "rip" | ||||||
|  |         }; | ||||||
|  |         Reg reg_val[10] = { R0, R1, R2, R3, R4, Rbp, Rsp, Rfl, Rcs, Rip }; | ||||||
|  |         for (size_t i = 0; i < 10; ++i) { | ||||||
|  |             if (strcmp(reg_key[i], ident) == 0) { | ||||||
|  |                 free(ident); | ||||||
|  |                 return poperand_new_reg(reg_val[i], loc); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return poperand_new_ident(PoTy_Ident, ident, loc); | ||||||
|  |     } else if (parser_eat(parser, TT_Int)) { | ||||||
|  |         char* str = parser_ident_val(parser, parser->eaten); | ||||||
|  |         uint16_t imm = (uint16_t)strtoul(str, NULL, 10); | ||||||
|  |         free(str); | ||||||
|  |         return poperand_new_imm(imm, loc); | ||||||
|  |     } else if (parser_eat(parser, TT_Binary)) { | ||||||
|  |         char* str = parser_ident_val(parser, parser->eaten); | ||||||
|  |         uint16_t imm = (uint16_t)strtoul(&str[2], NULL, 2); | ||||||
|  |         free(str); | ||||||
|  |         return poperand_new_imm(imm, loc); | ||||||
|  |     } else if (parser_eat(parser, TT_Hex)) { | ||||||
|  |         char* str = parser_ident_val(parser, parser->eaten); | ||||||
|  |         uint16_t imm = (uint16_t)strtoul(&str[2], NULL, 16); | ||||||
|  |         free(str); | ||||||
|  |         return poperand_new_imm(imm, loc); | ||||||
|  |     } else if (parser_eat(parser, '.')) { | ||||||
|  |         if (!parser_eat(parser, TT_Ident)) { | ||||||
|  |             parser_report(parser, "expected identifier", parser->tok.loc); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         char* ident = parser_ident_val(parser, parser->eaten); | ||||||
|  |         return poperand_new_ident(PoTy_SubLabel, ident, loc); | ||||||
|  |     } else if (parser_eat(parser, '(')) { | ||||||
|  |         POperand* operand = parser_parse_operand_2(parser, parser_binary_prec); | ||||||
|  |         if (!parser_eat(parser, ')')) { | ||||||
|  |             parser_report(parser, "expected ')'", parser->tok.loc); | ||||||
|  |             poperand_free(operand); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         return operand; | ||||||
|  |     } else { | ||||||
|  |         parser_report(parser, "expected operand", parser->tok.loc); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline POperand* parser_parse_operand_1(Parser* parser) | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     Loc loc = parser->tok.loc; | ||||||
|  |     if (parser_eat(parser, '-')) { | ||||||
|  |         POperand* operand = parser_parse_operand_1(parser); | ||||||
|  |         return poperand_new_unary(PoTy_Negate, operand, loc); | ||||||
|  |     } else if (parser_eat(parser, '!')) { | ||||||
|  |         POperand* operand = parser_parse_operand_1(parser); | ||||||
|  |         return poperand_new_unary(PoTy_Not, operand, loc); | ||||||
|  |     } else { | ||||||
|  |         return parser_parse_operand_0(parser); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline POperand* parser_parse_operand_2(Parser* parser, int prec) | ||||||
|  | { | ||||||
|  |     const POperandTy op_tys[] = { | ||||||
|  |         PoTy_Or, | ||||||
|  |         PoTy_Xor, | ||||||
|  |         PoTy_And, | ||||||
|  |         PoTy_Shl, | ||||||
|  |         PoTy_Shr, | ||||||
|  |         PoTy_Add, | ||||||
|  |         PoTy_Sub, | ||||||
|  |         PoTy_Mul, | ||||||
|  |         PoTy_Div, | ||||||
|  |         PoTy_Mod, | ||||||
|  |     }; | ||||||
|  |     const TokTy op_tts[] = { | ||||||
|  |         '|', | ||||||
|  |         '^', | ||||||
|  |         '&', | ||||||
|  |         TT_DoubleGt, | ||||||
|  |         TT_DoubleLt, | ||||||
|  |         '+', | ||||||
|  |         '-', | ||||||
|  |         '*', | ||||||
|  |         '/', | ||||||
|  |         '%', | ||||||
|  |     }; | ||||||
|  |     const int op_precs[] = { 6, 5, 4, 3, 3, 2, 2, 1, 1, 1 }; | ||||||
|  |     static_assert(sizeof(op_tys) / sizeof(op_tys[0]) | ||||||
|  |             == sizeof(op_tts) / sizeof(op_tts[0]), | ||||||
|  |         "misaligned"); | ||||||
|  |     static_assert(sizeof(op_tys) / sizeof(op_tys[0]) | ||||||
|  |             == sizeof(op_precs) / sizeof(op_precs[0]), | ||||||
|  |         "misaligned"); | ||||||
|  | 
 | ||||||
|  |     if (prec == 0) { | ||||||
|  |         return parser_parse_operand_1(parser); | ||||||
|  |     } | ||||||
|  |     POperand* left = parser_parse_operand_2(parser, prec - 1); | ||||||
|  |     bool should_continue = true; | ||||||
|  |     while (should_continue) { | ||||||
|  |         should_continue = false; | ||||||
|  |         for (size_t i = 0; i < sizeof(op_tys) / sizeof(op_tys[0]); ++i) { | ||||||
|  |             if (prec >= op_precs[i] && parser_eat(parser, op_tts[i])) { | ||||||
|  |                 POperand* right = parser_parse_operand_2(parser, prec - 1); | ||||||
|  |                 left = poperand_new_binary(op_tys[0], left, right, left->loc); | ||||||
|  |                 should_continue = true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return left; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline POperand* parser_parse_operand_3(Parser* parser) | ||||||
|  | { | ||||||
|  |     if (!parser_test(parser, TT_Ident)) { | ||||||
|  |         return parser_parse_operand_2(parser, parser_binary_prec); | ||||||
|  |     } | ||||||
|  |     Loc loc = parser->tok.loc; | ||||||
|  |     char* ident = parser_ident_val(parser, parser->eaten); | ||||||
|  |     if (strcmp(ident, "u8") == 0) { | ||||||
|  |         free(ident); | ||||||
|  |         if (!parser_eat(parser, '[')) { | ||||||
|  |             parser_report(parser, "expected '['", parser->tok.loc); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         POperand* operand = parser_parse_operand_2(parser, parser_binary_prec); | ||||||
|  |         if (!parser_eat(parser, ']')) { | ||||||
|  |             parser_report(parser, "expected ']'", parser->tok.loc); | ||||||
|  |             poperand_free(operand); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         return poperand_new_unary(PoTy_MemU8, operand, loc); | ||||||
|  |     } else if (strcmp(ident, "u16") == 0) { | ||||||
|  |         free(ident); | ||||||
|  |         if (!parser_eat(parser, '[')) { | ||||||
|  |             parser_report(parser, "expected '['", parser->tok.loc); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         POperand* operand = parser_parse_operand_2(parser, parser_binary_prec); | ||||||
|  |         if (!parser_eat(parser, ']')) { | ||||||
|  |             parser_report(parser, "expected ']'", parser->tok.loc); | ||||||
|  |             poperand_free(operand); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         return poperand_new_unary(PoTy_MemU16, operand, loc); | ||||||
|  |     } else { | ||||||
|  |         free(ident); | ||||||
|  |         return parser_parse_operand_2(parser, parser_binary_prec); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PLine* parser_next(Parser* parser) | ||||||
|  | { | ||||||
|  |     char* ident; | ||||||
|  |     Loc loc; | ||||||
|  |     PLabel* labels = parser_parse_labels(parser, &ident, &loc); | ||||||
|  | 
 | ||||||
|  |     POperand* ops[3]; | ||||||
|  |     size_t ops_size = 0; | ||||||
|  | 
 | ||||||
|  |     if (!parser_test(parser, TT_Eof) && !parser_test(parser, '\n')) { | ||||||
|  |         POperand* operand = parser_parse_operand_3(parser); | ||||||
|  |         if (!operand) { | ||||||
|  |             goto error_free_ops; | ||||||
|  |         } | ||||||
|  |         ops[ops_size++] = operand; | ||||||
|  |         while (!parser_test(parser, TT_Eof) && !parser_test(parser, '\n') | ||||||
|  |             && ops_size < 3) { | ||||||
|  |             if (!parser_eat(parser, ',')) { | ||||||
|  |                 parser_report(parser, "expected ','", parser->tok.loc); | ||||||
|  |                 goto error_free_ops; | ||||||
|  |             } | ||||||
|  |             POperand* operand = parser_parse_operand_3(parser); | ||||||
|  |             if (!operand) { | ||||||
|  |                 goto error_free_ops; | ||||||
|  |             } | ||||||
|  |             ops[ops_size++] = operand; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (!parser_eat(parser, '\n') && !parser_test(parser, TT_Eof)) { | ||||||
|  |         parser_report(parser, "expected newline", parser->tok.loc); | ||||||
|  |         goto error_free_ops; | ||||||
|  |     } | ||||||
|  |     parser_skip_newlines(parser); | ||||||
|  | 
 | ||||||
|  |     switch (ops_size) { | ||||||
|  |         case 0: | ||||||
|  |             return pline_new_0(ident, labels, loc); | ||||||
|  |         case 1: | ||||||
|  |             return pline_new_1(ident, labels, loc, ops[0]); | ||||||
|  |         case 2: | ||||||
|  |             return pline_new_2(ident, labels, loc, ops[0], ops[1]); | ||||||
|  |         case 3: | ||||||
|  |         default: | ||||||
|  |             return pline_new_3(ident, labels, loc, ops[0], ops[1], ops[2]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | error_free_ops: | ||||||
|  |     for (size_t i = 0; i < ops_size; ++i) | ||||||
|  |         if (ops[i]) | ||||||
|  |             poperand_free(ops[i]); | ||||||
|  |     plabel_free(labels); | ||||||
|  |     free(ident); | ||||||
|  |     return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     const char* input_file; | ||||||
|  |     const char* output_file; | ||||||
|  | } Args; | ||||||
|  | 
 | ||||||
|  | static inline Args parse_args(int argc, char** argv); | ||||||
|  | 
 | ||||||
|  | int main(int argc, char** argv) | ||||||
|  | { | ||||||
|  |     Args args = parse_args(argc, argv); | ||||||
|  | 
 | ||||||
|  |     FILE* input_fp = fopen(args.input_file, "r"); | ||||||
|  |     if (!input_fp) { | ||||||
|  |         fprintf(stderr, | ||||||
|  |             "error: could not open input file '%s': %s\n", | ||||||
|  |             args.input_file, | ||||||
|  |             strerror(errno)); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     fseek(input_fp, 0L, SEEK_END); | ||||||
|  |     size_t file_size = (size_t)ftell(input_fp); | ||||||
|  |     rewind(input_fp); | ||||||
|  | 
 | ||||||
|  |     char* input_text = calloc(file_size + 1, sizeof(char)); | ||||||
|  |     size_t bytes_read = fread(input_text, sizeof(char), file_size, input_fp); | ||||||
|  |     fclose(input_fp); | ||||||
|  |     if (bytes_read != file_size) { | ||||||
|  |         fprintf(stderr, | ||||||
|  |             "error: could not read input file '%s': %s\n", | ||||||
|  |             args.input_file, | ||||||
|  |             strerror(errno)); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Parser parser; | ||||||
|  |     parser_construct(&parser, args.input_file, input_text); | ||||||
|  | 
 | ||||||
|  |     while (!parser_done(&parser)) { | ||||||
|  |         PLine* line = parser_next(&parser); | ||||||
|  |         if (!line) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         pline_free(line); | ||||||
|  |         if (parser_error_occured(&parser)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     free(input_text); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline Args parse_args(int argc, char** argv) | ||||||
|  | { | ||||||
|  |     const char* input_file = NULL; | ||||||
|  |     const char* output_file = NULL; | ||||||
|  |     for (int i = 1; i < argc; ++i) { | ||||||
|  |         if (strcmp(argv[i], "-o") == 0) { | ||||||
|  |             i += 1; | ||||||
|  |             if (i >= argc) { | ||||||
|  |                 fprintf(stderr, "error: no filename given to -o\n"); | ||||||
|  |                 exit(1); | ||||||
|  |             } | ||||||
|  |             output_file = argv[i]; | ||||||
|  |         } else { | ||||||
|  |             if (input_file != NULL) { | ||||||
|  |                 fprintf(stderr, "error: multiple input files specified\n"); | ||||||
|  |                 exit(1); | ||||||
|  |             } | ||||||
|  |             input_file = argv[i]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (input_file == NULL) { | ||||||
|  |         fprintf(stderr, "error: no input file\n"); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  |     if (output_file == NULL) { | ||||||
|  |         output_file = "out.o"; | ||||||
|  |     } | ||||||
|  |     return (Args) { | ||||||
|  |         input_file, | ||||||
|  |         output_file, | ||||||
|  |     }; | ||||||
|  | } | ||||||
							
								
								
									
										140
									
								
								kern/main.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								kern/main.asm
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | |||||||
|  | 
 | ||||||
|  | start: | ||||||
|  |     ; rsp points *at* the top element | ||||||
|  |     mov Rbp, 2048 | ||||||
|  |     mov rsp, 2048 - 2 | ||||||
|  | 
 | ||||||
|  |     lit interrupt_table | ||||||
|  |     or rfl, rfl, 1 << Fl_Int | ||||||
|  | 
 | ||||||
|  |     or rfl, Rfl, 1 << Fl_Vcd | ||||||
|  | 
 | ||||||
|  |     mov16 r0, 512 | ||||||
|  |     mov16 r1, 1 | ||||||
|  |     int Int_DiskRead | ||||||
|  | 
 | ||||||
|  | main_loop: | ||||||
|  |     hlt | ||||||
|  |     jmp main_loop | ||||||
|  | 
 | ||||||
|  | interrupt_table: | ||||||
|  |     ; size | ||||||
|  |     d16 1  | ||||||
|  |     data keyboard_interrupt | ||||||
|  |     nop | ||||||
|  | 
 | ||||||
|  | keyboard_interrupt: | ||||||
|  |     and rfl, rfl, !(1 << Fl_Int) | ||||||
|  |     push rbp | ||||||
|  |     mov rbp, Rsp | ||||||
|  |     push r0 | ||||||
|  |     push r1 | ||||||
|  |     push r2 | ||||||
|  |     push r3 | ||||||
|  | 
 | ||||||
|  |     in r0, Device_Keyboard | ||||||
|  | 
 | ||||||
|  |     cmp r0, 44 | ||||||
|  |     mov r1, rfl | ||||||
|  |     and r1, r1, 1 << Fl_Eq | ||||||
|  |     jnz r1, .L0 | ||||||
|  | 
 | ||||||
|  |     cmp r0, 42 | ||||||
|  |     mov16 r1, rfl | ||||||
|  |     and r1, r1, 1 << Fl_Eq | ||||||
|  |     jnz r1, .L1 | ||||||
|  | 
 | ||||||
|  |     cmp r0, 40 | ||||||
|  |     mov r1, rfl | ||||||
|  |     and r1, r1, 1 << Fl_Eq | ||||||
|  |     jnz r1, .L2 | ||||||
|  | 
 | ||||||
|  |     jmp .L3 | ||||||
|  | 
 | ||||||
|  | .L0: | ||||||
|  |     mov R0, 32 ; ' ' | ||||||
|  |     call put_char | ||||||
|  |     jmp .L4 | ||||||
|  | 
 | ||||||
|  | .L1: | ||||||
|  |     mov r1, screen_x | ||||||
|  |     cmp r1, 0 | ||||||
|  |     mov r2, rfl | ||||||
|  |     and r2, r2, 1 << Fl_Eq | ||||||
|  |     jnz r2, .L4 | ||||||
|  |     sub r1, r1, 1 | ||||||
|  |     mov screen_x, R1 | ||||||
|  |     ; mov r0, ' ' | ||||||
|  |     call put_char | ||||||
|  |     mov16 r1, screen_x | ||||||
|  |     sub r1, r1, 1 | ||||||
|  |     mov screen_x, R1 | ||||||
|  |     jmp .L4 | ||||||
|  | 
 | ||||||
|  | .L2: | ||||||
|  |     mov r1, screen_y | ||||||
|  |     add r1, r1, 1 | ||||||
|  |     mov screen_y, R1 | ||||||
|  |     mov r1, 0 | ||||||
|  |     mov screen_x, R1 | ||||||
|  |     jmp .L4 | ||||||
|  | 
 | ||||||
|  | .L3: | ||||||
|  |     ; add r0, r0, 'A' - 4 | ||||||
|  |     call put_char | ||||||
|  |     jmp .L4 | ||||||
|  | 
 | ||||||
|  | .L4: | ||||||
|  | 
 | ||||||
|  |     pop r3 | ||||||
|  |     pop r2 | ||||||
|  |     pop r1 | ||||||
|  |     pop r0 | ||||||
|  |     mov rsp, rbp | ||||||
|  |     pop rbp | ||||||
|  |     or rfl, rfl, 1 << Fl_Int | ||||||
|  |     iret | ||||||
|  | 
 | ||||||
|  | put_char: | ||||||
|  |     push rbp | ||||||
|  |     mov rbp, rsp | ||||||
|  |     push r1 | ||||||
|  |     push r2 | ||||||
|  | 
 | ||||||
|  |     mov r2, screen_y | ||||||
|  |     mul r2, r2, vcd_width_in_ch | ||||||
|  |     mov r1, screen_x | ||||||
|  |     add r1, r1, 0x0c00 | ||||||
|  |     add r1, r1, r2 | ||||||
|  |     mov r1, r0 | ||||||
|  | 
 | ||||||
|  |     mov r1, screen_x | ||||||
|  |     add r1, r1, 1 | ||||||
|  |     mov screen_x, r1 | ||||||
|  | 
 | ||||||
|  |     cmp r1, vcd_width_in_ch | ||||||
|  |     mov r2, rfl | ||||||
|  |     and r2, r2, 1 << Fl_Eq | ||||||
|  |     jnz r2, .L0 | ||||||
|  |     jmp .L1 | ||||||
|  | 
 | ||||||
|  | .L0: | ||||||
|  |     mov r1, screen_y | ||||||
|  |     add r1, r1, 1 | ||||||
|  |     mov screen_y, r1 | ||||||
|  |     mov r1, 0 | ||||||
|  |     mov screen_x, r1 | ||||||
|  | 
 | ||||||
|  | .L1: | ||||||
|  |     pop r1 | ||||||
|  |     pop r2 | ||||||
|  |     mov rsp, rbp | ||||||
|  |     pop rbp | ||||||
|  |     ret | ||||||
|  | 
 | ||||||
|  | screen_x: | ||||||
|  |     d16 0 | ||||||
|  | screen_y: | ||||||
|  |     d16 0 | ||||||
|  | 
 | ||||||
|  | ; vim: syntax=nasm | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user