1use crate::instruction::*;
2use crate::{
3 MASK_VALUE, OFFSET_IS_ADDRESS, OFFSET_IS_INDIRECT, OFFSET_IS_STATE, OFFSET_OPERAND_1,
4 OFFSET_OPERAND_2, OFFSET_OPERAND_3, OFFSET_OP_CODE,
5};
6use half::f16;
7
8const UNUSED_WORD: u64 = 0;
10
11pub fn serialize(instruction: &Instruction) -> u64 {
13 match instruction {
14 NOP() => 0,
15 HLT() => 1 << OFFSET_OP_CODE,
16 SYN() => 2 << OFFSET_OP_CODE,
17 IIMOV(lint, rint) => make_instruction(3, make_lint(lint), make_rint(rint), UNUSED_WORD),
18 IDMOV(lint, rdouble) => {
19 make_instruction(4, make_lint(lint), make_rdouble(rdouble), UNUSED_WORD)
20 }
21 DIMOV(ldouble, rint) => {
22 make_instruction(5, make_ldouble(ldouble), make_rint(rint), UNUSED_WORD)
23 }
24 DDMOV(ldouble, rdouble) => {
25 make_instruction(6, make_ldouble(ldouble), make_rdouble(rdouble), UNUSED_WORD)
26 }
27 IADD(lint1, lint2, rint) => {
28 make_instruction(7, make_lint(lint1), make_lint(lint2), make_rint(rint))
29 }
30 IDIV(lint1, lint2, rint) => {
31 make_instruction(8, make_lint(lint1), make_lint(lint2), make_rint(rint))
32 }
33 IMOD(lint1, lint2, rint) => {
34 make_instruction(9, make_lint(lint1), make_lint(lint2), make_rint(rint))
35 }
36 IMUL(lint1, lint2, rint) => {
37 make_instruction(10, make_lint(lint1), make_lint(lint2), make_rint(rint))
38 }
39 ISUB(lint1, lint2, rint) => {
40 make_instruction(11, make_lint(lint1), make_lint(lint2), make_rint(rint))
41 }
42 DADD(ldouble1, ldouble2, rdouble) => make_instruction(
43 12,
44 make_ldouble(ldouble1),
45 make_ldouble(ldouble2),
46 make_rdouble(rdouble),
47 ),
48 DDIV(ldouble1, ldouble2, rdouble) => make_instruction(
49 13,
50 make_ldouble(ldouble1),
51 make_ldouble(ldouble2),
52 make_rdouble(rdouble),
53 ),
54 DMOD(ldouble1, ldouble2, rdouble) => make_instruction(
55 14,
56 make_ldouble(ldouble1),
57 make_ldouble(ldouble2),
58 make_rdouble(rdouble),
59 ),
60 DMUL(ldouble1, ldouble2, rdouble) => make_instruction(
61 15,
62 make_ldouble(ldouble1),
63 make_ldouble(ldouble2),
64 make_rdouble(rdouble),
65 ),
66 DSUB(ldouble1, ldouble2, rdouble) => make_instruction(
67 16,
68 make_ldouble(ldouble1),
69 make_ldouble(ldouble2),
70 make_rdouble(rdouble),
71 ),
72 IJEQ(lint1, lint2, code_offset) => make_instruction(
73 17,
74 make_lint(lint1),
75 make_lint(lint2),
76 make_code_offset(code_offset.offset),
77 ),
78 IJNE(lint1, lint2, code_offset) => make_instruction(
79 18,
80 make_lint(lint1),
81 make_lint(lint2),
82 make_code_offset(code_offset.offset),
83 ),
84 IJGT(lint1, lint2, code_offset) => make_instruction(
85 19,
86 make_lint(lint1),
87 make_lint(lint2),
88 make_code_offset(code_offset.offset),
89 ),
90 IJLT(lint1, lint2, code_offset) => make_instruction(
91 20,
92 make_lint(lint1),
93 make_lint(lint2),
94 make_code_offset(code_offset.offset),
95 ),
96 DJEQ(ldouble1, ldouble2, code_offset) => make_instruction(
97 21,
98 make_ldouble(ldouble1),
99 make_ldouble(ldouble2),
100 make_code_offset(code_offset.offset),
101 ),
102 DJNE(ldouble1, ldouble2, code_offset) => make_instruction(
103 22,
104 make_ldouble(ldouble1),
105 make_ldouble(ldouble2),
106 make_code_offset(code_offset.offset),
107 ),
108 DJGT(ldouble1, ldouble2, code_offset) => make_instruction(
109 23,
110 make_ldouble(ldouble1),
111 make_ldouble(ldouble2),
112 make_code_offset(code_offset.offset),
113 ),
114 DJLT(ldouble1, ldouble2, code_offset) => make_instruction(
115 24,
116 make_ldouble(ldouble1),
117 make_ldouble(ldouble2),
118 make_code_offset(code_offset.offset),
119 ),
120 }
121}
122
123pub fn make_instruction(op_code: u64, operand1: u64, operand2: u64, operand3: u64) -> u64 {
124 (op_code << OFFSET_OP_CODE)
125 | (operand1 << OFFSET_OPERAND_1)
126 | (operand2 << OFFSET_OPERAND_2)
127 | (operand3 << OFFSET_OPERAND_3)
128}
129
130fn make_operand(is_address: bool, is_indirect: bool, is_state: bool, value: u16) -> u64 {
131 (if is_address {
132 1 << OFFSET_IS_ADDRESS
133 } else {
134 0
135 }) | (if is_indirect {
136 1 << OFFSET_IS_INDIRECT
137 } else {
138 0
139 }) | (if is_state { 1 << OFFSET_IS_STATE } else { 0 })
140 | value as u64
141}
142
143fn make_ldouble(ldouble: &LeftDouble) -> u64 {
144 match ldouble {
145 LeftDouble::State(index, mode) => make_operand(true, *mode == Mode::Indirect, true, *index),
146 LeftDouble::Input(index, mode) => {
147 make_operand(true, *mode == Mode::Indirect, false, *index)
148 }
149 LeftDouble::Constant(value) => {
150 make_operand(false, false, false, f16::from_f64(*value).to_bits())
151 }
152 }
153}
154
155fn make_lint(lint: &LeftInteger) -> u64 {
156 match lint {
157 LeftInteger::State(index, mode) => {
158 make_operand(true, *mode == Mode::Indirect, true, *index)
159 }
160 LeftInteger::Input(index, mode) => {
161 make_operand(true, *mode == Mode::Indirect, false, *index)
162 }
163 LeftInteger::Constant(value) => make_operand(false, false, false, *value as u16),
164 }
165}
166
167fn make_rdouble(rdouble: &RightDouble) -> u64 {
168 match rdouble {
169 RightDouble::State(index, mode) => {
170 make_operand(true, *mode == Mode::Indirect, true, *index)
171 }
172 RightDouble::Output(index, mode) => {
173 make_operand(true, *mode == Mode::Indirect, false, *index)
174 }
175 }
176}
177
178fn make_rint(rint: &RightInteger) -> u64 {
179 match rint {
180 RightInteger::State(index, mode) => {
181 make_operand(true, *mode == Mode::Indirect, true, *index)
182 }
183 RightInteger::Output(index, mode) => {
184 make_operand(true, *mode == Mode::Indirect, false, *index)
185 }
186 }
187}
188
189fn make_code_offset(code_offset: i16) -> u64 {
190 (code_offset as u64) & MASK_VALUE
191}