kompiler 0.2.0 → 0.3.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
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