rpicsim 0.2.4 → 0.2.5

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
  SHA1:
3
- metadata.gz: 360adb3e53d15c48aed0e03a171f1225da93b449
4
- data.tar.gz: 6cb9ef3afd2aa5ae18921e4f8ffc7d68b2ed03bc
3
+ metadata.gz: afe68ca6fbd8c66eefc707b4927bbb453d2e37ef
4
+ data.tar.gz: fe03453f4ef52094c9f4bc7ec792c146ac1828a4
5
5
  SHA512:
6
- metadata.gz: 7563dced8a0e911600556d60da82723c3162f766a11aa68efa2a23c6f369258a5a51d1d76458f2b7d57aad740cb72ba929ceb5b4555006b90e29047d89e93e94
7
- data.tar.gz: f2ee852bed01b1858ff873509f4a6209b4022e258295d04a96e5b540ac07338254b3ed34aa24720d5f3028c1481b92c587ace0c4ae0d0782787c0fc5c5f03dc8
6
+ metadata.gz: e87d3ca4fbd555c4de565aaef804caf1214bb75cf0d742fd48ac0a2bedbca23dc974937e2ef731fd015b469a1d93c947345fa0c8b0bc3392606e16766ef65eb8
7
+ data.tar.gz: 5d07e1d1f9cf043b908477eba77f668205ea2460ff6df5e1484dd8e1743945c3533d0b31ca9f0c0dd4ec8e373e141d7a0ede172488cd7a1265e768b15190e67b
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ group :development do
4
4
  gem 'rspec'
5
5
  gem 'rake'
6
6
  gem 'simplecov'
7
- gem 'deg-yard' # My little fork of the yard gem that has some bug fixes.
7
+ gem 'yard'
8
8
  gem 'guard'
9
9
  gem 'guard-rspec'
10
10
  gem 'rubocop', '0.18.1' # They made breaking changes in 0.19.x so let's not update yet.
data/docs/ChangeLog.md CHANGED
@@ -1,6 +1,14 @@
1
1
  Change log
2
2
  ====
3
3
 
4
+ 0.2.5
5
+ ----
6
+ Released on 2014-05-02.
7
+
8
+ - {RPicSim::Sim#stack_push} and {RPicSim::Sim#return} now update the TOSU, TOSH, and TOSL registers if they exist.
9
+ This fixes bugs that were happening when using those methods in PIC18 simulations.
10
+ - Added recognition for more types of symbols found in XC8-generated COF files, but there are still issues with proper identification of variables in programs compiled with XC8.
11
+
4
12
  0.2.4
5
13
  ----
6
14
  Released on 2014-03-17.
data/docs/KnownIssues.md CHANGED
@@ -191,3 +191,9 @@ These issues might affect other PIC architectures as well.
191
191
 
192
192
  These issues are tested in `spec/integration/adc_midrange_spec.rb`. The bad modulus issue was {http://www.microchip.com/forums/m760886.aspx reported to Microchip} in November 2013.
193
193
 
194
+
195
+ Variables from XC8 are not correctly identified
196
+ ----
197
+
198
+ RAM variables in programs using the XC8 compiler are often misidentified as being in program memory, and you need to get their address using {RPicSim::ProgramFile#symbols_in_program_memory}.
199
+ Some variables are not be identified at all, and you would have to write code to get their addresses from the SYM file.
@@ -70,11 +70,12 @@ module RPicSim
70
70
  end
71
71
 
72
72
  private
73
+
73
74
  def generate
74
75
  @max_depths = { @root => 0 }
75
76
  @back_links = Hash.new { [] }
76
77
  instructions_to_process = [root]
77
- while !instructions_to_process.empty?
78
+ until instructions_to_process.empty?
78
79
  instruction = instructions_to_process.pop
79
80
  instruction.transitions.reverse_each do |transition|
80
81
  ni = transition.next_instruction
@@ -97,6 +98,7 @@ module RPicSim
97
98
  end
98
99
  end
99
100
  end
101
+
100
102
  public
101
103
 
102
104
  # Returns all the {Instruction}s that have the worse case possible call stack depth.
@@ -161,8 +163,8 @@ module RPicSim
161
163
 
162
164
  # For each instruction that has a code path leading to it, pick out
163
165
  # the shortest code path (in terms of interesting instructions).
164
- code_paths = code_paths.group_by { |cp| cp.instructions.last }.map do |instr, code_paths|
165
- code_paths.min_by { |cp| cp.interesting_instructions.count }
166
+ code_paths = code_paths.group_by { |cp| cp.instructions.last }.map do |instr, paths|
167
+ paths.min_by { |cp| cp.interesting_instructions.count }
166
168
  end
167
169
 
168
170
  code_paths
@@ -297,6 +299,5 @@ module RPicSim
297
299
  interesting_instructions.join("\n") + "\n"
298
300
  end
299
301
  end
300
-
301
302
  end
302
303
  end
@@ -35,7 +35,7 @@ module RPicSim
35
35
  end
36
36
 
37
37
  def valid_address?(address)
38
- find_memory(address) != nil
38
+ !find_memory(address).nil?
39
39
  end
40
40
 
41
41
  private
data/lib/rpicsim/flaws.rb CHANGED
@@ -83,6 +83,5 @@ module RPicSim
83
83
  flaw.affects_version '2.05', false
84
84
  flaw.probably_affects_other_versions :false
85
85
  end
86
-
87
86
  end
88
87
  end
@@ -206,9 +206,10 @@ module RPicSim
206
206
  end
207
207
 
208
208
  private
209
+
209
210
  # For certain opcodes, this method gets over-written.
210
211
  def generate_transitions
211
- [ advance(1) ]
212
+ [advance(1)]
212
213
  end
213
214
 
214
215
  # Makes a transition representing the default behavior: the microcontroller
@@ -217,7 +218,7 @@ module RPicSim
217
218
  transition(address + num * size)
218
219
  end
219
220
 
220
- def transition(addr, attrs={})
221
+ def transition(addr, attrs = {})
221
222
  Transition.new(self, addr, @instruction_store, attrs)
222
223
  end
223
224
 
@@ -260,7 +261,7 @@ module RPicSim
260
261
  module Goto
261
262
  def generate_transitions
262
263
  # Assumption: The GOTO instruction's k operand is absolute on all architectures
263
- [ transition(k_address, non_local: true) ]
264
+ [transition(k_address, non_local: true)]
264
265
  end
265
266
  end
266
267
 
@@ -269,7 +270,7 @@ module RPicSim
269
270
  # skipped depending on some condition.
270
271
  module ConditionalSkip
271
272
  def generate_transitions
272
- [ advance(1), advance(2) ]
273
+ [advance(1), advance(2)]
273
274
  end
274
275
  end
275
276
 
@@ -284,25 +285,25 @@ module RPicSim
284
285
  # This module is mixed into any {Instruction} that represents a subroutine call.
285
286
  module Call
286
287
  def generate_transitions
287
- [ transition(k_address, call_depth_change: 1), advance(1) ]
288
+ [transition(k_address, call_depth_change: 1), advance(1)]
288
289
  end
289
290
  end
290
291
 
291
292
  module RelativeCall
292
293
  def generate_transitions
293
- [ transition(n_address, call_depth_change: 1), advance(1) ]
294
+ [transition(n_address, call_depth_change: 1), advance(1)]
294
295
  end
295
296
  end
296
297
 
297
298
  module ConditionalRelativeBranch
298
299
  def generate_transitions
299
- [ transition(n_address, non_local: true), advance(1) ]
300
+ [transition(n_address, non_local: true), advance(1)]
300
301
  end
301
302
  end
302
303
 
303
304
  module RelativeBranch
304
305
  def generate_transitions
305
- [ transition(relative_target_address, non_local: true) ]
306
+ [transition(relative_target_address, non_local: true)]
306
307
  end
307
308
  end
308
309
 
@@ -328,7 +329,6 @@ module RPicSim
328
329
  def call_depth_change
329
330
  @attrs.fetch(:call_depth_change, 0)
330
331
  end
331
-
332
332
  end
333
333
  end
334
334
  end
@@ -45,6 +45,5 @@ module RPicSim
45
45
  def valid_address?(address)
46
46
  @mplab_memory.valid_address?(address)
47
47
  end
48
-
49
48
  end
50
49
  end
@@ -72,6 +72,7 @@ module RPicSim
72
72
  end
73
73
 
74
74
  private
75
+
75
76
  def remove_vars(vars, var_names_to_remove)
76
77
  vars.reject! do |key, val|
77
78
  name = key.is_a?(Integer) ? key : key.name
@@ -85,6 +86,5 @@ module RPicSim
85
86
 
86
87
  [:PCL, :PCLATH, :STATUS]
87
88
  end
88
-
89
89
  end
90
90
  end
@@ -64,6 +64,7 @@ module RPicSim::Mplab
64
64
  end
65
65
 
66
66
  private
67
+
67
68
  # Gets a com.microchip.mplab.mdbcore.debugger.Debugger object.
68
69
  def debugger
69
70
  lookup Mdbcore.debugger.Debugger.java_class
@@ -102,6 +103,5 @@ module RPicSim::Mplab
102
103
  $stderr.puts "warning: MPLAB X will be looking for files at a bad path: #{path}"
103
104
  end
104
105
  end
105
-
106
106
  end
107
107
  end
@@ -98,6 +98,5 @@ module RPicSim::Mplab
98
98
  unsigned
99
99
  end
100
100
  end
101
-
102
101
  end
103
102
  end
@@ -90,7 +90,7 @@ module RPicSim::Mplab
90
90
  end
91
91
 
92
92
  def cannot_find_mplab_error
93
- 'Cannot find MPLABX. Install it in the standard location or ' +
93
+ 'Cannot find MPLABX. Install it in the standard location or ' \
94
94
  'set the RPICSIM_MPLABX environment variable to its full path.'
95
95
  end
96
96
 
@@ -37,7 +37,7 @@ module RPicSim::Mplab
37
37
  MplabObserver.new(@memory) do |event|
38
38
  next if event.EventType != Mdbcore.memory::MemoryEvent::EVENTS::MEMORY_CHANGED
39
39
  address_ranges = event.AffectedAddresses.map do |mr|
40
- mr.Address...(mr.Address+mr.Size)
40
+ mr.Address...(mr.Address + mr.Size)
41
41
  end
42
42
  yield address_ranges
43
43
  end
@@ -7,7 +7,7 @@ module RPicSim::Mplab
7
7
  raise "File does not exist: #{filename}" if !File.exist?(filename) # Avoid a Java exception.
8
8
 
9
9
  if !File.realdirpath(filename).split('/').include?('dist')
10
- raise 'The file must be inside a directory named dist or else the MCLoader ' +
10
+ raise 'The file must be inside a directory named dist or else the MCLoader ' \
11
11
  'class will throw an exception saying that it cannot find the COF file.'
12
12
  end
13
13
 
@@ -56,22 +56,29 @@ module RPicSim::Mplab
56
56
  # 22 MPASM program memory or EEPROM
57
57
  # 40 XC8 local variable (pointer to a struct?)
58
58
  # 44 XC8 local variable
59
+ # 64 XC8 program memory function
59
60
  # 65 XC8 program memory function
61
+ # 66 XC8 program memory function
62
+ # 69 XC8 program memory function
60
63
  # 76 XC8 program memory function
64
+ # 78 XC8 program memory function
65
+ # 79 XC8 program memory function
66
+ # 81 XC8 program memory function
67
+ # 82 XC8 program memory function
68
+ # 104 XC8 program memory variable (array of unions) (but sometimes in RAM instead)
61
69
  # 108 XC8 program memory variable (array)
62
- # 110 XC8 program memory variable (struct)
70
+ # 110 XC8 program memory variable (struct) (but sometimes in RAM instead)
71
+ # 111 XC8 program memory variable (array of uint32_t) (but sometimes it is in RAM instead)
63
72
  # 366 XC8 program memory variable (array of pointers)
64
73
  #
65
74
  # TODO: make a test for each of these cases; TestXC8.c and program_file_spec.rb only only has a few
66
75
  def memory_type(symbol)
67
76
  case symbol.m_lType
68
- when 0, 2, 8, 12
77
+ when 0, 2, 8, 12, 40, 44, 108
69
78
  :ram
70
79
  when 22
71
80
  EepromRange.include?(symbol.address) ? :eeprom : :program_memory
72
- when 12, 40, 44, 108
73
- :ram
74
- when 14, 65, 76, 110, 366
81
+ when 14, 64, 65, 66, 69, 76, 78, 79, 81, 82, 104, 110, 111, 366
75
82
  :program_memory
76
83
  else
77
84
  :unknown
@@ -80,7 +87,7 @@ module RPicSim::Mplab
80
87
 
81
88
  # Useful for debugging.
82
89
  # Just put this line in your simulation class definition temporarily:
83
- # pp program_file.instance_variable_get(:@mplab_program_file).send(:symbol_dump)
90
+ # pp program_file.instance_variable_get(:@mplab_program_file).send(:symbol_dump).sort
84
91
  def symbol_dump
85
92
  symbols.map { |s| [s.m_Symbol, s.m_lType, s.address, memory_type(s)] }
86
93
  end
@@ -1,5 +1,4 @@
1
1
  module RPicSim
2
-
3
2
  # Instances of this class represent the program counter in a
4
3
  # simulated microcontroller.
5
4
  class ProgramCounter
@@ -2,6 +2,10 @@ require_relative 'mplab'
2
2
  require_relative 'label'
3
3
  require_relative 'instruction'
4
4
 
5
+ # TODO: interface for adding labels and/or symbols from other sources because
6
+ # sometimes the COF file is inadequate. When symbols have the same address,
7
+ # think about how to choose the more interesting one in a stack trace (fewer underscores?)
8
+
5
9
  module RPicSim
6
10
  # Represents a PIC program file (e.g. COF or HEX).
7
11
  class ProgramFile
@@ -97,6 +101,7 @@ module RPicSim
97
101
  end
98
102
 
99
103
  private
104
+
100
105
  def message_for_label_not_found(name)
101
106
  message = "Cannot find label named '#{name}'."
102
107
 
@@ -42,7 +42,6 @@ module RPicSim
42
42
  raise "Invalid sim_shortcuts configuration value: #{configuration_value.inspect}"
43
43
  end
44
44
  end
45
-
46
45
  end
47
46
  end
48
47
  end
@@ -10,7 +10,7 @@ module RPicSim
10
10
  # graph backwards in order to find code_paths for a given instruction.
11
11
  def self.depth_first_search_simple(root_nodes)
12
12
  unprocessed_nodes = root_nodes.reverse
13
- while !unprocessed_nodes.empty?
13
+ until unprocessed_nodes.empty?
14
14
  node = unprocessed_nodes.pop
15
15
  nodes = yield node
16
16
  unprocessed_nodes.concat(nodes.reverse)
data/lib/rpicsim/sim.rb CHANGED
@@ -19,10 +19,8 @@ module RPicSim
19
19
  # This class keeps track of the state of the simulation and provides methods for
20
20
  # running the simulation, reading the state, and changing the state.
21
21
  class Sim
22
-
23
22
  # These methods should be called while defining a subclass of {Sim}.
24
23
  module ClassDefinitionMethods
25
-
26
24
  # Specifies what exact device the firmware runs on.
27
25
  # @param device [String] The device name, for example "PIC10F322".
28
26
  def use_device(device)
@@ -72,7 +70,7 @@ module RPicSim
72
70
  # firmware and call it a different thing in your tests.
73
71
  # This option is ignored if +:address is specified.
74
72
  # * +:address+: An integer to use as the address of the variable.
75
- def def_var(name, type, opts={})
73
+ def def_var(name, type, opts = {})
76
74
  if @variable_set.nil?
77
75
  raise 'The device and filename need to be specified before defining variables.'
78
76
  end
@@ -81,7 +79,6 @@ module RPicSim
81
79
 
82
80
  self::Shortcuts.send(:define_method, name) { var name }
83
81
  end
84
-
85
82
  end
86
83
 
87
84
  # These are class methods that you can call on subclasses of {Sim}.
@@ -108,6 +105,7 @@ module RPicSim
108
105
  attr_reader :program_file
109
106
 
110
107
  private
108
+
111
109
  # This gets called when a new subclass of PicSim is created.
112
110
  def inherited(subclass)
113
111
  subclass.instance_eval do
@@ -127,7 +125,6 @@ module RPicSim
127
125
  @variable_set.def_memory_type :program_memory, program_file.symbols_in_program_memory
128
126
  @variable_set.def_memory_type :eeprom, program_file.symbols_in_eeprom
129
127
  end
130
-
131
128
  end
132
129
 
133
130
  # This module is used in RPicSim's {file:RSpecIntegration.md RSpec integration}
@@ -217,11 +214,15 @@ module RPicSim
217
214
 
218
215
  # Returns a string like "PIC10F322" specifying the PIC device number.
219
216
  # @return [String]
220
- def device; self.class.device; end
217
+ def device
218
+ self.class.device
219
+ end
221
220
 
222
221
  # Returns the path to the firmware file.
223
222
  # @return [String]
224
- def filename; self.class.filename; end
223
+ def filename
224
+ self.class.filename
225
+ end
225
226
 
226
227
  # Makes a new simulation using the settings specified when the class was defined.
227
228
  def initialize
@@ -392,7 +393,7 @@ module RPicSim
392
393
  # This option is a more powerful version of +cycle_limit+, so it cannot
393
394
  # be used at the same time as +cycle_limit+.
394
395
  # @return The condition that was met which caused the run to stop.
395
- def run_to(conditions, opts={})
396
+ def run_to(conditions, opts = {})
396
397
  conditions = Array(conditions)
397
398
  if conditions.empty?
398
399
  raise ArgumentError, 'Must specify at least one condition.'
@@ -420,8 +421,8 @@ module RPicSim
420
421
  max_cycle = start_cycle + opts[:cycle_limit] if opts[:cycle_limit]
421
422
  end
422
423
 
423
- # Loop as long as none of the conditions are satisfied.
424
- while !(met_condition_index = condition_procs.find_index(&:call))
424
+ # Loop until one of the conditions is satisfied.
425
+ until (met_condition_index = condition_procs.find_index(&:call))
425
426
  if max_cycle && cycle_count >= max_cycle
426
427
  raise "Failed to reach #{conditions.inspect} after #{cycle_count - start_cycle} cycles."
427
428
  end
@@ -476,7 +477,7 @@ module RPicSim
476
477
  # generally point to a subroutine in program memory that will end by
477
478
  # executing a return instructions.
478
479
  # @param opts Any of the options supported by {#run_to}.
479
- def run_subroutine(location, opts={})
480
+ def run_subroutine(location, opts = {})
480
481
  stack_push pc.value
481
482
  goto location
482
483
  run_to :return, opts
@@ -509,6 +510,7 @@ module RPicSim
509
510
  # Simulate popping the stack.
510
511
  stack_pointer.value -= 1
511
512
  pc.value = @stack_memory.read_word(stack_pointer.value)
513
+ update_top_of_stack_registers
512
514
  end
513
515
 
514
516
  # Generates a friendly human-readable string description of where the
@@ -525,6 +527,7 @@ module RPicSim
525
527
 
526
528
  @stack_memory.write_word(stack_pointer.value, value)
527
529
  stack_pointer.value += 1
530
+ update_top_of_stack_registers
528
531
  end
529
532
 
530
533
  # Gets the contents of the stack as an array of integers.
@@ -553,6 +556,26 @@ module RPicSim
553
556
  StackTrace.new(entries)
554
557
  end
555
558
 
559
+ private
560
+
561
+ # Update the TOSU:TOSH:TOSL registers because the simulator uses those
562
+ # (if they exist) when simulating a return instruction.
563
+ def update_top_of_stack_registers
564
+ return unless @sfrs.key?(:TOSL)
565
+
566
+ tos = if stack_pointer.value == 0
567
+ 0
568
+ else
569
+ @stack_memory.read_word(stack_pointer.value - 1)
570
+ end
571
+
572
+ reg(:TOSL).value = tos >> 0 & 0xFF
573
+ reg(:TOSH).value = tos >> 8 & 0xFF
574
+ reg(:TOSU).value = tos >> 16 & 0xFF if @sfrs.key?(:TOSU)
575
+ end
576
+
577
+ public
578
+
556
579
  def inspect
557
580
  "#<#{self.class}:0x%x, #{pc_description}, stack_pointer = #{stack_pointer.value}>" % object_id
558
581
  end
@@ -579,7 +602,7 @@ module RPicSim
579
602
  c
580
603
 
581
604
  when Integer
582
- Proc.new { pc.value == c }
605
+ proc { pc.value == c }
583
606
 
584
607
  when :return
585
608
  current_val = stack_pointer.value
@@ -588,7 +611,7 @@ module RPicSim
588
611
  else
589
612
  target_val = current_val - 1
590
613
  end
591
- Proc.new { stack_pointer.value == target_val }
614
+ proc { stack_pointer.value == target_val }
592
615
 
593
616
  when Label
594
617
  convert_condition_to_proc c.address
@@ -619,6 +642,7 @@ module RPicSim
619
642
  end
620
643
 
621
644
  private
645
+
622
646
  def ram_vars
623
647
  ram_var_names = self.class.variable_set.var_names_for_memory(:ram)
624
648
  @vars.values_at(*ram_var_names)
@@ -632,5 +656,4 @@ module RPicSim
632
656
  @assembly.device_info.code_address_increment
633
657
  end
634
658
  end
635
-
636
659
  end
@@ -6,7 +6,7 @@ module RPicSim
6
6
  @entries = entries
7
7
  end
8
8
 
9
- def output(io, padding='')
9
+ def output(io, padding = '')
10
10
  @entries.reverse_each do |entry|
11
11
  output_entry(entry, io, padding)
12
12
  end
@@ -54,6 +54,7 @@ module RPicSim::Storage
54
54
  end
55
55
 
56
56
  private
57
+
57
58
  def check_value(value, allowed_values)
58
59
  if !allowed_values.include?(value)
59
60
  raise ArgumentError, "Invalid value #{value} written to #{name}."
@@ -75,7 +76,6 @@ module RPicSim::Storage
75
76
  check_value val, 0..255
76
77
  @memory.write_byte(@address, val)
77
78
  end
78
-
79
79
  end
80
80
 
81
81
  # Represents a signed 8-bit variable.
@@ -231,5 +231,4 @@ module RPicSim::Storage
231
231
  @memory.write_word(@address, val)
232
232
  end
233
233
  end
234
-
235
234
  end
@@ -21,7 +21,7 @@ module RPicSim
21
21
  @vars_for_memory_by_address[name] = {}
22
22
  end
23
23
 
24
- def def_var(name, type, opts={})
24
+ def def_var(name, type, opts = {})
25
25
  allowed_keys = [:memory, :symbol, :address]
26
26
  invalid_keys = opts.keys - allowed_keys
27
27
  if !invalid_keys.empty?
@@ -69,12 +69,12 @@ module RPicSim
69
69
  end
70
70
 
71
71
  vars_by_address = @vars_for_memory_by_address[memory_type]
72
- variable.addresses.each do |address|
73
- if vars_by_address[address]
72
+ variable.addresses.each do |occupied_address|
73
+ if vars_by_address[occupied_address]
74
74
  raise 'Variable %s overlaps with %s at 0x%x' %
75
- [variable, @vars_by_address[address], address]
75
+ [variable, vars_by_address[occupied_address], occupied_address]
76
76
  end
77
- vars_by_address[address] = variable
77
+ vars_by_address[occupied_address] = variable
78
78
  end
79
79
 
80
80
  @vars_for_memory[memory_type][name] = variable
@@ -1,3 +1,3 @@
1
1
  module RPicSim
2
- VERSION = '0.2.4'
2
+ VERSION = '0.2.5'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpicsim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pololu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-17 00:00:00.000000000 Z
11
+ date: 2014-05-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: