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

Subversion Repositories ssbcc

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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