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

Subversion Repositories ssbcc

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

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

Line No. Rev Author Line
1 2 sinclairrf
################################################################################
2
#
3 6 sinclairrf
# Copyright 2013-2014, Sinclair R.F., Inc.
4 2 sinclairrf
#
5
################################################################################
6
 
7
import math;
8
import re;
9
 
10
from ssbccPeripheral import SSBCCperipheral
11
from ssbccUtil import IsPowerOf2;
12
from ssbccUtil import SSBCCException;
13
 
14
class UART(SSBCCperipheral):
15
  """
16
  Transmit/receive UART:
17
    1 start bit
18
    8 data bits
19
    1 or 2 stop bits\n
20
  Usage:
21
    PERIPHERAL UART    inport=I_inport_name        \\
22
                       outport=O_outport_name      \\
23
                       inempty=I_inempty_name      \\
24
                       outstatus=I_outstatus_name  \\
25
                       baudmethod={clk/rate|count} \\
26
                       [insignal=i_name]           \\
27
                       [outsignal=o_name]          \\
28
                       [noSync|sync=n]             \\
29
                       [noDeglitch|deglitch=n]     \\
30
                       [noInFIFO|inFIFO=n]         \\
31
                       [noOutFIFO|outFIFO=n]       \\
32 6 sinclairrf
                       [{CTS|CTSn}=i_cts_name]     \\
33
                       [{RTR|RTRn}=i_rtr_name]     \\
34
                       [nStop={1|2}]\n
35 2 sinclairrf
  Where:
36
    inport=I_inport_name
37
      specifies the symbol used by the inport instruction to read a received by
38
      from the peripheral
39
      Note:  The name must start with "I_".
40
    outport=O_outport_name
41
      specifies the symbol used by the outport instruction to write a byte to
42
      the peripheral
43
      Note:  The name must start with "O_".
44
    inempty=I_inempty_name
45
      specifies the symbol used by the inport instruction to get the empty
46
      status of the input side of the peripheral
47
      Note:  The name must start with "I_".
48
    outstatus=I_outstatus_name
49
      specifies the symbol used by the inport instruction to get the status of
50
      the output side of the peripheral
51
      Note:  The name must start with "I_".
52
    baudmethod
53
      specifies the method to generate the desired bit rate:
54
      1st method:  clk/rate
55
        clk is the frequency of "i_clk" in Hz
56
          a number will be interpreted as the clock frequency in Hz
57
          a symbol will be interpreted as a parameter
58
            Note:  this parameter must have been declared with a "PARAMETER"
59
            command
60
        rate is the desired baud rate
61
          this is specified as per "clk"
62
      2nd method:
63
        specify the number of "i_clk" clock cycles between bit edges
64
      Note:  clk, rate, and count can be parameters or constants.  For example,
65
             the following uses the parameter G_CLK_FREQ_HZ for the clock
66
             frequency and a hard-wired baud rate of 9600:
67
             "baudmethod=G_CLK_FREQ_HZ/9600".
68
      Note:  The numeric values can have Verilog-style '_' separators between
69
             the digits.  For example, 100_000_000 represents 100 million.
70
    insignal=i_name
71
      optionally specifies the name of the single-bit transmit signal
72
      Default:  i_UART_Rx
73
    outsignal=o_name
74
      optionally specifies the name of the output signal
75
      Default:  o_UART_Tx
76
    noSync
77
      optionally state no synchronization or registration is performed on the
78
      input signal.
79
    sync=n
80
      optionally state that an n-bit synchronizer will be performed on the
81
      input signal.
82
      Note:  sync=3 is the default.
83
    noDeglitch
84
      optionally state that no deglitching is performed on the input signal.
85
      Note:  This is the default.
86
    deglitching=n
87
      optionally state that an n-bit deglitcher is performed on the input signal
88
      Note:  Deglitching consists of changing the output state when n
89
             successive input bits are in the opposite state.
90
    noInFIFO
91
      optionally state that the peripheral will not have an input FIFO
92
      Note:  This is the default.
93
    inFIFO=n
94
      optionally add a FIFO of depth n to the input side of the UART
95
      Note:  n must be a power of 2.
96
    noOutFIFO
97
      optionally state that the peripheral will not have an output FIFO
98
      Note:  This is the default.
99
    outFIFO=n
100
      optionally add a FIFO of depth n to the output side of the UART
101
      Note:  n must be a power of 2.
102 6 sinclairrf
    CTS=i_cts_name or CTSn=i_cts_name
103
      optionally specify an input handshake signal to control whether or not the
104
      peripheral transmits data
105
      Note:  If CTS is specified then the transmitter is active when i_cts_name
106
             is high.  If CTSn is specified then the transmitter is active when
107
             i_cts_name is low.
108
      Note:  The default, i.e., neither CTS nor CTSn is specified, is to always
109
             enable the transmitter.
110
      Note:  If there is no FIFO and the CTS/CTSn handshake indicates that the
111
             data flow is disabled, then the busy signal will be high and the
112
             processor code must not transmit the next byte.
113
    RTR=i_rtr_name or RTRn=i_rtr_name
114
      optionally specify an output handshake signal to indicate that the
115
      peripheral is ready to receive data
116
      Note:  If RTR is specified then the receiver indicates it is ready when
117
             i_rtr_name is high.  If RTRn is specified then the transmitter
118
             indicates it is ready when i_rtr_name is low.
119
      Note:  The default, i.e., neither CTS nor CTSn is specified, is to always
120
             enable the receiver.
121
      Note:  If there is no FIFO and the RTR/RTRn handshake indicates that the
122
             receiver is not ready as soon as it starts receiving data and
123
             until that data is read from the peripheral.
124 2 sinclairrf
    nStop=n
125
      optionally configure the peripheral for n stop bits
126
      default:  1 stop bit
127
      Note:  n must be 1 or 2
128 6 sinclairrf
      Note:  the peripheral does not accept 1.5 stop bits\n
129 2 sinclairrf
  The following ports are provided by this peripheral:
130
    I_inport_name
131
      input a recieved byte from the peripheral
132
      Note:  If there is no input FIFO, then this is the last received byte.
133
             If there is an input FIFO, then this is the next byte in the FIFO.
134
      Note:  If there is an input FIFO and the read would cause a FIFO
135
             underflow, this will repeat the last received byte.
136
    O_outport_name
137
      output the next 8-bit value to transmit or to queue for transmission
138
      Note:  If there is no output FIFO or if there is an output FIFO and this
139
             write would cause a FIFO overflow, then this byte will be
140
             discarded.
141
    I_inempty_name
142
      input the empty status of the input side of the peripheral
143
      bit 0:  input empty
144
        this bit will be high when the input side of the peripheral has one or
145
        more bytes read to be read
146
        Note:  If there is no FIFO this means that a single byte is ready to be
147
               read and has not been read.  If there is an input FIFO this
148
               means that there are one or more bytes in the FIFO.
149
        Note:  "Empty" is used rather than "ready" to facilitate loops that
150
               respond when there is a new byte ready to be processed.  See the
151
               examples below.
152
    I_outstatus_name
153
      input the status of the output side of the peripheral
154
      bit 0:  output busy
155
        this bit will be high when the output side of the peripheral cannot
156
        accept more writes
157
        Note:  If there is no FIFO this means that the peripheral is still
158
               transmitting the last byte.  If there is an output FIFO it means
159
               that it is full.\n
160
        Note:  "Busy" is used rather that "ready" to facilitate loops that wait
161 6 sinclairrf
               for a not-busy status to send the next byte.  See the examples below.\n
162 2 sinclairrf
  WARNING:  The peripheral is very simple and does not protect against writing a
163
            new value in the middle of a transmition or writing to a full FIFO.
164
            Adding such logic would be contrary to the design principle of
165
            keeping the HDL small and relying on the assembly code to provide
166
            the protection.\n
167
  Example:  Configure the UART for 115200 baud using a 100 MHz clock and
168
            transmit the message "Hello World!"\n
169
    Within the processor architecture file include the configuration command:\n
170
    PERIPHERAL UART_Tx O_UART_TX I_UART_TX baudmethod=100_000_000/115200\n
171
    Use the following assembly code to transmit the message "Hello World!".
172
    This transmits the entire message whether or not the peripheral has a FIFO.\n
173
    N"Hello World!\\r\\n"
174
      :loop .outport(O_UART_TX) :wait .inport(I_UART_TX_BUSY) .jumpc(wait) .jumpc(loop,nop) drop
175
  """
176
 
177
  def __init__(self,peripheralFile,config,param_list,loc):
178
    # Use the externally provided file name for the peripheral
179
    self.peripheralFile = peripheralFile;
180
    # Get the parameters.
181 6 sinclairrf
    allowables = (
182
      ( 'CTS',          r'i_\w+$',      None,           ),
183
      ( 'CTSn',         r'i_\w+$',      None,           ),
184
      ( 'RTR',          r'o_\w+$',      None,           ),
185
      ( 'RTRn',         r'o_\w+$',      None,           ),
186
      ( 'baudmethod',   r'\S+$',        lambda v : self.RateMethod(config,v), ),
187
      ( 'deglitch',     r'[1-9]\d*$',   int,            ),
188
      ( 'inFIFO',       r'[1-9]\d*$',   lambda v : self.IntPow2(v), ),
189
      ( 'inempty',      r'I_\w+$',      None,           ),
190
      ( 'inport',       r'I_\w+$',      None,           ),
191
      ( 'insignal',     r'i_\w+$',      None,           ),
192
      ( 'noDeglitch',   None,           None,           ),
193
      ( 'noInFIFO',     None,           None,           ),
194
      ( 'noOutFIFO',    None,           None,           ),
195
      ( 'noSync',       None,           None,           ),
196
      ( 'nStop',        r'[12]$',       int,            ),
197
      ( 'outFIFO',      r'[1-9]\d*$',   lambda v : self.IntPow2(v), ),
198
      ( 'outport',      r'O_\w+$',      None,           ),
199
      ( 'outsignal',    r'o_\w+$',      None,           ),
200
      ( 'outstatus',    r'I_\w+$',      None,           ),
201
      ( 'sync',         r'[1-9]\d*$',   int,            ),
202
    );
203
    names = [a[0] for a in allowables];
204 2 sinclairrf
    for param_tuple in param_list:
205
      param = param_tuple[0];
206 6 sinclairrf
      if param not in names:
207
        raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,));
208
      param_test = allowables[names.index(param)];
209
      self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]);
210 2 sinclairrf
    # Ensure the required parameters are provided.
211
    for paramname in (
212
        'baudmethod',
213
        'inempty',
214
        'inport',
215
        'outport',
216
        'outstatus',
217
      ):
218
      if not hasattr(self,paramname):
219
        raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,));
220
    # Set optional parameters.
221
    for optionalpair in (
222 6 sinclairrf
        ( 'insignal',   'i_UART_Rx',    ),
223
        ( 'nStop',      1,              ),
224
        ( 'outsignal',  'o_UART_Tx',    ),
225 2 sinclairrf
      ):
226
      if not hasattr(self,optionalpair[0]):
227
        setattr(self,optionalpair[0],optionalpair[1]);
228
    # Ensure exclusive pair configurations are set and consistent.
229
    for exclusivepair in (
230 6 sinclairrf
        ( 'CTS',        'CTSn',         None,           None,   ),
231
        ( 'RTR',        'RTRn',         None,           None,   ),
232
        ( 'noSync',     'sync',         'sync',         3,      ),
233
        ( 'noDeglitch', 'deglitch',     'noDeglitch',   True,   ),
234
        ( 'noInFIFO',   'inFIFO',       'noInFIFO',     True,   ),
235
        ( 'noOutFIFO',  'outFIFO',      'noOutFIFO',    True,   ),
236 2 sinclairrf
      ):
237
      if hasattr(self,exclusivepair[0]) and hasattr(self,exclusivepair[1]):
238
        raise SSBCCException('Only one of "%s" and "%s" can be specified at %s' % (exclusivepair[0],exclusivepair[1],loc,));
239 6 sinclairrf
      if not hasattr(self,exclusivepair[0]) and not hasattr(self,exclusivepair[1]) and exclusivepair[2]:
240 2 sinclairrf
        setattr(self,exclusivepair[2],exclusivepair[3]);
241 6 sinclairrf
    # Convert configurations to alternative format.
242
    for equivalent in (
243
        ( 'noDeglitch', 'deglitch',     0,      ),
244
        ( 'noInFIFO',   'inFIFO',       0,      ),
245
        ( 'noOutFIFO',  'outFIFO',      0,      ),
246
        ( 'noSync',     'sync',         0,      ),
247
      ):
248
      if hasattr(self,equivalent[0]):
249
        delattr(self,equivalent[0]);
250
        setattr(self,equivalent[1],equivalent[2]);
251 2 sinclairrf
    # Set the string used to identify signals associated with this peripheral.
252
    self.namestring = self.outsignal;
253
    # Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
254 6 sinclairrf
    for ioEntry in (
255
        ( 'insignal',   1,      'input',        ),
256
        ( 'outsignal',  1,      'output',       ),
257
        ( 'CTS',        1,      'input',        ),
258
        ( 'CTSn',       1,      'input',        ),
259
        ( 'RTR',        1,      'output',       ),
260
        ( 'RTRn',       1,      'output',       ),
261
      ):
262
      if hasattr(self,ioEntry[0]):
263
        config.AddIO(getattr(self,ioEntry[0]),ioEntry[1],ioEntry[2],loc);
264 2 sinclairrf
    config.AddSignal('s__%s__Rx'          % self.namestring,8,loc);
265
    config.AddSignal('s__%s__Rx_empty'    % self.namestring,1,loc);
266
    config.AddSignal('s__%s__Rx_rd'       % self.namestring,1,loc);
267
    config.AddSignal('s__%s__Tx'          % self.namestring,8,loc);
268
    config.AddSignal('s__%s__Tx_busy'     % self.namestring,1,loc);
269
    config.AddSignal('s__%s__Tx_wr'       % self.namestring,1,loc);
270
    config.AddInport((self.inport,
271
                    ('s__%s__Rx'          % self.namestring,8,'data',),
272
                    ('s__%s__Rx_rd'       % self.namestring,1,'strobe',),
273
                   ),loc);
274
    config.AddInport((self.inempty,
275
                   ('s__%s__Rx_empty'     % self.namestring,1,'data',),
276
                  ),loc);
277
    config.AddOutport((self.outport,False,
278
                   ('s__%s__Tx'           % self.namestring,8,'data',),
279
                   ('s__%s__Tx_wr'        % self.namestring,1,'strobe',),
280
                  ),loc);
281
    config.AddInport((self.outstatus,
282
                   ('s__%s__Tx_busy'      % self.namestring,1,'data',),
283
                 ),loc);
284
    # Add the 'clog2' function to the processor (if required).
285
    config.functions['clog2'] = True;
286
 
287
  def GenVerilog(self,fp,config):
288
    for bodyextension in ('_Rx.v','_Tx.v',):
289
      body = self.LoadCore(self.peripheralFile,bodyextension);
290 6 sinclairrf
      if hasattr(self,'RTR') or hasattr(self,'RTRn'):
291
        body = re.sub(r'@RTR_BEGIN@\n','',body);
292
        body = re.sub(r'@RTR_END@\n','',body);
293
      else:
294
        if re.search(r'@RTR_BEGIN@',body):
295
          body = re.sub(r'@RTR_BEGIN@.*?@RTR_END@\n','',body,flags=re.DOTALL);
296 2 sinclairrf
      for subpair in (
297 6 sinclairrf
          ( r'@RTR_SIGNAL@',    self.RTR if hasattr(self,'RTR') else self.RTRn if hasattr(self,'RTRn') else '', ),
298
          ( r'@RTR_INVERT@',    '' if hasattr(self,'RTR') else '!', ),
299
          ( r'\bL__',           'L__@NAME@__',          ),
300
          ( r'\bgen__',         'gen__@NAME@__',        ),
301
          ( r'\bs__',           's__@NAME@__',          ),
302
          ( r'@INPORT@',        self.insignal,          ),
303
          ( r'@BAUDMETHOD@',    str(self.baudmethod),   ),
304
          ( r'@SYNC@',          str(self.sync),         ),
305
          ( r'@DEGLITCH@',      str(self.deglitch),     ),
306
          ( r'@INFIFO@',        str(self.inFIFO),       ),
307
          ( r'@ENABLED@',       self.CTS if hasattr(self,'CTS') else ('!%s' % self.CTSn) if hasattr(self,'CTSn') else '1\'b1', ),
308
          ( r'@NSTOP@',         str(self.nStop),        ),
309
          ( r'@OUTFIFO@',       str(self.outFIFO),      ),
310
          ( r'@NAME@',          self.namestring,        ),
311
        ):
312
        if re.search(subpair[0],body):
313
          body = re.sub(subpair[0],subpair[1],body);
314 2 sinclairrf
      body = self.GenVerilogFinal(config,body);
315
      fp.write(body);

powered by: WebSVN 2.1.0

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