rpicsim 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/Gemfile +7 -6
  4. data/Introduction.md +3 -1
  5. data/README.md +2 -2
  6. data/docs/ChangeLog.md +6 -0
  7. data/docs/Contributing.md +1 -1
  8. data/docs/DefiningSimulationClass.md +11 -10
  9. data/docs/HowMPLABXIsFound.md +1 -1
  10. data/docs/IntegrationTesting.md +1 -1
  11. data/docs/IntroductionToRSpec.md +8 -5
  12. data/docs/IntroductionToRuby.md +2 -2
  13. data/docs/KnownIssues.md +46 -57
  14. data/docs/Labels.md +5 -4
  15. data/docs/Manual.md +1 -1
  16. data/docs/Memories.md +70 -0
  17. data/docs/PersistentExpectations.md +31 -2
  18. data/docs/Pins.md +5 -7
  19. data/docs/PreventingCallStackOverflow.md +4 -6
  20. data/docs/QuickStartGuide.md +5 -5
  21. data/docs/RSpecIntegration.md +2 -2
  22. data/docs/RamWatcher.md +22 -11
  23. data/docs/Running.md +4 -6
  24. data/docs/Stubbing.md +4 -4
  25. data/docs/SupportedDevices.md +2 -11
  26. data/docs/SupportedMPLABXVersions.md +1 -0
  27. data/docs/SupportedOperatingSystems.md +3 -2
  28. data/docs/UnitTesting.md +1 -1
  29. data/docs/Variables.md +81 -25
  30. data/lib/rpicsim.rb +0 -12
  31. data/lib/rpicsim/call_stack_info.rb +43 -47
  32. data/lib/rpicsim/composite_memory.rb +53 -0
  33. data/lib/rpicsim/flaws.rb +34 -22
  34. data/lib/rpicsim/instruction.rb +204 -48
  35. data/lib/rpicsim/label.rb +4 -4
  36. data/lib/rpicsim/memory.rb +44 -23
  37. data/lib/rpicsim/memory_watcher.rb +14 -22
  38. data/lib/rpicsim/mplab.rb +38 -119
  39. data/lib/rpicsim/mplab/mplab_assembly.rb +23 -18
  40. data/lib/rpicsim/mplab/mplab_device_info.rb +9 -9
  41. data/lib/rpicsim/mplab/mplab_disassembler.rb +5 -6
  42. data/lib/rpicsim/mplab/mplab_instruction.rb +87 -16
  43. data/lib/rpicsim/mplab/mplab_loader.rb +106 -0
  44. data/lib/rpicsim/mplab/mplab_memory.rb +19 -6
  45. data/lib/rpicsim/mplab/mplab_nmmr_info.rb +4 -4
  46. data/lib/rpicsim/mplab/mplab_observer.rb +15 -10
  47. data/lib/rpicsim/mplab/mplab_pin.rb +3 -3
  48. data/lib/rpicsim/mplab/mplab_processor.rb +5 -5
  49. data/lib/rpicsim/mplab/mplab_program_file.rb +29 -17
  50. data/lib/rpicsim/mplab/mplab_register.rb +5 -5
  51. data/lib/rpicsim/mplab/mplab_sfr_info.rb +4 -4
  52. data/lib/rpicsim/mplab/mplab_simulator.rb +27 -30
  53. data/lib/rpicsim/pin.rb +6 -6
  54. data/lib/rpicsim/program_counter.rb +3 -3
  55. data/lib/rpicsim/program_file.rb +39 -81
  56. data/lib/rpicsim/rspec/be_predicate.rb +1 -1
  57. data/lib/rpicsim/rspec/helpers.rb +1 -1
  58. data/lib/rpicsim/rspec/persistent_expectations.rb +17 -2
  59. data/lib/rpicsim/rspec/sim_diagnostics.rb +5 -5
  60. data/lib/rpicsim/search.rb +1 -1
  61. data/lib/rpicsim/sim.rb +153 -228
  62. data/lib/rpicsim/stack_pointer.rb +41 -0
  63. data/lib/rpicsim/stack_trace.rb +1 -1
  64. data/lib/rpicsim/storage/memory_integer.rb +235 -0
  65. data/lib/rpicsim/{register.rb → storage/register.rb} +18 -18
  66. data/lib/rpicsim/variable.rb +25 -211
  67. data/lib/rpicsim/variable_set.rb +93 -0
  68. data/lib/rpicsim/version.rb +2 -2
  69. metadata +9 -4
  70. data/docs/SFRs.md +0 -71
@@ -1,35 +1,47 @@
1
1
  module RPicSim::Mplab
2
2
  # This class creates and wraps a com.microchip.mplab.mdbcore.program.interfaces.IProgramFile
3
3
  class MplabProgramFile
4
+ EepromRange = 0xF00000..0xFFFFFF
5
+
4
6
  def initialize(filename, device)
5
7
  raise "File does not exist: #{filename}" if !File.exist?(filename) # Avoid a Java exception.
6
-
7
- if !File.realdirpath(filename).split("/").include?("dist")
8
- raise "The file must be inside a directory named dist or else the MCLoader " +
9
- "class will throw an exception saying that it cannot find the COF file."
8
+
9
+ if !File.realdirpath(filename).split('/').include?('dist')
10
+ raise 'The file must be inside a directory named dist or else the MCLoader ' +
11
+ 'class will throw an exception saying that it cannot find the COF file.'
10
12
  end
11
-
12
- factory = Lookup.getDefault.lookup(Mdbcore.program.spi.IProgramFileProviderFactory.java_class)
13
+
14
+ factory = Lookup.getDefault.lookup(Mdbcore.program.spi.IProgramFileProviderFactory.java_class)
13
15
  @program_file = factory.getProvider(filename, device)
14
16
  @program_file.Load
15
17
  end
16
-
17
- def symbols_in_code_space
18
- @symbols_in_code_space ||= Hash[
19
- symbols.select { |s| s.m_lType != 0 }.map { |s| [s.m_Symbol.to_sym, s.address] }
20
- ]
21
- end
22
-
18
+
23
19
  def symbols_in_ram
24
20
  @symbols_in_ram ||= Hash[
25
21
  symbols.select { |s| s.m_lType == 0 }.map { |s| [s.m_Symbol.to_sym, s.address] }
26
22
  ]
27
23
  end
28
-
24
+
25
+ def symbols_in_program_memory
26
+ @symbols_in_code_space ||= Hash[
27
+ symbols
28
+ .select { |s| s.m_lType != 0 && !EepromRange.include?(s.address) }
29
+ .map { |s| [s.m_Symbol.to_sym, s.address] }
30
+ ]
31
+ end
32
+
33
+ def symbols_in_eeprom
34
+ @symbols_in_eeprom ||= Hash[
35
+ symbols
36
+ .select { |s| s.m_lType != 0 && EepromRange.include?(s.address) }
37
+ .map { |s| [s.m_Symbol.to_sym, s.address - EepromRange.min] }
38
+ ]
39
+ end
40
+
29
41
  private
30
-
42
+
31
43
  def symbols
32
44
  @program_file.getSymbolTable.getSymbols(0, 0)
33
45
  end
34
- end
35
- end
46
+ end
47
+ end
@@ -4,22 +4,22 @@ module RPicSim::Mplab
4
4
  def initialize(register)
5
5
  @register = register
6
6
  end
7
-
7
+
8
8
  def write(value)
9
9
  @register.write(value)
10
10
  value
11
11
  end
12
-
12
+
13
13
  def read
14
14
  @register.read
15
15
  end
16
-
16
+
17
17
  def name
18
18
  @register.getName
19
19
  end
20
-
20
+
21
21
  def address
22
22
  @register.getAddress
23
23
  end
24
24
  end
25
- end
25
+ end
@@ -1,21 +1,21 @@
1
1
  module RPicSim::Mplab
2
2
  class MplabSfrInfo
3
3
  attr_reader :address
4
-
4
+
5
5
  # @param address The address of the register.
6
6
  # @param register [com.microchip.crownking.edc.Register]
7
7
  def initialize(address, register)
8
8
  @address = address
9
9
  @register = register
10
10
  end
11
-
11
+
12
12
  # Returns how many bits the register has.
13
13
  def width
14
14
  @register.width
15
15
  end
16
-
16
+
17
17
  def name
18
18
  @register.name
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -2,10 +2,10 @@ require_relative 'mplab_memory'
2
2
  require_relative 'mplab_processor'
3
3
 
4
4
  module RPicSim::Mplab
5
- # DeviceInfo is a wrapper for the MPLAB xPIC class which gives us information
6
- # about the target PIC device.
5
+ # This class is a wrapper for thecom.microchip.mplab.mdbcore.simulator.Simulator
6
+ # class, which helps manage running a simulation.
7
7
  class MplabSimulator
8
- # Makes a new DeviceInfo object.
8
+ # Makes a new MplabSimulator object.
9
9
  # @param simulator [com.microchip.mplab.mdbcore.simulator.Simulator]
10
10
  def initialize(simulator)
11
11
  @simulator = simulator
@@ -18,7 +18,7 @@ module RPicSim::Mplab
18
18
  def fr_memory
19
19
  @fr_memory ||= MplabMemory.new data_store.getFileMemory
20
20
  end
21
-
21
+
22
22
  def sfr_memory
23
23
  @sfr_memory ||= MplabMemory.new data_store.getSFRMemory
24
24
  end
@@ -26,25 +26,33 @@ module RPicSim::Mplab
26
26
  def nmmr_memory
27
27
  @nmmr_memory ||= MplabMemory.new data_store.getNMMRMemory
28
28
  end
29
-
29
+
30
30
  def program_memory
31
31
  @program_memory ||= MplabMemory.new data_store.getProgMemory
32
32
  end
33
-
33
+
34
34
  def stack_memory
35
35
  @stack_memory ||= MplabMemory.new data_store.getStackMemory
36
36
  end
37
-
37
+
38
38
  def test_memory
39
39
  @test_memory ||= MplabMemory.new data_store.getTestMemory
40
40
  end
41
-
41
+
42
+ def config_memory
43
+ @config_memory ||= MplabMemory.new data_store.getCFGMemory
44
+ end
45
+
46
+ def eeprom_memory
47
+ @eeprom_memory ||= MplabMemory.new data_store.getEEDataMemory
48
+ end
49
+
42
50
  def processor
43
51
  @processor ||= MplabProcessor.new data_store.getProcessor
44
52
  end
45
-
53
+
46
54
  def pins
47
- pin_descs = (0...data_store.getNumPins).collect { |i| data_store.getPinDesc(i) }
55
+ pin_descs = (0...data_store.getNumPins).map { |i| data_store.getPinDesc(i) }
48
56
 
49
57
  pin_set = data_store.getProcessor.getPinSet
50
58
 
@@ -56,11 +64,11 @@ module RPicSim::Mplab
56
64
  pin_set.getPin name # Trigger the lazy loading.
57
65
  end
58
66
 
59
- pins = (0...pin_set.getNumPins).collect do |i|
67
+ (0...pin_set.getNumPins).map do |i|
60
68
  MplabPin.new pin_set.getPin(i)
61
69
  end
62
70
  end
63
-
71
+
64
72
  def check_peripherals
65
73
  check_peripherals_in_data_store
66
74
  check_peripheral_set
@@ -71,32 +79,21 @@ module RPicSim::Mplab
71
79
  def data_store
72
80
  @simulator.getDataStore
73
81
  end
74
-
82
+
75
83
  def check_peripherals_in_data_store
76
84
  if data_store.getNumPeriphs == 0
77
- raise "MPLAB X failed to load any peripheral descriptions into the data store."
85
+ raise 'MPLAB X failed to load any peripheral descriptions into the data store.'
78
86
  end
79
87
  end
80
88
 
81
89
  def check_peripheral_set
82
90
  peripherals = data_store.getProcessor.getPeripheralSet
83
91
  if peripherals.getNumPeripherals == 0
84
- raise "MPLAB X failed to load any peripherals into the PeripheralSet."
92
+ raise 'MPLAB X failed to load any peripherals into the PeripheralSet.'
85
93
  end
86
94
  end
87
-
88
- # This is commented out because MPLAB X v2.00 with the PIC18F25K50
89
- # reports three missing peripherals:
90
- # PBADEN_PCFG
91
- # config
92
- # CONFIG3H.PBADEN
93
- #
94
- #def check_missing_peripherals
95
- # peripherals = data_store.getProcessor.getPeripheralSet
96
- # if peripherals.getMissingPeripherals.to_a.size > 0
97
- # raise "This device has missing peripherals: " + peripherals.getMissingReasons().to_a.inspect
98
- # end
99
- #end
100
-
95
+
96
+ # Note: if you are troubleshooting missing peripherals, you could check:
97
+ # data_store.getProcessor.getPeripheralSet.getMissingPeripherals.to_a
101
98
  end
102
- end
99
+ end
@@ -6,7 +6,7 @@ module RPicSim
6
6
  # Initializes a new Pin object to wrap the given MplabPin.
7
7
  # @param mplab_pin [Mplab::MplabPin]
8
8
  def initialize(mplab_pin)
9
- raise ArgumentError, "mplab_pin is nil" if mplab_pin.nil?
9
+ raise ArgumentError, 'mplab_pin is nil' if mplab_pin.nil?
10
10
  @mplab_pin = mplab_pin
11
11
  end
12
12
 
@@ -26,12 +26,12 @@ module RPicSim
26
26
  def output?
27
27
  @mplab_pin.output?
28
28
  end
29
-
29
+
30
30
  # Returns true if the pin is currently configured to be an input.
31
31
  def input?
32
32
  !@mplab_pin.output?
33
33
  end
34
-
34
+
35
35
  # Returns true if the pin is currently configured to be an output and
36
36
  # it is driving high.
37
37
  def driving_high?
@@ -49,13 +49,13 @@ module RPicSim
49
49
  def names
50
50
  @mplab_pin.names
51
51
  end
52
-
52
+
53
53
  def to_s
54
54
  @mplab_pin.name
55
- end
55
+ end
56
56
 
57
57
  def inspect
58
- "#<%s %s>" % [self.class, to_s]
58
+ '#<%s %s>' % [self.class, to_s]
59
59
  end
60
60
  end
61
61
  end
@@ -7,13 +7,13 @@ module RPicSim
7
7
  def initialize(processor)
8
8
  @processor = processor
9
9
  end
10
-
10
+
11
11
  def value
12
12
  @processor.get_pc
13
13
  end
14
-
14
+
15
15
  def value=(val)
16
16
  @processor.set_pc(val)
17
17
  end
18
18
  end
19
- end
19
+ end
@@ -7,33 +7,50 @@ module RPicSim
7
7
  class ProgramFile
8
8
  attr_reader :filename
9
9
  attr_reader :device
10
-
10
+
11
+ attr_reader :address_increment
12
+
11
13
  # @param filename [String] The path to the program file.
12
14
  # @param device [String] The name of the device the file is for (e.g. "PIC10F322").
13
15
  def initialize(filename, device)
14
16
  @filename = filename
15
17
  @device = device
18
+
16
19
  @mplab_program_file = Mplab::MplabProgramFile.new(filename, device)
17
-
20
+
18
21
  @assembly = Mplab::MplabAssembly.new(device)
19
22
  @assembly.load_file(filename)
20
23
  @address_increment = @assembly.device_info.code_address_increment
21
-
24
+
22
25
  @instructions = []
23
26
  end
24
-
27
+
25
28
  # Returns a hash associating RAM variable names (as symbols) to their addresses.
26
29
  # @return (Hash)
27
- def var_addresses
28
- @var_addresses ||= @mplab_program_file.symbols_in_ram
30
+ def symbols_in_ram
31
+ @mplab_program_file.symbols_in_ram
32
+ end
33
+
34
+ # Returns a hash associating program memory symbol names (as Ruby symbols)
35
+ # to their addresses.
36
+ # @return (Hash)
37
+ def symbols_in_program_memory
38
+ @mplab_program_file.symbols_in_program_memory
39
+ end
40
+
41
+ # Returns a hash associating EEPROM memory symbol names (as Ruby symbols)
42
+ # to their addresses.
43
+ # @return (Hash)
44
+ def symbols_in_eeprom
45
+ @mplab_program_file.symbols_in_eeprom
29
46
  end
30
-
47
+
31
48
  # Returns a hash associating program memory label names (as symbols) to their addresses.
32
49
  # @return (Hash)
33
50
  def labels
34
51
  @labels ||= begin
35
52
  hash = {}
36
- @mplab_program_file.symbols_in_code_space.each do |name, address|
53
+ symbols_in_program_memory.each do |name, address|
37
54
  hash[name] = Label.new(name, address)
38
55
  end
39
56
  hash
@@ -50,7 +67,7 @@ module RPicSim
50
67
  if !label
51
68
  raise ArgumentError, message_for_label_not_found(name)
52
69
  end
53
- return label
70
+ label
54
71
  end
55
72
 
56
73
  # Generates a friendly human-readable string description of the given address in
@@ -58,19 +75,19 @@ module RPicSim
58
75
  # @param address [Integer] An address in program memory.
59
76
  # @return [String]
60
77
  def address_description(address)
61
- desc = address < 0 ? address.to_s : ("0x%04x" % [address])
78
+ desc = address < 0 ? address.to_s : ('0x%04x' % [address])
62
79
  reference_points = labels.values.reject { |label| label.address > address }
63
- label = reference_points.max_by &:address
64
-
80
+ label = reference_points.max_by(&:address)
81
+
65
82
  if label
66
83
  offset = address - label.address
67
- desc << " = " + label.name.to_s
68
- desc << "+%#x" % [offset] if offset != 0
84
+ desc << ' = ' + label.name.to_s
85
+ desc << '+%#x' % [offset] if offset != 0
69
86
  end
70
-
71
- return desc
87
+
88
+ desc
72
89
  end
73
-
90
+
74
91
  # Gets an {Instruction} object representing the PIC instruction at the given
75
92
  # address in program memory.
76
93
  # @param address [Integer]
@@ -78,7 +95,7 @@ module RPicSim
78
95
  def instruction(address)
79
96
  @instructions[address] ||= make_instruction(address)
80
97
  end
81
-
98
+
82
99
  private
83
100
  def message_for_label_not_found(name)
84
101
  message = "Cannot find label named '#{name}'."
@@ -87,74 +104,15 @@ module RPicSim
87
104
  name.to_s.start_with?(label_sym.to_s)
88
105
  end
89
106
  if !maybe_intended_labels.empty?
90
- message << " MPASM truncates labels. You might have meant: " +
91
- maybe_intended_labels.join(", ") + "."
107
+ message << ' MPASM truncates labels. You might have meant: ' +
108
+ maybe_intended_labels.join(', ') + '.'
92
109
  end
93
110
  message
94
111
  end
95
112
 
96
113
  def make_instruction(address)
97
114
  mplab_instruction = @assembly.disassembler.disassemble(address)
98
-
99
- # Convert the increment, which is the number of bytes, into 'size',
100
- # which is the same units as the flash address space.
101
- if @address_increment == 1
102
- # Non-PIC18 architectures: flash addresses are in terms of words
103
- # so we devide by two to convert from bytes to words.
104
- size = mplab_instruction.inc / 2
105
- elsif @address_increment == 2
106
- # PIC18 architecture: No change necessary because both are in terms
107
- # of bytes.
108
- size = mplab_instruction.inc
109
- else
110
- raise "Cannot handle address increment value of #{@address_increment}."
111
- end
112
-
113
- # TODO: add support for all other 8-bit PIC architectures
114
- properties = Array case mplab_instruction.opcode
115
- when 'ADDWF'
116
- when 'ANDWF'
117
- when 'CPFSEQ' then [:conditional_skip]
118
- when 'CLRF'
119
- when 'CLRW'
120
- when 'COMF'
121
- when 'DECF'
122
- when 'DECFSZ' then [:conditional_skip]
123
- when 'INCF'
124
- when 'INCFSZ' then [:conditional_skip]
125
- when 'IORWF'
126
- when 'MOVWF'
127
- when 'MOVF'
128
- when 'NOP'
129
- when 'RLF'
130
- when 'RRF'
131
- when 'SUBWF'
132
- when 'SWAPF'
133
- when 'XORWF'
134
- when 'BCF'
135
- when 'BSF'
136
- when 'BTFSC' then [:conditional_skip]
137
- when 'BTFSS' then [:conditional_skip]
138
- when 'ADDLW'
139
- when 'ANDLW'
140
- when 'CALL' then [:call]
141
- when 'CLRWDT'
142
- when 'GOTO' then [:goto]
143
- when 'IORLW'
144
- when 'MOVLW'
145
- when 'RETFIE' then [:return]
146
- when 'RETLW' then [:return]
147
- when 'RETURN' then [:return]
148
- when 'SLEEP'
149
- when 'XORLW'
150
- else
151
- raise "Unrecognized opcode #{mplab_instruction.opcode} " +
152
- "(#{address_description(address)}, operands #{mplab_instruction.operands.inspect})."
153
- end
154
-
155
- Instruction.new(address, self, mplab_instruction.opcode,
156
- mplab_instruction.operands, size, @address_increment,
157
- mplab_instruction.instruction_string, properties)
115
+ Instruction.new(mplab_instruction, address, @address_increment, self)
158
116
  end
159
117
  end
160
- end
118
+ end