lignite 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,116 @@
1
+ module Lignite
2
+ # Compile a conditional jump forward or backward
3
+ class Condition
4
+ # Call that instruction of the compiler
5
+ # that jumps by *offset* according to the condition that we implement
6
+ def cond_jump(_compiler, _offset)
7
+ raise ScriptError, "subclasses must override this"
8
+ end
9
+
10
+ # Negation of this condition.
11
+ # An `if(cond){ body }` becomes roughly `cond.not.jump_forward(body.size); body`
12
+ def not
13
+ raise ScriptError, "subclasses must override this"
14
+ end
15
+
16
+ def jump_forward(compiler, body_size)
17
+ cond_jump(compiler, body_size)
18
+ end
19
+
20
+ def jump_back(compiler, body_size, self_size = nil)
21
+ if self_size.nil?
22
+ fake = compiler.clone_context
23
+ jump_back(fake, body_size, 0)
24
+ self_size = fake.bytes.bytesize
25
+ end
26
+
27
+ cond_jump(compiler, - (body_size + self_size))
28
+ end
29
+ end
30
+
31
+ # A condition that is always true
32
+ class Always < Condition
33
+ def not
34
+ Never.new
35
+ end
36
+
37
+ def cond_jump(compiler, offset)
38
+ compiler.jr(JumpOffset.new(offset))
39
+ end
40
+ end
41
+
42
+ # A condition that is never true
43
+ class Never < Condition
44
+ def not
45
+ Always.new
46
+ end
47
+
48
+ def cond_jump(compiler, _offset)
49
+ # Never jump: do a jump of size 0
50
+ # but it must be a jump because code size calculations need that
51
+ compiler.jr(JumpOffset.new(0))
52
+ end
53
+ end
54
+
55
+ # Less-than (32 bit)
56
+ class Lt32 < Condition
57
+ def initialize(a, b)
58
+ @a = a
59
+ @b = b
60
+ end
61
+
62
+ def not
63
+ Gteq32.new(@a, @b)
64
+ end
65
+
66
+ def cond_jump(compiler, offset)
67
+ compiler.jr_lt32(@a, @b, JumpOffset.new(offset))
68
+ end
69
+ end
70
+
71
+ # Greater-than-or-equal (32 bit)
72
+ class Gteq32 < Condition
73
+ def initialize(a, b)
74
+ @a = a
75
+ @b = b
76
+ end
77
+
78
+ def not
79
+ Lt32.new(@a, @b)
80
+ end
81
+
82
+ def cond_jump(compiler, offset)
83
+ compiler.jr_gteq32(@a, @b, JumpOffset.new(offset))
84
+ end
85
+ end
86
+
87
+ # Test a boolean flag
88
+ class Flag < Condition
89
+ def initialize(f)
90
+ @f = f
91
+ end
92
+
93
+ def not
94
+ NotFlag.new(@f)
95
+ end
96
+
97
+ def cond_jump(compiler, offset)
98
+ compiler.jr_true(@f, JumpOffset.new(offset))
99
+ end
100
+ end
101
+
102
+ # Test a negated boolean flag
103
+ class NotFlag < Condition
104
+ def initialize(f)
105
+ @f = f
106
+ end
107
+
108
+ def not
109
+ Flag.new(@f)
110
+ end
111
+
112
+ def cond_jump(compiler, offset)
113
+ compiler.jr_false(@f, JumpOffset.new(offset))
114
+ end
115
+ end
116
+ end
@@ -5,18 +5,22 @@ module Lignite
5
5
  class Connection
6
6
  include Bytes
7
7
  include Logger
8
+ extend Logger
8
9
 
9
10
  # @return [Connection] Try a {Usb} connection first, then a {Bluetooth} one.
10
11
  def self.create
11
12
  @c ||= Replay.new(ENV["LIGNITE_REPLAY"]) if ENV["LIGNITE_REPLAY"]
12
13
 
13
14
  @c ||= begin
15
+ logger.debug "Connection: trying USB"
14
16
  Usb.new
15
17
  rescue NoUsbDevice
18
+ logger.debug "Connection: trying BT"
16
19
  Bluetooth.new
17
20
  end
18
21
 
19
22
  @c = Tap.new(@c, ENV["LIGNITE_TAP"]) if ENV["LIGNITE_TAP"]
23
+ logger.debug "Connection: #{@c.inspect}"
20
24
  @c
21
25
  end
22
26
 
@@ -140,7 +140,7 @@ module Lignite
140
140
 
141
141
  bytes = u8(0x09)
142
142
  bytes += param_simple(objid)
143
- bytes += param_multiple(*parameters)
143
+ bytes += param_n_multiple(*parameters)
144
144
  logger.debug "returning bytecode: #{bytes.inspect}"
145
145
  bytes
146
146
  end
@@ -862,7 +862,23 @@ module Lignite
862
862
  bytes
863
863
  end
864
864
 
865
- # Could not define init_bytes: Unhandled param type PARVALUES
865
+ # Move LENGTH number of DATA8 from BYTE STREAM to memory DESTINATION START
866
+ # @param destination [PAR8] (out) First element in DATA8 array to be initiated
867
+ # @param length [PAR32] (in) Number of elements to initiate
868
+ # @param source [PARVALUES] (in) First element to initiate DATA8 array with
869
+ def init_bytes(destination, length, *source)
870
+ logger.debug do
871
+ args = [destination, length, *source]
872
+ "called init_bytes with #{args.inspect}"
873
+ end
874
+
875
+ bytes = u8(0x2F)
876
+ bytes += param_simple(destination)
877
+ bytes += param_simple(length)
878
+ bytes += param_multiple(*source)
879
+ logger.debug "returning bytecode: #{bytes.inspect}"
880
+ bytes
881
+ end
866
882
 
867
883
  # Move 8 bit value from SOURCE to DESTINATION
868
884
  # @param source [PAR8] (in)
@@ -6045,7 +6061,7 @@ module Lignite
6045
6061
  bytes += param_simple(no)
6046
6062
  bytes += param_simple(type)
6047
6063
  bytes += param_simple(mode)
6048
- bytes += param_multiple(*values)
6064
+ bytes += param_n_multiple(*values)
6049
6065
  logger.debug "returning bytecode: #{bytes.inspect}"
6050
6066
  bytes
6051
6067
  end
@@ -6070,7 +6086,7 @@ module Lignite
6070
6086
  bytes += param_simple(no)
6071
6087
  bytes += param_simple(type)
6072
6088
  bytes += param_simple(mode)
6073
- bytes += param_multiple(*values)
6089
+ bytes += param_n_multiple(*values)
6074
6090
  logger.debug "returning bytecode: #{bytes.inspect}"
6075
6091
  bytes
6076
6092
  end
@@ -6095,7 +6111,7 @@ module Lignite
6095
6111
  bytes += param_simple(no)
6096
6112
  bytes += param_simple(type)
6097
6113
  bytes += param_simple(mode)
6098
- bytes += param_multiple(*values)
6114
+ bytes += param_n_multiple(*values)
6099
6115
  logger.debug "returning bytecode: #{bytes.inspect}"
6100
6116
  bytes
6101
6117
  end
@@ -6277,7 +6293,7 @@ module Lignite
6277
6293
  bytes += param_simple(type)
6278
6294
  bytes += param_simple(mode)
6279
6295
  bytes += param_simple(format)
6280
- bytes += param_multiple(*values)
6296
+ bytes += param_n_multiple(*values)
6281
6297
  logger.debug "returning bytecode: #{bytes.inspect}"
6282
6298
  bytes
6283
6299
  end
@@ -7559,19 +7575,95 @@ module Lignite
7559
7575
  #
7560
7576
  Lignite::INIT8 = 8
7561
7577
 
7562
- # Could not define array_init8: Unhandled param type PARVALUES
7578
+ #
7579
+ # @param handle [PAR16] (in) Array handle
7580
+ # @param index [PAR32] (in) Index to element to write
7581
+ # @param elements [PAR32] (in) Number of elements to write
7582
+ # @param values [PARVALUES] (in)
7583
+ def array_init8(handle, index, elements, *values)
7584
+ logger.debug do
7585
+ args = [handle, index, elements, *values]
7586
+ "called array_init8 with #{args.inspect}"
7587
+ end
7588
+
7589
+ bytes = u8(0xC1)
7590
+ bytes += param_simple(8)
7591
+ bytes += param_simple(handle)
7592
+ bytes += param_simple(index)
7593
+ bytes += param_simple(elements)
7594
+ bytes += param_multiple(*values)
7595
+ logger.debug "returning bytecode: #{bytes.inspect}"
7596
+ bytes
7597
+ end
7563
7598
  #
7564
7599
  Lignite::INIT16 = 9
7565
7600
 
7566
- # Could not define array_init16: Unhandled param type PARVALUES
7601
+ #
7602
+ # @param handle [PAR16] (in) Array handle
7603
+ # @param index [PAR32] (in) Index to element to write
7604
+ # @param elements [PAR32] (in) Number of elements to write
7605
+ # @param values [PARVALUES] (in)
7606
+ def array_init16(handle, index, elements, *values)
7607
+ logger.debug do
7608
+ args = [handle, index, elements, *values]
7609
+ "called array_init16 with #{args.inspect}"
7610
+ end
7611
+
7612
+ bytes = u8(0xC1)
7613
+ bytes += param_simple(9)
7614
+ bytes += param_simple(handle)
7615
+ bytes += param_simple(index)
7616
+ bytes += param_simple(elements)
7617
+ bytes += param_multiple(*values)
7618
+ logger.debug "returning bytecode: #{bytes.inspect}"
7619
+ bytes
7620
+ end
7567
7621
  #
7568
7622
  Lignite::INIT32 = 10
7569
7623
 
7570
- # Could not define array_init32: Unhandled param type PARVALUES
7624
+ #
7625
+ # @param handle [PAR16] (in) Array handle
7626
+ # @param index [PAR32] (in) Index to element to write
7627
+ # @param elements [PAR32] (in) Number of elements to write
7628
+ # @param values [PARVALUES] (in)
7629
+ def array_init32(handle, index, elements, *values)
7630
+ logger.debug do
7631
+ args = [handle, index, elements, *values]
7632
+ "called array_init32 with #{args.inspect}"
7633
+ end
7634
+
7635
+ bytes = u8(0xC1)
7636
+ bytes += param_simple(10)
7637
+ bytes += param_simple(handle)
7638
+ bytes += param_simple(index)
7639
+ bytes += param_simple(elements)
7640
+ bytes += param_multiple(*values)
7641
+ logger.debug "returning bytecode: #{bytes.inspect}"
7642
+ bytes
7643
+ end
7571
7644
  #
7572
7645
  Lignite::INITF = 11
7573
7646
 
7574
- # Could not define array_initf: Unhandled param type PARVALUES
7647
+ #
7648
+ # @param handle [PAR16] (in) Array handle
7649
+ # @param index [PAR32] (in) Index to element to write
7650
+ # @param elements [PAR32] (in) Number of elements to write
7651
+ # @param values [PARVALUES] (in)
7652
+ def array_initf(handle, index, elements, *values)
7653
+ logger.debug do
7654
+ args = [handle, index, elements, *values]
7655
+ "called array_initf with #{args.inspect}"
7656
+ end
7657
+
7658
+ bytes = u8(0xC1)
7659
+ bytes += param_simple(11)
7660
+ bytes += param_simple(handle)
7661
+ bytes += param_simple(index)
7662
+ bytes += param_simple(elements)
7663
+ bytes += param_multiple(*values)
7664
+ logger.debug "returning bytecode: #{bytes.inspect}"
7665
+ bytes
7666
+ end
7575
7667
  #
7576
7668
  Lignite::SIZE = 12
7577
7669
 
@@ -8924,7 +9016,7 @@ module Lignite
8924
9016
  bytes += param_simple(hardware)
8925
9017
  bytes += param_simple(boxname)
8926
9018
  bytes += param_simple(type)
8927
- bytes += param_multiple(*values)
9019
+ bytes += param_n_multiple(*values)
8928
9020
  logger.debug "returning bytecode: #{bytes.inspect}"
8929
9021
  bytes
8930
9022
  end
@@ -8942,7 +9034,7 @@ module Lignite
8942
9034
  bytes = u8(0xDA)
8943
9035
  bytes += param_simple(no)
8944
9036
  bytes += param_simple(length)
8945
- bytes += param_multiple(*values)
9037
+ bytes += param_n_multiple(*values)
8946
9038
  logger.debug "returning bytecode: #{bytes.inspect}"
8947
9039
  bytes
8948
9040
  end
@@ -32,14 +32,15 @@ module Lignite
32
32
  desc "download BRICK_FILENAME [LOCAL_FILENAME]", "download a file"
33
33
  map "dl" => "download"
34
34
  def download(brick_filename, local_filename = nil)
35
+ chunk_size = 1000 # 2000 stalls, 4096 goes out of sync in our code
35
36
  local_filename ||= File.basename(brick_filename)
36
- fsize, handle, data = sc.begin_upload(4096, brick_filename)
37
+ fsize, handle, data = sc.begin_upload(chunk_size, brick_filename)
37
38
  File.open(local_filename, "w") do |f|
38
39
  loop do
39
40
  f.write(data)
40
41
  fsize -= data.bytesize
41
42
  break if fsize.zero?
42
- handle, data = sc.continue_upload(handle, 4096)
43
+ handle, data = sc.continue_upload(handle, chunk_size)
43
44
  end
44
45
  end
45
46
  end
@@ -55,6 +56,12 @@ module Lignite
55
56
  puts raw_ls(name)
56
57
  end
57
58
 
59
+ desc "asm RUBYFILE RBFFILE", "assemble RUBYFILE to RBFFILE"
60
+ def asm(ruby_fn, rbf_fn)
61
+ a = Assembler.new
62
+ a.assemble(ruby_fn, rbf_fn)
63
+ end
64
+
58
65
  no_commands do
59
66
  def raw_list_files(name)
60
67
  name ||= EV3TOOL_HOME
@@ -0,0 +1,18 @@
1
+ module Lignite
2
+ # A specialized Integer.
3
+ # When compiling jumps, the jump instruction itself must have a constant size
4
+ # so this class is special-cased in {OpCompiler#param_simple}.
5
+ class JumpOffset
6
+ # @return [Integer]
7
+ attr_reader :value
8
+
9
+ def size
10
+ 2
11
+ end
12
+
13
+ def initialize(v)
14
+ raise "Jumping too far: #{value}" if v.abs > 32767
15
+ @value = v
16
+ end
17
+ end
18
+ end
@@ -13,9 +13,18 @@ module Lignite
13
13
 
14
14
  # 0x02 | 0x04 | 0x08 -> [1, 2, 3]
15
15
  def nos_as_indices
16
- [0, 1, 2, 3].find_all do |n|
16
+ r = [0, 1, 2, 3].find_all do |n|
17
17
  (nos & (1 << n)) != 0
18
18
  end
19
+ r
20
+ end
21
+
22
+ # 0x02 | 0x04 | 0x08 -> [0x02, 0x04, 0x08]
23
+ def nos_as_bits
24
+ r = [1, 2, 4, 8].find_all do |n|
25
+ (nos & n) != 0
26
+ end
27
+ r
19
28
  end
20
29
 
21
30
  def initialize(layer, nos, dc = Lignite::DirectCommands.new)
@@ -85,17 +94,17 @@ module Lignite
85
94
  end
86
95
 
87
96
  # ATTR running?
97
+ # @return [Boolean] true if busy/running
88
98
  def test
89
99
  layer = @layer
90
- nos_as_indices.map do |no|
91
- busy = dc.with_reply do
92
- data8 :busy
93
- block do
94
- output_test(layer, no, :busy)
95
- end
100
+ nos = @nos
101
+ busy = dc.with_reply do
102
+ data8 :busy
103
+ block do
104
+ output_test(layer, nos, :busy)
96
105
  end
97
- busy
98
106
  end
107
+ busy != 0
99
108
  end
100
109
 
101
110
  # which commands are affected? not output_start they say
@@ -43,22 +43,29 @@ module Lignite
43
43
 
44
44
  PRIMPAR_LABEL = 0x20
45
45
 
46
- def make_lcn(n, bytes)
47
- case bytes
48
- when 0
49
- [n & PRIMPAR_VALUE]
50
- when 1
51
- [PRIMPAR_LONG | PRIMPAR_1_BYTE, n & 0xff]
52
- when 2
53
- [PRIMPAR_LONG | PRIMPAR_2_BYTES, n & 0xff, (n >> 8) & 0xff]
54
- else
55
- [PRIMPAR_LONG | PRIMPAR_4_BYTES,
56
- n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff]
46
+ # @param n [Integer] value to encode
47
+ # @param next_size [Integer] how many bytes follow the initial opcode
48
+ # @return [ByteString]
49
+ def numeric_literal_with_size(n, next_size)
50
+ bytes = case next_size
51
+ when 0
52
+ [n & PRIMPAR_VALUE]
53
+ when 1
54
+ [PRIMPAR_LONG | PRIMPAR_1_BYTE, n & 0xff]
55
+ when 2
56
+ [PRIMPAR_LONG | PRIMPAR_2_BYTES, n & 0xff, (n >> 8) & 0xff]
57
+ else
58
+ [PRIMPAR_LONG | PRIMPAR_4_BYTES,
59
+ n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff]
57
60
  end
61
+ bytes.map(&:chr).join("")
58
62
  end
59
63
 
60
- def make_lc(n, bytes = nil)
61
- bytes ||= if (-31..31).cover? n
64
+ # @param n [Integer] value to encode
65
+ # @param next_size [Integer] how many bytes follow the initial opcode
66
+ # @return [ByteString]
67
+ def numeric_literal(n, next_size = nil)
68
+ next_size ||= if (-31..31).cover? n
62
69
  0
63
70
  elsif (-127..127).cover? n
64
71
  1
@@ -67,12 +74,13 @@ module Lignite
67
74
  else
68
75
  4
69
76
  end
70
- make_lcn(n, bytes)
77
+ numeric_literal_with_size(n, next_size)
71
78
  end
72
79
 
80
+ # @return [ByteString]
73
81
  def make_v(n, local_or_global)
74
82
  vartag = PRIMPAR_VARIABEL | local_or_global
75
- if (0..31).cover? n
83
+ bytes = if (0..31).cover? n
76
84
  [vartag | (n & PRIMPAR_VALUE)]
77
85
  elsif (0..255).cover? n
78
86
  [vartag | PRIMPAR_LONG | PRIMPAR_1_BYTE, n & 0xff]
@@ -82,10 +90,12 @@ module Lignite
82
90
  [vartag | PRIMPAR_LONG | PRIMPAR_4_BYTES,
83
91
  n & 0xff, (n >> 8) & 0xff, (n >> 16) & 0xff, (n >> 24) & 0xff]
84
92
  end
93
+ bytes.map(&:chr).join("")
85
94
  end
86
95
 
87
96
  # Reference a variable.
88
97
  # (For declaring, see {VariableDeclarer}.)
98
+ # @return [ByteString]
89
99
  def make_var(sym)
90
100
  raise "No variables declared, cannot process symbols" if @locals.nil? && @globals.nil?
91
101
  if @locals.key?(sym)
@@ -99,27 +109,43 @@ module Lignite
99
109
  end
100
110
  end
101
111
 
112
+ # @return [ByteString]
113
+ def param_n_multiple(*args)
114
+ u8(args.size) + param_multiple(*args)
115
+ end
116
+
102
117
  # @return [ByteString]
103
118
  def param_multiple(*args)
104
- u8(args.size) + args.map { |a| param_simple(a) }.join("")
119
+ args.map { |a| param_simple(a) }.join("")
105
120
  end
106
121
 
107
122
  # @return [ByteString]
108
- def param_simple(x)
123
+ def param_simple_numeric(x)
109
124
  case x
110
125
  when Integer
111
- make_lc(x).map(&:chr).join("")
112
- when Complex
113
- # a Complex number:
114
- # #real: just like an Integer above, but
115
- # #imag tells how many bytes to use for it
116
- make_lc(x.real, x.imag).map(&:chr).join("")
117
- when String
118
- u8(0x80) + x + u8(0x00)
126
+ numeric_literal(x)
119
127
  when Float
120
128
  u8(0x83) + f32(x)
129
+ else
130
+ raise ArgumentError, "Unexpected type: #{x.class}"
131
+ end
132
+ end
133
+
134
+ # @return [ByteString]
135
+ def param_simple(x)
136
+ case x
137
+ when Numeric
138
+ param_simple_numeric(x)
139
+ when JumpOffset
140
+ numeric_literal(x.value, x.size)
141
+ when String
142
+ u8(0x80) + x + u8(0x00)
143
+ when true
144
+ param_simple(1)
145
+ when false
146
+ param_simple(0)
121
147
  when Symbol
122
- make_var(x).map(&:chr).join("")
148
+ make_var(x)
123
149
  else
124
150
  raise ArgumentError, "Unexpected type: #{x.class}"
125
151
  end