aboutsummaryrefslogtreecommitdiff
path: root/tools/stack_machine_instruction.h
blob: 003fa19caa99ba10c2bb671a97a78394f2e62bf1 (about) (plain)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <stdbool.h>

#include "wasm_compile.h"

/*
 * TODO: this enum is to be removed; it it only still here as a cheat sheet
 * for use when defining missing inline functions for those instructions
 */
enum instruction_code {
	STORE,
	STORE_P,
	STOREB,
	STOREB_P,
	STOREW,
	STOREW_P,
	LOAD,
	LOAD_P,
	LOADBZX,
	LOADBZX_P,
	LOADBSX,
	LOADBSX_P,
	LOADWZX,
	LOADWZX_P,
	LOADWSX,
	LOADWSX_P,
	HALT,
	NOP,
	SWAP,
	SET_SP,
	JUMP,
	TEE,
	GET_FRAME,
	CONST,
	CALL,
	ADD,
	SUB,
	DIV,
	MUL,
	DROP,
	RET,
	COND_JUMP
};

#define DATA_NONE            0
#define DATA_KNOWN           1
#define DATA_KNOWN_21_BITS   2
#define DATA_KNOWN_6_BITS    3
#define DATA_INSTR_ADDR      4
#define DATA_ADDR_AFTER      5

struct instruction_data {
	char info;
	union {
		uint32_t im;
		struct instruction **ptr;
	} data;
};

struct instruction {
	struct instruction *prev, *next;
	uint32_t address;
	bool address_assigned;
	uint16_t encoding;
	struct instruction_data data;
};

#define NO_DATA ((struct instruction_data) {			\
			.info = DATA_NONE			\
		})

inline static uint8_t im_instruction_size(int32_t im)
{
	if (im < POW(6) && im >= -POW(6))
		return 2;
	else if (im < POW(21) && im >= -POW(21))
		return 4;
	else
		return 6;
}

inline static struct instruction_data im(uint32_t im)
{
	struct instruction_data data;

	data.data.im = im;

	uint8_t size = im_instruction_size(im);

	if (size == 2)
		data.info = DATA_KNOWN_6_BITS;
	else if (size == 4)
		data.info = DATA_KNOWN_21_BITS;
	else
		data.info = DATA_KNOWN;

	return data;
}

inline static struct instruction_data ptr(struct instruction **val) {
	struct instruction_data data;

	data.info = DATA_INSTR_ADDR;
	data.data.ptr = val;

	return data;
}

inline static struct instruction_data ptr_after(struct instruction **val) {
	struct instruction_data data;

	data.info = DATA_ADDR_AFTER;
	data.data.ptr = val;

	return data;
}

int add_instruction(struct instruction **expr, uint16_t encoding,
		    struct instruction_data data);

/* Define stack machine instructions, that take immediate operands */
#define X(instr, encoding)						\
	inline static int i_##instr(struct instruction_data data,	\
				    struct instruction **expr)		\
	{								\
		return add_instruction(expr, encoding, data);		\
	}

/* Define stack machine instructions, that *don't* take immediate operands */
#define Y(instr, encoding)						\
	inline static int i_##instr(struct instruction **expr)		\
	{								\
		return add_instruction(expr, encoding, NO_DATA);	\
	}

X(store,       0x7E00) /* 0111_1110_0xxx_xxxx */
X(store_p,     0x6E00) /* 0110_1110_0xxx_xxxx */
X(storeb_p,    0x6C00) /* 0110_1100_0xxx_xxxx */
X(storew_p,    0x6D00) /* 0110_1101_0xxx_xxxx */
X(load,        0x5E00) /* 0101_1110_0xxx_xxxx */
X(load_p,      0x4E00) /* 0100_1110_0xxx_xxxx */
X(loadbzx_p,   0x4C00) /* 0100_1100_0xxx_xxxx */
X(loadbsx_p,   0x4C80) /* 0100_1100_1xxx_xxxx */
X(loadwzx_p,   0x4D00) /* 0100_1101_0xxx_xxxx */
X(loadwsx_p,   0x4D80) /* 0100_1101_1xxx_xxxx */
Y(nop,         0x0001) /* 0000_0000_0000_0001 */
Y(swap,        0x0002) /* 0000_0000_0000_0010 */
X(set_sp,      0x4000) /* 0100_0000_0xxx_xxxx */
X(jump,        0x4080) /* 0100_0000_1xxx_xxxx */
X(add_sp,      0x4100) /* 0100_0001_0xxx_xxxx */
Y(tee,         0x1000) /* 0001_0000_0000_0000 */
Y(get_frame,   0x1001) /* 0001_0000_0000_0001 */
X(const,       0x5000) /* 0101_0000_0xxx_xxxx */
X(call,        0x5080) /* 0101_0000_1xxx_xxxx */
Y(add,         0x3000) /* 0011_0000_0000_0000 */
Y(sub,         0x3001) /* 0011_0000_0000_0001 */
Y(div,         0x3002) /* 0011_0000_0000_0010 */
Y(mul,         0x3003) /* 0011_0000_0000_0011 */
Y(drop,        0x3004) /* 0011_0000_0000_0100 */
Y(ret,         0x3080) /* 0011_0000_1000_0000 */
X(cond_jump,   0x7080) /* 0111_0000_1xxx_xxxx */
X(cond_jump_n, 0x7100) /* 0111_0001_0xxx_xxxx */
Y(halt,        0x0000) /* 0000_0000_0000_0000 */

#undef X
#undef Y