rpicsim 0.2.4 → 0.2.5

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
  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: