kompiler 0.2.0 → 0.3.0.pre.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: fc460a4bb7ead297f0fe530c19304038f4d3980103cde260df057c52b35cfeeb
4
- data.tar.gz: 57ea6ace09f3b1a5c3d0914d9edbbd02a83a5002b5c55ecde398f593cdcbb211
3
+ metadata.gz: 94839a8d70f8124e207b1c57efcefd4b97bc0b981a38f9319fddce27510954c7
4
+ data.tar.gz: 257358df8104b1e130361095b6d2c25f6fdac542918af69687313cc00a7bd4d2
5
5
  SHA512:
6
- metadata.gz: 8c78b06f86db101176939c5aad994950e60d63827fe1a1470d5fad991fb9f2f3d26efef86981039fa2c41b22f034ad2c953bead0961ea4ea411ec583d64e5a27
7
- data.tar.gz: 4c001f5a2c64e4a26752c98a116ff85138733662fe376e4b470352731cee721688bd194760f89e949552cf59e3824ef7b2ac607f6ab696732d783dff1b779cf6
6
+ metadata.gz: 91804940ae6a1182841aa27d781c410ecae3644500c64907119409ae019e192c75d79bc3ef661ea8aac56b27113fce6ca2bb54c487cd0684f702a42913e445c7
7
+ data.tar.gz: 6e05374e4e6b0f279aedc8e3087d21bc0bfbc919b431453fd7f1382a0fa39777a37f3e65cfd646576cb806fc0cc07f119649ae080ad6d3b495d372e60c93ca8c
@@ -3,26 +3,26 @@
3
3
 
4
4
  module Kompiler
5
5
 
6
- class Architecture
6
+ module Architecture
7
+
8
+ @instructions = []
9
+ @registers = []
7
10
 
8
- @@instructions = []
9
- @@registers = []
10
-
11
11
  def self.set_arch instructions, registers
12
- @@instructions = instructions
13
- @@registers = registers
12
+ @instructions = instructions
13
+ @registers = registers
14
14
  end
15
15
 
16
- def self.load_arch(arch_name)
17
- require "kompiler/arch/#{arch_name.downcase}/load"
18
- end
16
+ # def self.load_arch(arch_name)
17
+ # require "kompiler/arch/#{arch_name.downcase}/load"
18
+ # end
19
19
 
20
20
  def self.instructions
21
- @@instructions
21
+ @instructions
22
22
  end
23
23
 
24
24
  def self.registers
25
- @@registers
25
+ @registers
26
26
  end
27
27
 
28
28
  end
@@ -3,13 +3,13 @@
3
3
 
4
4
  module Kompiler
5
5
 
6
- class ARMv8A
6
+ module ARMv8A
7
7
 
8
8
  def self.instructions
9
- @@instructions
9
+ @instructions
10
10
  end
11
11
 
12
- @@instructions = [
12
+ @instructions = [
13
13
  { keyword: "mov",
14
14
  operands: [{type: "register", restrictions: {reg_size: 64}}, {type: "immediate", restrictions: {}}],
15
15
  mc_constructor: [
@@ -354,6 +354,91 @@ end
354
354
  ],
355
355
  bitsize: 32
356
356
  },
357
+
358
+ {
359
+ keyword: "ldp",
360
+ name: "Load Pair",
361
+ description: "Loads data for two registers from memory at the address specified by the third register, and writes the data to two general-purpose registers.",
362
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Destination Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}],
363
+ bitsize: 32,
364
+ mc_constructor: [
365
+ # Check for register sizes
366
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "ldp Error: Register sizes are not the same"]],
367
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
368
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
369
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
370
+ ["get_bits", 0, 0, 7], # imm7
371
+ ["bits", 1, 0,1,0, 0, 1,0,1, 0],
372
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
373
+ ]
374
+ },
375
+ {
376
+ keyword: "ldp_signed",
377
+ name: "Load Pair (signed offset)",
378
+ description: "Loads data for two registers from memory at the address specified by the third register, with a signed immediate offset added, and writes the data to two general-purpose registers.",
379
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}, {type: "immediate", name: "Address Offset"}],
380
+ bitsize: 32,
381
+ mc_constructor: [
382
+ # Check for register sizes
383
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "ldp_signed Error: Register sizes are not the same"]],
384
+ # Establish the immediate offset alignment using the register size
385
+ ["set_var", "imm_alignment", ["case", ["get_key", ["get_operand", 0], :reg_size], 32, 4, 64, 8, 0]],
386
+ # Check if the immediate offset is properly aligned
387
+ ["if_eq_else", ["modulo", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, [], ["raise_error", "ldp_signed Error: The immediate offset is not properly aligned"]],
388
+
389
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
390
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
391
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
392
+ ["get_bits", ["divide", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, 7], # imm7
393
+ ["bits", 1, 0,1,0, 0, 1,0,1, 0],
394
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
395
+ ]
396
+ },
397
+ {
398
+ keyword: "ldp_pre_index",
399
+ name: "Load Pair (pre-index, signed offset)",
400
+ description: "Loads data for two registers from memory at the address specified by the third register, with a signed immediate offset added permanently before reading, and writes the data to two general-purpose registers.",
401
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}, {type: "immediate", name: "Address Offset"}],
402
+ bitsize: 32,
403
+ mc_constructor: [
404
+ # Check for register sizes
405
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "ldp_pre_index Error: Register sizes are not the same"]],
406
+ # Establish the immediate offset alignment using the register size
407
+ ["set_var", "imm_alignment", ["case", ["get_key", ["get_operand", 0], :reg_size], 32, 4, 64, 8, 0]],
408
+ # Check if the immediate offset is properly aligned
409
+ ["if_eq_else", ["modulo", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, [], ["raise_error", "ldp_pre_index Error: The immediate offset is not properly aligned"]],
410
+
411
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
412
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
413
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
414
+ ["get_bits", ["divide", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, 7], # imm7
415
+ ["bits", 1, 1,1,0, 0, 1,0,1, 0],
416
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
417
+ ]
418
+ },
419
+ {
420
+ keyword: "ldp_post_index",
421
+ name: "Load Pair (post-index, signed offset)",
422
+ description: "Loads data for two registers from memory at the address specified by the third register, with a signed immediate offset added permanently after reading, and writes the data to two general-purpose registers.",
423
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}, {type: "immediate", name: "Address Offset"}],
424
+ bitsize: 32,
425
+ mc_constructor: [
426
+ # Check for register sizes
427
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "ldp_post_index Error: Register sizes are not the same"]],
428
+ # Establish the immediate offset alignment using the register size
429
+ ["set_var", "imm_alignment", ["case", ["get_key", ["get_operand", 0], :reg_size], 32, 4, 64, 8, 0]],
430
+ # Check if the immediate offset is properly aligned
431
+ ["if_eq_else", ["modulo", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, [], ["raise_error", "ldp_post_index Error: The immediate offset is not properly aligned"]],
432
+
433
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
434
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
435
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
436
+ ["get_bits", ["divide", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, 7], # imm7
437
+ ["bits", 1, 1,0,0, 0, 1,0,1, 0],
438
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
439
+ ]
440
+ },
441
+
357
442
  {
358
443
  keyword: "strh",
359
444
  operands: [{type: "register", restrictions: {reg_size: 32}}, {type: "register", restrictions: {reg_size: 64}}],
@@ -503,6 +588,90 @@ end
503
588
  bitsize: 32
504
589
  },
505
590
 
591
+ {
592
+ keyword: "stp",
593
+ name: "Store Pair",
594
+ description: "Stores the contents of two general-purpose registers at the address specified by the third register.",
595
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}],
596
+ bitsize: 32,
597
+ mc_constructor: [
598
+ # Check for register sizes
599
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "stp Error: Register sizes are not the same"]],
600
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
601
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
602
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
603
+ ["get_bits", 0, 0, 7], # imm7
604
+ ["bits", 0, 0,1,0, 0, 1,0,1, 0],
605
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
606
+ ]
607
+ },
608
+ {
609
+ keyword: "stp_signed",
610
+ name: "Store Pair (signed offset)",
611
+ description: "Stores the contents of two general-purpose registers at the address specified by the third register, with a signed immediate offset added.",
612
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}, {type: "immediate", name: "Address Offset"}],
613
+ bitsize: 32,
614
+ mc_constructor: [
615
+ # Check for register sizes
616
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "stp Error: Register sizes are not the same"]],
617
+ # Establish the immediate offset alignment using the register size
618
+ ["set_var", "imm_alignment", ["case", ["get_key", ["get_operand", 0], :reg_size], 32, 4, 64, 8, 0]],
619
+ # Check if the immediate offset is properly aligned
620
+ ["if_eq_else", ["modulo", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, [], ["raise_error", "stp Error: The immediate offset is not properly aligned"]],
621
+
622
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
623
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
624
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
625
+ ["get_bits", ["divide", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, 7], # imm7
626
+ ["bits", 0, 0,1,0, 0, 1,0,1, 0],
627
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
628
+ ]
629
+ },
630
+ {
631
+ keyword: "stp_pre_index",
632
+ name: "Store Pair (pre-index, signed offset)",
633
+ description: "Stores the contents of two general-purpose registers at the address specified by the third register, with a permanent signed immediate offset added before writing.",
634
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}, {type: "immediate", name: "Address Offset"}],
635
+ bitsize: 32,
636
+ mc_constructor: [
637
+ # Check for register sizes
638
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "stp Error: Register sizes are not the same"]],
639
+ # Establish the immediate offset alignment using the register size
640
+ ["set_var", "imm_alignment", ["case", ["get_key", ["get_operand", 0], :reg_size], 32, 4, 64, 8, 0]],
641
+ # Check if the immediate offset is properly aligned
642
+ ["if_eq_else", ["modulo", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, [], ["raise_error", "stp Error: The immediate offset is not properly aligned"]],
643
+
644
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
645
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
646
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
647
+ ["get_bits", ["divide", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, 7], # imm7
648
+ ["bits", 0, 1,1,0, 0, 1,0,1, 0],
649
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
650
+ ]
651
+ },
652
+ {
653
+ keyword: "stp_post_index",
654
+ name: "Store Pair (post-index, signed offset)",
655
+ description: "Stores the contents of two general-purpose registers at the address specified by the third register, with a permanent signed immediate offset added after writing.",
656
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 1"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Content Register 2"}, {type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Address Register"}, {type: "immediate", name: "Address Offset"}],
657
+ bitsize: 32,
658
+ mc_constructor: [
659
+ # Check for register sizes
660
+ ["if_eq_else", ["get_key", ["get_operand", 0], :reg_size], ["get_key", ["get_operand", 1], :reg_size], [], ["raise_error", "stp Error: Register sizes are not the same"]],
661
+ # Establish the immediate offset alignment using the register size
662
+ ["set_var", "imm_alignment", ["case", ["get_key", ["get_operand", 0], :reg_size], 32, 4, 64, 8, 0]],
663
+ # Check if the immediate offset is properly aligned
664
+ ["if_eq_else", ["modulo", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, [], ["raise_error", "stp Error: The immediate offset is not properly aligned"]],
665
+
666
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
667
+ ["get_bits", ["get_key", ["get_operand", 2], :reg_value], 0, 5],
668
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
669
+ ["get_bits", ["divide", ["get_operand", 3], ["get_var", "imm_alignment"]], 0, 7], # imm7
670
+ ["bits", 0, 1,0,0, 0, 1,0,1, 0],
671
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], []] # opc
672
+ ]
673
+ },
674
+
506
675
 
507
676
  {
508
677
  keyword: "cmp",
@@ -2,7 +2,9 @@
2
2
  # Licensed under the Apache License, Version 2.0. See LICENSE file for details.
3
3
 
4
4
  require 'kompiler/architectures/armv8a/instructions.rb'
5
+ require 'kompiler/architectures/armv8a/sys_instructions.rb'
5
6
  require 'kompiler/architectures/armv8a/registers.rb'
7
+ require 'kompiler/architectures/armv8a/sys_registers.rb'
6
8
 
7
9
 
8
- Kompiler::Architecture.set_arch(Kompiler::ARMv8A.instructions, Kompiler::ARMv8A.registers)
10
+ Kompiler::Architecture.set_arch(Kompiler::ARMv8A.instructions + Kompiler::ARMv8A.sys_instructions, Kompiler::ARMv8A.registers + Kompiler::ARMv8A.sys_registers)
@@ -3,13 +3,13 @@
3
3
 
4
4
  module Kompiler
5
5
 
6
- class ARMv8A
6
+ module ARMv8A
7
7
 
8
8
  def self.registers
9
- @@registers
9
+ @registers
10
10
  end
11
11
 
12
- @@registers = [
12
+ @registers = [
13
13
  {:reg_name=>"w0", :reg_value=>0, :reg_size=>32, :reg_type=>"gpr"},
14
14
  {:reg_name=>"w1", :reg_value=>1, :reg_size=>32, :reg_type=>"gpr"},
15
15
  {:reg_name=>"w2", :reg_value=>2, :reg_size=>32, :reg_type=>"gpr"},
@@ -26,6 +26,22 @@ end
26
26
  {:reg_name=>"w13", :reg_value=>13, :reg_size=>32, :reg_type=>"gpr"},
27
27
  {:reg_name=>"w14", :reg_value=>14, :reg_size=>32, :reg_type=>"gpr"},
28
28
  {:reg_name=>"w15", :reg_value=>15, :reg_size=>32, :reg_type=>"gpr"},
29
+ {:reg_name=>"w16", :reg_value=>16, :reg_size=>32, :reg_type=>"gpr"},
30
+ {:reg_name=>"w17", :reg_value=>17, :reg_size=>32, :reg_type=>"gpr"},
31
+ {:reg_name=>"w18", :reg_value=>18, :reg_size=>32, :reg_type=>"gpr"},
32
+ {:reg_name=>"w19", :reg_value=>19, :reg_size=>32, :reg_type=>"gpr"},
33
+ {:reg_name=>"w20", :reg_value=>20, :reg_size=>32, :reg_type=>"gpr"},
34
+ {:reg_name=>"w21", :reg_value=>21, :reg_size=>32, :reg_type=>"gpr"},
35
+ {:reg_name=>"w22", :reg_value=>22, :reg_size=>32, :reg_type=>"gpr"},
36
+ {:reg_name=>"w23", :reg_value=>23, :reg_size=>32, :reg_type=>"gpr"},
37
+ {:reg_name=>"w24", :reg_value=>24, :reg_size=>32, :reg_type=>"gpr"},
38
+ {:reg_name=>"w25", :reg_value=>25, :reg_size=>32, :reg_type=>"gpr"},
39
+ {:reg_name=>"w26", :reg_value=>26, :reg_size=>32, :reg_type=>"gpr"},
40
+ {:reg_name=>"w27", :reg_value=>27, :reg_size=>32, :reg_type=>"gpr"},
41
+ {:reg_name=>"w28", :reg_value=>28, :reg_size=>32, :reg_type=>"gpr"},
42
+ {:reg_name=>"w29", :reg_value=>29, :reg_size=>32, :reg_type=>"gpr"},
43
+ {:reg_name=>"w30", :reg_value=>30, :reg_size=>32, :reg_type=>"gpr"},
44
+ {:reg_name=>"w31", :reg_value=>31, :reg_size=>32, :reg_type=>"gpr"},
29
45
  {:reg_name=>"x0", :reg_value=>0, :reg_size=>64, :reg_type=>"gpr"},
30
46
  {:reg_name=>"x1", :reg_value=>1, :reg_size=>64, :reg_type=>"gpr"},
31
47
  {:reg_name=>"x2", :reg_value=>2, :reg_size=>64, :reg_type=>"gpr"},
@@ -0,0 +1,97 @@
1
+ # Copyright 2024 Kyrylo Shyshko
2
+ # Licensed under the Apache License, Version 2.0. See LICENSE file for details.
3
+
4
+ module Kompiler
5
+
6
+ module ARMv8A
7
+
8
+ def self.sys_instructions
9
+ @sys_instructions
10
+ end
11
+
12
+ @sys_instructions = [
13
+ {
14
+ keyword: "mrs",
15
+ name: "Move from system register",
16
+ description: "Moves the contents of a system register to a 64-bit general-purpose register",
17
+ operands: [{type: "register", restrictions: {reg_type: "gpr", reg_size: 64}, name: "Destination general-purpose register"}, {type: "register", restrictions: {reg_type: "sr"}, name: "Source system register"}],
18
+ mc_constructor: [
19
+ ["set_var", "sr_encoding", ["get_key", ["get_operand", 1], :reg_encoding]],
20
+ ["get_bits", ["get_key", ["get_operand", 0], :reg_value], 0, 5],
21
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "op2"], 0, 3],
22
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "CRm"], 0, 4],
23
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "CRn"], 0, 4],
24
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "op1"], 0, 3],
25
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "op0"], 0, 2],
26
+ ["bits", 1], # L
27
+ ["bits", 0,0,1,0,1,0,1,0,1,1]
28
+ ],
29
+ bitsize: 32
30
+ },
31
+ {
32
+ keyword: "msr",
33
+ name: "Move general-purpose register to system register",
34
+ description: "Writes the contents of a general-purpose register to a system register",
35
+ operands: [{type: "register", restrictions: {reg_type: "sr"}, name: "Destination system register"}, {type: "register", restrictions: {reg_type: "gpr"}, name: "Source general-purpose register"}],
36
+ mc_constructor: [
37
+ ["set_var", "sr_encoding", ["get_key", ["get_operand", 0], :reg_encoding]],
38
+ ["get_bits", ["get_key", ["get_operand", 1], :reg_value], 0, 5],
39
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "op2"], 0, 3],
40
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "CRm"], 0, 4],
41
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "CRn"], 0, 4],
42
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "op1"], 0, 3],
43
+ ["get_bits", ["get_key", ["get_var", "sr_encoding"], "op0"], 0, 2],
44
+ ["bits", 0], # L
45
+ ["bits", 0,0,1,0,1,0,1,0,1,1]
46
+ ],
47
+ bitsize: 32
48
+ },
49
+ {
50
+ keyword: "msr",
51
+ name: "Move immediate value to special register",
52
+ description: "Moves an immediate value to selected bits of the PSTATE",
53
+ operands: [{type: "register", name: "Destination system register"}, {type: "immediate", name: "Immediate value"}],
54
+ mc_constructor: [
55
+ # Case for PSTATE special register encodings
56
+ ["case", ["downcase_str", ["get_key", ["get_operand_hash", 0], :definition]],
57
+ "spsel", ["concat", ["set_var", "op1", 0b000], ["set_var", "op2", 0b101]],
58
+ "daifset", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b110]],
59
+ "daifclr", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b111]],
60
+ "uao", ["concat", ["set_var", "op1", 0b000], ["set_var", "op2", 0b011]],
61
+ "pan", ["concat", ["set_var", "op1", 0b000], ["set_var", "op2", 0b100]],
62
+ "allint", ["concat", ["set_var", "op1", 0b001], ["set_var", "op2", 0b000], ["if_eq_else", ["bit_and", ["get_operand", 1], 0b001], ["get_operand", 1], [], ["raise_warning", "msr ALLINT Warning: The immediate value is not valid for the instruction - Continuing build."]] ],
63
+ "pm", ["concat", ["set_var", "op1", 0b001], ["set_var", "op2", 0b000], ["if_eq_else", ["bit_and", ["get_operand", 1], 0b011], ["get_operand", 1], [], ["raise_warning", "msr PM Warning: The immediate value is not valid for the instruction - Continuing build."]]],
64
+ "ssbs", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b001]],
65
+ "dit", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b010]],
66
+ "svcrsm", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b011], ["if_eq_else", ["bit_and", ["get_operand", 1], 0b0011], ["get_operand", 1], [], ["raise_warning", "msr SVCRSM Warning: The immediate value is not valid for the instruction - Continuing build."]]],
67
+ "svcrza", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b011], ["if_eq_else", ["bit_and", ["get_operand", 1], 0b0101], ["get_operand", 1], [], ["raise_warning", "msr SVCRZA Warning: The immediate value is not valid for the instruction - Continuing build."]]],
68
+ "svcrsmza", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b011], ["if_eq_else", ["bit_and", ["get_operand", 1], 0b0111], ["get_operand", 1], [], ["raise_warning", "msr SVCRSMZA Warning: The immediate value is not valid for the instruction - Continuing build."]]],
69
+ "tco", ["concat", ["set_var", "op1", 0b011], ["set_var", "op2", 0b100]],
70
+ ["raise_error", "msr Error: The specified PSTATE special register was not found - Program build not possible."]
71
+ ],
72
+ ["bits", 1,1,1,1,1],
73
+ ["get_bits", ["get_var", "op2"], 0, 3],
74
+ ["get_bits", ["get_operand", 1], 0, 4],
75
+ ["bits", 0,0,1,0],
76
+ ["get_bits", ["get_var", "op1"], 0, 3],
77
+ ["bits", 0,0, 0, 0,0,1,0,1,0,1,0,1,1],
78
+ ],
79
+ bitsize: 32
80
+ },
81
+
82
+
83
+ {
84
+ keyword: "eret",
85
+ name: "Exception Return",
86
+ description: "Restores PSTATE from SPSR, and branches to the address held in ELR. ",
87
+ operands: [],
88
+ mc_constructor: [
89
+ ["bits", 0,0,0,0,0, 1,1,1,1,1, 0, 0, 0,0,0,0, 1,1,1,1,1, 0,0,1, 0, 1,1,0,1,0,1,1],
90
+ ],
91
+ bitsize: 32
92
+ },
93
+ ]
94
+
95
+ end # Kompiler::ARMv8A
96
+
97
+ end # Kompiler
@@ -0,0 +1,39 @@
1
+ # Copyright 2024 Kyrylo Shyshko
2
+ # Licensed under the Apache License, Version 2.0. See LICENSE file for details.
3
+
4
+ module Kompiler
5
+
6
+ module ARMv8A
7
+
8
+ def self.sys_registers
9
+ @sys_registers
10
+ end
11
+
12
+ @sys_registers = [
13
+ {reg_name: "mpidr_el0", reg_size: 64, reg_type: "sr", reg_encoding: {"op0"=>3, "op1"=>0, "CRn"=>0, "CRm"=>0, "op2"=>5}, rw_type: "ro"},
14
+
15
+ {reg_name: "vbar_el1", reg_size: 64, reg_type: "sr", reg_encoding: {"op0"=>0b11, "op1"=>0, "CRn"=>0b1100, "CRm"=>0, "op2"=>0}, rw_type: "rw"},
16
+ {reg_name: "vbar_el12", reg_size: 64, reg_type: "sr", reg_encoding: {"op0"=>0b11, "op1"=>0b101, "CRn"=>0b1100, "CRm"=>0, "op2"=>0}, rw_type: "rw"},
17
+ {reg_name: "vbar_el2", reg_size: 64, reg_type: "sr", reg_encoding: {"op0"=>0b11, "op1"=>0b100, "CRn"=>0b1100, "CRm"=>0, "op2"=>0}, rw_type: "rw"},
18
+ {reg_name: "vbar_el3", reg_size: 64, reg_type: "sr", reg_encoding: {"op0"=>0b11, "op1"=>0b110, "CRn"=>0b1100, "CRm"=>0, "op2"=>0}, rw_type: "rw"},
19
+
20
+
21
+ # Special registers for the MSR (immediate) instruction (some of them were previously defined already)
22
+ {reg_name: "SPSel", reg_type: "pstate_reg"},
23
+ {reg_name: "DAIFSet", reg_type: "pstate_reg"},
24
+ {reg_name: "DAIFClr", reg_type: "pstate_reg"},
25
+ {reg_name: "UAO", reg_type: "pstate_reg"},
26
+ {reg_name: "PAN", reg_type: "pstate_reg"},
27
+ {reg_name: "ALLINT", reg_type: "pstate_reg"},
28
+ {reg_name: "PM", reg_type: "pstate_reg"},
29
+ {reg_name: "SSBS", reg_type: "pstate_reg"},
30
+ {reg_name: "DIT", reg_type: "pstate_reg"},
31
+ {reg_name: "SVCRSM", reg_type: "pstate_reg"},
32
+ {reg_name: "SVCRZA", reg_type: "pstate_reg"},
33
+ {reg_name: "SVCRSMZA", reg_type: "pstate_reg"},
34
+ {reg_name: "TCO", reg_type: "pstate_reg"},
35
+ ]
36
+
37
+ end # Kompiler::ARMv8A
38
+
39
+ end # Kompiler
@@ -168,7 +168,7 @@ def self.construct_program_mc(parsed_lines, labels)
168
168
  lines_bytes = ""
169
169
 
170
170
 
171
- program_state = {labels: labels, current_address: 0}
171
+ program_state = {labels: labels, current_address: 0, instruction_variables: {}}
172
172
 
173
173
  parsed_lines.each do |line|
174
174
  case line[:type]
@@ -179,6 +179,7 @@ def self.construct_program_mc(parsed_lines, labels)
179
179
  mc_constructor = line[:instruction][:mc_constructor]
180
180
 
181
181
  instr_bits = Kompiler::MachineCode_AST.build_mc(mc_constructor, program_state)
182
+ program_state[:instruction_variables] = Hash.new # Clear the instruction variables after running the instruction
182
183
 
183
184
  instr_bytes = bits_to_bytes(instr_bits)
184
185
 
@@ -259,4 +260,4 @@ end
259
260
 
260
261
  end # Kompiler::CompilerFunctions
261
262
 
262
- end # Kompiler
263
+ end # Kompiler
@@ -3,13 +3,13 @@
3
3
 
4
4
  module Kompiler
5
5
 
6
- class Directives
6
+ module Directives
7
7
 
8
8
  def self.directives
9
- @@DIRECTIVES
9
+ @directives
10
10
  end
11
11
 
12
- @@DIRECTIVES = [
12
+ @directives = [
13
13
  {
14
14
  keyword: "zeros",
15
15
  func: lambda do |operands, state|
@@ -3,10 +3,11 @@
3
3
 
4
4
  module Kompiler
5
5
 
6
- class MachineCode_AST
6
+ module MachineCode_AST
7
7
 
8
- MC_AST_NODES = [
8
+ @MC_AST_NODES = [
9
9
  {name: "get_operand", n_args: 1, func: lambda {|args, state| state[:operands][args[0]][:value]} },
10
+ {name: "get_operand_hash", n_args: 1, func: lambda {|args, state| state[:operands][args[0]] } },
10
11
  {name: "get_bits", n_args: 3, func: lambda {|args, state| (args[1]...(args[1] + args[2])).map{|bit_i| args[0][bit_i]} } },
11
12
  {name: "get_bits_signed", n_args: 3, func: lambda do |args, state|
12
13
  if args[1] == 0
@@ -38,9 +39,21 @@ MC_AST_NODES = [
38
39
  end
39
40
  eval_mc_node_arg(args.last, state)
40
41
  end},
41
- {name: "raise_error", n_args: 1, func: lambda {|args, state| raise args[0] } },
42
- {name: "get_key", n_args: 2, func: lambda {|args, state| args[0][args[1]] }},
42
+
43
+ {name: "raise_error", n_args: 1, func: lambda {|args, state| raise args[0]; [] } },
44
+ {name: "raise_warning", n_args: 1, func: lambda {|args, state| puts args[0]; [] } },
45
+
46
+ {name: "get_key", n_args: 2, func: lambda {|args, state| args[0].keys.include?(args[1]) ? args[0][args[1]] : raise("MC Constructor get_key Error: The key \"#{args[1]}\" doesn't exist - Program build not possible. This is likely a problem with the ISA configuration, not the program being compiled.") }},
43
47
  {name: "concat", n_args: "any", func: lambda {|args, state| args.flatten}},
48
+ {name: "set_var", n_args: 2, func: lambda {|args, state| state[:instruction_variables][args[0]] = args[1]; [] }},
49
+ {name: "get_var", n_args: 1, func: lambda {|args, state| state[:instruction_variables].keys.include?(args[0]) ? state[:instruction_variables][args[0]] : raise("Instruction variable \"#{args[0]}\" not found: Program build not possible. This is likely a program with the ISA configuration, not the program being compiled.") }},
50
+
51
+ # String manipulations
52
+ {name: "downcase_str", n_args: 1, func: lambda {|args, state| args[0].downcase }},
53
+
54
+ # Bit manipulations
55
+ {name: "bit_and", n_args: 2, func: lambda {|args, state| args[0] & args[1] }},
56
+ {name: "bit_or", n_args: 2, func: lambda {|args, state| args[0] | args[1] }},
44
57
  ]
45
58
 
46
59
  def self.is_ast_node(val)
@@ -57,7 +70,8 @@ def self.run_mc_ast(node, state)
57
70
  node_name = node[0]
58
71
  node_args = node[1..]
59
72
 
60
- node_logic = MC_AST_NODES.filter{|any_node| any_node[:name] == node_name}[0]
73
+
74
+ node_logic = @MC_AST_NODES.filter{|any_node| any_node[:name] == node_name}[0]
61
75
 
62
76
  if !node_logic
63
77
  raise "MC Node \"#{node_name}\" wasn't found. Cannot build the program"
@@ -97,4 +111,4 @@ end
97
111
 
98
112
  end # Kompiler::MC_AST
99
113
 
100
- end # Kompiler
114
+ end # Kompiler
@@ -86,7 +86,10 @@ end
86
86
 
87
87
  def self.check_register_operand(str)
88
88
  Kompiler::Architecture.registers.each do |register|
89
- return [true, register] if str == register[:reg_name]
89
+ # Downcase both the string and the register if the register name is not case sensitive (the default)
90
+ processed_str = register[:case_sensitive] ? str : str.downcase
91
+ processed_reg_name = register[:case_sensitive] ? register[:reg_name] : register[:reg_name].downcase
92
+ return [true, register] if processed_str == processed_reg_name
90
93
  end
91
94
  return [false, nil]
92
95
  end
@@ -172,16 +175,16 @@ end
172
175
  def self.check_immediate_operand(operand_str)
173
176
 
174
177
  is_bin, bin_value = check_binary_operand(operand_str)
175
- return [true, {type: "immediate", value: bin_value, def_type: "binary"}] if is_bin
178
+ return [true, {type: "immediate", value: bin_value, def_type: "binary", definition: operand_str}] if is_bin
176
179
 
177
180
  is_decimal, decimal_value = check_decimal_operand(operand_str)
178
- return [true, {type: "immediate", value: decimal_value, def_type: "decimal"}] if is_decimal
181
+ return [true, {type: "immediate", value: decimal_value, def_type: "decimal", definition: operand_str}] if is_decimal
179
182
 
180
183
  is_hex, hex_value = check_hex_operand(operand_str)
181
- return [true, {type: "immediate", value: hex_value, def_type: "hex"}] if is_hex
184
+ return [true, {type: "immediate", value: hex_value, def_type: "hex", definition: operand_str}] if is_hex
182
185
 
183
186
  is_char, char_value = check_char_operand(operand_str)
184
- return [true, {type: "immediate", value: char_value, def_type: "char"}] if is_char
187
+ return [true, {type: "immediate", value: char_value, def_type: "char", definition: operand_str}] if is_char
185
188
 
186
189
  return [false, nil]
187
190
  end
@@ -208,11 +211,11 @@ def self.parse_operand_str(operand_str)
208
211
 
209
212
  # Check if the operand is a register
210
213
  is_register, register = check_register_operand(operand_str)
211
- return {type: "register", value: register, register: register} if is_register
214
+ return {type: "register", value: register, register: register, definition: operand_str} if is_register
212
215
 
213
216
  # Check if the operand is a string
214
217
  is_string = operand_str[0] == "\""
215
- return {type: "string", value: operand_str[1...-1], string: operand_str[1...-1]} if is_string
218
+ return {type: "string", value: operand_str[1...-1], string: operand_str[1...-1], definition: operand_str} if is_string
216
219
 
217
220
  # Checks if it's an immediate
218
221
  is_immediate, immediate_val = check_immediate_operand(operand_str)
@@ -225,7 +228,7 @@ def self.parse_operand_str(operand_str)
225
228
 
226
229
  # The operand is a label if it doesn't start with a number and doesn't include spaces
227
230
  is_label = check_label_operand(operand_str)
228
- return {type: "label", value: operand_str} if is_label
231
+ return {type: "label", value: operand_str, definition: operand_str} if is_label
229
232
 
230
233
 
231
234
  # If no checks succeeded, return false
@@ -319,128 +322,37 @@ end
319
322
 
320
323
 
321
324
 
322
-
323
-
324
- # def self.parse_instruction_line(line)
325
- # keyword = ""
326
- # i = 0
327
- #
328
- # # Loop until a non-whitespace character
329
- # while i < line.size
330
- # break if ![" ", "\t"].include?(line[i])
331
- # i += 1
332
- # end
333
- #
334
- # # Loop to get the keyword
335
- # loop do
336
- # # Exit out of the loop if the character is a whitespace
337
- # break if [" ", "\t"].include?(line[i]) || i >= line.size
338
- # # Add the character if not a whitespace
339
- # keyword << line[i]
340
- # # Proceed to the next character
341
- # i += 1
342
- # end
343
- #
344
- # operand_strings = []
345
- #
346
- # # Loop for operands
347
- # loop do
348
- # break if i >= line.size
349
- #
350
- # # Whitespace - skip
351
- # if [" ", "\t"].include? line[i]
352
- # i += 1
353
- # next
354
- # end
355
- #
356
- # # If a string operand - parse the string
357
- # if line[i] == "\""
358
- #
359
- # str_content, parsed_size = parse_str(line[i..])
360
- # operand_strings << line[i...(i + parsed_size)]
361
- # i += parsed_size
362
- #
363
- # # If anything else - parse until whitespace, comma or end of line
364
- # else
365
- # content = ""
366
- #
367
- # while i < line.size
368
- # break if [" ", ","].include? line[i]
369
- # content << line[i]
370
- # i += 1
371
- # end
372
- #
373
- # operand_strings << content
374
- # end
375
- #
376
- #
377
- # # After operand parsed
378
- # # Loop to meet a comma or end of line
379
- # # Give error if stuff except whitespace
380
- #
381
- # while i < line.size
382
- # # If comma, move to next character and repeat the bigger operand loop
383
- # if line[i] == ","
384
- # i += 1
385
- # break
386
- # end
387
- # # If non-whitespace, raise an error
388
- # # raise "Error: Unparsed content - exiting" if ![" ", "\t"].include?(line[i])
389
- # return false if ![" ", "\t"].include?(line[i])
390
- # i += 1
391
- # end
392
- # end
393
- #
394
- # # If end of line not reached, return an error
395
- # if i != line.size
396
- # return false
397
- # end
398
- #
399
- #
400
- # # Parse operand strings into operand types and values
401
- #
402
- # operands = []
403
- #
404
- # operand_strings.each do |operand_str|
405
- # operand = parse_operand_str(operand_str)
406
- # return false if operand == false
407
- # operands << operand
408
- # end
409
- #
410
- # return [keyword, operands]
411
- # end
412
-
413
-
414
-
415
325
  def self.check_operand_match(operand_description, operand)
416
326
 
417
327
  # If operand type doesn't not match, return false
418
328
  return false if operand[:type] != operand_description[:type]
419
329
 
420
- # If no operand restrictions, return true
421
- return true if !operand_description.keys.include?(:restrictions)
330
+ # Get the restrictions
331
+ operand_restrictions = operand_description[:restrictions]
332
+ return true if !operand_restrictions # If no restrictions, return true
422
333
 
423
- case operand_description[:type]
334
+ # Get the operand's values / encoding
335
+ case operand[:type]
424
336
  when "register"
425
-
426
- # Check register type match
427
- if operand_description[:restrictions].keys.include?(:reg_type)
428
- return false if operand[:register][:reg_type] != operand_description[:restrictions][:reg_type]
429
- end
430
-
431
- # Check register size match
432
- if operand_description[:restrictions].keys.include?(:reg_size)
433
- return false if operand[:register][:reg_size] != operand_description[:restrictions][:reg_size]
434
- end
435
-
337
+ operand_encoding = operand[:value]
436
338
  when "immediate"
437
-
438
-
439
-
440
- when "label"
441
-
442
-
443
-
339
+ operand_encoding = operand[:value]
340
+ when "string"
341
+ operand_encoding = Hash.new
342
+ end
343
+
344
+ # Loop through each restriction to see if the operand matches it
345
+ operand_restrictions.each do |r_key, r_spec|
346
+ # Get the restricted value of the operand
347
+ op_value = operand_encoding[r_key]
348
+
349
+ # Check if it matches the restriction specification
350
+ # If an array, the OR algorithm works (the operand key value must be one of the specified values in the r_spec list)
351
+ if r_spec.is_a? Array
352
+ return false if !r_spec.include?(op_value)
353
+ else # If not an array, just check of equality
354
+ return false if op_value != r_spec
355
+ end
444
356
  end
445
357
 
446
358
 
@@ -448,6 +360,9 @@ def self.check_operand_match(operand_description, operand)
448
360
  return true
449
361
  end
450
362
 
363
+
364
+
365
+
451
366
 
452
367
  # Returns array of [status, operands]
453
368
  # If status = false, operands = nil; otherwise, status = true, operands = instruction operands
@@ -531,4 +446,4 @@ end
531
446
  end # End Kompiler::Parsers
532
447
 
533
448
 
534
- end # End Kompiler
449
+ end # End Kompiler
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kompiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyryl Shyshko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-04 00:00:00.000000000 Z
11
+ date: 2024-12-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Kompiler is a low-level, modular and extendable compiler for any architecture.
14
14
  By default Kompiler supports ARMv8-a, but other architecture extensions can be downloaded
@@ -30,6 +30,8 @@ files:
30
30
  - lib/kompiler/architectures/armv8a/instructions.rb
31
31
  - lib/kompiler/architectures/armv8a/load.rb
32
32
  - lib/kompiler/architectures/armv8a/registers.rb
33
+ - lib/kompiler/architectures/armv8a/sys_instructions.rb
34
+ - lib/kompiler/architectures/armv8a/sys_registers.rb
33
35
  - lib/kompiler/compiler_functions.rb
34
36
  - lib/kompiler/directives.rb
35
37
  - lib/kompiler/mc_builder.rb