origen_arm_debug 0.4.0
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 +7 -0
- data/config/application.rb +59 -0
- data/config/commands.rb +51 -0
- data/config/development.rb +17 -0
- data/config/environment.rb +3 -0
- data/config/users.rb +19 -0
- data/config/version.rb +8 -0
- data/lib/origen_arm_debug.rb +16 -0
- data/lib/origen_arm_debug/abs_if_jtag.rb +255 -0
- data/lib/origen_arm_debug/abs_if_swd.rb +269 -0
- data/lib/origen_arm_debug/core_access_M4.rb +0 -0
- data/lib/origen_arm_debug/driver.rb +67 -0
- data/lib/origen_arm_debug/dut.rb +51 -0
- data/lib/origen_arm_debug/dut_jtag.rb +17 -0
- data/lib/origen_arm_debug/dut_swd.rb +14 -0
- data/lib/origen_arm_debug/jtag_ap.rb +0 -0
- data/lib/origen_arm_debug/jtag_dp.rb +0 -0
- data/lib/origen_arm_debug/mem_ap.rb +387 -0
- data/lib/origen_arm_debug/sw_dp.rb +0 -0
- data/lib/origen_arm_debug/swj_dp.rb +437 -0
- data/pattern/read_write_reg.rb +20 -0
- data/templates/web/index.md.erb +89 -0
- data/templates/web/layouts/_basic.html.erb +16 -0
- data/templates/web/partials/_navbar.html.erb +22 -0
- data/templates/web/release_notes.md.erb +5 -0
- metadata +126 -0
@@ -0,0 +1,269 @@
|
|
1
|
+
# To use this driver the $soc model must define the following pins (an alias is fine):
|
2
|
+
# :swd_clk
|
3
|
+
# :swd_dio
|
4
|
+
#
|
5
|
+
# API methods:
|
6
|
+
# R_dp - debug register read - just a dummy function in origen
|
7
|
+
# RE_dp - debug register read/expect - expect compares not implemented
|
8
|
+
# R_ap - read a specific address - just a dummy function in origen
|
9
|
+
# W_dp - debug register write
|
10
|
+
# W_ap - write a specific address
|
11
|
+
# WR_ap - write a specific address, then read back
|
12
|
+
|
13
|
+
module OrigenARMDebug
|
14
|
+
class ABSIF_SWD
|
15
|
+
attr_reader :owner
|
16
|
+
include Origen::Registers
|
17
|
+
|
18
|
+
def initialize(owner, options = {})
|
19
|
+
@current_apaddr = 0
|
20
|
+
@orundetect = 0
|
21
|
+
@owner = owner
|
22
|
+
end
|
23
|
+
|
24
|
+
# Highest level implementation of API - abstracted from 'read' and 'write' for future merging with JTAG debug
|
25
|
+
def R_dp(name, rdata, options = {})
|
26
|
+
cc 'Reading ' + name
|
27
|
+
read_dp(name, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def RE_dp(name, edata, options = {})
|
31
|
+
R_dp(name, edata, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def R_ap(addr, rdata, options = {})
|
35
|
+
cc 'Reading address ' + addr.to_s(16)
|
36
|
+
read_ap(addr, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def WAIT_RE_ap(addr, edata, options = {})
|
40
|
+
options = { mask: 0xffffffff, r_attempts: 1 }.merge(options)
|
41
|
+
|
42
|
+
# just assume that it always passes
|
43
|
+
actual = edata
|
44
|
+
|
45
|
+
R_ap(addr, actual, options)
|
46
|
+
|
47
|
+
cc "ABS-IF: WAIT_RE-AP: addr = 0x#{addr.to_s(16)}, "\
|
48
|
+
"actual = 0x#{actual.to_s(16)}, "\
|
49
|
+
"expected = 0x#{edata.to_s(16)}, "\
|
50
|
+
"mask = 0x#{options[:mask].to_s(16)}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def W_dp(name, wdata, options = {})
|
54
|
+
cc 'Writing 0x' + wdata.to_s(16) + ' to ' + name
|
55
|
+
write_dp(name, wdata, options)
|
56
|
+
end
|
57
|
+
|
58
|
+
def WR_dp(name, wdata, options = {})
|
59
|
+
options = { edata: 0x00000000, mask: 0xffffffff,
|
60
|
+
w_attempts: 1, r_attempts: 1
|
61
|
+
}.merge(options)
|
62
|
+
|
63
|
+
# just assume that it always passes
|
64
|
+
actual = options[:edata] & options[:mask]
|
65
|
+
|
66
|
+
W_dp(name, wdata, options)
|
67
|
+
R_dp(name, actual, options)
|
68
|
+
|
69
|
+
cc "ABS-IF: WR-DP: #{name} write = 0x#{wdata.to_s(16)}, "\
|
70
|
+
"read = 0x#{actual.to_s(16)}, "\
|
71
|
+
"expected = 0x#{options[:edata].to_s(16)}, "\
|
72
|
+
"mask = 0x#{options[:mask].to_s(16)}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def W_ap(addr, wdata, options = {})
|
76
|
+
options = { w_attempts: 1 }.merge(options)
|
77
|
+
cc 'Writing 0x' + wdata.to_s(16) + ' to address 0x' + addr.to_s(16)
|
78
|
+
write_ap(addr, wdata, options)
|
79
|
+
end
|
80
|
+
|
81
|
+
def WR_ap(addr, wdata, options = {})
|
82
|
+
options = { edata: 0x00000000, mask: 0xffffffff,
|
83
|
+
w_attempts: 1, r_attempts: 1
|
84
|
+
}.merge(options)
|
85
|
+
|
86
|
+
# just assume that it always passes
|
87
|
+
actual = wdata & options[:mask]
|
88
|
+
W_ap(addr, wdata, options)
|
89
|
+
options.delete(:w_delay) if options.key?(:w_delay)
|
90
|
+
R_ap(addr, actual, options)
|
91
|
+
|
92
|
+
cc "ABS-IF: WR-AP: addr = 0x#{addr.to_s(16)}, "\
|
93
|
+
"write = 0x#{wdata.to_s(16)}, "\
|
94
|
+
"read = 0x#{actual.to_s(16)}, "\
|
95
|
+
"expected = 0x#{options[:edata].to_s(16)}, "\
|
96
|
+
"mask = 0x#{options[:mask].to_s(16)}"
|
97
|
+
end
|
98
|
+
|
99
|
+
# SWD-specific functions
|
100
|
+
def read_dp(name, options = {})
|
101
|
+
case name
|
102
|
+
when 'IDCODE' then dpacc_access(name, 1, 0x55555555, options)
|
103
|
+
when 'ABORT' then cc 'Write only register!'
|
104
|
+
when 'CTRL/STAT' then dpacc_access(name, 1, 0x55555555, options)
|
105
|
+
when 'SELECT' then cc 'Write only register!'
|
106
|
+
when 'RDBUFF' then dpacc_access(name, 1, 0x55555555, options)
|
107
|
+
when 'WCR' then dpacc_access(name, 1, 0x55555555, options)
|
108
|
+
when 'RESEND' then dpacc_access(name, 1, 0x55555555, options)
|
109
|
+
else cc 'Unknown SW-DP register name'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def write_dp(name, wdata, options = {})
|
114
|
+
case name
|
115
|
+
when 'IDCODE' then cc 'SW-DP register is read-only'
|
116
|
+
when 'ABORT' then dpacc_access(name, 0, wdata, options)
|
117
|
+
when 'CTRL/STAT' then dpacc_access(name, 0, wdata, options)
|
118
|
+
when 'SELECT' then dpacc_access(name, 0, wdata, options)
|
119
|
+
when 'RDBUFF' then cc 'SW-DP register is read-only'
|
120
|
+
when 'WCR' then dpacc_access(name, 0, wdata, options)
|
121
|
+
when 'RESEND' then cc 'SW-DP register is read-only'
|
122
|
+
else cc 'Unknown SW-DP register name'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def write_ap(addr, wdata, options = {})
|
127
|
+
apacc_access(addr, 0, wdata, options)
|
128
|
+
end
|
129
|
+
|
130
|
+
def read_ap(addr, options = {})
|
131
|
+
# Create another copy of options with select keys removed. This first read is junk so we do not want to
|
132
|
+
# store it or compare it.
|
133
|
+
junk_options = options.clone.delete_if do |key, val|
|
134
|
+
(key.eql?(:r_mask) && val.eql?('store')) || key.eql?(:compare_data)
|
135
|
+
end
|
136
|
+
# pass junk options onto the first apacc access
|
137
|
+
apacc_access(addr, 1, 0x55555555, junk_options)
|
138
|
+
read_dp('RDBUFF', options) # This is the real data
|
139
|
+
end
|
140
|
+
|
141
|
+
# Low-level access functions
|
142
|
+
def dpacc_access(name, rwb, wdata, options = {})
|
143
|
+
addr = get_dp_addr(name)
|
144
|
+
if (name == 'CTRL/STAT')
|
145
|
+
cc 'CTRL/STAT'
|
146
|
+
set_apselect(@current_apaddr & 0xFFFFFFFE, options)
|
147
|
+
end
|
148
|
+
if (name == 'WCR')
|
149
|
+
cc 'NOT IMPLEMENTED'
|
150
|
+
end
|
151
|
+
|
152
|
+
acc_access(addr, rwb, 0, wdata, options)
|
153
|
+
|
154
|
+
if (name == 'WCR')
|
155
|
+
cc 'NOT IMPLEMENTED'
|
156
|
+
end
|
157
|
+
if (name == 'CTRL/STAT')
|
158
|
+
@orundetect = wdata & 0x1
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def apacc_access(addr, rwb, wdata, options = {})
|
163
|
+
set_apselect((addr & 0xFFFFFFFE) | (@current_apaddr & 1), options)
|
164
|
+
options.delete(:w_delay) if options.key?(:w_delay)
|
165
|
+
acc_access((addr & 0xC), rwb, 1, wdata, options)
|
166
|
+
end
|
167
|
+
|
168
|
+
def get_dp_addr(name)
|
169
|
+
case name
|
170
|
+
when 'IDCODE' then return 0x0
|
171
|
+
when 'ABORT' then return 0x0
|
172
|
+
when 'CTRL/STAT' then return 0x4
|
173
|
+
when 'WCR' then return 0x4
|
174
|
+
when 'RESEND' then return 0x8
|
175
|
+
when 'SELECT' then return 0x8
|
176
|
+
when 'RDBUFF' then return 0xC
|
177
|
+
else cc 'Unknown SW-DP register name'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def acc_access(address, rwb, ap_dp, wdata, options = {})
|
182
|
+
start = 1
|
183
|
+
apndp = ap_dp
|
184
|
+
rnw = rwb
|
185
|
+
addr = address >> 2
|
186
|
+
parity_pr = ap_dp ^ rwb ^ (addr >> 3) ^ (addr >> 2) & (0x01) ^ (addr >> 1) & (0x01) ^ addr & 0x01
|
187
|
+
trn = 0
|
188
|
+
data = wdata
|
189
|
+
require_dp = @orundetect
|
190
|
+
line_reset = 0
|
191
|
+
stop = 0
|
192
|
+
park = 1
|
193
|
+
|
194
|
+
cc 'SWD transaction'
|
195
|
+
cc 'Packet Request Phase'
|
196
|
+
|
197
|
+
annotate 'Send Start Bit'
|
198
|
+
owner.owner.swd.send_data(start, 1)
|
199
|
+
cc('Send APnDP Bit (DP or AP Access Register Bit)', prefix: true)
|
200
|
+
owner.owner.swd.send_data(apndp, 1)
|
201
|
+
c2 'Send RnW Bit (read or write bit)'
|
202
|
+
owner.owner.swd.send_data(rnw, 1)
|
203
|
+
c2 'Send Address Bits (2 bits)'
|
204
|
+
owner.owner.swd.send_data(addr, 2)
|
205
|
+
c2 'Send Parity Bit'
|
206
|
+
owner.owner.swd.send_data(parity_pr, 1)
|
207
|
+
c2 'Send Stop Bit'
|
208
|
+
owner.owner.swd.send_data(stop, 1)
|
209
|
+
c2 'Send Park Bit'
|
210
|
+
owner.owner.swd.send_data(park, 1)
|
211
|
+
|
212
|
+
cc 'Acknowledge Response phase'
|
213
|
+
owner.owner.swd.send_data(0xf, trn + 1)
|
214
|
+
owner.owner.swd.get_data (3)
|
215
|
+
cc 'Read/Write Data Phase'
|
216
|
+
if (rwb == 1)
|
217
|
+
cc 'Read'
|
218
|
+
if options[:r_mask] == 'store'
|
219
|
+
owner.owner.pin(:swd_dio).store
|
220
|
+
end
|
221
|
+
cc 'SWD 32-Bit Read Data Start'
|
222
|
+
owner.owner.swd.get_data(32, options)
|
223
|
+
cc 'SWD 32-Bit Read Data End'
|
224
|
+
cc 'Get Read Parity Bit'
|
225
|
+
owner.owner.swd.get_data(1)
|
226
|
+
cc 'Send Read ACK bits'
|
227
|
+
owner.owner.swd.send_data(0xf, trn + 1)
|
228
|
+
else
|
229
|
+
cc 'Write'
|
230
|
+
cc 'Send ACK Bits'
|
231
|
+
owner.owner.swd.send_data(0xf, trn + 1)
|
232
|
+
cc 'SWD 32-Bit Write Start'
|
233
|
+
owner.owner.swd.send_data(data, 32, options)
|
234
|
+
cc 'SWD 32-Bit Write End'
|
235
|
+
cc 'Send Write Parity Bit'
|
236
|
+
owner.owner.swd.send_data(swd_xor_calc(32, data), 1)
|
237
|
+
end
|
238
|
+
|
239
|
+
if options.key?(:w_delay)
|
240
|
+
cc "SWD DIO to 0 for #{options[:w_delay]} cycles"
|
241
|
+
owner.owner.swd.swd_dio_to_0(options[:w_delay])
|
242
|
+
else
|
243
|
+
cc 'SWD DIO to 0 for 10 cycles'
|
244
|
+
owner.owner.swd.swd_dio_to_0(10)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def set_apselect(addr, options = {})
|
249
|
+
addr &= 0xff0000f1
|
250
|
+
cc "SET_APSelect: addr = 0x#{addr.to_s(16)} "
|
251
|
+
|
252
|
+
if (addr != @current_apaddr)
|
253
|
+
cc 'SET_APSelect: write_dp SELECT'
|
254
|
+
write_dp('SELECT', addr & 0xff0000ff, options)
|
255
|
+
end
|
256
|
+
|
257
|
+
@current_apaddr = addr
|
258
|
+
end
|
259
|
+
|
260
|
+
# Calculate exclusive OR
|
261
|
+
def swd_xor_calc(size, number)
|
262
|
+
xor = 0
|
263
|
+
size.times do |bit|
|
264
|
+
xor ^= (number >> bit) & 0x01
|
265
|
+
end
|
266
|
+
xor
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
File without changes
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module OrigenARMDebug
|
2
|
+
class Driver
|
3
|
+
# Returns the parent object that instantiated the driver, could be
|
4
|
+
# either a DUT object or a protocol abstraction
|
5
|
+
attr_reader :owner
|
6
|
+
|
7
|
+
# Initialize class variables
|
8
|
+
#
|
9
|
+
# @param [Object] owner Parent object
|
10
|
+
# @param [Hash] options Options to customize the operation
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# DUT.new.arm_debug
|
14
|
+
#
|
15
|
+
def initialize(owner, options = {})
|
16
|
+
@owner = owner
|
17
|
+
end
|
18
|
+
|
19
|
+
def swj_dp
|
20
|
+
if owner.respond_to?(:swd)
|
21
|
+
@swj_dp ||= SWJ_DP.new(self, :swd)
|
22
|
+
elsif owner.respond_to?(:jtag)
|
23
|
+
@swj_dp ||= SWJ_DP.new(self, :jtag)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns an instance of the OrigenARMDebug::MemAP
|
28
|
+
def mem_ap
|
29
|
+
@mem_ap ||= MemAP.new(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Method to add additional Memory Access Ports (MEM-AP) with specified base address
|
33
|
+
# name - short name for mem_ap that is being created
|
34
|
+
# base_address - base address
|
35
|
+
def add_mem_ap(name, base_address)
|
36
|
+
instance_variable_set("@#{name}", MemAP.new(self, name: name, base_address: base_address))
|
37
|
+
self.class.send(:attr_accessor, name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_register(reg_or_val, options = {})
|
41
|
+
mem_ap.read(reg_or_val.address, size: reg_or_val.size, compare_data: reg_or_val.data)
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_register(reg_or_val, options = {})
|
45
|
+
mem_ap.write(reg_or_val.address, reg_or_val.data, size: reg_or_val.size)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def arm_debug_driver
|
51
|
+
return @arm_debug_driver if @arm_debug_driver
|
52
|
+
if owner.respond_to?(:jtag)
|
53
|
+
@arm_debug_driver = owner.jtag
|
54
|
+
elsif owner.respond_to?(:swd)
|
55
|
+
@arm_debug_driver = owner.swd
|
56
|
+
else
|
57
|
+
puts 'Cannot find a compatible physical driver!'
|
58
|
+
puts 'The ARM debug protocol supports the following phyiscal drivers:'
|
59
|
+
puts ' JTAG - http://origen-sdk.org/origen_jtag'
|
60
|
+
puts ' Single Wire Debug - http://origen-sdk.org/origen_swd'
|
61
|
+
puts ' Background Debug - http://origen-sdk.org/origen_bdm'
|
62
|
+
puts "Add one to your #{owner.class} to resolve this error."
|
63
|
+
fail 'ARM Debug error!'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module OrigenARMDebug
|
2
|
+
# This is a dummy DUT model which is used
|
3
|
+
# to instantiate and test the ARMDebug locally
|
4
|
+
# during development.
|
5
|
+
#
|
6
|
+
# It is not included when this library is imported.
|
7
|
+
class DUT
|
8
|
+
include OrigenARMDebug
|
9
|
+
include Origen::Callbacks
|
10
|
+
include Origen::Registers
|
11
|
+
|
12
|
+
# Initializes simple dut model with test register and required jtag/swd pins
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# $dut = OrigenARMDebug::DUT.new
|
16
|
+
#
|
17
|
+
def initialize
|
18
|
+
add_reg :dap, 0x0, 35, data: { pos: 0, bits: 35 }
|
19
|
+
|
20
|
+
add_reg :test, 0x0, 32, data: { pos: 0, bits: 32 },
|
21
|
+
bit: { pos: 0 }
|
22
|
+
|
23
|
+
arm_debug.add_mem_ap('mem_ap', 0x00000000)
|
24
|
+
arm_debug.add_mem_ap('mdm_ap', 0x01000000)
|
25
|
+
arm_debug.add_mem_ap('alt_ahbapi', 0x02000000)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add any custom startup business here.
|
29
|
+
#
|
30
|
+
# @param [Hash] options Options to customize the operation
|
31
|
+
def startup(options)
|
32
|
+
$tester.set_timeset('arm_debug', 40)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Read data from a register
|
36
|
+
#
|
37
|
+
# @param [Register] reg Register name or address value
|
38
|
+
# @param [Hash] options Options to customize the operation
|
39
|
+
def read_register(reg, options = {})
|
40
|
+
arm_debug.read_register(reg, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Write data to a register
|
44
|
+
#
|
45
|
+
# @param [Register] reg Register name or address value
|
46
|
+
# @param [Hash] options Options to customize the operation
|
47
|
+
def write_register(reg, options = {})
|
48
|
+
arm_debug.write_register(reg, options)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module OrigenARMDebug
|
2
|
+
class JTAG_DUT < DUT
|
3
|
+
include OrigenJTAG
|
4
|
+
include Origen::Pins
|
5
|
+
|
6
|
+
# Adds jtag-required pins to the simple dut model
|
7
|
+
# Returns nothing.
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
add_pin :tclk
|
11
|
+
add_pin :tdi
|
12
|
+
add_pin :tdo
|
13
|
+
add_pin :tms
|
14
|
+
add_pin :trst
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,387 @@
|
|
1
|
+
module OrigenARMDebug
|
2
|
+
class MemAP
|
3
|
+
# ARM Debug Interface v5.1
|
4
|
+
MEM_ADDR_CSW = 0x00000000
|
5
|
+
MEM_ADDR_TAR = 0x00000004
|
6
|
+
MEM_ADDR_DRW = 0x0000000C
|
7
|
+
MEM_ADDR_BD0 = 0x00000010
|
8
|
+
MEM_ADDR_BD1 = 0x00000014
|
9
|
+
MEM_ADDR_BD2 = 0x00000018
|
10
|
+
MEM_ADDR_BD3 = 0x0000001C
|
11
|
+
MEM_ADDR_CFG = 0x000000F4
|
12
|
+
MEM_ADDR_BASE = 0x000000F8
|
13
|
+
MEM_ADDR_IDR = 0x000000FC
|
14
|
+
|
15
|
+
# Returns the parent object that instantiated the driver
|
16
|
+
attr_reader :owner
|
17
|
+
|
18
|
+
# Initialize class variables
|
19
|
+
#
|
20
|
+
# @param [Object] owner Parent object
|
21
|
+
# @param [Hash] options Options to customize the operation
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# DUT.new.arm_debug.mem_ap
|
25
|
+
#
|
26
|
+
def initialize(owner, options = {})
|
27
|
+
@owner = owner
|
28
|
+
@name = options[:name].nil? ? 'default' : options[:name]
|
29
|
+
@base_address = options[:base_address].nil? ? 0x00000000 : options[:base_address]
|
30
|
+
|
31
|
+
# reset values for MEM-AP registers
|
32
|
+
@current_csw = 0x00000000
|
33
|
+
@current_tar = 0xffffffff
|
34
|
+
@current_dsw = 0x00000000
|
35
|
+
end
|
36
|
+
|
37
|
+
# Shortcut name to SWJ-DP Debug Port
|
38
|
+
def debug_port
|
39
|
+
owner.swj_dp
|
40
|
+
end
|
41
|
+
alias_method :dp, :debug_port
|
42
|
+
|
43
|
+
# -----------------------------------------------------------------------------
|
44
|
+
# User API
|
45
|
+
# -----------------------------------------------------------------------------
|
46
|
+
|
47
|
+
# Method to read from a mem_ap register
|
48
|
+
#
|
49
|
+
# @param [Integer] addr Address of register to be read from
|
50
|
+
# @param [Hash] options Options to customize the operation
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# # don't care what data actually is
|
54
|
+
# mem_ap.read(0x2000000, size: 32)
|
55
|
+
#
|
56
|
+
# # expect read data to be = 0x5a5a5a5a
|
57
|
+
# mem_ap.read(0x2000000, size: 32, edata: 0x5a5a5a5a)
|
58
|
+
#
|
59
|
+
# # expect read data to be = 0xXXXXXX5a (mask out all bits except [7:0])
|
60
|
+
# mem_ap.read(0x2000000, size: 32, edata: 0x5a5a5a5a, r_mask: 0x000000ff)
|
61
|
+
#
|
62
|
+
# Returns nothing.
|
63
|
+
def read(addr, options = {})
|
64
|
+
options = { size: 32 }.merge(options)
|
65
|
+
options = { r_mask: 'mask', r_attempts: 1 }.merge(options)
|
66
|
+
msg = 'Arm Debug: Shift out data for reading'
|
67
|
+
options = { arm_debug_comment: msg }.merge(options)
|
68
|
+
size = options[:size]
|
69
|
+
|
70
|
+
set_size(size)
|
71
|
+
set_addr(addr)
|
72
|
+
debug_port.read_ap(drw_reg_addr, options)
|
73
|
+
rdata = get_rdata(size, addr, rdata)
|
74
|
+
increment_addr
|
75
|
+
|
76
|
+
cc "MEM-AP(#{@name}): R-#{size.to_s(10)}: "\
|
77
|
+
"addr=0x#{addr.to_s(16).rjust(size / 4, '0')}"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Method to write to a mem_ap register
|
81
|
+
#
|
82
|
+
# @param [Integer] addr Address of register to be read from
|
83
|
+
# @param [Integer] wdata Data to be written
|
84
|
+
# @param [Hash] options Options to customize the operation
|
85
|
+
#
|
86
|
+
# @example
|
87
|
+
# mem_ap.write(0x2000000, 0xc3c3a5a5, size: 32)
|
88
|
+
#
|
89
|
+
# Returns nothing.
|
90
|
+
def write(addr, wdata, options = {});
|
91
|
+
options = { size: 32 }.merge(options)
|
92
|
+
options = { w_attempts: 1 }.merge(options)
|
93
|
+
msg = "Arm Debug: Shift in data to write: #{wdata.to_hex}"
|
94
|
+
options = { arm_debug_comment: msg }.merge(options)
|
95
|
+
size = options[:size]
|
96
|
+
|
97
|
+
set_size(size)
|
98
|
+
set_addr(addr)
|
99
|
+
wdata = get_wdata(size, addr, wdata)
|
100
|
+
debug_port.write_ap(drw_reg_addr, wdata, options)
|
101
|
+
increment_addr
|
102
|
+
|
103
|
+
cc "MEM-AP(#{@name}): WR-#{size.to_s(10)}: "\
|
104
|
+
"addr=0x#{addr.to_s(16).rjust(size / 4, '0')}, "\
|
105
|
+
"data=0x#{wdata.to_s(16).rjust(size / 4, '0')}"
|
106
|
+
end
|
107
|
+
|
108
|
+
# Method to write and then read from a mem_ap register (legacy)
|
109
|
+
#
|
110
|
+
# @param [Integer] addr Address of register to be read from
|
111
|
+
# @param [Integer] wdata Data to be written
|
112
|
+
# @param [Hash] options Options to customize the operation
|
113
|
+
#
|
114
|
+
# @example
|
115
|
+
# # don't care what read-back data actually is
|
116
|
+
# mem_ap.write_read(0x2000000, 0xc3c3a5a5, size: 32)
|
117
|
+
#
|
118
|
+
# # expect read-back data to be same as write data = 0xc3c3a5a5
|
119
|
+
# mem_ap.read(0x2000000, 0xc3c3a5a5, size: 32, edata: 0xc3c3a5a5)
|
120
|
+
#
|
121
|
+
# # expect read-back data to be = 0xXXXXXXa5 (mask out all bits except [7:0])
|
122
|
+
# mem_ap.read(0x2000000, 0xc3c3a5a5, size: 32, edata: 0xc3c3a5a5, r_mask: 0x000000ff)
|
123
|
+
#
|
124
|
+
# Returns nothing.
|
125
|
+
def write_read(addr, wdata, options = {})
|
126
|
+
options = { size: 32 }.merge(options)
|
127
|
+
options = { edata: 0x00000000, r_mask: 0xffffffff, actual: 0x00000000 }.merge(options)
|
128
|
+
options = { w_attempts: 1, r_attempts: 2 }.merge(options)
|
129
|
+
size = options[:size]
|
130
|
+
|
131
|
+
write(addr, wdata, options)
|
132
|
+
options[:edata] = wdata & options[:r_mask] if options[:edata] == 0x00000000
|
133
|
+
read(addr, options)
|
134
|
+
actual = wdata & options[:r_mask]
|
135
|
+
|
136
|
+
cc "MEM-AP(#{@name}): WR-#{size.to_s(10)}: "\
|
137
|
+
"addr=0x#{addr.to_s(16).rjust(size / 4, '0')}, "\
|
138
|
+
"wdata=0x#{wdata.to_s(16).rjust(size / 4, '0')}, "\
|
139
|
+
"read=0x#{actual.to_s(16).rjust(size / 4, '0')}, "\
|
140
|
+
"expect=0x#{options[:edata].to_s(16).rjust(size / 4, '0')}, "\
|
141
|
+
"mask=0x#{options[:r_mask].to_s(16).rjust(size / 4, '0')}"
|
142
|
+
end
|
143
|
+
|
144
|
+
# -----------------------------------------------------------------------------
|
145
|
+
# Legacy Support (to be phased out)
|
146
|
+
# -----------------------------------------------------------------------------
|
147
|
+
|
148
|
+
# Method to read from a mem_ap register (legacy)
|
149
|
+
#
|
150
|
+
# @param [Integer] addr Address of register to be read from
|
151
|
+
# @param [Integer] rdata This really does nothing since only care about value
|
152
|
+
# of options[:edata]
|
153
|
+
# @param [Hash] options Options to customize the operation
|
154
|
+
# Returns nothing.
|
155
|
+
def R(addr, rdata, options = {})
|
156
|
+
# Warn caller that this method is being deprecated
|
157
|
+
msg = 'Use mem_ap.read(addr, options) instead of R(addr, rdata, options)'
|
158
|
+
Origen.deprecate msg
|
159
|
+
|
160
|
+
# Patch arguments and send to new method
|
161
|
+
options = { rdata: rdata }.merge(options)
|
162
|
+
read(addr, options)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Method to write to a mem_ap register (legacy)
|
166
|
+
#
|
167
|
+
# @param [Integer] addr Address of register to be written to
|
168
|
+
# @param [Integer] wdata Data to be written
|
169
|
+
# @param [Hash] options Options to customize the operation
|
170
|
+
# Returns nothing.
|
171
|
+
def W(addr, wdata, options = {})
|
172
|
+
# Warn caller that this method is being deprecated
|
173
|
+
msg = 'Use mem_ap.write(addr, wdata, options) instead of W(addr, wdata, options)'
|
174
|
+
Origen.deprecate msg
|
175
|
+
|
176
|
+
# Patch arguments and send to new method
|
177
|
+
write(addr, wdata, options)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Method to write and then read from a mem_ap register (legacy)
|
181
|
+
#
|
182
|
+
# @param [Integer] addr Address of register to be read from
|
183
|
+
# @param [Integer] wdata Data to be written
|
184
|
+
# @param [Hash] options Options to customize the operation
|
185
|
+
# Returns nothing.
|
186
|
+
def WR(addr, wdata, options = {})
|
187
|
+
# Warn caller that this method is being deprecated
|
188
|
+
msg = 'Use mem_ap.write_read(addr, wdata, options) instead of WR(addr, wdata, options)'
|
189
|
+
Origen.deprecate msg
|
190
|
+
|
191
|
+
# Patch arguments and send to new method
|
192
|
+
write_read(addr, wdata, options)
|
193
|
+
end
|
194
|
+
|
195
|
+
# -----------------------------------------------------------------------------
|
196
|
+
# Support Code
|
197
|
+
# -----------------------------------------------------------------------------
|
198
|
+
|
199
|
+
private
|
200
|
+
|
201
|
+
# Sets the size of the data (by writing to the CSW size bits). It will only
|
202
|
+
# write to the size if the size from the previous transaction has changed
|
203
|
+
#
|
204
|
+
# @param [Integer] size Size of data, supports 8-bit, 16-bit, and 32-bit
|
205
|
+
def set_size(size)
|
206
|
+
case size
|
207
|
+
when 8 then new_size = 0x00000000
|
208
|
+
when 16 then new_size = 0x00000001
|
209
|
+
when 32 then new_size = 0x00000002
|
210
|
+
else new_size = 0x00000002
|
211
|
+
end
|
212
|
+
|
213
|
+
if (@current_csw == 0x00000000)
|
214
|
+
debug_port.read_ap(csw_reg_addr)
|
215
|
+
@current_csw = 0x23000040
|
216
|
+
end
|
217
|
+
|
218
|
+
csw_size = @current_csw & 0x00000003
|
219
|
+
if (csw_size != new_size)
|
220
|
+
new_csw = (@current_csw & 0xfffffffc) | new_size
|
221
|
+
debug_port.write_ap(csw_reg_addr, new_csw)
|
222
|
+
@current_csw = new_csw
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# Sets the addr of the transaction.
|
227
|
+
#
|
228
|
+
# @param [Integer] addr Address of data to be read from or written to
|
229
|
+
def set_addr(addr)
|
230
|
+
arm_debug_comment = "Arm Debug: Shift in read/write address: #{addr.to_hex}"
|
231
|
+
options = { arm_debug_comment: arm_debug_comment }
|
232
|
+
|
233
|
+
if (@current_tar != addr)
|
234
|
+
debug_port.write_ap(tar_reg_addr, addr, options)
|
235
|
+
end
|
236
|
+
@current_tar = addr;
|
237
|
+
end
|
238
|
+
|
239
|
+
# Increment the address for the next transaction.
|
240
|
+
def increment_addr
|
241
|
+
current_csw_5_4 = (@current_csw & 0x00000030) >> 4
|
242
|
+
current_csw_2_0 = @current_csw & 0x00000007
|
243
|
+
if (current_csw_5_4 == 0b01)
|
244
|
+
case current_csw_2_0
|
245
|
+
when 0b000 then @current_tar += 1 # Increment single
|
246
|
+
when 0b001 then @current_tar += 2 # Increment single
|
247
|
+
when 0b010 then @current_tar += 4 # Increment single
|
248
|
+
end
|
249
|
+
elsif (current_csw_5_4 == 0b10)
|
250
|
+
@current_tar += 4 # Increment packed
|
251
|
+
end
|
252
|
+
|
253
|
+
if current_csw_5_4 && ((@current_tar & 0xfffffc00) == 0xffffffff)
|
254
|
+
# reset tar when attempting to increment past 1kB boundary
|
255
|
+
@current_tar = 0xffffffff
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
# Create a bit-wise mask based on size, address and mask parameters.
|
260
|
+
#
|
261
|
+
# @param [Integer] size Size of data, supports 8-bit, 16-bit, and 32-bit
|
262
|
+
# @param [Integer] addr Address of data to be read from or written to
|
263
|
+
# @param [Integer] mask Mask for full data, used to create nibble mask
|
264
|
+
def get_mask(size, addr, mask)
|
265
|
+
addr_1_0 &= 0x00000003
|
266
|
+
case size
|
267
|
+
when 8
|
268
|
+
case addr_1_0
|
269
|
+
when 0b00 then mask &= 0x000000ff
|
270
|
+
when 0b01 then mask &= 0x0000ff00
|
271
|
+
when 0b10 then mask &= 0x00ff0000
|
272
|
+
when 0b11 then mask &= 0xff000000
|
273
|
+
end
|
274
|
+
when 16
|
275
|
+
case addr_1_0
|
276
|
+
when 0b00 then mask &= 0x0000ffff
|
277
|
+
when 0b10 then mask &= 0xffff0000
|
278
|
+
end
|
279
|
+
when 32
|
280
|
+
mask &= 0xffffffff
|
281
|
+
end
|
282
|
+
mask
|
283
|
+
end
|
284
|
+
|
285
|
+
# Create a bit-wise read-data based on size, address and rdata parameters.
|
286
|
+
#
|
287
|
+
# @param [Integer] size Size of data, supports 8-bit, 16-bit, and 32-bit
|
288
|
+
# @param [Integer] addr Address of data to be read from or written to
|
289
|
+
# @param [Integer] rdata Full data for read, used to create nibble read data
|
290
|
+
def get_rdata(size, addr, rdata)
|
291
|
+
addr_1_0 &= 0x00000003
|
292
|
+
case size
|
293
|
+
when 8
|
294
|
+
case addr_1_0
|
295
|
+
when 0b00 then rdata = 0x000000ff & rdata
|
296
|
+
when 0b01 then rdata = 0x000000ff & (rdata >> 8)
|
297
|
+
when 0b10 then rdata = 0x000000ff & (rdata >> 16)
|
298
|
+
when 0b11 then rdata = 0x000000ff & (rdata >> 24)
|
299
|
+
end
|
300
|
+
when 16
|
301
|
+
case addr_1_0
|
302
|
+
when 0b00 then rdata = 0x0000ffff & rdata
|
303
|
+
when 0b10 then rdata = 0x0000ffff & (rdata >> 16)
|
304
|
+
end
|
305
|
+
when 32
|
306
|
+
rdata = rdata
|
307
|
+
end
|
308
|
+
rdata
|
309
|
+
end
|
310
|
+
|
311
|
+
# Create a bit-wise read-data based on size, address and wdata parameters.
|
312
|
+
#
|
313
|
+
# @param [Integer] size Size of data, supports 8-bit, 16-bit, and 32-bit
|
314
|
+
# @param [Integer] addr Address of data to be read from or written to
|
315
|
+
# @param [Integer] wdata Full data for write, used to create nibble write data
|
316
|
+
def get_wdata(size, addr, wdata);
|
317
|
+
addr_1_0 &= 0x00000003
|
318
|
+
case size
|
319
|
+
when 8
|
320
|
+
case addr_1_0
|
321
|
+
when 0b00 then wdata = 0x000000ff & wdata
|
322
|
+
when 0b01 then wdata = 0x0000ff00 & (wdata << 8)
|
323
|
+
when 0b10 then wdata = 0x00ff0000 & (wdata << 16)
|
324
|
+
when 0b11 then wdata = 0xff000000 & (wdata << 24)
|
325
|
+
end
|
326
|
+
when 16
|
327
|
+
case addr_1_0
|
328
|
+
when 0b00 then wdata = 0x0000ffff & wdata
|
329
|
+
when 0b10 then wdata = 0xffff0000 & (wdata << 16)
|
330
|
+
end
|
331
|
+
when 32
|
332
|
+
wdata = wdata
|
333
|
+
end
|
334
|
+
wdata
|
335
|
+
end
|
336
|
+
|
337
|
+
# Returns address of CSW register for this mem-ap instance
|
338
|
+
def csw_reg_addr
|
339
|
+
MEM_ADDR_CSW + @base_address
|
340
|
+
end
|
341
|
+
|
342
|
+
# Returns address of TAR register for this mem-ap instance
|
343
|
+
def tar_reg_addr
|
344
|
+
MEM_ADDR_TAR + @base_address
|
345
|
+
end
|
346
|
+
|
347
|
+
# Returns address of DRW register for this mem-ap instance
|
348
|
+
def drw_reg_addr
|
349
|
+
MEM_ADDR_DRW + @base_address
|
350
|
+
end
|
351
|
+
|
352
|
+
# Returns address of BD0 register for this mem-ap instance
|
353
|
+
def bdo_reg_addr
|
354
|
+
MEM_ADDR_BD0 + @base_address
|
355
|
+
end
|
356
|
+
|
357
|
+
# Returns address of BD1 register for this mem-ap instance
|
358
|
+
def bd1_reg_addr
|
359
|
+
MEM_ADDR_BD1 + @base_address
|
360
|
+
end
|
361
|
+
|
362
|
+
# Returns address of BD2 register for this mem-ap instance
|
363
|
+
def bd2_reg_addr
|
364
|
+
MEM_ADDR_BD2 + @base_address
|
365
|
+
end
|
366
|
+
|
367
|
+
# Returns address of BD3 register for this mem-ap instance
|
368
|
+
def bd3_reg_addr
|
369
|
+
MEM_ADDR_BD3 + @base_address
|
370
|
+
end
|
371
|
+
|
372
|
+
# Returns address of CFG register for this mem-ap instance
|
373
|
+
def cfg_reg_addr
|
374
|
+
MEM_ADDR_CFG + @base_address
|
375
|
+
end
|
376
|
+
|
377
|
+
# Returns address of BASE register for this mem-ap instance
|
378
|
+
def base_reg_addr
|
379
|
+
MEM_ADDR_BASE + @base_address
|
380
|
+
end
|
381
|
+
|
382
|
+
# Returns address of IDR register for this mem-ap instance
|
383
|
+
def idr_reg_addr
|
384
|
+
MEM_ADDR_IDR + @base_address
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|