1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
#include <ek/ops.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
/* I guess using the zero register might be okay in some scenarios, but for now
* I'll just keep it an illegal register */
#define ASSERT_REG(x) {assert(x->kind == LOC_REG); assert(x->reg > 0 && x->reg < 81);}
#define ASSERT_MEM(x) {assert(x->kind == LOC_MEM); assert(x->reg > 0 && x->reg < 81);}
static int print_comment(struct op *op, FILE *f)
{
fprintf(f, "/* %s */\n", op->string);
return 0;
}
static int print_label(struct op *op, FILE *f)
{
fprintf(f, "%s:\n", op->string);
return 0;
}
static int print_li(struct op *op, FILE *f)
{
struct loc *o = &op->outputs;
assert(o->next == NULL);
/* unsure if this will always hold, but for now */
ASSERT_REG(o);
fprintf(f, "li x%zd, %lld\n", o->reg, op->constant);
return 0;
}
static int print_mv(struct op *op, FILE *f)
{
struct loc *i = &op->inputs;
struct loc *o = &op->outputs;
assert(i->next == NULL);
assert(o->next == NULL);
ASSERT_REG(i);
ASSERT_REG(o);
fprintf(f, "mv x%zd, x%zd\n", o->reg, i->reg);
return 0;
}
static int print_stt(struct op *op, FILE *f)
{
struct loc *i = &op->inputs;
struct loc *o = &op->outputs;
assert(i->next == NULL);
assert(o->next == NULL);
ASSERT_REG(i);
ASSERT_MEM(o);
fprintf(f, "st t, x%zd, %lld(x%zd)\n", i->reg, o->off, o->reg);
return 0;
}
static int print_ret(struct op *op, FILE *f)
{
/* technically speaking ret takes a number of inputs, but they should be
* marshaled into registers with moves etc. so don't worry about them
* here */
fprintf(f, "jalr x0, 0(x21)\n");
/* eventually add in proper ret alias to assembly language once I go
* through calling conventions etc. */
return 0;
}
static int print_op(struct op *op, FILE *f)
{
int ret = 0;
switch (op->opcode) {
case OP_COMMENT: ret = print_comment(op, f); break;
case OP_LABEL: ret = print_label(op, f); break;
case OP_LI: ret = print_li(op, f); break;
case OP_MV: ret = print_mv(op, f); break;
case OP_STT: ret = print_stt(op, f); break;
case OP_RET: ret = print_ret(op, f); break;
default: abort();
}
return ret;
}
int print_asm(struct ops *ops, const char *output)
{
FILE *f = fopen(output, "w");
/* main should probably be mangled here as well */
fprintf(f, "jal x21, main\n");
/* tell simulator to turn off (very much temp) */
fprintf(f, "li x1, 3\n");
fprintf(f, "csrrw mpower, x0, x1\n");
int ret = 0;
struct op *op = ops->base;
while (op) {
if ((ret = print_op(op, f)))
break;
op = op->next;
}
fclose(f);
return ret;
}
|