1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
|
--
-- Copyright 2018 Ettus Research, a National Instruments Company
--
-- SPDX-License-Identifier: LGPL-3.0-or-later
--
-- This package contains functions for reading and writing N310 registers.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package PkgRegs is
-- RegPort Type Definitions : ---------------------------------------------------------
-- ------------------------------------------------------------------------------------
constant kAddressWidth : integer := 16;
subtype InterfaceData_t is std_logic_vector(31 downto 0);
type RegDataAry_t is array (natural range <>) of InterfaceData_t;
constant kRegPortDataZero : InterfaceData_t := (others => '0');
-- The type of the signal used to communicate from the Interface
-- component to the frameworks
type RegPortIn_t is record
Address : unsigned(kAddressWidth - 1 downto 0);
Data : InterfaceData_t;
Rd : boolean; -- Must be a one clock cycle pulse
Wt : boolean; -- Must be a one clock cycle pulse
end record;
-- The type of the signal used to communicate to the Interface
-- component from the frameworks
-- Ready is just the Ready signal from the Handshake component.
-- Address in RegPortIn_t should be valid in the cycle where Data, DataValid,
-- or Ready are being sampled by the bus communication interface.
type RegPortOut_t is record
Data : InterfaceData_t;
DataValid : boolean; -- Must be a one clock cycle pulse
Ready : boolean; -- Must be valid one clock after Wt assertion
end record;
-- Constants for the RegPort
constant kRegPortInZero : RegPortIn_t := (
Address => to_unsigned(0,kAddressWidth),
Data => (others => '0'),
Rd => false,
Wt => false);
constant kRegPortOutZero : RegPortOut_t := (
Data => (others=>'0'),
DataValid => false,
Ready => true);
-- Register Offset Types : ------------------------------------------------------------
-- ------------------------------------------------------------------------------------
-- Custom type for defining register spaces. Is it assumed that all defined register
-- addresses for each space are kOffset <= Address < kOffset+kWidth. Therefore when
-- Address equals kOffset+kWidth, we are not talking to this space but the space
-- above it.
type RegOffset_t is record
kOffset : integer;
kWidth : integer;
end record;
constant kRegOffsetZero : RegOffset_t := (kOffset => 16#0#, kWidth => 16#04#);
-- Access Functions : -----------------------------------------------------------------
-- ------------------------------------------------------------------------------------
-- Helper function to combine register ports on their way back upstream.
function "+" (L, R : RegPortOut_t) return RegPortOut_t;
function Mask(RegPortIn : in RegPortIn_t;
kRegisterOffset : in RegOffset_t) return RegPortIn_t;
-- Helper functions to determine when a register is targeted by the RegPort. There
-- are three groups: RegSelected, RegWrite, and RegRead. The latter two call
-- RegSelected to determine if a register is targeted and being read or written.
-- RegSelected is also overloaded to accommodate the RegOffset_t type.
-- function RegSelected (RegPortIn : RegPortIn_t;
-- RegisterOffset : RegOffset_t) return boolean;
function RegSelected (RegOffset : integer;
RegPortIn : RegPortIn_t) return boolean;
function RegWrite (Address : integer;
RegPortIn : RegPortIn_t) return boolean;
function RegRead (Address : integer;
RegPortIn : RegPortIn_t) return boolean;
function OrArray(ArrayIn : RegDataAry_t) return std_logic_vector;
-- Flattening Functions : -------------------------------------------------------------
-- ------------------------------------------------------------------------------------
constant kFlatRegPortInSize : natural := kAddressWidth +
InterfaceData_t'length +
2;
subtype FlatRegPortIn_t is std_logic_vector(kFlatRegPortInSize-1 downto 0);
constant kFlatRegPortOutSize : natural := InterfaceData_t'length +
2;
subtype FlatRegPortOut_t is std_logic_vector(kFlatRegPortOutSize-1 downto 0);
function Flatten(Var : RegPortIn_t) return FlatRegPortIn_t;
function Unflatten(Var : FlatRegPortIn_t) return RegPortIn_t;
function Flatten(Var : RegPortOut_t) return FlatRegPortOut_t;
function Unflatten(Var : FlatRegPortOut_t) return RegPortOut_t;
end PkgRegs;
package body PkgRegs is
-- Combines RegPortOut_t types together
function "+" (L, R : RegPortOut_t) return RegPortOut_t
is
variable ReturnVal : RegPortOut_t;
begin
ReturnVal := kRegPortOutZero;
ReturnVal.Data := L.Data or R.Data;
ReturnVal.DataValid := L.DataValid or R.DataValid;
ReturnVal.Ready := L.Ready and R.Ready;
return ReturnVal;
end function;
-- This function lops off the portion of the register bus that is
-- decoded in the InAddrSpace function in order to reduce the number of bits
-- decoded by the register read logic. Also, the Rd and Wt strobes are gated
-- as well.
function Mask(RegPortIn : in RegPortIn_t;
kRegisterOffset : in RegOffset_t) return RegPortIn_t
is
variable RegPortInVar : RegPortIn_t;
variable InSpace : boolean := false;
begin
InSpace := (RegPortIn.Address >= kRegisterOffset.kOffset) and
(RegPortIn.Address < kRegisterOffset.kOffset + kRegisterOffset.kWidth);
-- Compare the most significant bits of the address bus downto the LSb
-- that we just calculated.
if InSpace then
-- If in address space then allow Rd and Wt to assert
RegPortInVar.Rd := RegPortIn.Rd;
RegPortInVar.Wt := RegPortIn.Wt;
else
RegPortInVar.Rd := kRegPortInZero.Rd;
RegPortInVar.Wt := kRegPortInZero.Wt;
end if;
RegPortInVar.Data := RegPortIn.Data;
RegPortInVar.Address := RegPortIn.Address - kRegisterOffset.kOffset;
return RegPortInVar;
end function Mask;
-- Returns true when this chip is selected and the address matches the register.
-- Note that RegOffset is divided by 4 before being compared against the register
-- port Address value.
function RegSelected (RegOffset : integer;
RegPortIn : RegPortIn_t) return boolean is
begin
return RegPortIn.Address = to_unsigned(RegOffset, RegPortIn.Address'length);
end function RegSelected;
-- Returns true when the register is being written.
function RegWrite (Address : integer;
RegPortIn : RegPortIn_t) return boolean is
begin
return RegSelected(Address, RegPortIn) and RegPortIn.Wt;
end function RegWrite;
-- Returns true when the register is being read.
function RegRead (Address : integer;
RegPortIn : RegPortIn_t) return boolean is
begin
return RegSelected(Address, RegPortIn) and RegPortIn.Rd;
end function RegRead;
-- Overloaded version of RegSelected for the RegOffset_t
-- NOTE!!! Offset <= Address < Offset+Width
-- Therefore, this function assumes that when Address = Offset+Width we are talking to
-- a different register group than the one given in RegisterOffset.
-- function RegSelected (RegPortIn : RegPortIn_t;
-- RegisterOffset : RegOffset_t) return boolean is
-- begin
-- return (RegPortIn.Address >= to_unsigned(RegisterOffset.kOffset, RegPortIn.Address'length)) and
-- (RegPortIn.Address < to_unsigned(RegisterOffset.kOffset + RegisterOffset.kWidth, RegPortIn.Address'length));
-- end function RegSelected;
function OrArray(ArrayIn : RegDataAry_t) return std_logic_vector
is
variable ReturnVar : std_logic_vector(ArrayIn(ArrayIn'right)'range);
begin
ReturnVar := (others => '0');
for i in ArrayIn'range loop
ReturnVar := ReturnVar or ArrayIn(i);
end loop;
return ReturnVar;
end function OrArray;
function to_Boolean (s : std_ulogic) return boolean is
begin
return (To_X01(s)='1');
end to_Boolean;
function to_StdLogic(b : boolean) return std_ulogic is
begin
if b then
return '1';
else
return '0';
end if;
end to_StdLogic;
-----------------------------------------------------
-- REG PORTS (FROM PkgCommunicationInterface)
--
-- subtype InterfaceData_t is std_logic_vector(31 downto 0);
--
-- constant kAddressWidth : positive := kAddressWidth - 2;
--
-- type RegPortIn_t is record
-- Address : unsigned(kAddressWidth - 1 downto 0);
-- Data : InterfaceData_t;
-- Rd : boolean; -- Must be a one clock cycle pulse
-- Wt : boolean; -- Must be a one clock cycle pulse
-- end record;
function Flatten(Var : RegPortIn_t) return FlatRegPortIn_t is
variable Index : natural;
variable RetVar : FlatRegPortIn_t;
begin
Index := 0;
RetVar(Index) := to_StdLogic(Var.Wt); Index := Index + 1;
RetVar(Index) := to_StdLogic(Var.Rd); Index := Index + 1;
RetVar(Index + Var.Data'length - 1 downto Index) := std_logic_vector(Var.Data);
Index := Index + Var.Data'length;
RetVar(Index + Var.Address'length - 1 downto Index) := std_logic_vector(Var.Address);
Index := Index + Var.Address'length;
return RetVar;
end function Flatten;
function Unflatten(Var : FlatRegPortIn_t) return RegPortIn_t is
variable Index : natural;
variable RetVal : RegPortIn_t;
begin
Index := 0;
RetVal.Wt := to_Boolean(Var(Index)); Index := Index + 1;
RetVal.Rd := to_Boolean(Var(Index)); Index := Index + 1;
RetVal.Data := InterfaceData_t(Var(Index + RetVal.Data'length - 1 downto Index));
Index := Index + RetVal.Data'length;
RetVal.Address := unsigned(Var(Index + RetVal.Address'length - 1 downto Index));
Index := Index + RetVal.Address'length;
return RetVal;
end function Unflatten;
-- type RegPortOut_t is record
-- Data : InterfaceData_t;
-- DataValid : boolean; -- Must be a one clock cycle pulse
-- Ready : boolean; -- Must be valid one clock after Wt assertion
-- end record;
function Flatten(Var : RegPortOut_t) return FlatRegPortOut_t is
variable Index : natural;
variable RetVar : FlatRegPortOut_t;
begin
Index := 0;
RetVar(Index) := to_StdLogic(Var.Ready); Index := Index + 1;
RetVar(Index) := to_StdLogic(Var.DataValid); Index := Index + 1;
RetVar(Index + Var.Data'length - 1 downto Index) := std_logic_vector(Var.Data);
Index := Index + Var.Data'length;
return RetVar;
end function Flatten;
function Unflatten(Var : FlatRegPortOut_t) return RegPortOut_t is
variable Index : natural;
variable RetVal : RegPortOut_t;
begin
Index := 0;
RetVal.Ready := to_Boolean(Var(Index)); Index := Index + 1;
RetVal.DataValid := to_Boolean(Var(Index)); Index := Index + 1;
RetVal.Data := InterfaceData_t(Var(Index + RetVal.Data'length - 1 downto Index));
Index := Index + RetVal.Data'length;
return RetVal;
end function Unflatten;
end PkgRegs;
|