aboutsummaryrefslogtreecommitdiff
#include <stdbool.h>

#include "wasm_compile.h"

#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;
	const char *name;
};

#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, const char *name);

/* 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, #instr);	\
	}

/* 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, #instr); \
	}

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(eq,          0x3007) /* 0011_0000_0000_0111 */
Y(lt,          0x3008) /* 0011_0000_0000_1000 */
Y(ult,         0x3009) /* 0011_0000_0000_1001 */
Y(le,          0x300A) /* 0011_0000_0000_1010 */
Y(ule,         0x300B) /* 0011_0000_0000_1011 */
Y(gt,          0x300C) /* 0011_0000_0000_1100 */
Y(ugt,         0x300D) /* 0011_0000_0000_1101 */
Y(ge,          0x300E) /* 0011_0000_0000_1110 */
Y(uge,         0x300F) /* 0011_0000_0000_1111 */
Y(rem,         0x3010) /* 0011_0000_0001_0000 */
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