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 2

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
    PERIPHERAL AXI4_Lite_Master                                 \\
21
                                basePortName=<name>             \\
22
                                address=<O_address>             \\
23
                                data=<O_data>                   \\
24
                                write_enable=<O_write_enable>   \\
25
                                command_read=<O_command_read>   \\
26
                                command_write=<O_command_write> \\
27
                                busy=<I_busy>                   \\
28
                                error=<I_error>                 \\
29
                                read=<I_read>                   \\
30
                                address_width=<N>               \\
31
                                synchronous={True|False}
32
  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
    write_enable=<O_write_enable>
51
      specifies the symbol used to set the 4 write enable bits
52
    command_read=<O_command_read>
53
      specifies the symbol used to start the AXI4-Lite master core to issue a
54
      read and store the received data
55
    command_write=<O_command_write>
56
      specifies the symbol used to start the AXI4-Lite master core to issue a
57
      write
58
    busy=<I_busy>
59
      specifies the symbol used to read the busy/not-busy status of the core
60
      Note:  A non-zero value means the core is busy.
61
    error=<I_error>
62
      specified the symbol used to read the error status of the last write or
63
      read transaction on the core
64
      Note:  A non-zero value means an error was encountered.  Errors can be
65
             reset by resetting the interface or by re-attempting the write or
66
             read operation.
67
    read=<I_read>
68
      specifies the symbol used to read successive bytes of the received 32-bit
69
      value starting with the LSB
70
    address_width=<N>
71
      specifies the width of the 8-bit aligned address\n
72
    synchronous={True|False}
73
      indicates whether or not he micro controller clock and the AXI4-Lite bus
74
      are synchronous
75
  Example:  Xilinx' AXI_DMA core has a 7-bit address range for its register
76
    address map.  The PERIPHERAL configuration statement to interface to this
77
    core would be:\n
78
      PERIPHERAL AXI4_Lite_Master                                       \
79
                        basePortName=myAxiDmaDevice                     \
80
                        address=O_myAxiDmaDevice_address                \
81
                        data=O_myAxiDmaDevice_data                      \
82
                        write_enable=O_myAxiDmaDevice_wen               \
83
                        command_read=O_myAxiDmaDevice_cmd_read          \
84
                        command_write=O_myAxiDmaDevice_cmd_write        \
85
                        busy=I_myAxiDmaDevice_busy                      \
86
                        error=I_myAxiDmaDevice_error                    \
87
                        read=I_myAxiDmaDevice_read                      \
88
                        address_width=7                                 \
89
                        synchronous=True\n
90
    To write to the memory master to slave start address, use the
91
    following, where "start_address" is a 4-byte variable set elsewhere in the
92
    program:\n
93
      ; Set the 7-bit register address.
94
      0x18 .outport(O_myAxiDmaDevice_address)
95
      ; Read the 4-byte start address from memory.
96
      .fetchvector(start_address,4)
97
      ; write the address to the AXI4-Lite master
98
      ${4-1} :loop_data
99
        swap .outport(O_myAxiDmaDevice_data)
100
      .jumpc(loop_data,1-) drop
101
      ; Ensure all 4 bytes will be written.
102
      0x0F .outport(O_myAxiDmaDevice_wen)
103
      ; Issue the write strobe.
104
      .outstrobe(O_myAxiDmaDevice_cmd_write)
105
      ; Wait for the write operation to finish.
106
      :loop_write_wait
107
        .inport(I_myAxiDmaDevice_busy)
108
      .jumpc(loop_write_wait)\n
109
    Alternatively, a function could be defined as follows:\n
110
      ; Write the specified 32-bit value to the specified 7-bit address.
111
      ; ( u_LSB u u u_MSB u_addr - )
112
      .function myAxiDmaDevice_write
113
        ; Write the 7-bit register address.
114
        .outport(O_myAxiDmaDevice_address)
115
        ; Write the 32-bit value, starting with the MSB.
116
        ${4-1} :loop_data
117
          swap .outport(O_myAxiDmaDevice_data)
118
        .jumpc(loop_data,1-) drop
119
        ; Ensure all 4 bytes will be written.
120
        0x0F .outport(O_myAxiDmaDevice_wen)
121
        ; Issue the write strobe.
122
        .outstrobe(O_myAxiDmaDevice_cmd_write)
123
        ; Wait for the write operation to finish.
124
        :loop_write_wait
125
          .inport(I_myAxiDmaDevice_busy)
126
        .jumpc(loop_write_wait)
127
        ; That's all
128
        .return\n
129
    And the write could then be performed using the following code:\n
130
      .constant AXI_DMA_MM2S_Start_Address 0x18
131
      ...
132
      ; Write the start address to the AXI DMA.
133
      .fetchvector(start_address,4)
134
      .call(myAxiDmaDevice_write,AXI_DMA_MM2S_Start_Address)\n
135
  Example:  Suppose the AXI4-Lite Master peripheral is connected to a memory
136
    with a 22-bit address width, i.e., a 4 MB address range.  The PERIPHERAL
137
    configuration command would be similar to the above except the string
138
    "myAxiDmaDevice" would need to be changed to the new hardware peripheral and
139
    the address width would be set using "address_width=22".\n
140
    The 22-bit address would be set using 3 bytes.  For example, the address
141
    0x020100 would be set by:\n
142
      0x00 .outport(O_myAxiMaster_address)
143
      0x01 .outport(O_myAxiMaster_address)
144
      0x02 .outport(O_myAxiMaster_address)\n
145
    The 2 msb of the first, most-significant, address byte will be dropped by
146
    the shift register receiving the address and the 2 lsb of the last, least
147
    significant, address byte will be written as zeros to the AXI Lite
148
    peripheral.\n
149
  LEGAL NOTICE:  ARM has restrictions on what kinds of applications can use
150
  interfaces based on their AXI protocol.  Ensure your application is in
151
  compliance with their restrictions before using this peripheral for an AXI
152
  interface.
153
  """
154
 
155
  def __init__(self,peripheralFile,config,param_list,loc):
156
    # Use the externally provided file name for the peripheral
157
    self.peripheralFile = peripheralFile;
158
    # Get the parameters.
159
    allowables = (
160
      ('address',       r'O_\w+$',              None,           ),
161
      ('address_width', r'[1-9]\d*$',           int,            ),
162
      ('basePortName',  r'\w+$',                None,           ),
163
      ('command_read',  r'O_\w+$',              None,           ),
164
      ('command_write', r'O_\w+$',              None,           ),
165
      ('data',          r'O_\w+$',              None,           ),
166
      ('read',          r'I_\w+$',              None,           ),
167
      ('busy',          r'I_\w+$',              None,           ),
168
      ('error',         r'I_\w+$',              None,           ),
169
      ('synchronous',   r'(True|False)$',       bool,           ),
170
      ('write_enable',  r'O_\w+$',              None,           ),
171
    );
172
    names = [a[0] for a in allowables];
173
    for param_tuple in param_list:
174
      param = param_tuple[0];
175
      if param not in names:
176
        raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,));
177
      param_test = allowables[names.index(param)];
178
      self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]);
179
    # Ensure the required parameters are provided (all parameters are required).
180
    for paramname in names:
181
      if not hasattr(self,paramname):
182
        raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,));
183
    # There are no optional parameters.
184
    # Temporary:  Warning message
185
    if not self.synchronous:
186
      raise SSBCCException('synchronous=False has not been validated yet');
187
    # Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
188
    for signal in (
189
      ( 'i_%s_aresetn',         1,                      'input',        ),
190
      ( 'i_%s_aclk',            1,                      'input',        ),
191
      ( 'o_%s_awvalid',         1,                      'output',       ),
192
      ( 'i_%s_awready',         1,                      'input',        ),
193
      ( 'o_%s_awaddr',          self.address_width,     'output',       ),
194
      ( 'o_%s_wvalid',          1,                      'output',       ),
195
      ( 'i_%s_wready',          1,                      'input',        ),
196
      ( 'o_%s_wdata',           32,                     'output',       ),
197
      ( 'o_%s_wstrb',           4,                      'output',       ),
198
      ( 'i_%s_bresp',           2,                      'input',        ),
199
      ( 'i_%s_bvalid',          1,                      'input',        ),
200
      ( 'o_%s_bready',          1,                      'output',       ),
201
      ( 'o_%s_arvalid',         1,                      'output',       ),
202
      ( 'i_%s_arready',         1,                      'input',        ),
203
      ( 'o_%s_araddr',          self.address_width,     'output',       ),
204
      ( 'i_%s_rvalid',          1,                      'input',        ),
205
      ( 'o_%s_rready',          1,                      'output',       ),
206
      ( 'i_%s_rdata',           32,                     'input',        ),
207
      ( 'i_%s_rresp',           2,                      'input',        ),
208
    ):
209
      thisName = signal[0] % self.basePortName;
210
      config.AddIO(thisName,signal[1],signal[2],loc);
211
    config.AddSignal('s__%s__address' % self.basePortName, self.address_width, loc);
212
    config.AddSignal('s__%s__rd' % self.basePortName, 1, loc);
213
    config.AddSignal('s__%s__wr' % self.basePortName, 1, loc);
214
    config.AddSignal('s__%s__busy' % self.basePortName, 5, loc);
215
    config.AddSignal('s__%s__error' % self.basePortName, 2, loc);
216
    config.AddSignal('s__%s__read' % self.basePortName, 32, loc);
217
    self.ix_address = config.NOutports();
218
    config.AddOutport((self.address,False,
219
                      # empty list -- disable normal output port signal generation
220
                      ),loc);
221
    self.ix_data = config.NOutports();
222
    config.AddOutport((self.data,False,
223
                      # empty list -- disable normal output port signal generation
224
                      ),loc);
225
    config.AddOutport((self.write_enable,False,
226
                      ('o_%s_wstrb' % self.basePortName, 4, 'data', ),
227
                      ),loc);
228
    config.AddOutport((self.command_read,True,
229
                      ('s__%s__rd' % self.basePortName, 1, 'strobe', ),
230
                      ),loc);
231
    config.AddOutport((self.command_write,True,
232
                      ('s__%s__wr' % self.basePortName, 1, 'strobe', ),
233
                      ),loc);
234
    config.AddInport((self.busy,
235
                     ('s__%s__busy' % self.basePortName, 5, 'data', ),
236
                     ),loc);
237
    config.AddInport((self.error,
238
                     ('s__%s__error' % self.basePortName, 2, 'data', ),
239
                     ),loc);
240
    self.ix_read = config.NInports();
241
    config.AddInport((self.read,
242
                     ('s__%s__read' % self.basePortName, 32, 'data', ),
243
                     ),loc);
244
 
245
  def GenVerilog(self,fp,config):
246
    body = self.LoadCore(self.peripheralFile,'.v');
247
    # avoid i_clk and i_rst
248
    for subpair in (
249
      (r'\bgen__',              'gen__@NAME@__',                        ),
250
      (r'\bL__',                'L__@NAME@__',                          ),
251
      (r'\bs__',                's__@NAME@__',                          ),
252
      (r'\bi_a',                'i_@NAME@_a',                           ),
253
      (r'\bi_b',                'i_@NAME@_b',                           ),
254
      (r'\bi_rd',               'i_@NAME@_rd',                          ),
255
      (r'\bi_rr',               'i_@NAME@_rr',                          ),
256
      (r'\bi_rv',               'i_@NAME@_rv',                          ),
257
      (r'\bi_w',                'i_@NAME@_w',                           ),
258
      (r'\bo_',                 'o_@NAME@_',                            ),
259
      (r'@ADDRESS_WIDTH@',      str(self.address_width),                ),
260
      (r'@ISSYNC@',             "1'b1" if self.synchronous else "1'b0", ),
261
      (r'@IX_ADDRESS@',         str(self.ix_address),                   ),
262
      (r'@IX_DATA@',            str(self.ix_data),                      ),
263
      (r'@IX_READ@',            str(self.ix_read),                      ),
264
      (r'@NAME@',               self.basePortName,                      ),
265
    ):
266
      body = re.sub(subpair[0],subpair[1],body);
267
    body = self.GenVerilogFinal(config,body);
268
    fp.write(body);

powered by: WebSVN 2.1.0

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