OpenCores
URL https://opencores.org/ocsvn/ssbcc/ssbcc/trunk

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [core/] [9x8/] [peripherals/] [AXI4_Lite_Master.py] - Blame information for rev 3

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 sinclairrf
################################################################################
2
#
3
# Copyright 2013, Sinclair R.F., Inc.
4
#
5
################################################################################
6
 
7
import math
8
import re;
9
 
10
from ssbccPeripheral import SSBCCperipheral
11
from ssbccUtil import SSBCCException;
12
 
13
class AXI4_Lite_Master(SSBCCperipheral):
14
  """
15
  AXI-Lite master for 32-bit reads and 8, 16, and 32-bit writes.\n
16
  256 bytes addressable by a single 8-bit value.  The data is stored in little
17
  endian format (i.e., the LSB of the 32-bit word is stored in the lowest
18
  numbered address).\n
19
  Usage:
20 3 sinclairrf
    PERIPHERAL AXI4_Lite_Master                                         \\
21
                                basePortName=<name>                     \\
22
                                address=<O_address>                     \\
23
                                data=<O_data>                           \\
24
                                command_read=<O_command_read>           \\
25
                                command_write=<O_command_write>         \\
26
                                busy=<I_busy>                           \\
27
                                error=<I_error>                         \\
28
                                read=<I_read>                           \\
29
                                address_width=<N>                       \\
30
                                synchronous={True|False}                \\
31
                                write_enable=<O_write_enable>|noWSTRB\n
32 2 sinclairrf
  Where:
33
    basePortName=<name>
34
      specifies the name used to construct the multiple AXI4-Lite signals
35
    address=<O_address>
36
      specifies the symbol used to set the address used for read and write
37
      operations from and to the dual-port memory
38
      Note:  If the address is 8 bits or less, a single write to this port will
39
             set the address.  If the address is 9 bits or longer, then multiple
40
             writes to this address, starting with the MSB of the address, are
41
             required to set all of the address bits.  See the examples for
42
             illustrations of how this works.
43
      Note:  The 2 lsb of the address are ignored.  I.e., all addresses will be
44
             treated as 32-bit aligned.
45
    data=<O_data>
46
      specifies the symbol used to set the 32-bit data for write operations
47
      Note:  Four outputs to this address are required, starting with the MSB of
48
             the 32-bit value,  See the examples for illustrations of how this
49
             works.
50
    command_read=<O_command_read>
51
      specifies the symbol used to start the AXI4-Lite master core to issue a
52
      read and store the received data
53
    command_write=<O_command_write>
54
      specifies the symbol used to start the AXI4-Lite master core to issue a
55
      write
56
    busy=<I_busy>
57
      specifies the symbol used to read the busy/not-busy status of the core
58
      Note:  A non-zero value means the core is busy.
59
    error=<I_error>
60
      specified the symbol used to read the error status of the last write or
61
      read transaction on the core
62
      Note:  A non-zero value means an error was encountered.  Errors can be
63
             reset by resetting the interface or by re-attempting the write or
64
             read operation.
65
    read=<I_read>
66
      specifies the symbol used to read successive bytes of the received 32-bit
67
      value starting with the LSB
68
    address_width=<N>
69
      specifies the width of the 8-bit aligned address\n
70
    synchronous={True|False}
71
      indicates whether or not he micro controller clock and the AXI4-Lite bus
72
      are synchronous
73 3 sinclairrf
    write_enable=<O_write_enable>
74
      optionally specify the symbol used to set the 4 write enable bits
75
      Note:  This must be used if one or more of the slaves includes the
76
      optional WSTRB      signals.
77
    noWSTRB
78
      indicates that the optional WSTRB signal should not be included
79
      Note:  This must be specified if write_enable is not specified.\n
80
  Vivado Users:
81
    The peripheral creates a TCL script to facilitate turning the micro
82
    controller into an IP core.  Look for a file with the name
83
    "vivado_<basePortName>.tcl".\n
84 2 sinclairrf
  Example:  Xilinx' AXI_DMA core has a 7-bit address range for its register
85
    address map.  The PERIPHERAL configuration statement to interface to this
86
    core would be:\n
87
      PERIPHERAL AXI4_Lite_Master                                       \
88
                        basePortName=myAxiDmaDevice                     \
89
                        address=O_myAxiDmaDevice_address                \
90
                        data=O_myAxiDmaDevice_data                      \
91
                        command_read=O_myAxiDmaDevice_cmd_read          \
92
                        command_write=O_myAxiDmaDevice_cmd_write        \
93
                        busy=I_myAxiDmaDevice_busy                      \
94
                        error=I_myAxiDmaDevice_error                    \
95
                        read=I_myAxiDmaDevice_read                      \
96
                        address_width=7                                 \
97 3 sinclairrf
                        synchronous=True                                \\
98
                        write_enable=O_myAxiDmaDevice_wen\n
99 2 sinclairrf
    To write to the memory master to slave start address, use the
100
    following, where "start_address" is a 4-byte variable set elsewhere in the
101
    program:\n
102
      ; Set the 7-bit register address.
103
      0x18 .outport(O_myAxiDmaDevice_address)
104
      ; Read the 4-byte start address from memory.
105
      .fetchvector(start_address,4)
106
      ; write the address to the AXI4-Lite master
107
      ${4-1} :loop_data
108
        swap .outport(O_myAxiDmaDevice_data)
109
      .jumpc(loop_data,1-) drop
110
      ; Ensure all 4 bytes will be written.
111
      0x0F .outport(O_myAxiDmaDevice_wen)
112
      ; Issue the write strobe.
113
      .outstrobe(O_myAxiDmaDevice_cmd_write)
114
      ; Wait for the write operation to finish.
115
      :loop_write_wait
116
        .inport(I_myAxiDmaDevice_busy)
117
      .jumpc(loop_write_wait)\n
118
    Alternatively, a function could be defined as follows:\n
119
      ; Write the specified 32-bit value to the specified 7-bit address.
120
      ; ( u_LSB u u u_MSB u_addr - )
121
      .function myAxiDmaDevice_write
122
        ; Write the 7-bit register address.
123
        .outport(O_myAxiDmaDevice_address)
124
        ; Write the 32-bit value, starting with the MSB.
125
        ${4-1} :loop_data
126
          swap .outport(O_myAxiDmaDevice_data)
127
        .jumpc(loop_data,1-) drop
128
        ; Ensure all 4 bytes will be written.
129
        0x0F .outport(O_myAxiDmaDevice_wen)
130
        ; Issue the write strobe.
131
        .outstrobe(O_myAxiDmaDevice_cmd_write)
132
        ; Wait for the write operation to finish.
133
        :loop_write_wait
134
          .inport(I_myAxiDmaDevice_busy)
135
        .jumpc(loop_write_wait)
136
        ; That's all
137
        .return\n
138
    And the write could then be performed using the following code:\n
139
      .constant AXI_DMA_MM2S_Start_Address 0x18
140
      ...
141
      ; Write the start address to the AXI DMA.
142
      .fetchvector(start_address,4)
143
      .call(myAxiDmaDevice_write,AXI_DMA_MM2S_Start_Address)\n
144
  Example:  Suppose the AXI4-Lite Master peripheral is connected to a memory
145
    with a 22-bit address width, i.e., a 4 MB address range.  The PERIPHERAL
146
    configuration command would be similar to the above except the string
147
    "myAxiDmaDevice" would need to be changed to the new hardware peripheral and
148
    the address width would be set using "address_width=22".\n
149
    The 22-bit address would be set using 3 bytes.  For example, the address
150
    0x020100 would be set by:\n
151
      0x00 .outport(O_myAxiMaster_address)
152
      0x01 .outport(O_myAxiMaster_address)
153
      0x02 .outport(O_myAxiMaster_address)\n
154
    The 2 msb of the first, most-significant, address byte will be dropped by
155
    the shift register receiving the address and the 2 lsb of the last, least
156
    significant, address byte will be written as zeros to the AXI Lite
157
    peripheral.\n
158
  LEGAL NOTICE:  ARM has restrictions on what kinds of applications can use
159
  interfaces based on their AXI protocol.  Ensure your application is in
160
  compliance with their restrictions before using this peripheral for an AXI
161
  interface.
162
  """
163
 
164
  def __init__(self,peripheralFile,config,param_list,loc):
165
    # Use the externally provided file name for the peripheral
166
    self.peripheralFile = peripheralFile;
167
    # Get the parameters.
168
    allowables = (
169
      ('address',       r'O_\w+$',              None,           ),
170
      ('address_width', r'[1-9]\d*$',           int,            ),
171
      ('basePortName',  r'\w+$',                None,           ),
172
      ('command_read',  r'O_\w+$',              None,           ),
173
      ('command_write', r'O_\w+$',              None,           ),
174
      ('data',          r'O_\w+$',              None,           ),
175
      ('read',          r'I_\w+$',              None,           ),
176
      ('busy',          r'I_\w+$',              None,           ),
177
      ('error',         r'I_\w+$',              None,           ),
178 3 sinclairrf
      ('noWSTRB',       None,                   None,           ),
179 2 sinclairrf
      ('synchronous',   r'(True|False)$',       bool,           ),
180
      ('write_enable',  r'O_\w+$',              None,           ),
181
    );
182
    names = [a[0] for a in allowables];
183
    for param_tuple in param_list:
184
      param = param_tuple[0];
185
      if param not in names:
186
        raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,));
187
      param_test = allowables[names.index(param)];
188
      self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]);
189 3 sinclairrf
    # Ensure the required parameters are provided.
190
    for paramname in (
191
      'address',
192
      'address_width',
193
      'basePortName',
194
      'command_read',
195
      'command_write',
196
      'data',
197
      'read',
198
      'busy',
199
      'error',
200
      'synchronous',
201
    ):
202 2 sinclairrf
      if not hasattr(self,paramname):
203
        raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,));
204 3 sinclairrf
    # Ensure one and only one of the complementary optional values are set.
205
    if not hasattr(self,'write_enable') and not hasattr(self,'noWSTRB'):
206
      raise SSBCCException('One of "write_enable" or "noWSTRB" must be set at %s' % loc);
207
    if hasattr(self,'write_enable') and hasattr(self,'noWSTRB'):
208
      raise SSBCCException('Only one of "write_enable" or "noWSTRB" can be set at %s' % loc);
209
    self.noWSTRB = hasattr(self,'noWSTRB');
210 2 sinclairrf
    # Temporary:  Warning message
211
    if not self.synchronous:
212
      raise SSBCCException('synchronous=False has not been validated yet');
213
    # Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
214
    for signal in (
215
      ( 'i_%s_aresetn',         1,                      'input',        ),
216
      ( 'i_%s_aclk',            1,                      'input',        ),
217
      ( 'o_%s_awvalid',         1,                      'output',       ),
218
      ( 'i_%s_awready',         1,                      'input',        ),
219
      ( 'o_%s_awaddr',          self.address_width,     'output',       ),
220
      ( 'o_%s_wvalid',          1,                      'output',       ),
221
      ( 'i_%s_wready',          1,                      'input',        ),
222
      ( 'o_%s_wdata',           32,                     'output',       ),
223 3 sinclairrf
      ( 'o_%s_wstrb',           4,                      'output',       ) if not self.noWSTRB else None,
224 2 sinclairrf
      ( 'i_%s_bresp',           2,                      'input',        ),
225
      ( 'i_%s_bvalid',          1,                      'input',        ),
226
      ( 'o_%s_bready',          1,                      'output',       ),
227
      ( 'o_%s_arvalid',         1,                      'output',       ),
228
      ( 'i_%s_arready',         1,                      'input',        ),
229
      ( 'o_%s_araddr',          self.address_width,     'output',       ),
230
      ( 'i_%s_rvalid',          1,                      'input',        ),
231
      ( 'o_%s_rready',          1,                      'output',       ),
232
      ( 'i_%s_rdata',           32,                     'input',        ),
233
      ( 'i_%s_rresp',           2,                      'input',        ),
234
    ):
235 3 sinclairrf
      if not signal:
236
        continue
237 2 sinclairrf
      thisName = signal[0] % self.basePortName;
238
      config.AddIO(thisName,signal[1],signal[2],loc);
239
    config.AddSignal('s__%s__address' % self.basePortName, self.address_width, loc);
240
    config.AddSignal('s__%s__rd' % self.basePortName, 1, loc);
241
    config.AddSignal('s__%s__wr' % self.basePortName, 1, loc);
242
    config.AddSignal('s__%s__busy' % self.basePortName, 5, loc);
243
    config.AddSignal('s__%s__error' % self.basePortName, 2, loc);
244
    config.AddSignal('s__%s__read' % self.basePortName, 32, loc);
245
    self.ix_address = config.NOutports();
246
    config.AddOutport((self.address,False,
247
                      # empty list -- disable normal output port signal generation
248
                      ),loc);
249
    self.ix_data = config.NOutports();
250
    config.AddOutport((self.data,False,
251
                      # empty list -- disable normal output port signal generation
252
                      ),loc);
253 3 sinclairrf
    if not self.noWSTRB:
254
      config.AddOutport((self.write_enable,False,
255 2 sinclairrf
                      ('o_%s_wstrb' % self.basePortName, 4, 'data', ),
256
                      ),loc);
257
    config.AddOutport((self.command_read,True,
258
                      ('s__%s__rd' % self.basePortName, 1, 'strobe', ),
259
                      ),loc);
260
    config.AddOutport((self.command_write,True,
261
                      ('s__%s__wr' % self.basePortName, 1, 'strobe', ),
262
                      ),loc);
263
    config.AddInport((self.busy,
264
                     ('s__%s__busy' % self.basePortName, 5, 'data', ),
265
                     ),loc);
266
    config.AddInport((self.error,
267
                     ('s__%s__error' % self.basePortName, 2, 'data', ),
268
                     ),loc);
269
    self.ix_read = config.NInports();
270
    config.AddInport((self.read,
271
                     ('s__%s__read' % self.basePortName, 32, 'data', ),
272
                     ),loc);
273
 
274
  def GenVerilog(self,fp,config):
275
    body = self.LoadCore(self.peripheralFile,'.v');
276
    # avoid i_clk and i_rst
277
    for subpair in (
278
      (r'\bgen__',              'gen__@NAME@__',                        ),
279
      (r'\bL__',                'L__@NAME@__',                          ),
280
      (r'\bs__',                's__@NAME@__',                          ),
281
      (r'\bi_a',                'i_@NAME@_a',                           ),
282
      (r'\bi_b',                'i_@NAME@_b',                           ),
283
      (r'\bi_rd',               'i_@NAME@_rd',                          ),
284
      (r'\bi_rr',               'i_@NAME@_rr',                          ),
285
      (r'\bi_rv',               'i_@NAME@_rv',                          ),
286
      (r'\bi_w',                'i_@NAME@_w',                           ),
287
      (r'\bo_',                 'o_@NAME@_',                            ),
288
      (r'@ADDRESS_WIDTH@',      str(self.address_width),                ),
289
      (r'@ISSYNC@',             "1'b1" if self.synchronous else "1'b0", ),
290
      (r'@IX_ADDRESS@',         str(self.ix_address),                   ),
291
      (r'@IX_DATA@',            str(self.ix_data),                      ),
292
      (r'@IX_READ@',            str(self.ix_read),                      ),
293
      (r'@NAME@',               self.basePortName,                      ),
294
    ):
295
      body = re.sub(subpair[0],subpair[1],body);
296
    body = self.GenVerilogFinal(config,body);
297
    fp.write(body);
298 3 sinclairrf
 
299
    # Write the TCL script to facilitate creating Vivado IP for the port.
300
    vivadoFile = os.path.join(os.path.dirname(self.peripheralFile),'vivado_AXI4_Lite_Bus.py');
301
    execfile(vivadoFile,globals());
302
    WriteTclScript('master',self.basePortName,self.address_width,noWSTRB=self.noWSTRB);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.