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

Subversion Repositories ssbcc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 sinclairrf
################################################################################
2
#
3
# Copyright 2015, Sinclair R.F., Inc.
4
#
5
################################################################################
6
 
7
from ssbccPeripheral import SSBCCinterruptPeripheral
8
from ssbccUtil import SSBCCException
9
 
10
class interrupt(SSBCCinterruptPeripheral):
11
  """
12
  Interrupt peripheral for 1 to 8 interrupt inputs.\n
13
  This implements a variable-width interrupt input of up to 8 bits and
14
  generates an interrupt when one of these goes from low to high, provided that
15
  an interrupt is not already in progress.\n
16
  Usage:
17
    PERIPHERAL interrupt insignal<N>=[!]{i_name|s__name}[,C_NAME]       \\
18
                         [inport=I_NAME]                                \\
19
                         [outmaskport=O_NAME]                           \\
20
                         [inmaskport=I_NAME]                            \\
21
                         [initmask=<value>]\n
22
  Where:
23
    insignal<N>={i_name|s__name}[,C_NAME]
24
      specifies one of the eight possible single-bit signal that will trigger
25
      the interrupt and optionally specify a constant defined by the interrupt
26
      bit position
27
      Note:  Replace <N> with 0, 1, ..., 7
28
      Note:  If the signal name starts with "i_" it will be added as a single
29
             bit wide input to the processor.  If the signal name starts with
30
             "s__" it must be a signal from another peripheral with the given
31
             name.
32
      Note:  If the signal name is preceded by a an exclamation mark, i.e., a
33
             "!", then the signal will be treated as falling-edge triggered
34
             instead of rising edge triggered.
35
      Note:  External signals may need to be synchronized to the micro
36
             controller clock.
37
    inport=I_NAME
38
      provide the input port name to read the interrupt signal
39
      Note:  This port is prohibited if there is only one interrupt signal and
40
             it is required if there is more than one interrupt signal.
41
    outmaskport=O_NAME
42
      optionally specifies a port to provide an enable/disable mask to
43
      the interrupt signals
44
    inmaskport=I_NAME
45
      optionally specifies a port to read the current enable/disable mask
46
      Note:  This cannot be used if outmaskport is not specified.
47
    initmask=<value>
48
      optionally specifies the initial value of the mask
49
      Note:  This cannot be used if outmaskport is not specified.
50
      Note:  The value is either a Verilog format value or a decimal value.
51
      Note:  If this is not specified then all interrupt bits will be enabled.\n
52
  Example:  Trigger an interrupt when a 1 clock wide strobe is received from an
53
            external timer.\n
54
            # In the architecture file
55
            PERIPHERAL interrupt insignal0=i_timer_strobe\n
56
            ; In the assembly file
57
            .interrupt
58
              ; Do the timer event.
59
              ...
60
              ; Return from the interrupt.
61
              .returni\n
62
  Example:  Monitor an external timer strobe and a FIFO empty flag (which is
63
            high when the FIFO is empty).\n
64
            # In the architecture file
65
            PERIPHERAL outFIFO_async data=o_fifo ... outempty=I_EMPTY
66
            PERIPHERAL interrupt insignal0=!s__o_fifo__outempty_in,C_INTERRUPT_MASK_FIFO \\
67
                                 insignal1=i_timer_strobe,C_INTERRUPT_MASK_TIMER         \\
68
                                 inport=I_INTERRUPT\n
69
            ; In the assembly file
70
            .interrupt
71
              ; Read the interrupt condition.
72
              .inport(I_INTERRUPT)
73
              ; If the interrupt was triggered by the timer, then handle the
74
              ; timer event (but don't throw away the rest of the interrupt
75
              ; condition).
76
              dup C_INTERRUPT_MASK_TIMER & .callc(...)
77
              ; If the interrupt was triggered by the FIFO becoming empty, then
78
              ; do whatever's appropriate (and throw away the interrupt
79
              ; condition).
80
              C_INTERRUPT_MASK_FIFO & .callc(...)
81
              ; Return from the interrupt.
82
              .returni\n
83
  WARNING:  Setting the interrupt mask does not disable interrupts occuring
84
            before a bit in the mask is cleared.  I.e., if a particular
85
            interrupt bit is disabled by a new interrupt mask, but an interrupt
86
            for that bit occured before the mask bit was cleared, then that
87
            interrupt bit will still have caused a pending interrupt.  This is
88
            particularly important when the processor is starting.\n
89
            This can be resolved in part by using the following code at the top
90
            of the interrupt handler:\n
91
              .inport(I_INTERRUPT) .inport(I_INTERRUPT_MASK) &
92
            where .inport(I_INTERRUPT) gets the interrupt event(s) and
93
            .inport(I_INTERRUPT_MASK) gets the current interrupt mask.
94
  """
95
 
96
  def __init__(self,peripheralFile,config,param_list,loc):
97
    """
98
    Configure this peripheral as an interrupt peripheral.
99
    """
100
    # Invoke the base class __init__ function before doing anything else.
101
    SSBCCinterruptPeripheral.__init__(self,config,loc)
102
    # Use the externally provided file name for the peripheral
103
    self.peripheralFile = peripheralFile
104
    # Get the parameters.
105
    allowables = (
106
      ( 'initmask',     r'\S+$',                lambda v : self.IntValueMethod(v), ),
107
      ( 'inmaskport',   r'I_\w+$',              None, ),
108
      ( 'inport',       r'I_\w+$',              None, ),
109
      ( 'outmaskport',  r'O_\w+$',              None, ),
110
    )
111
    names = [a[0] for a in allowables]
112
    self.insignal = [None for ix in range(config.Get('data_width'))]
113
    self.invert = 0
114
    for param_tuple in param_list:
115
      param = param_tuple[0]
116
      if re.match(r'insignal[0-7]$',param):
117
        if param_tuple[1] == None:
118
          raise SSBCCException('"%s" missing value at %s' % (param,loc,))
119
        ix = int(param[-1])
120
        if self.insignal[ix]:
121
          raise SSBCCException('%s already specified at %s' % (param,loc,))
122
        pars = re.findall(r'(!?)(i_\w+|s__\w+)(,C_\w+)?$',param_tuple[1])
123
        if not pars or not pars[0][1]:
124
          raise SSBCCException('I/O symbol at %s does not match required format "[!]{i_name|s__name}[,C_name]":  "%s"' % (loc,param_tuple[1],))
125
        pars = pars[0]
126
        if pars[0]:
127
          self.invert |= 2**ix
128
        self.insignal[ix] = pars[1]
129
        if pars[2]:
130
          config.AddConstant(pars[2][1:],2**ix,loc)
131
      elif param in names:
132
        param_test = allowables[names.index(param)]
133
        self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2])
134
      else:
135
        raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,))
136
    # Ensure the required parameters are set.
137
    if not any(self.insignal):
138
      raise SSBCCException('Required parameter insignal<N> missing at %s' % loc)
139
    self.width = sum(1 for ix in range(len(self.insignal)) if self.insignal[ix])
140
    ixMissing = [ix for ix in range(self.width) if not self.insignal[ix]]
141
    if ixMissing:
142
      raise SSBCCException('insignal%d missing at %s' % (ixMissing[0],loc,))
143
    if self.width == 1:
144
      if hasattr(self,'inport'):
145
        raise SSBCCException('Parameter "inport" is prohibited when there is only one interrupt signal at %s' % loc)
146
    else:
147
      if not hasattr(self,'inport'):
148
        raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,))
149
    # Ensure optional parameters are consistent.
150
    for opt in ('inmaskport','initmask',):
151
      if hasattr(self,opt) and not hasattr(self,'outmaskport'):
152
        raise SSBCCException('Optional parameter "%s" requires "outmaskport" at %s' % (opt,loc,))
153
    if hasattr(self,'initmask'):
154
      if self.initmask >= 2**self.width:
155
        raise SSBCCException('Value of "initmask" exceeds interrupt width at %s' % loc)
156
    # Create the signal for the triggering interrupt source.
157
    config.AddSignal('s_interrupt_trigger',self.width,loc)
158
    # Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
159
    for ix in [ix for ix in range(self.width) if re.match(r'i_',self.insignal[ix])]:
160
      config.AddIO(self.insignal[ix],1,'input',loc)
161
    if hasattr(self,'inport'):
162
      self.ix_inport = config.NInports()
163
      config.AddInport((self.inport,
164
                       ('s_interrupt_trigger',self.width,'data',),
165
                      ),
166
                      loc)
167
    if not hasattr(self,'initmask'):
168
      self.initmask= '%d\'h%X' % (self.width,2**self.width-1,)
169
    if hasattr(self,'outmaskport'):
170
      self.masksignal = 's_interrupt_mask'
171
      config.AddSignalWithInit(self.masksignal,self.width,None,loc)
172
      config.AddOutport((self.outmaskport,False,
173
                        (self.masksignal,self.width,'data',self.initmask,),
174
                       ),
175
                       loc)
176
      if hasattr(self,'inmaskport'):
177
        config.AddInport((self.inmaskport,
178
                         (self.masksignal,self.width,'data',),
179
                        ),
180
                        loc)
181
    else:
182
      self.masksignal = self.initmask
183
 
184
  def GenVerilog(self,fp,config):
185
    body = self.LoadCore(self.peripheralFile,'.v');
186
    if self.width == 1:
187
      body = re.sub(r'reg s_interrupt_trigger_any.*?\n','',body);
188
      while re.search(r' {4,}s_interrupt_trigger_any',body):
189
        body = re.sub(r' {4,}s_interrupt_trigger_any.*?\n','',body);
190
      body = re.sub(r's_interrupt_trigger_any','s_interrupt_trigger',body);
191
    if not hasattr(self,'inport'):
192
      clear_trigger = 's_interrupt';
193
    else:
194
      clear_trigger = 's_inport && (s_T == %d)' % self.ix_inport;
195
    for subpair in (
196
      ( r'@CLEAR_TRIGGER@',     clear_trigger, ),
197
      ( r'@IX_OUTPORT_DIS@',    '8\'h%02X' % self.ix_outport_interrupt_dis, ),
198
      ( r'@IX_OUTPORT_ENA@',    '8\'h%02X' % self.ix_outport_interrupt_ena, ),
199
      ( r'@INSIGNAL@',          '{ %s }' % ', '.join(self.insignal[ix] for ix in range(self.width-1,-1,-1)), ),
200
      ( r'@INVERT@',            '%d\'h%X' % (self.width,self.invert,), ),
201
      ( r'@MASK@',              self.masksignal, ),
202
      ( r'@WIDTH@ ',            '' if self.width==1 else '[%d:0] ' % (self.width-1,), ),
203
      ( r'@ZERO@',              '%d\'h0' % self.width, ),
204
    ):
205
      body = re.sub(subpair[0],subpair[1],body);
206
    body = self.GenVerilogFinal(config,body);
207
    fp.write(body);

powered by: WebSVN 2.1.0

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