Compare commits
2 Commits
4f6520c470
...
0bdbaa7f1f
Author | SHA1 | Date | |
---|---|---|---|
0bdbaa7f1f | |||
af0214739c |
1
Makefile
1
Makefile
@ -8,7 +8,6 @@ C_FLAGS = \
|
||||
-Wall -Wextra -Wpedantic -Wconversion \
|
||||
-pedantic -pedantic-errors \
|
||||
-Wno-unused-variable \
|
||||
-Wno-unused-parameter \
|
||||
-I. \
|
||||
|
||||
L_FLAGS = -pthread
|
||||
|
@ -114,7 +114,7 @@ typedef struct {
|
||||
uint16_t offset;
|
||||
} Line;
|
||||
|
||||
uint16_t assemble_to_binary(
|
||||
uint16_t assemble_lines_with_labels(
|
||||
uint16_t* out, const Line* lines, size_t lines_size);
|
||||
|
||||
Line s_label(int label);
|
||||
|
@ -105,6 +105,7 @@ Line s_jnz_l(Reg op1_reg, int op2_label)
|
||||
{
|
||||
return (Line) {
|
||||
.ty = LineTy_Jnz_Label,
|
||||
.op1 = (Ex) { .reg = (uint16_t)op1_reg },
|
||||
.op2 = (Ex) { .label = op2_label },
|
||||
};
|
||||
}
|
||||
|
175
asm/main.c
175
asm/main.c
@ -37,6 +37,8 @@ typedef enum {
|
||||
TT_Int,
|
||||
TT_Binary,
|
||||
TT_Hex,
|
||||
TT_Char,
|
||||
TT_Str,
|
||||
TT_Newline = '\n',
|
||||
TT_DoubleLt,
|
||||
TT_DoubleGt,
|
||||
@ -119,6 +121,18 @@ 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 int lexer_skip_literal_char(Lexer* lexer)
|
||||
{
|
||||
char ch = lexer->ch;
|
||||
lexer_step(lexer);
|
||||
if (ch == '\\') {
|
||||
if (lexer_done(lexer))
|
||||
return -1;
|
||||
lexer_step(lexer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void lexer_report(Lexer* lexer, const char* msg, Loc loc)
|
||||
{
|
||||
lexer->error_occured = true;
|
||||
@ -138,7 +152,7 @@ static inline void lexer_report(Lexer* lexer, const char* msg, Loc loc)
|
||||
int line_len = (int)line_end - (int)line_start;
|
||||
|
||||
fprintf(stderr,
|
||||
"error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n",
|
||||
"error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n",
|
||||
msg,
|
||||
lexer->filename,
|
||||
loc.line,
|
||||
@ -146,14 +160,14 @@ static inline void lexer_report(Lexer* lexer, const char* msg, Loc loc)
|
||||
loc.line,
|
||||
line_len,
|
||||
line,
|
||||
loc.col - 2,
|
||||
loc.col - 1,
|
||||
' ');
|
||||
}
|
||||
|
||||
Tok lexer_next(Lexer* lexer)
|
||||
{
|
||||
const char* ident_chars = "abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_";
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
|
||||
const char* int_chars = "1234567890";
|
||||
const char* hex_chars = "01234567889abcdefABCDEF";
|
||||
|
||||
@ -212,6 +226,26 @@ Tok lexer_next(Lexer* lexer)
|
||||
} else {
|
||||
return lexer_tok(lexer, TT_Int, loc);
|
||||
}
|
||||
} else if (lexer->ch == '\'') {
|
||||
lexer_step(lexer);
|
||||
lexer_skip_literal_char(lexer);
|
||||
if (lexer_done(lexer) || lexer->ch != '\'') {
|
||||
lexer_report(lexer, "malformed character literal", loc);
|
||||
return lexer_tok(lexer, TT_Err, loc);
|
||||
}
|
||||
lexer_step(lexer);
|
||||
return lexer_tok(lexer, TT_Char, loc);
|
||||
} else if (lexer->ch == '"') {
|
||||
lexer_step(lexer);
|
||||
while (!lexer_done(lexer) && lexer->ch != '"') {
|
||||
lexer_skip_literal_char(lexer);
|
||||
}
|
||||
if (lexer_done(lexer) || lexer->ch != '"') {
|
||||
lexer_report(lexer, "malformed string literal", loc);
|
||||
return lexer_tok(lexer, TT_Err, loc);
|
||||
}
|
||||
lexer_step(lexer);
|
||||
return lexer_tok(lexer, TT_Str, loc);
|
||||
} else if (lexer->ch == '<') {
|
||||
lexer_step(lexer);
|
||||
if (!lexer_done(lexer) && lexer->ch == '<') {
|
||||
@ -235,9 +269,9 @@ Tok lexer_next(Lexer* lexer)
|
||||
lexer_step(lexer);
|
||||
return lexer_tok(lexer, (TokTy)ch, loc);
|
||||
} else {
|
||||
lexer_report(lexer, "illegal character '%c'", loc);
|
||||
lexer_report(lexer, "illegal character", loc);
|
||||
lexer_step(lexer);
|
||||
return lexer_next(lexer);
|
||||
return lexer_tok(lexer, TT_Err, loc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,6 +327,7 @@ typedef enum {
|
||||
PoTy_Imm,
|
||||
PoTy_Ident,
|
||||
PoTy_SubLabel,
|
||||
PoTy_Str,
|
||||
PoTy_MemU8,
|
||||
PoTy_MemU16,
|
||||
PoTy_Not,
|
||||
@ -317,7 +352,7 @@ struct POperand {
|
||||
union {
|
||||
Reg reg;
|
||||
uint16_t imm;
|
||||
char* ident;
|
||||
char* str;
|
||||
POperand* operand;
|
||||
struct {
|
||||
POperand* left;
|
||||
@ -338,10 +373,10 @@ POperand* poperand_new_imm(uint16_t imm, Loc loc)
|
||||
*operand = (POperand) { .ty = PoTy_Imm, .loc = loc, .imm = imm };
|
||||
return operand;
|
||||
}
|
||||
POperand* poperand_new_ident(POperandTy ty, char* ident, Loc loc)
|
||||
POperand* poperand_new_str(POperandTy ty, char* str, Loc loc)
|
||||
{
|
||||
POperand* operand = malloc(sizeof(POperand));
|
||||
*operand = (POperand) { .ty = ty, .loc = loc, .ident = ident };
|
||||
*operand = (POperand) { .ty = ty, .loc = loc, .str = str };
|
||||
return operand;
|
||||
}
|
||||
POperand* poperand_new_unary(POperandTy ty, POperand* inner, Loc loc)
|
||||
@ -366,7 +401,8 @@ void poperand_free(POperand* operand)
|
||||
break;
|
||||
case PoTy_Ident:
|
||||
case PoTy_SubLabel:
|
||||
free(operand->ident);
|
||||
case PoTy_Str:
|
||||
free(operand->str);
|
||||
break;
|
||||
case PoTy_MemU8:
|
||||
case PoTy_MemU16:
|
||||
@ -399,40 +435,19 @@ typedef struct {
|
||||
POperand* ops[];
|
||||
} PLine;
|
||||
|
||||
PLine* pline_new_0(char* op, PLabel* labels, Loc loc)
|
||||
PLine* pline_new(
|
||||
char* op, PLabel* labels, Loc loc, size_t ops_size, POperand** ops)
|
||||
{
|
||||
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;
|
||||
PLine* line = malloc(sizeof(PLine) + sizeof(POperand*) * ops_size);
|
||||
*line = (PLine) {
|
||||
.labels = labels,
|
||||
.op = op,
|
||||
.loc = loc,
|
||||
.ops_size = ops_size,
|
||||
};
|
||||
for (size_t i = 0; i < ops_size; ++i) {
|
||||
line->ops[i] = ops[i];
|
||||
}
|
||||
return line;
|
||||
}
|
||||
void pline_free(PLine* pline)
|
||||
@ -515,7 +530,7 @@ static inline void parser_report(Parser* parser, const char* msg, Loc loc)
|
||||
int line_len = (int)line_end - (int)line_start;
|
||||
|
||||
fprintf(stderr,
|
||||
"error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n",
|
||||
"error: %s\n --> %s:%d:%d\n |\n%5d|%.*s\n |%*c^\n",
|
||||
msg,
|
||||
parser->lexer.filename,
|
||||
loc.line,
|
||||
@ -523,7 +538,7 @@ static inline void parser_report(Parser* parser, const char* msg, Loc loc)
|
||||
loc.line,
|
||||
line_len,
|
||||
line,
|
||||
loc.col - 2,
|
||||
loc.col - 1,
|
||||
' ');
|
||||
}
|
||||
|
||||
@ -572,6 +587,24 @@ static inline PLabel* parser_parse_labels(
|
||||
return labels;
|
||||
}
|
||||
|
||||
static inline char literal_char_val(const char* str)
|
||||
{
|
||||
if (str[0] == '\\') {
|
||||
switch (str[1]) {
|
||||
case '0':
|
||||
return 0;
|
||||
case 't':
|
||||
return '\t';
|
||||
case 'n':
|
||||
return '\n';
|
||||
default:
|
||||
return str[1];
|
||||
}
|
||||
} else {
|
||||
return str[0];
|
||||
}
|
||||
}
|
||||
|
||||
static const int parser_binary_prec = 6;
|
||||
static inline POperand* parser_parse_operand_2(Parser* parser, int prec);
|
||||
|
||||
@ -590,7 +623,7 @@ static inline POperand* parser_parse_operand_0(Parser* parser)
|
||||
return poperand_new_reg(reg_val[i], loc);
|
||||
}
|
||||
}
|
||||
return poperand_new_ident(PoTy_Ident, ident, loc);
|
||||
return poperand_new_str(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);
|
||||
@ -606,13 +639,28 @@ static inline POperand* parser_parse_operand_0(Parser* parser)
|
||||
uint16_t imm = (uint16_t)strtoul(&str[2], NULL, 16);
|
||||
free(str);
|
||||
return poperand_new_imm(imm, loc);
|
||||
} else if (parser_eat(parser, TT_Char)) {
|
||||
char* str = parser_ident_val(parser, parser->eaten);
|
||||
uint16_t imm = (uint16_t)literal_char_val(&str[1]);
|
||||
free(str);
|
||||
return poperand_new_imm(imm, loc);
|
||||
} else if (parser_eat(parser, TT_Str)) {
|
||||
char* lit = parser_ident_val(parser, parser->eaten);
|
||||
size_t lit_len = strlen(lit);
|
||||
char* str = calloc(lit_len - 1, sizeof(char));
|
||||
size_t str_len = 0;
|
||||
for (size_t i = 1; i < lit_len - 2; ++i) {
|
||||
str[i] = literal_char_val(&lit[i]);
|
||||
}
|
||||
free(lit);
|
||||
return poperand_new_str(PoTy_Str, str, 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);
|
||||
return poperand_new_str(PoTy_SubLabel, ident, loc);
|
||||
} else if (parser_eat(parser, '(')) {
|
||||
POperand* operand = parser_parse_operand_2(parser, parser_binary_prec);
|
||||
if (!parser_eat(parser, ')')) {
|
||||
@ -697,13 +745,18 @@ static inline POperand* parser_parse_operand_2(Parser* parser, int prec)
|
||||
|
||||
static inline POperand* parser_parse_operand_3(Parser* parser)
|
||||
{
|
||||
Loc loc = parser->tok.loc;
|
||||
if (parser_eat(parser, TT_LBracket)) {
|
||||
parser_report(parser, "expected 'u8' or 'u16'", loc);
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
char* ident = parser_ident_val(parser, parser->tok);
|
||||
if (strcmp(ident, "u8") == 0) {
|
||||
free(ident);
|
||||
parser_step(parser);
|
||||
if (!parser_eat(parser, '[')) {
|
||||
parser_report(parser, "expected '['", parser->tok.loc);
|
||||
return NULL;
|
||||
@ -717,6 +770,7 @@ static inline POperand* parser_parse_operand_3(Parser* parser)
|
||||
return poperand_new_unary(PoTy_MemU8, operand, loc);
|
||||
} else if (strcmp(ident, "u16") == 0) {
|
||||
free(ident);
|
||||
parser_step(parser);
|
||||
if (!parser_eat(parser, '[')) {
|
||||
parser_report(parser, "expected '['", parser->tok.loc);
|
||||
return NULL;
|
||||
@ -740,7 +794,9 @@ PLine* parser_next(Parser* parser)
|
||||
Loc loc;
|
||||
PLabel* labels = parser_parse_labels(parser, &ident, &loc);
|
||||
|
||||
POperand* ops[3];
|
||||
const size_t max_ops_size = 64;
|
||||
// TODO: Move allocation out-of-band.
|
||||
POperand** ops = malloc(sizeof(POperand) * max_ops_size);
|
||||
size_t ops_size = 0;
|
||||
|
||||
if (!parser_test(parser, TT_Eof) && !parser_test(parser, '\n')) {
|
||||
@ -751,6 +807,12 @@ PLine* parser_next(Parser* parser)
|
||||
ops[ops_size++] = operand;
|
||||
while (!parser_test(parser, TT_Eof) && !parser_test(parser, '\n')
|
||||
&& ops_size < 3) {
|
||||
if (ops_size >= max_ops_size) {
|
||||
parser_report(parser,
|
||||
"exceeded maximum number of operands (64)",
|
||||
parser->tok.loc);
|
||||
goto error_free_ops;
|
||||
}
|
||||
if (!parser_eat(parser, ',')) {
|
||||
parser_report(parser, "expected ','", parser->tok.loc);
|
||||
goto error_free_ops;
|
||||
@ -768,22 +830,15 @@ PLine* parser_next(Parser* parser)
|
||||
}
|
||||
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]);
|
||||
}
|
||||
PLine* line = pline_new(ident, labels, loc, ops_size, ops);
|
||||
free(ops);
|
||||
return line;
|
||||
|
||||
error_free_ops:
|
||||
for (size_t i = 0; i < ops_size; ++i)
|
||||
if (ops[i])
|
||||
poperand_free(ops[i]);
|
||||
free(ops);
|
||||
plabel_free(labels);
|
||||
free(ident);
|
||||
return NULL;
|
||||
|
@ -7,7 +7,7 @@
|
||||
-pedantic
|
||||
-pedantic-errors
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-parameter
|
||||
# -Wno-unused-parameter
|
||||
# -Wno-unused-function
|
||||
-I.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
start:
|
||||
; rsp points *at* the top element
|
||||
mov Rbp, 2048
|
||||
mov rbp, 2048
|
||||
mov rsp, 2048 - 2
|
||||
|
||||
lit interrupt_table
|
||||
@ -25,12 +25,22 @@ interrupt_table:
|
||||
|
||||
keyboard_interrupt:
|
||||
and rfl, rfl, !(1 << Fl_Int)
|
||||
push rbp
|
||||
; push rbp
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], rbp
|
||||
mov rbp, Rsp
|
||||
push r0
|
||||
push r1
|
||||
push r2
|
||||
push r3
|
||||
; push r0
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], r0
|
||||
; push r1
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], r1
|
||||
; push r2
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], r2
|
||||
; push r3
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], r3
|
||||
|
||||
in r0, Device_Keyboard
|
||||
|
||||
@ -52,7 +62,7 @@ keyboard_interrupt:
|
||||
jmp .L3
|
||||
|
||||
.L0:
|
||||
mov R0, 32 ; ' '
|
||||
mov R0, ' '
|
||||
call put_char
|
||||
jmp .L4
|
||||
|
||||
@ -80,26 +90,42 @@ keyboard_interrupt:
|
||||
jmp .L4
|
||||
|
||||
.L3:
|
||||
; add r0, r0, 'A' - 4
|
||||
add r0, r0, 'A' - 4
|
||||
call put_char
|
||||
jmp .L4
|
||||
|
||||
.L4:
|
||||
|
||||
pop r3
|
||||
pop r2
|
||||
pop r1
|
||||
pop r0
|
||||
; pop r3
|
||||
mov r3, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
; pop r2
|
||||
mov r2, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
; pop r1
|
||||
mov r1, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
; pop r0
|
||||
mov r0, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
; pop rbp
|
||||
mov rbp, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
or rfl, rfl, 1 << Fl_Int
|
||||
iret
|
||||
|
||||
put_char:
|
||||
push rbp
|
||||
; push rbp
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], rbp
|
||||
mov rbp, rsp
|
||||
push r1
|
||||
push r2
|
||||
; push r1
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], r1
|
||||
; push r2
|
||||
add rsp, rsp, 2
|
||||
mov u16 [rsp], r2
|
||||
|
||||
mov r2, screen_y
|
||||
mul r2, r2, vcd_width_in_ch
|
||||
@ -126,10 +152,16 @@ put_char:
|
||||
mov screen_x, r1
|
||||
|
||||
.L1:
|
||||
pop r1
|
||||
pop r2
|
||||
; pop r1
|
||||
mov r1, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
; pop r2
|
||||
mov r2, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
; pop rbp
|
||||
mov rbp, u16 [rsp]
|
||||
sub rsp, rsp, 2
|
||||
ret
|
||||
|
||||
screen_x:
|
||||
|
@ -203,7 +203,7 @@ void write_program(FILE* fp)
|
||||
|
||||
printf("assembling program...\n");
|
||||
uint16_t program_size
|
||||
= assemble_to_binary(program, program_asm, program_asm_size);
|
||||
= assemble_lines_with_labels(program, program_asm, program_asm_size);
|
||||
printf("done!\n");
|
||||
printf("program size = %d\n", program_size);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user