kompiler 0.3.0.pre.4 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b00e5940820b7f2798ede46f7014a87ab43d7ade0ca171c223eae550668673c0
4
- data.tar.gz: dcd9d7bd8d170a37206d51a6b427c48217d115f048620404b045a8f6005eb6e0
3
+ metadata.gz: 18cda0db09b288b5ad14ebb5feb99e13fe03ea5a7897d603285b0aab0c8bdb77
4
+ data.tar.gz: e84247276f40846adef9798d8ea6584dc3fe156caaa18495c668ee7f99506e9e
5
5
  SHA512:
6
- metadata.gz: 023ae20fa5229d793e71ebea06bc46dea243170129e12eaf5c099c16dabdabcecb6302f0893ef17cbf0128c30a8d7d9f0b77841ecfa6ddb871d18e0c517373d4
7
- data.tar.gz: ae856004b38f75b46b4b62c7455c5f94cbeb2f21dd34e54443ff776f4fbb23432eb42f389bd706f3d649c8b2d69bee3a3e2d2cf7095d24178c32e50f32b47149
6
+ metadata.gz: d682ae38a0d09b9ca8c584de5a3687554a97962ab227fcfb1bd7f458d0f5c48ff1ca0386db8ddcd6f80832e5d94a53b12a655164a23e58bd168128dd8a05106e
7
+ data.tar.gz: 04e832aff94a2948615b3f9ca03db1cc75648673873ec9a4678aab6f09aa24b595d9a276910cf53f00de34dffebb0bfc7675b1150749bdfcbe6225bae2778401
data/bin/kompile CHANGED
@@ -16,29 +16,118 @@
16
16
 
17
17
  require 'kompiler'
18
18
 
19
+
20
+ arg_string = ARGV.join(" ")
21
+
22
+ arg_words = []
23
+ arg_keys = []
24
+ arg_opts = []
25
+ arg_letters = []
26
+
27
+ current_i = 0
28
+
29
+ permitted_word_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", ".", "-"]
30
+
31
+ whitespace_chars = ["\t", " "]
32
+
33
+ def get_word string, permitted_word_chars, offset = 0
34
+ if string[0] == '"'
35
+ str_content, n_parsed = Kompiler::Parsers.parse_str(string[offset..])
36
+ return str_content, n_parsed + offset
37
+ else
38
+ current_i = offset
39
+ word = ""
40
+ while permitted_word_chars.include? string[current_i]
41
+ word << string[current_i]
42
+ current_i += 1
43
+ end
44
+ return word, current_i
45
+ end
46
+ end
47
+
48
+
49
+ while current_i < arg_string.size
50
+
51
+ if whitespace_chars.include? arg_string[current_i]
52
+ current_i += 1
53
+ end
54
+
55
+ if arg_string[current_i] == "-" && arg_string[current_i + 1] == "-"
56
+ current_i += 2
57
+ keyword, current_i = get_word(arg_string, permitted_word_chars, current_i)
58
+
59
+
60
+ if arg_string[current_i] == "="
61
+ current_i += 1
62
+ value, current_i = get_word(arg_string, permitted_word_chars, current_i)
63
+
64
+ arg_keys << [keyword, value]
65
+ elsif whitespace_chars.include?(arg_string[current_i]) || current_i == arg_string.size
66
+ arg_opts << keyword
67
+ else
68
+ puts "Unrecognized argument syntax at index #{current_i}"
69
+ exit
70
+ end
71
+
72
+ next
73
+ end
74
+
75
+ if arg_string[current_i] == "-"
76
+ current_i += 1
77
+
78
+ letters, current_i = get_word(arg_string, permitted_word_chars, current_i)
79
+
80
+ arg_letters += letters.chars
81
+
82
+ next
83
+ end
84
+
85
+
86
+ word, current_i = get_word(arg_string, permitted_word_chars, current_i)
87
+ arg_words << word
88
+ end
89
+
90
+
91
+
92
+
19
93
  # Print the help screen if requested
20
- if (ARGV.size == 1) && ["--help", "-h"].include?(ARGV[0])
21
- puts """Usage: kompile [options] | [<input_file> <output_file> [architecture]]
94
+ if arg_opts.include?("help") || arg_letters.include?("h")
95
+ puts """Usage: kompile <input_file> [<output_file>] [compile_options]
96
+ or: kompile OPTION
22
97
 
23
- Available options:
24
- --help, -h Prints this screen
25
- --list-architectures Prints available architectures
26
- -L Alias to --list-architectures
98
+ Compile a file:
99
+ input_file Path to the input file
100
+ output_file Path to the output file (optional, default is out.bin)
101
+
102
+ Compilation options:
103
+ --arch=<arch_name> Compile for the specified architecture (optional, default is armv8a)
104
+ --wrap=<format> Wrap the compiled program in the specified format (default is none)
27
105
 
28
- To compile, run:
29
- kompile <input_file> <output_file> [architecture]
106
+ Available wrapping formats:
107
+ none
108
+ elf.obj
109
+ elf.exec
110
+ mach-o.obj [not implemented yet]
111
+ mach-o.exec [not implemented yet]
30
112
 
31
- Arguments:
32
- <input_file> The path to the input file
33
- <output_file> The path where the compiled output will be saved
34
- [architecture] (Optional) One of the installed architectures to use for compilation (defaults to \"armv8a\")
113
+ Additional options for wrapping are:
114
+ --elf-machine=<type> Specifies ELF header's e_machine to be the type provided (default is 0)
115
+ --elf-class=<class> Specifies the ELF file's class to either 32 or 64 (default is 64)
116
+ --mach-o-machine=<cputype.subtype> Specifies Mach-O header's cputype and subtype
117
+ to be the type provided
118
+
119
+ Available options:
120
+ --help, -h Prints this information
121
+ --list-architectures Lists available architectures
122
+ --list-instructions [arch] Lists available instructions for the specified architecture
123
+ --list-registers [arch] Lists available registers for the specified architecture
35
124
  """
36
125
  exit # Exit
37
126
  end
38
127
 
39
128
 
40
129
  # Print the available architectures if requested
41
- if (ARGV.size == 1) && ["--list-architectures", "-L"].include?(ARGV[0])
130
+ if arg_opts == ["list-architectures"]
42
131
  Kompiler::ArchManager.load_all_entries()
43
132
  puts "Available architectures:"
44
133
 
@@ -48,52 +137,171 @@ if (ARGV.size == 1) && ["--list-architectures", "-L"].include?(ARGV[0])
48
137
  exit # Exit
49
138
  end
50
139
 
51
- in_filename = ARGV[0]
52
- out_filename = ARGV[1]
53
- arch_name = ARGV[2] || "armv8a"
140
+ if arg_opts == ["list-instructions"]
141
+ arch_name = arg_words[0] || "armv8a"
142
+ Kompiler::ArchManager.load_all_entries()
143
+ arch = Kompiler::ArchManager.get_arch(arch_name)
144
+
145
+ require arch[:include_path]
146
+
147
+ Kompiler::Architecture.instructions.each do |instr|
148
+ puts "#{instr[:keyword]} (#{instr[:operands].size} operands): #{instr[:name]}"
149
+ puts instr[:description]
150
+ puts
151
+ end
152
+
153
+ exit
154
+ end
155
+
156
+ if arg_opts == ["list-registers"]
157
+ arch_name = arg_words[0] || "armv8a"
158
+ Kompiler::ArchManager.load_all_entries()
159
+ arch = Kompiler::ArchManager.get_arch(arch_name)
160
+
161
+ require arch[:include_path]
162
+
163
+ Kompiler::Architecture.registers.each do |reg|
164
+ puts "#{reg[:reg_name]}"
165
+ end
166
+
167
+ exit
168
+ end
169
+
170
+
171
+
172
+ if arg_words.size < 1
173
+ puts "kompile: No input file path provided."
174
+ puts "Type \"kompile --help\" for more information."
175
+ exit
176
+ end
177
+
178
+ in_filename = arg_words[0]
179
+ out_filename = (arg_words.size > 1) ? arg_words[1] : "out.bin"
180
+
54
181
 
55
182
  if !in_filename
56
183
  puts "Error: No input file provided"
57
184
  exit
58
185
  end
59
186
 
187
+ if !File.exist?(in_filename)
188
+ puts "Error: File \"#{in_filename}\" doesn't exist"
189
+ exit
190
+ end
191
+
192
+
60
193
  if !out_filename
61
194
  puts "Error: No output file provided"
62
195
  exit
63
196
  end
64
197
 
65
- if !File.exist?(in_filename)
66
- puts "Error: #{in_filename} doesn't exist"
198
+
199
+
200
+
201
+
202
+ wrap_opt = arg_keys.select{_1[0] == "wrap"}
203
+
204
+
205
+ if wrap_opt.size > 1
206
+ puts "kompile: Only one wrapping option can be provided with \"--wrap\"."
207
+ puts "Type \"kompile --help\" for more information."
67
208
  exit
209
+ elsif wrap_opt.size == 1
210
+ wrap_opt = wrap_opt[0][1]
211
+ else
212
+ wrap_opt = "none"
68
213
  end
69
214
 
70
- # Load all the architecture entries
71
215
 
72
- Kompiler::ArchManager.load_all_entries()
216
+ if !["elf.obj", "elf.exec", "mach-o.obj", "mach-o.exec", "none"].include?(wrap_opt)
217
+ puts "kompile: Unknown wrapping option \"#{wrap_opt}\"."
218
+ puts "Type \"kompile --help\" for more information."
219
+ exit
220
+ end
221
+
222
+
223
+
73
224
 
74
- # Find the right architecture
75
- arch = Kompiler::ArchManager.get_arch(arch_name)
225
+ arch_opt = arg_keys.select{_1[0] == "arch"}
76
226
 
77
- if arch == nil
78
- puts "Error: Architecture \"#{arch_name}\" not found."
227
+ if arch_opt.size > 1
228
+ puts "kompile: Only one architecture can be provided with \"--arch\"."
229
+ puts "Type \"kompile --help\" for more information."
79
230
  exit
231
+ elsif arch_opt.size == 1
232
+ arch_name = arch_opt[0][1]
233
+ else
234
+ arch_name = "armv8a"
80
235
  end
81
236
 
82
- # Get the include path for the architecture
83
- arch_include_path = arch[:include_path]
237
+ # Load all the architecture entries
238
+
239
+ Kompiler::ArchManager.load_all_entries()
84
240
 
85
241
  # Load the architecture
242
+
243
+ arch_config = Kompiler::ArchManager.get_arch(arch_name)
244
+
245
+ if arch_config == nil
246
+ puts "kompile: Could not find the architecture \"#{arch_name}\"."
247
+ puts "Type \"kompile --list-architectures\" for the list of known architectures."
248
+ exit
249
+ end
250
+
86
251
  begin
87
- require arch_include_path
88
- rescue LoadError => e
89
- puts "Error: Could not load #{arch_name} architecture's configuration."
252
+ Kompiler::ArchManager.load_arch(arch_name)
253
+ rescue
254
+ puts "kompile: Could not load the architecture \"#{arch_name}\"."
90
255
  exit
91
256
  end
92
257
 
93
- code = File.read(in_filename)
94
258
 
95
- compiled_bytes_str = Kompiler::CompilerFunctions.compile(code, [in_filename])
96
259
 
97
- File.open(out_filename, "wb") do |file|
98
- file.write compiled_bytes_str
260
+ code = File.binread(in_filename)
261
+
262
+ detailed_out = Kompiler::CompilerFunctions.detailed_compile(code)
263
+
264
+ # p detailed_out
265
+
266
+ out = nil
267
+
268
+ code = detailed_out[:machine_code]
269
+ labels = detailed_out[:labels]
270
+
271
+ labels.delete "here"
272
+
273
+
274
+ case wrap_opt
275
+ when "none"
276
+ out = code
277
+ when "elf.obj"
278
+ elf_machine = arg_keys.filter{_1[0] == "elf-machine"}[0]
279
+ elf_machine = (elf_machine != nil) ? elf_machine[1].to_i : 0
280
+
281
+ elf_class = arg_keys.filter{_1[0] == "elf-class"}[0]
282
+ elf_class ||= ["elf-class", "64"]
283
+ elf_class = elf_class[1].to_i
284
+
285
+ symbols = Kompiler::Wrappers::ELF.labels_to_symbols(labels)
286
+ out = Kompiler::Wrappers::ELF.wrap_obj(code, symbols, machine: elf_machine, elf_class: elf_class)
287
+ when "elf.exec"
288
+ elf_machine = arg_keys.filter{_1[0] == "elf-machine"}[0]
289
+ elf_machine = (elf_machine != nil) ? elf_machine[1].to_i : 0
290
+
291
+ elf_class = arg_keys.filter{_1[0] == "elf-class"}[0]
292
+ elf_class ||= ["elf-class", "64"]
293
+ elf_class = elf_class[1].to_i
294
+
295
+ symbols = Kompiler::Wrappers::ELF.labels_to_symbols(labels)
296
+ out = Kompiler::Wrappers::ELF.wrap_exec(code, symbols, machine: elf_machine, elf_class: elf_class)
297
+ when "mach-o.obj"
298
+ puts "Mach-O not yet implemented."
299
+ exit
300
+ when "mach-o.exec"
301
+ puts "Mach-O not yet implemented."
302
+ exit
99
303
  end
304
+
305
+
306
+ File.binwrite out_filename, out
307
+
@@ -1,6 +1,11 @@
1
1
  # Copyright 2024 Kyrylo Shyshko
2
2
  # Licensed under the Apache License, Version 2.0. See LICENSE file for details.
3
3
 
4
+ #
5
+ # Implements logic for managing all available architectures.
6
+ #
7
+
8
+
4
9
  module Kompiler
5
10
 
6
11
  # Object for managing architecture entries / available architectures
@@ -22,6 +27,10 @@ module Kompiler
22
27
  def self.load_all_entries
23
28
  Gem.find_files("kompiler/arch_entries/*").each { |file| require file }
24
29
  end
30
+
31
+ def self.load_arch arch_name
32
+ require get_arch(arch_name)[:include_path]
33
+ end
25
34
  end
26
35
 
27
- end
36
+ end
@@ -1,6 +1,10 @@
1
1
  # Copyright 2024 Kyrylo Shyshko
2
2
  # Licensed under the Apache License, Version 2.0. See LICENSE file for details.
3
3
 
4
+ #
5
+ # Implements logic to set and read info of the currently used architecture.
6
+ #
7
+
4
8
  module Kompiler
5
9
 
6
10
  module Architecture
@@ -27,4 +31,4 @@ end
27
31
 
28
32
  end
29
33
 
30
- end
34
+ end
@@ -13,7 +13,7 @@ end
13
13
  { keyword: "mov",
14
14
  name: "Move (immediate)",
15
15
  description: "Moves an immediate value to the destination register",
16
- operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination"}, {type: "immediate", restrictions: {}, name: "Immediate value"}],
16
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "immediate", restrictions: {}, name: "Immediate value"}],
17
17
  mc_constructor: [
18
18
  ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5],
19
19
  ["get_bits", ["get_operand", 1], 0, 16],
@@ -25,7 +25,7 @@ end
25
25
  { keyword: "mov",
26
26
  name: "Move (register)",
27
27
  description: "Copies the value in the source register to the destination register",
28
- operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source"}],
28
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register"}],
29
29
  mc_constructor: [
30
30
  ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "mov Error: Register sizes are not the same"]],
31
31
  ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5], # Rd
@@ -40,7 +40,7 @@ end
40
40
  { keyword: "mov_sp",
41
41
  name: "Move (to/from SP)",
42
42
  description: "Move between a general-purpose register and the stack pointer.",
43
- operands: [{type: "register", restrictions: {reg_type: "gpr"}}, {type: "register", restrictions: {reg_type: "gpr"}}],
43
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register"}],
44
44
  mc_constructor: [
45
45
  # Get the non-SP register
46
46
  ["if_eq_else", ["downcase_str", ["get_key", ["get_operand", 0], :reg_name]], "sp", ["set_var", "non_sp_reg", ["get_operand", 1]], ["set_var", "non_sp_reg", ["get_operand", 0]]],
@@ -53,32 +53,26 @@ end
53
53
  bitsize: 32
54
54
  },
55
55
  { keyword: "mvn", # MVN writes the bitwise opposite of the source register to a destination register
56
- description: "MVN writes the bitwise opposite of the source register to the destination register",
57
- operands: [{type: "register", restrictions: {reg_size: 64}, name: "Destination"}, {type: "register", restrictions: {reg_size: 64}, name: "Source"}],
58
- mc_constructor: [
59
- ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5], # Rd
60
- ["bits", 1,1,1,1,1], # Rn
61
- ["bits", 0,0,0,0,0,0], # imm6 (shift amount) set to zero
62
- ["get_bits", ["encode_gp_register", ["get_operand", 1]], 0, 5], # Rm
63
- ["bits", 1, 0,0, 0,1,0,1,0,1,0, 1] # N - shift type (zero / LSL) - bits
64
- ],
65
- bitsize: 32
66
- },
67
- { keyword: "mvn", # MVN writes the bitwise opposite of the source register to a destination register
68
- description: "MVN writes the bitwise opposite of the source register to the destination register",
69
- operands: [{type: "register", restrictions: {reg_size: 32}, name: "Destination"}, {type: "register", restrictions: {reg_size: 32}, name: "Source"}],
56
+ name: "Move inverse",
57
+ description: "Writes the bitwise opposite of the source register value to the destination register.",
58
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register"}],
70
59
  mc_constructor: [
60
+ ["ensure_eq", ["get_operand_key", 0, :reg_size], ["get_operand_key", 1, :reg_size], "mvn Error: Register sizes are not the same."],
61
+
71
62
  ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5], # Rd
72
63
  ["bits", 1,1,1,1,1], # Rn
73
64
  ["bits", 0,0,0,0,0,0], # imm6 (shift amount) set to zero
74
65
  ["get_bits", ["encode_gp_register", ["get_operand", 1]], 0, 5], # Rm
75
- ["bits", 1, 0,0, 0,1,0,1,0,1,0, 0] # N - shift type (zero / LSL) - bits
66
+ ["bits", 1, 0,0, 0,1,0,1,0,1,0], # N - shift type (zero / LSL) - bits
67
+ ["case", ["get_operand_key", 0, :reg_size], 32, ["bits", 0], 64, ["bits", 1], [0]]
76
68
  ],
77
69
  bitsize: 32
78
70
  },
79
71
  {
80
72
  keyword: "add",
81
- operands: [{type: "register", restrictions: {reg_type: "gpr"}}, {type: "register", restrictions: {reg_type: "gpr"}}, {type: "immediate"}],
73
+ name: "Add (immediate)",
74
+ description: "Adds the source register value and the immediate value, and writes the result to the destination register.",
75
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register"}, {type: "immediate", name: "Immediate value"}],
82
76
  mc_constructor: [
83
77
  ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "add Error: Register sizes are not the same"]],
84
78
 
@@ -95,7 +89,7 @@ end
95
89
  keyword: "add",
96
90
  name: "ADD (registers)",
97
91
  description: "Adds two source registers and writes the result to the destination register",
98
- operands: [{type: "register", restrictions: {reg_type: "gpr"}}, {type: "register", restrictions: {reg_type: "gpr"}}, {type: "register", restrictions: {reg_type: "gpr"}}],
92
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register 2"}],
99
93
  mc_constructor: [
100
94
  # Make sure register sizes are the same
101
95
  ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "add Error: Register sizes are not the same"]],
@@ -115,9 +109,9 @@ end
115
109
 
116
110
  {
117
111
  keyword: "and",
118
- name: "And (register)",
112
+ name: "Bitwise And (register)",
119
113
  description: "Performs a bitwise AND of two register values and writes the result to the destination register.",
120
- operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Register 2"}],
114
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register 2"}],
121
115
  mc_constructor: [
122
116
  ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "and Error: Register sizes are not the same"]],
123
117
  ["if_eq_else", ["get_key", ["get_operand", 1], :reg_size], ["get_key", ["get_operand", 2], :reg_size], [], ["raise_error", "and Error: Register sizes are not the same"]],
@@ -135,17 +129,21 @@ end
135
129
 
136
130
  {
137
131
  keyword: "orr", # And between registers, with shift set to zero
138
- name: "Or",
132
+ name: "Bitwise OR (register)",
139
133
  description: "Computes a logical bit-wise OR operation between two registers and writes the result to the destination register.",
140
- operands: [{type: "register", restrictions: {reg_size: 64}, name: "Destination"}, {type: "register", restrictions: {reg_size: 64}, name: "Register 1"}, {type: "register", restrictions: {reg_size: 64}, name: "Register 2"}],
134
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source register 2"}],
141
135
  mc_constructor: [
136
+ ["ensure_eq", ["get_operand_key", 0, :reg_size], ["get_operand_key", 1, :reg_size], "orr Error: Register sizes are not the same."],
137
+
142
138
  ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5],
143
139
  ["get_bits", ["encode_gp_register", ["get_operand", 1]], 0, 5],
144
140
  ["get_bits", 0, 0, 6], # imm6 (shift amount) set to zero
145
141
  ["get_bits", ["encode_gp_register", ["get_operand", 2]], 0, 5],
146
142
  ["bits", 0], # N
147
143
  ["bits", 0,0], # shift type
148
- ["bits", 0,1,0,1,0, 1,0, 1],
144
+ ["bits", 0,1,0,1,0, 1,0],
145
+
146
+ ["case", ["get_operand_key", 0, :reg_size], 32, ["bits", 0], 64, ["bits", 1], ["bits", 0]],
149
147
  ],
150
148
  bitsize: 32
151
149
  },
@@ -180,13 +178,17 @@ end
180
178
  },
181
179
  {
182
180
  keyword: "b",
183
- operands: [{type: "immediate"}],
181
+ name: "Branch (immediate)",
182
+ description: "Branches (jumps) to a PC-relative offset specified by the immediae value.",
183
+ operands: [{type: "immediate", name: "Immediate PC Offset"}],
184
184
  mc_constructor: [["get_bits", ["get_operand", 0], 0, 26], ["bits", 1,0,1,0,0,0]],
185
185
  bitsize: 32
186
186
  },
187
187
  {
188
188
  keyword: "b",
189
- operands: [{type: "label"}],
189
+ name: "Branch (label)",
190
+ description: "Branches (jumps) to a label using a PC-relative offset.",
191
+ operands: [{type: "label", name: "Program label"}],
190
192
  mc_constructor: [
191
193
  ["if_eq_else", ["modulo", ["subtract", ["get_label_address", ["get_operand", 0]], ["get_current_address"]], 4], 0, [], ["raise_error", "Can't branch to the address - offset not divisible by 4 bytes."]], # Check if address is accessible
192
194
  ["get_bits", ["divide", ["subtract", ["get_label_address", ["get_operand", 0]], ["get_current_address"]], 4], 0, 26],
@@ -196,6 +198,8 @@ end
196
198
  },
197
199
  {
198
200
  keyword: "br",
201
+ name: "Branch (register)",
202
+ description: "Branches (jumps) to an address in a register.",
199
203
  operands: [{type: "register", restrictions: {reg_size: 64}}],
200
204
  mc_constructor: [
201
205
  ["bits", 0,0,0,0,0],
@@ -206,6 +210,8 @@ end
206
210
  },
207
211
  {
208
212
  keyword: "bl",
213
+ name: "Branch with link (label)",
214
+ description: "Branches (jumps) to a label using a PC-relative offset, and sets the register X30 to PC + 4.",
209
215
  operands: [{type: "label"}],
210
216
  mc_constructor: [
211
217
  ["if_eq_else", ["modulo", ["subtract", ["get_label_address", ["get_operand", 0]], ["get_current_address"]], 4], 0, [], ["raise_error", "Can't branch to the address - offset not divisible by 4 bytes."]], # Check if address is accessible
@@ -1148,6 +1154,49 @@ end
1148
1154
  bitsize: 32
1149
1155
  },
1150
1156
 
1157
+ {
1158
+ keyword: "sxtw",
1159
+ name: "Sign Extend Word",
1160
+ description: "Sign extends the 32-bit signed integer in the source general-purpose register to a 64-bit signed integer, and writes the result to the destination general-purpose register.",
1161
+ operands: [{type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 32}, name: "Source register"}],
1162
+ mc_constructor: [
1163
+ ["get_bits", ["get_operand_key", 0, :reg_value], 0, 5],
1164
+ ["get_bits", ["get_operand_key", 1, :reg_value], 0, 5],
1165
+ ["bits", 1,1,1,1,1,0, 0,0,0,0,0,0, 1, 0,1,1,0,0,1, 0,0, 1],
1166
+ ],
1167
+ bitsize: 32
1168
+ },
1169
+ {
1170
+ keyword: "sxth",
1171
+ name: "Sign Extend Halfword",
1172
+ description: "Sign extends the 16-bit signed integer in the source general-purpose register to the size of the destination register, and writes the result to the destination general-purpose register.",
1173
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 32}, name: "Source register"}],
1174
+ mc_constructor: [
1175
+ ["get_bits", ["get_operand_key", 0, :reg_value], 0, 5],
1176
+ ["get_bits", ["get_operand_key", 1, :reg_value], 0, 5],
1177
+ ["bits", 1,1,1,1,0,0, 0,0,0,0,0,0],
1178
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []],
1179
+ ["bits", 0,1,1,0,0,1, 0,0],
1180
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []],
1181
+ ],
1182
+ bitsize: 32
1183
+ },
1184
+ {
1185
+ keyword: "sxtb",
1186
+ name: "Sign Extend Byte",
1187
+ description: "Sign extends the 8-bit signed integer in the source general-purpose register to the size of the destination register, and writes the result to the destination general-purpose register.",
1188
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 32}, name: "Source register"}],
1189
+ mc_constructor: [
1190
+ ["get_bits", ["get_operand_key", 0, :reg_value], 0, 5],
1191
+ ["get_bits", ["get_operand_key", 1, :reg_value], 0, 5],
1192
+ ["bits", 1,1,1,0,0,0, 0,0,0,0,0,0],
1193
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []],
1194
+ ["bits", 0,1,1,0,0,1, 0,0],
1195
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []],
1196
+ ],
1197
+ bitsize: 32
1198
+ },
1199
+
1151
1200
  ]
1152
1201
 
1153
1202
  end # Kompiler::ARMv8A
@@ -5,6 +5,8 @@ require 'kompiler/architectures/armv8a/instructions.rb'
5
5
  require 'kompiler/architectures/armv8a/sys_instructions.rb'
6
6
  require 'kompiler/architectures/armv8a/registers.rb'
7
7
  require 'kompiler/architectures/armv8a/sys_registers.rb'
8
+ require 'kompiler/architectures/armv8a/simd_fp_instructions.rb'
9
+ require 'kompiler/architectures/armv8a/simd_fp_registers.rb'
8
10
 
9
11
 
10
- Kompiler::Architecture.set_arch(Kompiler::ARMv8A.instructions + Kompiler::ARMv8A.sys_instructions, Kompiler::ARMv8A.registers + Kompiler::ARMv8A.sys_registers)
12
+ Kompiler::Architecture.set_arch(Kompiler::ARMv8A.instructions + Kompiler::ARMv8A.sys_instructions + Kompiler::ARMv8A.simd_fp_instructions, Kompiler::ARMv8A.registers + Kompiler::ARMv8A.sys_registers + Kompiler::ARMv8A.simd_fp_registers)