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

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [ssbccPeripheral.py] - Blame information for rev 12

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 sinclairrf
# Copyright 2012-2015, Sinclair R.F., Inc.
2
# Base classes and utility function for generating general-purpose and interrupt
3
# peripherals.
4 2 sinclairrf
 
5
import re
6
 
7 12 sinclairrf
from ssbccUtil import IntValue
8 8 sinclairrf
from ssbccUtil import IsIntExpr
9 6 sinclairrf
from ssbccUtil import IsPosInt
10
from ssbccUtil import IsPowerOf2
11 8 sinclairrf
from ssbccUtil import ParseIntExpr
12 2 sinclairrf
from ssbccUtil import SSBCCException
13
 
14
class SSBCCperipheral:
15
  """Base class for peripherals"""
16
 
17
  def __init__(self,peripheralFile,config,param_list,loc):
18
    """
19
    Prototype constructor.
20
    peripheralFile      the full path name of the peripheral source
21
                        Note:  "__file__" doesn't work because 'execfile" and
22
                        "exec" are used to load the python script for the
23
                        peripheral.
24
    config              the ssbccConfig object for the processor core
25
    param_list          parameter list for the processor
26
    loc                 file name and line number for error messages
27
    """
28
    pass;
29
 
30
  def AddAttr(self,config,name,value,reformat,loc,optFn=None):
31
    """
32
    Add attribute to the peripheral:
33
    config      ssbccConfig object for the procedssor core
34
    name        attribute name
35
    value       possibly optional value for the attribute
36
    reformat    regular expression format for the attribute value
37
                Note:  reformat=None means the attribute can only be set to True
38
    loc         file name and line number for error messages
39
    optFn       optional function to set stored type
40 6 sinclairrf
                Note:  See IntPow, RateMethod, etc. below for example methods.
41 2 sinclairrf
    """
42
    if hasattr(self,name):
43
      raise SSBCCException('%s repeated at %s' % (name,loc,));
44
    if reformat == None:
45
      if value != None:
46
        raise SSBCCException('No parameter allowed for %s at %s' % (name,loc,));
47
      setattr(self,name,True);
48
    else:
49
      if value == None:
50
        raise SSBCCException('%s missing value at %s' % (name,loc,));
51
      if not re.match(reformat,value):
52
        raise SSBCCException('I/O symbol at %s does not match required format "%s":  "%s"' % (loc,reformat,value,));
53
      if optFn != None:
54 6 sinclairrf
        try:
55
          value = optFn(value);
56
        except SSBCCException,msg:
57
          raise SSBCCException('Parameter "%s=%s" at %s:  %s' % (name,value,loc,str(msg),));
58
        except:
59
          raise SSBCCException('Value for "%s" not parsable at %s:  "%s"' % (name,loc,value,));
60 2 sinclairrf
      setattr(self,name,value);
61
 
62
  def GenAssembly(self,config):
63
    """
64 6 sinclairrf
    Virtual method to generate assembly modules associated with the peripheral.
65 2 sinclairrf
    """
66
    pass;
67
 
68
  def GenHDL(self,fp,config):
69
    """
70
    Generate the peripheral HDL.
71
    fp          file pointer for the output processor
72
    config      ssbccConfig object for the procedssor core
73
    """
74
    if config.Get('hdl') == 'Verilog':
75
      self.GenVerilog(fp,config);
76
    elif config.Get('hdl') == 'VHDL':
77
      self.GenVHDL(fp,config);
78
    else:
79
      raise SSBCCException('HDL "%s" not implemented' % config.Get('hdl'));
80
 
81
  def GenVerilog(self,fp,config):
82
    """
83 6 sinclairrf
    Virtual method to generate the Verilog version of the peripheral.
84 2 sinclairrf
    Raise an exception if there is no Verilog version of the peripheral.
85
    """
86
    raise Exception('Verilog is not implemented for this peripheral');
87
 
88
  def GenVerilogFinal(self,config,body):
89
    """
90
    Clean up the peripheral code.
91
    Change "$clog2" to "clog2" for simulators and synthesis tools that don't
92
      recognize or process "$clog2."
93
    """
94
    if config.Get('define_clog2'):
95
      body = re.sub('\$clog2','clog2',body);
96
    return body;
97
 
98
  def GenVHDL(self,fp,config):
99
    """
100 6 sinclairrf
    Virtual method to generate the VHDL version of the peripheral.
101 2 sinclairrf
    Raise an exception if there is no VHDL version of the peripheral.
102
    """
103
    raise Exception('VHDL is not implemented for this peripheral');
104
 
105
  def LoadCore(self,filename,extension):
106
    """
107
    Read the source HDL for the peripheral from the same directory as the python
108
    script.
109
    filename    name for the python peripheral (usually "__file__")
110
    extension   the string such as ".v" or ".vhd" required by the HDL\n
111
    Note:  The '.' must be included in the extension.  For example, the UART
112
           peripheral uses '_Rx.v' and '_Tx.v' or similar to invoke the UART_Tx
113
           and UART_Rx HDL files.
114
    """
115
    hdlName = re.sub(r'\.py$',extension,filename);
116 11 sinclairrf
    fp = open(hdlName,'rt');
117 2 sinclairrf
    body = fp.read();
118
    fp.close();
119
    return body;
120
 
121 6 sinclairrf
  ##############################################################################
122
  #
123
  # Methods to supplement python intrisics for the optFn argument of AddAttr
124
  #
125
  # Note:  AddAttr embelleshes exception messages with the symbol name and
126
  #        source code line number.
127
  #
128
  # Note:  One weird side effect of using lambda expressions is that the
129
  #        functions won't be recognized unless they're members of the
130
  #        SSBCCperipheral class.
131
  #
132
  ##############################################################################
133
 
134 9 sinclairrf
  def IntPow2Method(self,config,value,lowLimit=1,highLimit=None):
135 6 sinclairrf
    """
136 9 sinclairrf
    Return the integer value of the argument if it is a power of 2 between the
137
    optional limits (inclusive).  Otherwise throw an error.\n
138
    Note:  Other than a lower limit of 1 for "lowLimit", IntMethod validates
139
           "lowLimit" and "highLimit".
140 6 sinclairrf
    """
141 9 sinclairrf
    value = self.IntMethod(config,value,lowLimit,highLimit)
142
    if lowLimit < 1:
143
      raise SSBCCException('Program bug:  lowLimit = %d is less than 1' % lowLimit);
144
    if not IsPowerOf2(value):
145
      raise SSBCCException('Must be a power of 2');
146
    return value;
147
 
148
  def IntMethod(self,config,value,lowLimit=None,highLimit=None):
149
    """
150
    Return the integer value of the argument.  Throw an error if the argument is
151
    unrecognized, not an integer, or is outside the optionally specified range.
152
    """
153
    if (lowLimit != None) and (highLimit != None) and (highLimit < lowLimit):
154
      raise SSBCCException('Program bug:  lowLimit = %d and highLimit = %d conflict' % (lowLimit,highLimit,));
155 6 sinclairrf
    if re.match(r'L_\w+$',value):
156
      if not config.IsParameter(value):
157
        raise SSBCCException('Unrecognized parameter');
158
      ix = [param[0] for param in config.parameters].index(value);
159
      value = config.parameters[ix][1];
160
    elif re.match(r'C_\w+$',value):
161
      if not config.IsConstant(value):
162
        raise SSBCCException('Unrecognized constant');
163
      value = config.constants[value];
164 8 sinclairrf
    value = ParseIntExpr(value);
165 9 sinclairrf
    if (lowLimit != None) and value < lowLimit:
166
      if lowLimit == 1:
167
        raise SSBCCException('Must be a positive integer');
168
      else:
169
        raise SSBCCException('Cannot be less than %d' % lowLimit);
170
    if (highLimit != None) and value > highLimit:
171
      raise SSBCCException('Cannot be more than %d' % highLimit);
172 6 sinclairrf
    return value;
173
 
174 12 sinclairrf
  def IntValueMethod(self,value):
175
    """
176
    """
177
    return IntValue(value);
178
 
179 6 sinclairrf
  def RateMethod(self,config,value):
180
    """
181
    Return the string to evaluate the provided value or ratio of two values.
182 9 sinclairrf
    The value can be an integer (including underscores), a constant, or a
183
    parameter.  Ratios are restated to do rounding instead of truncation.\n
184 6 sinclairrf
    Examples:
185
      123456
186
      123_456
187
      L_DIVISION_RATIO
188
      G_CLOCK_FREQUENCY_HZ/19200
189 9 sinclairrf
      C_CLOCK_FREQUENCY_HZ/19200
190 6 sinclairrf
      G_CLOCK_FREQUENCY_HZ/L_BAUD_RATE
191
      100_000_000/G_BAUD_RATE
192
    """
193 9 sinclairrf
    def LocalIntMethod(self,config,value,position=None):
194
      try:
195
        if config.IsParameter(value):
196
          return value;
197
        else:
198
          v = self.IntMethod(config,value,lowLimit=1);
199
          return str(v);
200
      except SSBCCException, msg:
201
        if not position:
202
          raise SSBCCException(msg);
203
        else:
204
          raise SSBCCException('%s in %s' % (msg,position,));
205 8 sinclairrf
    if value.find('/') < 0:
206 9 sinclairrf
      return LocalIntMethod(self,config,value);
207 6 sinclairrf
    else:
208
      ratearg = re.findall('([^/]+)',value);
209
      if len(ratearg) != 2:
210
        raise SSBCCException('Only one "/" allowed in expression');
211 9 sinclairrf
      ratearg[0] = LocalIntMethod(self,config,ratearg[0],'numerator');
212
      ratearg[1] = LocalIntMethod(self,config,ratearg[1],'denominator');
213 6 sinclairrf
      return '(%s+%s/2)/%s' % (ratearg[0],ratearg[1],ratearg[1],);
214 9 sinclairrf
 
215
  def TimeMethod(self,config,value,lowLimit=None,highLimit=None):
216
    """
217
    Convert the provided time from the specified units to seconds.
218
    """
219
    if not re.match(r'(0|[1-9]\d*)(\.\d*)?(e[+-]?\d+)?[mun]?s$',value):
220
      raise SSBCCException('Malformed time value');
221
    if value[-2:] == 'ms':
222
      v = float(value[:-2]) * 1.e-3;
223
    elif value[-2:] == 'us':
224
      v = float(value[:-2]) * 1.e-6;
225
    elif value[-2:] == 'ns':
226
      v = float(value[:-2]) * 1.e-9;
227
    else:
228
      v = float(value[:-1]);
229
    if (lowLimit != None) and (v < lowLimit):
230
      raise SSBCCException('%s must be %s or greater' % (v,lowLimit,));
231
    if (highLimit != None) and (v > highLimit):
232
      raise SSBCCException('%s must be %s or smaller' % (v,highLimit,));
233
    return v;
234 12 sinclairrf
 
235
################################################################################
236
#
237
# Base class for interrupt peripherals.
238
#
239
################################################################################
240
 
241
class SSBCCinterruptPeripheral(SSBCCperipheral):
242
  """
243
  Base class for interrupt peripherals.
244
  """
245
 
246
  instance = None;
247
 
248
  def __init__(self,config,loc):
249
    """
250
    Perform tasks common to all interrupt peripherals:
251
      Ensure only one interrupt peripheral is defined.
252
      Declare the O_INTERRUPT_DIS and O_INTERRUPT_ENA output ports.
253
        These are set/reset outports and only require 2 instructions.
254
        These 2-instruction sequences are automatically generated by the ".ena"
255
          and ".dis" macros.
256
      ...\n
257
    Note:  The "param_list" normally part of a peripheral __init__ method is
258
           missing.  First, it isn't required here.  Second, that helps ensure
259
           that this class is not instantiated by itself as a peripheral.
260
    """
261
    # Ensure only one interrupt peripheral gets defined.
262
    if SSBCCinterruptPeripheral.instance:
263
      raise SSBCCException('Interrupt peripheral already defined before line %d' % loc);
264
    SSBCCinterruptPeripheral.instance = self;
265
    # Add the signals required by the interrupt handler.
266
    config.AddSignal('s_interrupt',1,loc);
267
    config.AddSignal('s_interrupted',1,loc);
268
    # Add the outports to disable and enable interrupts.
269
    self.ix_outport_interrupt_dis = config.NOutports();
270
    config.AddOutport(('O_INTERRUPT_DIS',True,),loc);
271
    self.ix_outport_interrupt_ena = config.NOutports();
272
    config.AddOutport(('O_INTERRUPT_ENA',True,),loc);
273
 
274
################################################################################
275
#
276
# Utilties for interrupt peripherals.
277
#
278
################################################################################
279
 
280
def InterruptPeripheralAssigned():
281
  """
282
  Indicate whether or not an interrupt peripheral has been generated.
283
  """
284
  return True if SSBCCinterruptPeripheral.instance else False;

powered by: WebSVN 2.1.0

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