origen_arm_debug 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|