haxor 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  module Haxor
2
2
  class Consts
3
3
  MAJOR = 0
4
- MINOR = 3
4
+ MINOR = 4
5
5
  PATCH = 0
6
6
  GEM_VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
7
  VERSION = (MAJOR << 16) | (MINOR << 8) | PATCH
@@ -11,21 +11,8 @@ module Haxor
11
11
  WORD_SIZE = 8 # 64bit
12
12
  WORD_UNPACK = 'q<'
13
13
 
14
- RESERVED_MEM = 2048 # 1024 for CPU, 1024 for IVT
15
- IVT_ADDR = 1024
16
-
17
- # OpCode
18
- OPCODE_CMD_MASK = 0x0000_0000_0000_00ff
19
- OPCODE_FLG_MASK = 0xffff_ffff_ffff_ff00 # << 8
20
- OPCODE_FLG_OFFSET = 8
21
- # 8 bits of flag - 1st operand
22
- # 8 bits of flag - 2nd operand
23
-
24
- OPERAND_FLAGS = 8 # how many bits per operand
25
- OPERAND_DEREFERENCE = (1 << 0) # Dereference operand (aka *operand)
26
-
27
- # Flags Registry Flags
28
- FR_ZERO = 1 << 0 # a-b == 0
29
- FR_SIGN = 1 << 1 # a-b < 0
14
+ IVT_MEM = 1024
15
+ IVT_ADDR = 0
16
+ RESERVED_MEM = IVT_MEM
30
17
  end
31
18
  end
@@ -8,7 +8,7 @@ module Haxor
8
8
  @cpu = Vm::Cpu::Core.new
9
9
  @units = []
10
10
  @tokens = []
11
- @labels = @cpu.labels.clone
11
+ @labels = {}
12
12
  @stack = 4096
13
13
  end
14
14
 
@@ -56,9 +56,17 @@ module Haxor
56
56
  end
57
57
 
58
58
  def unwind_pointers
59
- walk_tokens(Token::Pointer) do |token|
60
- fail "Label not found: #{token.label}." unless @labels.key? token.label
61
- token.data = @labels[token.label].absolute_addr
59
+ walk_tokens(Token::Cmd) do |token|
60
+ next unless token.imm.is_a? String
61
+ fail "Label not found: #{token.imm}." unless @labels.key? token.imm
62
+
63
+ token.imm = @labels[token.imm].absolute_addr
64
+
65
+ if token.opts.include? :rel_imm
66
+ token.imm -= token.absolute_addr + Consts::WORD_SIZE
67
+ end
68
+
69
+ token.imm /= Consts::WORD_SIZE if token.opts.include? :x8
62
70
  end
63
71
  end
64
72
 
@@ -1,8 +1,35 @@
1
1
  module Haxor
2
2
  module Token
3
- class Cmd < Int64
3
+ class Cmd < Base
4
+ attr_accessor :cmd
5
+ attr_accessor :flags
6
+ attr_accessor :reg1
7
+ attr_accessor :reg2
8
+ attr_accessor :reg3
9
+ attr_accessor :imm
10
+ attr_accessor :opts
11
+
12
+ def initialize
13
+ @cmd = 0
14
+ @flags = 0
15
+ @reg1 = 0
16
+ @reg2 = 0
17
+ @reg3 = 0
18
+ @imm = 0
19
+ @opts = []
20
+ end
21
+
22
+ def size
23
+ Consts::WORD_SIZE
24
+ end
25
+
26
+ def to_bytecode
27
+ data = Utils.encode_opcode @cmd, @flags, @reg1, @reg2, @reg3, @imm
28
+ [data].pack Consts::WORD_UNPACK
29
+ end
30
+
4
31
  def to_s
5
- "Cmd -> 0x#{@data.to_s(16)}"
32
+ "CMD code:[0x#{@cmd.to_s(16)}], flags:[#{@flags.to_s(2)}], regs:[#{@reg1}, #{@reg2}, #{@reg3}], imm:[#{@imm}], opts:#{@opts}"
6
33
  end
7
34
  end
8
35
  end
@@ -0,0 +1,24 @@
1
+ module Haxor
2
+ module Utils
3
+ def self.encode_opcode(cmd = 0, flags = 0, reg1 = 0, reg2 = 0, reg3 = 0, imm = 0)
4
+ result = cmd
5
+ result |= flags << 7
6
+ result |= reg1 << 9
7
+ result |= reg2 << 15
8
+ result |= reg3 << 21
9
+ result |= imm << 27
10
+ result
11
+ end
12
+
13
+ def self.decode_opcode(opcode)
14
+ r = OpenStruct.new
15
+ r.cmd = opcode & 0x7f
16
+ r.flags = (opcode >> 7) & 0x03
17
+ r.reg1 = (opcode >> 9) & 0x3f
18
+ r.reg2 = (opcode >> 15) & 0x3f
19
+ r.reg3 = (opcode >> 21) & 0x3f
20
+ r.imm = (opcode >> 27)
21
+ r
22
+ end
23
+ end
24
+ end
@@ -9,12 +9,7 @@ module Haxor
9
9
  register_subsystem :mem, Mem.new(Consts::RESERVED_MEM)
10
10
  register_subsystem :stack, Stack.new
11
11
  register_subsystem :os, Os.new
12
- register_subsystem :registers, Registers.new
13
-
14
- subsystem(:cpu).labels.each do |_, label|
15
- subsystem(:mem).add_label label.label, label.absolute_addr
16
- subsystem(:registers).add_register label.label, label.absolute_addr
17
- end
12
+ # register_subsystem :registers, Registers.new
18
13
 
19
14
  @units = []
20
15
  @opcodes = {}
@@ -41,14 +36,16 @@ module Haxor
41
36
  @hdr = Header.new
42
37
  @hdr.parse! exe
43
38
 
44
- fail if @hdr.version != Consts::VERSION
39
+ if @hdr.version != Consts::VERSION
40
+ fail 'Program is compiled for different version of Haxor VM Machine'
41
+ end
45
42
 
46
43
  exe = exe[@hdr.size..-1] # cut off header
47
44
  subsystem(:mem).replace_region Consts::RESERVED_MEM, exe
48
- subsystem(:registers).write 'ip', @hdr.entry_point # instruction pointer
45
+ subsystem(:cpu).ip = @hdr.entry_point # instruction pointer
49
46
  subsystem(:mem).enlarge @hdr.bss_size
50
47
  subsystem(:mem).enlarge @hdr.stack_size
51
- subsystem(:registers).write 'sp', subsystem(:mem).size
48
+ subsystem(:cpu).reg Vm::Cpu::Core::REG_STACK, subsystem(:mem).size
52
49
  end
53
50
  end
54
51
  end
@@ -2,126 +2,257 @@ module Haxor
2
2
  module Vm
3
3
  module Cpu
4
4
  class Core < Subsystem
5
- attr_reader :struct
6
- attr_reader :labels
5
+ attr_accessor :ip
6
+
7
+ # Misc
8
+ OP_NOP = 0x00
9
+ OP_EXITI = 0x01
10
+ OP_SYSCALL = 0x02
11
+
12
+ # Arithmetic
13
+ OP_ADD = 0x10
14
+ OP_ADDI = 0x11
15
+ OP_SUB = 0x12
16
+ OP_MULT = 0x13
17
+ OP_DIV = 0x14
18
+ OP_MOD = 0x15
19
+
20
+ # Data transfer
21
+ OP_LW = 0x20
22
+ OP_SW = 0x21
23
+ OP_LUI = 0x22
24
+
25
+ # Logical
26
+ OP_AND = 0x30
27
+ OP_ANDI = 0x31
28
+ OP_OR = 0x32
29
+ OP_ORI = 0x33
30
+ OP_XOR = 0x34
31
+ OP_NOR = 0x35
32
+ OP_SLT = 0x36
33
+ OP_SLTI = 0x37
34
+
35
+ # Bitwise shift
36
+ OP_SLLI = 0x40
37
+ OP_SRLI = 0x41
38
+ OP_SLL = 0x42
39
+ OP_SRL = 0x43
40
+
41
+ # Branch/Jumps
42
+ OP_BEQ = 0x50
43
+ OP_BEQL = 0x51
44
+ OP_BNE = 0x52
45
+ OP_BNEL = 0x53
46
+ OP_J = 0x54
47
+ OP_JR = 0x55
48
+ OP_JAL = 0x56
49
+
50
+ REG_ZERO = 0
51
+ REG_STACK = 61
52
+ REG_RETURN = 62
53
+ REG_SYSCALL = 63
7
54
 
8
55
  def initialize
56
+ @registers = Array.new(64, 0)
9
57
  @units = []
10
58
  @opcodes = {}
59
+ init_opcodes
60
+ end
11
61
 
12
- register_unit Unit::Arithmetic.new
13
- register_unit Unit::Jumps.new
14
- register_unit Unit::Logical.new
15
- register_unit Unit::Transfer.new
16
- register_unit Unit::Various.new
62
+ def init_opcodes
63
+ bind_opcode OP_NOP, :op_nop
64
+ bind_opcode OP_ADD, :op_add
65
+ bind_opcode OP_ADDI, :op_addi
66
+ bind_opcode OP_SUB, :op_sub
67
+ bind_opcode OP_MULT, :op_mult
68
+ bind_opcode OP_DIV, :op_div
69
+ bind_opcode OP_MOD, :op_mod
70
+ bind_opcode OP_LW, :op_lw
71
+ bind_opcode OP_SW, :op_sw
72
+ bind_opcode OP_LUI, :op_lui
73
+ bind_opcode OP_AND, :op_and
74
+ bind_opcode OP_ANDI, :op_andi
75
+ bind_opcode OP_OR, :op_or
76
+ bind_opcode OP_ORI, :op_ori
77
+ bind_opcode OP_XOR, :op_xor
78
+ bind_opcode OP_NOR, :op_nor
79
+ bind_opcode OP_SLT, :op_slt
80
+ bind_opcode OP_SLTI, :op_slti
81
+ bind_opcode OP_SLLI, :op_slli
82
+ bind_opcode OP_SRLI, :op_srli
83
+ bind_opcode OP_SLL, :op_sll
84
+ bind_opcode OP_SRL, :op_srl
85
+ bind_opcode OP_BEQ, :op_beq
86
+ bind_opcode OP_BEQL, :op_beql
87
+ bind_opcode OP_BNE, :op_bne
88
+ bind_opcode OP_BNEL, :op_bnel
89
+ bind_opcode OP_J, :op_j
90
+ bind_opcode OP_JR, :op_jr
91
+ bind_opcode OP_JAL, :op_jal
92
+ bind_opcode OP_EXITI, :op_exiti
93
+ bind_opcode OP_SYSCALL, :op_syscall
94
+ end
17
95
 
18
- build_struct
96
+ def op_nop(info)
19
97
  end
20
98
 
21
- def bind_opcode(opcode, object, method)
22
- fail "OpCode already defined - #{opcode}." if @opcodes.key? opcode
23
- @opcodes[opcode] = {
24
- object: object,
25
- method: method
26
- }
99
+ def op_add(info)
100
+ reg info.reg1, reg(info.reg2) + reg(info.reg3)
27
101
  end
28
102
 
29
- def iterate
30
- opcode = subsystem(:mem).next_cell
31
- cmd = opcode & Consts::OPCODE_CMD_MASK
32
- subsystem(:mem).write 'op', opcode
103
+ def op_addi(info)
104
+ reg info.reg1, reg(info.reg2) + info.imm
105
+ end
106
+
107
+ def op_sub(info)
108
+ reg info.reg1, reg(info.reg2) - reg(info.reg3)
109
+ end
110
+
111
+ def op_mult(info)
112
+ reg info.reg1, reg(info.reg2) * reg(info.reg3)
113
+ end
114
+
115
+ def op_div(info)
116
+ reg info.reg1, reg(info.reg2) / reg(info.reg3)
117
+ end
118
+
119
+ def op_mod(info)
120
+ reg info.reg1, reg(info.reg2) % reg(info.reg3)
121
+ end
122
+
123
+ # reg1 = memory[reg2+imm]
124
+ def op_lw(info)
125
+ addr = reg(info.reg2) + info.imm
126
+ reg info.reg1, subsystem(:mem).read(addr)
127
+ end
128
+
129
+ # memory[reg1+imm] = reg2
130
+ def op_sw(info)
131
+ addr = reg(info.reg1) + info.imm
132
+ subsystem(:mem).write addr, reg(info.reg2)
133
+ end
134
+
135
+ def op_lui(info)
136
+ reg info.reg1, (info.imm << 32)
137
+ end
138
+
139
+ def op_and(info)
140
+ reg info.reg1, reg(info.reg2) & reg(info.reg3)
141
+ end
142
+
143
+ def op_andi(info)
144
+ reg info.reg1, reg(info.reg2) & info.imm
145
+ end
33
146
 
34
- fail "Call to not existing opcode #{cmd}." unless @opcodes.key? cmd
35
- # puts 'cmd = ' + cmd.to_s(16)
36
- # puts flg.to_s(16)
37
- @opcodes[cmd][:object].send(@opcodes[cmd][:method])
147
+ def op_or(info)
148
+ reg info.reg1, reg(info.reg2) | reg(info.reg3)
38
149
  end
39
150
 
40
- def reserved_mem
41
- 1024
151
+ def op_ori(info)
152
+ reg info.reg1, reg(info.reg2) | info.imm
42
153
  end
43
154
 
44
- def register_unit(unit)
45
- @units << unit
46
- unit.vm = self
47
- unit.register
155
+ def op_xor(info)
156
+ reg info.reg1, reg(info.reg2) ^ reg(info.reg3)
48
157
  end
49
158
 
50
- def operand
51
- operands(1)[0]
159
+ def op_nor(info)
160
+ reg info.reg1, ~(reg(info.reg2) | reg(info.reg3))
52
161
  end
53
162
 
54
- def operands(n = 2)
55
- flg = subsystem(:mem).read('op') & Consts::OPCODE_FLG_MASK
56
- flg >> Consts::OPCODE_FLG_OFFSET
163
+ def op_slt(info)
164
+ reg info.reg1, reg(info.reg2) < reg(info.reg3) ? 1 : 0
165
+ end
57
166
 
58
- result = []
59
- n.times do
60
- v = subsystem(:mem).next_cell
61
- v = subsystem(:mem).read a if (flg & Consts::OPERAND_DEREFERENCE != 0)
62
- result << v
63
- flg << Consts::OPERAND_FLAGS
64
- end
167
+ def op_slti(info)
168
+ reg info.reg1, reg(info.reg2) < info.imm ? 1 : 0
169
+ end
65
170
 
66
- result
171
+ def op_slli(info)
172
+ reg info.reg1, reg(info.reg2) << info.imm
67
173
  end
68
174
 
69
- private
175
+ def op_srli(info)
176
+ reg info.reg1, reg(info.reg2) >> info.imm
177
+ end
70
178
 
71
- def build_struct
72
- @struct = []
179
+ def op_sll(info)
180
+ reg info.reg1, reg(info.reg2) << reg(info.reg3)
181
+ end
73
182
 
74
- @struct << Token::Label.new('null')
75
- @struct << Token::Int64.new(0)
183
+ def op_srl(info)
184
+ reg info.reg1, reg(info.reg2) >> reg(info.reg3)
185
+ end
186
+
187
+ def op_beq(info)
188
+ branch(info.imm) if reg(info.reg1) == reg(info.reg2)
189
+ end
190
+
191
+ def op_beql(info)
192
+ return if reg(info.reg1) != reg(info.reg2)
193
+
194
+ reg REG_RETURN, @ip
195
+ branch(info.imm)
196
+ end
197
+
198
+ def op_bne(info)
199
+ branch info.imm if reg(info.reg1) != reg(info.reg2)
200
+ end
76
201
 
77
- @struct << Token::Label.new('registers')
202
+ def op_bnel(info)
203
+ return if reg(info.reg1) == reg(info.reg2)
78
204
 
79
- # instruction pointer
80
- @struct << Token::Label.new('ip')
81
- @struct << Token::Int64.new(0)
205
+ reg REG_RETURN, @ip
206
+ branch(info.imm)
207
+ end
82
208
 
83
- # stack pointer
84
- @struct << Token::Label.new('sp')
85
- @struct << Token::Int64.new(0)
209
+ def op_j(info)
210
+ jmp info.imm
211
+ end
86
212
 
87
- # base pointer
88
- @struct << Token::Label.new('bp')
89
- @struct << Token::Int64.new(0)
213
+ def op_jr(info)
214
+ @ip = reg(info.reg1)
215
+ end
90
216
 
91
- # arithmetic registry I
92
- @struct << Token::Label.new('ar')
93
- @struct << Token::Int64.new(0)
217
+ def op_jal(info)
218
+ reg REG_RETURN, @ip
219
+ jmp info.imm
220
+ end
94
221
 
95
- # arithmetic registry II
96
- @struct << Token::Label.new('dr')
97
- @struct << Token::Int64.new(0)
222
+ def op_exiti(info)
223
+ exit info.imm
224
+ end
98
225
 
99
- # flags registry
100
- @struct << Token::Label.new('fr')
101
- @struct << Token::Int64.new(0)
226
+ def op_syscall(_info)
227
+ @vm.subsystem(:os).syscall
228
+ end
102
229
 
103
- # currently processed opcode (with opcode flags)
104
- @struct << Token::Label.new('op')
105
- @struct << Token::Int64.new(0)
230
+ def reg(id, value = nil)
231
+ return @registers[id] if value.nil?
232
+ return if id == REG_ZERO # $0 cannot be overwritten
233
+ @registers[id] = value
234
+ end
106
235
 
107
- # system call
108
- @struct << Token::Label.new('sc')
109
- @struct << Token::Int64.new(0)
236
+ def jmp(addr)
237
+ @ip = addr * Consts::WORD_SIZE
238
+ end
110
239
 
111
- # general usage registers
112
- (1..10).each do |i|
113
- @struct << Token::Label.new(format('r%02d', i))
114
- @struct << Token::Int64.new(0)
115
- end
240
+ def branch(rel_addr)
241
+ @ip += rel_addr * Consts::WORD_SIZE
242
+ end
116
243
 
117
- addr = 0
118
- @labels = {}
119
- @struct.each do |token|
120
- token.absolute_addr = addr
121
- addr += token.size
244
+ def bind_opcode(opcode, method)
245
+ fail "OpCode already defined - #{opcode}." if @opcodes.key? opcode
246
+ @opcodes[opcode] = {
247
+ method: method
248
+ }
249
+ end
122
250
 
123
- @labels[token.label] = token if token.is_a? Token::Label
124
- end
251
+ def iterate
252
+ opcode = subsystem(:mem).read @ip
253
+ @ip += Consts::WORD_SIZE
254
+ info = Utils.decode_opcode opcode
255
+ send @opcodes[info.cmd][:method], info
125
256
  end
126
257
  end
127
258
  end