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

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [ssbccConfig.py] - Blame information for rev 3

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

Line No. Rev Author Line
1 2 sinclairrf
################################################################################
2
#
3
# Copyright 2012-2013, Sinclair R.F., Inc.
4
#
5
# Utilities required by ssbcc
6
#
7
################################################################################
8
 
9
import math
10
import os
11
import re
12
import sys
13
 
14
from ssbccUtil import *
15
 
16
class SSBCCconfig():
17
  """
18
  Container for ssbcc configuration commands, the associated parsing, and
19
  program generation.
20
  """
21
 
22
  def __init__(self):
23
    """
24
    Initialize the empty dictionaries holding the processor configuration
25
    parameters.  Initialize the paths to search for peripherals.
26
    """
27
    self.config         = dict();               # various settings, etc.
28
    self.constants      = dict();               # CONSTANTs
29
    self.functions      = dict();               # list of functions to define
30
    self.inports        = list();               # INPORT definitions
31
    self.ios            = list();               # List of I/Os
32
    self.outports       = list();               # OUTPORT definitions (see AddOutport)
33
    self.parameters     = list();               # PARAMETERs and LOCALPARAMs
34
    self.peripheral     = list();               # PERIPHERALs
35
    self.signals        = list();               # internal signals
36
    self.symbols        = list();               # constant, I/O, inport, etc.  names
37
 
38
    # list of memories
39
    self.memories = dict(name=list(), type=list(), maxLength=list());
40
 
41
    # list of how the memories will be instantiated
42
    self.config['combine'] = list();
43
 
44 3 sinclairrf
    # initial search path for .INCLUDE configuration commands
45
    self.includepaths = list();
46
    self.includepaths.append('.');
47
 
48 2 sinclairrf
    # initial search paths for peripherals
49 3 sinclairrf
    self.peripheralpaths = list();
50 2 sinclairrf
    self.peripheralpaths.append('.');
51
    self.peripheralpaths.append('peripherals');
52
    self.peripheralpaths.append(os.path.join(sys.path[0],'core/peripherals'));
53
 
54
  def AddConstant(self,name,value,loc):
55
    """
56
    Add the constant for the "CONSTANT" configuration command to the "constants"
57
    dictionary.\n
58
    name        symbol for the constant
59
    value       value of the constant
60
    loc         file name and line number for error messages
61
    """
62
    self.AddSymbol(name,loc);
63
    if name in self.constants:
64
      raise SSBCCException('CONSTANT "%s" already declared at %s' % (name,loc,));
65
    self.constants[name] = value;
66
 
67
  def AddIO(self,name,nBits,iotype,loc):
68
    """
69
    Add an I/O signal to the processor interface to the system.\n
70
    name        name of the I/O signal
71
    nBits       number of bits in the I/O signal
72
    iotype      signal direction:  "input", "output", or "inout"
73
    """
74
    if iotype != 'comment':
75
      self.AddSymbol(name,loc);
76
    self.ios.append((name,nBits,iotype,));
77
 
78
  def AddInport(self,port,loc):
79
    """
80
    Add an INPORT symbol to the processor.\n
81
    port        name of the INPORT symbol
82
    loc         file name and line number for error messages
83
    """
84
    name = port[0];
85
    self.AddSymbol(name,loc);
86
    self.inports.append(port);
87
 
88
  def AddMemory(self,cmd,loc):
89
    """
90
    Add a memory to the list of memories.\n
91
    cmd         3-element list as follows:
92
                [0] ==> type:  "RAM" or "ROM"
93
                [1] ==> memory name
94
                [2] ==> memory length (must be a power of 2)
95
    loc         file name and line number for error messages
96
    """
97
    self.memories['type'].append(cmd[0]);
98
    self.memories['name'].append(cmd[1]);
99
    maxLength = eval(cmd[2]);
100
    if not IsPowerOf2(maxLength):
101
      raise SSBCCException('Memory length must be a power of 2, not "%s", at %s' % (cmd[2],loc,));
102
    self.memories['maxLength'].append(eval(cmd[2]));
103
 
104
  def AddOutport(self,port,loc):
105
    """
106
    Add an OUTPORT symbol to the processor.\n
107
    port        tuple as follows:
108
                port[0] - name of the OUTPORT symbol
109
                port[1] - True if the outport is a strobe-only outport, false
110
                          otherwise
111
                port[2:] - zero or more tuples as follows:
112
                  (o_signal,width,type,[initialization],)
113
                where
114
                  o_signal is the name of the output signal
115
                  width is the number of bits in the signal
116
                  type is 'data' or 'strobe'
117
                  initialization is an optional initial/reset value for the
118
                    output signal
119
    loc         file name and line number for error messages
120
    """
121
    self.AddSymbol(port[0],loc);
122
    self.outports.append(port);
123
 
124
  def AddParameter(self,name,value,loc):
125
    """
126
    Add a PARAMETER to the processor.\n
127
    name        name of the PARAMETER
128
    value       value of the PARAMETER
129
    loc         file name and line number for error messages
130
    """
131
    if not re.match(r'[LG]_\w+$',name):
132
      raise Exception('Program Bug -- bad parameter name at %s' % loc);
133
    self.AddSymbol(name,loc);
134
    self.parameters.append((name,value,));
135
 
136
  def AddSignal(self,name,nBits,loc):
137
    """
138
    Add a signal without an initial value to the processor.\n
139
    name        name of the signal
140
    nBits       number of bits in the signal
141
    loc         file name and line number for error messages
142
    """
143
    self.AddSymbol(name,loc);
144
    self.signals.append((name,nBits,));
145
 
146
  def AddSignalWithInit(self,name,nBits,init,loc):
147
    """
148
    Add a signal with an initial/reset value to the processor.\n
149
    name        name of the signal
150
    nBits       number of bits in the signal
151
    init        initial/reset value of the signal
152
    loc         file name and line number for error messages
153
    """
154
    self.AddSymbol(name,loc);
155
    self.signals.append((name,nBits,init,));
156
 
157
  def AddSymbol(self,name,loc=None):
158
    """
159
    Add the specified name to the list of symbols.\n
160
    Note:  This symbol has no associated functionality and is only used for
161
           ".ifdef" conditionals.
162
    """
163
    if name in self.symbols:
164
      if loc == None:
165
        raise SSBCCException('Symbol "%s" already defined, no line number provided');
166
      else:
167
        raise SSBCCException('Symbol "%s" already defined before %s' % (name,loc,));
168
    self.symbols.append(name);
169
 
170 3 sinclairrf
  def AppendIncludePath(self,path):
171
    """
172
    Add the specified path to the end of the paths to search for .INCLUDE
173
    configuration commands.\n
174
    path        path to add to the list
175
    """
176
    self.includepaths.insert(-1,path);
177
 
178 2 sinclairrf
  def CompleteCombines(self):
179
    """
180
    Ensure all memories are assigned addresses.\n
181
    This modifies config['combine'] to include singleton entries for any
182
    memories not subject to the COMBINE configuration command.  It then computes
183
    how the memories will be packed together as well as properites for the
184
    packed memories.  These properties are:
185
      packing   how the memories will be packed as per PackCombinedMemory
186
      memName   HDL name of the memory
187
      memLength number of words in the memory
188
      memWidth  bit width of the memory words
189
    """
190
    # Create singleton entries for memory types and memories that aren't already listed in 'combine'.
191
    if not self.IsCombined('INSTRUCTION'):
192
      self.config['combine'].append({'mems':['INSTRUCTION',], 'memArch':'sync'});
193
    for memType in ('DATA_STACK','RETURN_STACK',):
194
      if not self.IsCombined(memType):
195
        self.config['combine'].append({'mems':[memType,], 'memArch':'LUT'});
196
    for memName in self.memories['name']:
197
      if not self.IsCombined(memName):
198
        self.config['combine'].append({'mems':[memName,], 'memArch':'LUT'});
199
    # Determine the HDL names for the memories.
200
    nRAMROMs = 0;
201
    for combined in self.config['combine']:
202
      if combined['mems'][0] == 'INSTRUCTION':
203
        combined['memName'] = 's_opcodeMemory';
204
      elif combined['mems'][0] == 'DATA_STACK':
205
        combined['memName'] = 's_data_stack';
206
      elif combined['mems'][0] == 'RETURN_STACK':
207
        combined['memName'] = 's_R_stack';
208
      else:
209
        nRAMROMs += 1;
210
    if nRAMROMs > 0:
211
      memNameFormat = 's_mem_%%0%dx' % ((CeilLog2(nRAMROMs)+3)/4);
212
    ixRAMROM = 0;
213
    for combined in self.config['combine']:
214
      if 'memName' in combined:
215
        continue;
216
      if nRAMROMs == 1:
217
        combined['memName'] = 's_mem';
218
      else:
219
        combined['memName'] = memNameFormat % ixRAMROM;
220
        ixRAMROM += 1;
221
    # Perform packing for all memories.
222
    for combined in self.config['combine']:
223
      self.PackCombinedMemory(combined);
224
 
225
  def Exists(self,name):
226
    """
227
    Return true if the requested attribute has been created in the ssbccConfig
228
    object.
229
    """
230
    return name in self.config;
231
 
232
  def Get(self,name):
233
    """
234
    Return the requested attribute from the ssbccConfig object.
235
    """
236
    if not self.Exists(name):
237
      raise Exception('Program Bug:  "%s" not found in config' % name);
238
    return self.config[name];
239
 
240
  def GetMemoryByBank(self,ixBank):
241
    """
242
    Return the parameters for a memory by its bank address.\n
243
    ixBank      index of the requested memory bank
244
    """
245
    if not 'bank' in self.memories:
246
      return None;
247
    if ixBank not in self.memories['bank']:
248
      return None;
249
    ixMem = self.memories['bank'].index(ixBank);
250
    return self.GetMemoryParameters(ixMem);
251
 
252
  def GetMemoryByName(self,name):
253
    """
254
    Return the parameters for a memory by its name.\n
255
    name        name of the requested memory
256
    """
257
    if not name in self.memories['name']:
258
      return None;
259
    ixMem = self.memories['name'].index(name);
260
    return self.GetMemoryParameters(ixMem);
261
 
262
  def GetMemoryParameters(self,rawIndex):
263
    """
264
    Return the parameters for a memory by its index in the list of memories.\n
265
    rawIndex    index within the list of memories
266
    """
267
    if type(rawIndex) == str:
268
      if not self.IsMemory(rawIndex):
269
        raise Exception('Program Bug:  reference to non-existent memory');
270
      ix = self.memories['name'].index(rawIndex);
271
    elif type(rawIndex) == int:
272
      if (rawIndex < 0) or (rawIndex >= len(self.memories['name'])):
273
        raise Exception('Program Bug:  bad memory index %d' % rawIndex);
274
      ix = rawIndex;
275
    else:
276
      raise Exception('Program Bug:  unrecognized index type "%s"' % type(rawIndex));
277
    outvalue = dict();
278
    outvalue['index'] = ix;
279
    for field in self.memories:
280
      outvalue[field] = self.memories[field][ix];
281
    return outvalue;
282
 
283
  def GetPacking(self,name):
284
    """
285
    Get the memory packing for the provided memory.
286
    """
287
    for combined in self.config['combine']:
288
      if name not in combined['mems']:
289
        continue;
290
      for port in combined['port']:
291
        for packing in port['packing']:
292
          if packing['name'] == name:
293
            return (combined,port,packing,);
294
    else:
295
      raise Exception('Program Bug -- %s not found in combined memories' % name);
296
 
297
  def GetParameterValue(self,name):
298
    """
299
    Get the value associated with the named parameter.
300
    """
301
    if name.find('[') != -1:
302
      ix = name.index('[');
303
      thisSlice = name[ix:];
304
      name = name[:ix];
305
    else:
306
      thisSlice = '[0+:8]';
307
    for ix in range(len(self.parameters)):
308
      if self.parameters[ix][0] == name:
309 3 sinclairrf
        return ExtractBits(IntValue(self.parameters[ix][1]),thisSlice);
310 2 sinclairrf
    else:
311
      raise Exception('Program Bug:  Parameter "%s" not found' % name);
312
 
313
  def InsertPeripheralPath(self,path):
314
    """
315
    Add the specified path to the beginning of the paths to search for
316
    peripherals.\n
317
    path        path to add to the list
318
    """
319
    self.peripheralpaths.insert(-1,path);
320
 
321
  def IsCombined(self,name):
322
    """
323
    Indicate whether or not the specified memory type has already been listed
324
    in a "COMBINE" configuration command.  The memory type should be one of
325
    DATA_STACK, INSTRUCTION, or RETURN_STACK.\n
326
    name        name of the specified memory type\n
327
    """
328
    for combined in self.config['combine']:
329
      if name in combined['mems']:
330
        return True;
331
    else:
332
      return False;
333
 
334
  def IsMemory(self,name):
335
    """
336
    Indicate whether or not the specified symbol is the name of a memory.
337
    """
338
    return (name in self.memories['name']);
339
 
340
  def IsParameter(self,name):
341
    """
342
    Indicate whether or not the specified symbol is the name of a parameter.
343
    """
344
    if re.match(r'[GL]_\w+',name) and name in self.symbols:
345
      return True;
346
    else:
347
      return False;
348
 
349
  def IsRAM(self,name):
350
    """
351
    Indicate whether or not the specified symbol is the name of a RAM.
352
    """
353
    if name not in self.memories['name']:
354
      return False;
355
    ix = self.memories['name'].index(name);
356
    return self.memories['type'][ix] == 'RAM';
357
 
358
  def IsROM(self,name):
359
    """
360
    Indicate whether or not the specified symbol is the name of a RAM.
361
    """
362
    if name not in self.memories['name']:
363
      return False;
364
    ix = self.memories['name'].index(name);
365
    return self.memories['type'][ix] == 'ROM';
366
 
367
  def IsStrobeOnlyOutport(self,outport):
368
    """
369
    Indicate whether or not the specified outport symbol only has strobes
370
    associated with it (i.e., it has no data signals).
371
    """
372
    return outport[1];
373
 
374
  def IsSymbol(self,name):
375
    """
376
    Indicate whether or not the specified name is a symbol.
377
    """
378
    return (name in self.symbols);
379
 
380
  def MemoryNameLengthList(self):
381
    """
382
    Return a list of tuples where each tuple is the name of a memory and its
383
    length.
384
    """
385
    outlist = list();
386
    for ix in range(len(self.memories['name'])):
387
      outlist.append((self.memories['name'][ix],self.memories['maxLength'][ix],));
388
    return outlist;
389
 
390
  def NInports(self):
391
    """
392
    Return the number of INPORTS.
393
    """
394
    return len(self.inports);
395
 
396
  def NMemories(self):
397
    """
398
    Return the number of memories.
399
    """
400
    return len(self.memories['name']);
401
 
402
  def NOutports(self):
403
    """
404
    Return the number of OUTPORTS.
405
    """
406
    return len(self.outports);
407
 
408
  def OverrideParameter(self,name,value):
409
    """
410
    Change the value of the specified parameter (based on the command line
411
    argument instead of the architecture file).\n
412
    name        name of the parameter to change
413
    value       new value of the parameter
414
    """
415
    for ix in range(len(self.parameters)):
416
      if self.parameters[ix][0] == name:
417
        break;
418
    else:
419
      raise SSBCCException('Command-line parameter or localparam "%s" not specified in the architecture file' % name);
420
    self.parameters[ix] = (name,value,);
421
 
422
  def PackCombinedMemory(self,combined):
423
    """
424
    Utility function for CompleteCombines.\n
425
    Determine packing strategy and resulting memory addresses and sizes.  This
426
    list has everything ssbccGenVerilog needs to construct the memory.\n
427
    The dual port memories can be used to do the following:
428
      1.  pack a single memory, either single-port or dual-port
429
      2.  pack two single-port memories sequentially, i.e., one at the start of
430
          the RAM and one toward the end of the RAM
431
      3.  pack one single-port memory at the start of the RAM and pack several
432
          compatible single-port memories in parallel toward the end of the RAM.
433
          Note:  Compatible means that they have the same address.
434
      4.  pack several compatible dual-port memories in parallel.\n
435
    These single-port or dual-port single or parallel packed memories are
436
    described in the 'port' list in combined.  Each entry in the port list has
437
    several parameters described below and a 'packing' list that describes the
438
    single or multiple memories attached to that port.\n
439
    The parameters for each of port is as follows:
440
      offset    start address of the memory in the packing
441
      nWords    number of RAM words reserved for the memory
442
                Note:  This can be larger than the aggregate number of words
443
                       required by the memory in order to align the memories to
444
                       power-of-2 address alignments.
445
      ratio     number of base memory entries for the memory
446
                Note:  This must be a power of 2.\n
447
    The contents of each entry in the packing are as follows:
448
      -- the following are from the memory declaration
449
      name      memory name
450
      length    number of elements in the memory based on the declared memory
451
                size
452
                Note:  This is based on the number of addresses required for
453
                       each memory entry (see ratio).
454
      nbits     width of the memory type
455
      -- the following are derived for the packing
456
      lane      start bit
457
                Note:  This is required in particular when memories are stacked
458
                       in parallel.
459
      nWords    number of memory addresses allocated for the memory based on
460
                the packing
461
                Note:  This will be larger than length when a small memory is
462
                       packed in parallel with a larger memory.  I.e., when
463
                       ratio is not one.
464
      ratio     number of base memory entries required to extract a single word
465
                for the memory type
466
                Note:  This allows return stack entries to occupy more than one
467
                       memory address when the return stack is combined with
468
                       other memory addresses.
469
                Note:  This must be a power of 2.\n
470
    The following entries are also added to "combined":
471
      nWords    number of words in the memory
472
      memWidth  bit width of the memory words\n
473
    Note:  If memories are being combined with the instructions space, they are
474
           always packed at the end of the instruction space, so the
475
           instruction space allocation is not included in the packing.
476
    """
477
    # Count how many memories of each type are being combined.
478
    nSinglePort = 0;
479
    nRAMs = 0;
480
    nROMs = 0;
481
    for memName in combined['mems']:
482
      if memName in ('INSTRUCTION','DATA_STACK','RETURN_STACK',):
483
        nSinglePort += 1;
484
      elif self.IsROM(memName):
485
        nROMs += 1;
486
      else:
487
        nRAMs += 1;
488
    if nRAMs > 0:
489
      nRAMs += nROMs;
490
      nROMs = 0;
491
    # Ensure the COMBINE configuration command is implementable in a dual-port RAM.
492
    if nSinglePort > 0 and nRAMs > 0:
493
      raise SSBCCException('Cannot combine RAMs with other memory types in COMBINE configuration command at %s' % combined['loc']);
494
    if nSinglePort > 2 or (nSinglePort > 1 and nROMs > 0):
495
      raise SSBCCException('Too many memory types in COMBINE configuration command at %s' % combined['loc']);
496
    # Start splitting the listed memories into the one or two output lists and ensure that single-port memories are listed in the correct order.
497
    mems = combined['mems'];
498
    ixMem = 0;
499
    split = list();
500
    if 'INSTRUCTION' in mems:
501
      if mems[0] != 'INSTRUCTION':
502
        raise SSBCCException('INSTRUCTION must be the first memory listed in the COMBINE configuration command at %s' % combined['loc']);
503
      split.append(['INSTRUCTION']);
504
      ixMem += 1;
505
    while len(mems[ixMem:]) > 0 and mems[ixMem] in ('DATA_STACK','RETURN_STACK',):
506
      split.append([mems[ixMem]]);
507
      ixMem += 1;
508
    for memName in ('DATA_STACK','RETURN_STACK',):
509
      if memName in mems[ixMem:]:
510
        raise SSBCCException('Single-port memory %s must be listed before ROMs in COMBINE configuration command at %s' % combined['loc']);
511
    if mems[ixMem:]:
512
      split.append(mems[ixMem:]);
513
    if not (1 <= len(split) <= 2):
514
      raise Exception('Program Bug -- bad COMBINE configuration command not caught');
515
    # Create the detailed packing information.
516
    combined['port'] = list();
517
    for thisSplit in split:
518
      packing = list();
519
      for memName in thisSplit:
520
        if memName == 'INSTRUCTION':
521
          packing.append({'name':memName, 'length':self.Get('nInstructions')['length'], 'nbits':9});
522
        elif memName == 'DATA_STACK':
523
          packing.append({'name':memName, 'length':self.Get('data_stack'), 'nbits':self.Get('data_width')});
524
        elif memName == 'RETURN_STACK':
525
          nbits = max(self.Get('data_width'),self.Get('nInstructions')['nbits']);
526
          packing.append({'name':memName, 'length':self.Get('return_stack'), 'nbits':nbits});
527
        else:
528
          thisMemory = self.GetMemoryParameters(memName);
529
          packing.append({'name':memName, 'length':CeilPow2(thisMemory['maxLength']), 'nbits':self.Get('data_width')});
530
      combined['port'].append({ 'packing':packing });
531
    # Calculate the width of the base memory.
532
    # Note:  This accommodates RETURN_STACK being an isolated memory.
533
    memWidth = combined['port'][0]['packing'][0]['nbits'] if len(combined['port']) == 1 else None;
534
    for port in combined['port']:
535
      for packing in port['packing']:
536
        tempMemWidth = packing['nbits'];
537
        if tempMemWidth > self.Get('sram_width'):
538
          tempMemWidth = self.Get('sram_width');
539
        if not memWidth:
540
          memWidth = tempMemWidth;
541
        elif tempMemWidth > memWidth:
542
          memWidth = tempMemWidth;
543
    combined['memWidth'] = memWidth;
544
    # Determine how the memories are packed.
545
    # Note:  "ratio" should be non-unity only for RETURN_STACK.
546
    for port in combined['port']:
547
      lane = 0;
548
      for packing in port['packing']:
549
        packing['lane'] = lane;
550
        ratio = CeilPow2((packing['nbits']+memWidth-1)/memWidth);
551
        packing['ratio'] = ratio;
552
        packing['nWords'] = ratio * packing['length'];
553
        lane += ratio;
554
    # Aggregate parameters each memory port.
555
    for port in combined['port']:
556
      ratio = CeilPow2(sum(packing['ratio'] for packing in port['packing']));
557
      maxLength = max(packing['length'] for packing in port['packing']);
558
      port['ratio'] = ratio;
559
      port['nWords'] = ratio * maxLength;
560
    combined['port'][0]['offset'] = 0;
561
    if len(combined['port']) > 1:
562
      if combined['mems'][0] == 'INSTRUCTION':
563
        nWordsTail = combined['port'][1]['nWords'];
564
        port0 = combined['port'][0];
565
        if port0['nWords'] <= nWordsTail:
566
          raise SSBCCException('INSTRUCTION length too small for "COMBINE INSTRUCTION,..." at %s' % combined['loc']);
567
        port0['nWords'] -= nWordsTail;
568
        port0['packing'][0]['nWords'] -= nWordsTail;
569
        port0['packing'][0]['length'] -= nWordsTail;
570
      else:
571
        maxNWords = max(port['nWords'] for port in combined['port']);
572
        for port in combined['port']:
573
          port['nWords'] = maxNWords;
574
      combined['port'][1]['offset'] = combined['port'][0]['nWords'];
575
    combined['nWords'] = sum(port['nWords'] for port in combined['port']);
576
 
577
  def ProcessCombine(self,loc,line):
578
    """
579
    Parse the "COMBINE" configuration command as follows:\n
580
    Validate the arguments to the "COMBINE" configuration command and append
581
    the list of combined memories and the associated arguments to "combine"
582
    property.\n
583
    The argument consists of one of the following:
584
      INSTRUCTION,{DATA_STACK,RETURN_STACK,rom_list}
585
      DATA_STACK
586
      DATA_STACK,{RETURN_STACK,rom_list}
587
      RETURN_STACK
588
      RETURN_STACK,{DATA_STACK,rom_list}
589
      mem_list
590
    where rom_list is a comma separated list of one or more ROMs and mem_list is
591
    a list of one or more RAMs or ROMs.
592
    """
593
    # Perform some syntax checking and get the list of memories to combine.
594
    cmd = re.findall(r'\s*COMBINE\s+(\S+)\s*$',line);
595
    if not cmd:
596
      raise SSBCCException('Malformed COMBINE configuration command on %s' % loc);
597
    mems = re.split(r',',cmd[0]);
598
    if (len(mems)==1) and ('INSTRUCTION' in mems):
599
      raise SSBCCException('"COMBINE INSTRUCTION" doesn\'t make sense at %s' % loc);
600
    if ('INSTRUCTION' in mems) and (mems[0] != 'INSTRUCTION'):
601
      raise SSBCCException('"INSTRUCTION" must be listed first in COMBINE configuration command at %s' % loc);
602
    recognized = ['INSTRUCTION','DATA_STACK','RETURN_STACK'] + self.memories['name'];
603
    unrecognized = [memName for memName in mems if memName not in recognized];
604
    if unrecognized:
605
      raise SSBCCException('"%s" not recognized in COMBINE configuration command at %s' % (unrecognized[0],loc,));
606
    alreadyUsed = [memName for memName in mems if self.IsCombined(memName)];
607
    if alreadyUsed:
608
      raise SSBCCException('"%s" already used in COMBINE configuration command before %s' % (alreadyUsed[0],loc,));
609
    repeated = [mems[ix] for ix in range(len(mems)-1) if mems[ix] in mems[ix+1]];
610
    if repeated:
611
      raise SSBCCException('"%s" repeated in COMBINE configuration command on %s' % (repeated[0],loc,));
612
    # Count the number of the different memory types being combined and validate the combination.
613
    nSinglePort = sum([thisMemName in ('INSTRUCTION','DATA_STACK','RETURN_STACK',) for thisMemName in mems]);
614
    nROM = len([thisMemName for thisMemName in mems if self.IsROM(thisMemName)]);
615
    nRAM = len([thisMemName for thisMemName in mems if self.IsRAM(thisMemName)]);
616
    if nRAM > 0:
617
      nRAM += nROM;
618
      nROM = 0;
619
    if nROM > 0:
620
      nSinglePort += 1;
621
    nDualPort = 1 if nRAM > 0 else 0;
622
    if nSinglePort + 2*nDualPort > 2:
623
      raise SSBCCException('Too many ports required for COMBINE configuration command at %s' % loc);
624
    # Append the listed memory types to the list of combined memories.
625
    self.config['combine'].append({'mems':mems, 'memArch':'sync', 'loc':loc});
626
 
627
  def ProcessInport(self,loc,line):
628
    """
629
    Parse the "INPORT" configuration commands as follows:
630
      The configuration command is well formatted.
631
      The number of signals matches the corresponding list of signal declarations.
632
      The port name starts with 'I_'.
633
      The signal declarations are valid.
634
        n-bit where n is an integer
635
        set-reset
636
        strobe
637
      That no other signals are specified in conjunction with a "set-reset" signal.
638
      The total input data with does not exceed the maximum data width.\n
639
    The input port is appended to the list of inputs as a tuple.  The first
640
    entry in the tuple is the port name.  The subsequent entries are tuples
641
    consisting of the following:
642
      signal name
643
      signal width
644
      signal type
645
    """
646
    cmd = re.findall(r'\s*INPORT\s+(\S+)\s+(\S+)\s+(I_\w+)\s*$',line);
647
    if not cmd:
648
      raise SSBCCException('Malformed INPORT statement at %s: "%s"' % (loc,line[:-1],));
649
    modes = re.findall(r'([^,]+)',cmd[0][0]);
650
    names = re.findall(r'([^,]+)',cmd[0][1]);
651
    portName = cmd[0][2];
652
    if len(modes) != len(names):
653
      raise SSBCCException('Malformed INPORT configuration command -- number of options don\'t match on %s: "%s"' % (loc,line[:-1],));
654
    # Append the input signal names, mode, and bit-width to the list of I/Os.
655
    has__set_reset = False;
656
    nBits = 0;
657
    thisPort = (portName,);
658
    for ix in range(len(names)):
659
      if re.match(r'^\d+-bit$',modes[ix]):
660
        thisNBits = int(modes[ix][0:-4]);
661
        self.AddIO(names[ix],thisNBits,'input',loc);
662
        thisPort += ((names[ix],thisNBits,'data',),);
663
        nBits = nBits + thisNBits;
664
      elif modes[ix] == 'set-reset':
665
        has__set_reset = True;
666
        self.AddIO(names[ix],1,'input',loc);
667
        thisPort += ((names[ix],1,'set-reset',),);
668
        self.AddSignal('s_SETRESET_%s' % names[ix],1,loc);
669
      elif modes[ix] == 'strobe':
670
        self.AddIO(names[ix],1,'output',loc);
671
        thisPort += ((names[ix],1,'strobe',),);
672
      else:
673
        raise SSBCCException('Unrecognized INPORT signal type "%s"' % modes[ix]);
674
      if has__set_reset and len(names) > 1:
675
        raise SSBCCException('set-reset cannot be simultaneous with other signals in "%s"' % line[:-1]);
676
      if nBits > self.Get('data_width'):
677
        raise SSBCCException('Signal width too wide in "%s"' % line[:-1]);
678
    self.AddInport(thisPort,loc);
679
 
680
  def ProcessOutport(self,line,loc):
681
    """
682
    Parse the "OUTPORT" configuration commands as follows:
683
      The configuration command is well formatted.
684
      The number of signals matches the corresponding list of signal declarations.
685
      The port name starts with 'O_'.
686
      The signal declarations are valid.
687
        n-bit[=value]
688
        strobe
689
      The total output data with does not exceed the maximum data width.\n
690
    The output port is appended to the list of outports as a tuple.  The first
691
    entry in this tuple is the port name.  The subsequent entries are tuples
692
    consisting of the following:
693
      signal name
694
      signal width
695
      signal type
696
      initial value (optional)
697
    """
698
    cmd = re.findall(r'^\s*OUTPORT\s+(\S+)\s+(\S+)\s+(O_\w+)\s*$',line);
699
    if not cmd:
700
      raise SSBCCException('Malformed OUTPUT configuration command on %s: "%s"' % (loc,line[:-1],));
701
    modes = re.findall(r'([^,]+)',cmd[0][0]);
702
    names = re.findall(r'([^,]+)',cmd[0][1]);
703
    portName = cmd[0][2];
704
    if len(modes) != len(names):
705
      raise SSBCCException('Malformed OUTPORT configuration command -- number of widths/types and signal names don\'t match on %s: "%s"' % (loc,line[:-1],));
706
    # Append the input signal names, mode, and bit-width to the list of I/Os.
707
    nBits = 0;
708
    isStrobeOnly = True;
709
    thisPort = tuple();
710
    for ix in range(len(names)):
711
      if re.match(r'\d+-bit',modes[ix]):
712
        isStrobeOnly = False;
713
        a = re.match(r'(\d+)-bit(=\S+)?$',modes[ix]);
714
        if not a:
715
          raise SSBCCException('Malformed bitwith/bitwidth=initialization on %s:  "%s"' % (loc,modes[ix],));
716
        thisNBits = int(a.group(1));
717
        self.AddIO(names[ix],thisNBits,'output',loc);
718
        if a.group(2):
719
          thisPort += ((names[ix],thisNBits,'data',a.group(2)[1:],),);
720
        else:
721
          thisPort += ((names[ix],thisNBits,'data',),);
722
        nBits = nBits + thisNBits;
723
        self.config['haveBitOutportSignals'] = 'True';
724
      elif modes[ix] == 'strobe':
725
        self.AddIO(names[ix],1,'output',loc);
726
        thisPort += ((names[ix],1,'strobe',),);
727
      else:
728
        raise SSBCCException('Unrecognized OUTPORT signal type on %s: "%s"' % (loc,modes[ix],));
729
      if nBits > 8:
730
        raise SSBCCException('Signal width too wide on %s:  in "%s"' % (loc,line[:-1],));
731
    self.AddOutport((portName,isStrobeOnly,)+thisPort,loc);
732
 
733
  def ProcessPeripheral(self,loc,line):
734
    """
735
    Process the "PERIPHERAL" configuration command as follows:
736
      Validate the format of the configuration command.
737
      Find the peripheral in the candidate list of paths for peripherals.
738
      Execute the file declaring the peripheral.
739
        Note:  This is done since I couldn't find a way to "import" the
740
               peripheral.  Executing the peripheral makes its definition local
741
               to this invokation of the ProcessPeripheral function, but the
742
               object subsequently created retains the required functionality
743
               to instantiate the peripheral
744
      Go through the parameters for the peripheral and do the following for each:
745
        If the argument for the peripheral is the string "help", then print the
746
          docstring for the peripheral and exit.
747
        Append the parameter name and its argument to the list of parameters
748
          (use "None" as the argument if no argument was provided).
749
      Append the instantiated peripheral to the list of peripherals.
750
        Note:  The "exec" function dynamically executes the instruction to
751
               instantiate the peripheral and append it to the list of
752
               peripherals.
753
    """
754
    # Validate the format of the peripheral configuration command and the the name of the peripheral.
755
    cmd = re.findall(r'\s*PERIPHERAL\s+(\w+)\s*(.*)$',line);
756
    if not cmd:
757
      raise SSBCCException('Missing peripheral name in %s:  %s' % (loc,line[:-1],));
758
    peripheral = cmd[0][0];
759
    # Find and execute the peripheral Python script.
760
    # Note:  Because "execfile" and "exec" method are used to load the
761
    #        peripheral python script, the __file__ object is set to be this
762
    #        file, not the peripheral source file.
763
    for testPath in self.peripheralpaths:
764
      fullperipheral = os.path.join(testPath,'%s.py' % peripheral);
765
      if os.path.isfile(fullperipheral):
766
        break;
767
    else:
768
      raise SSBCCException('Peripheral "%s" not found' % peripheral);
769
    execfile(fullperipheral);
770
    # Convert the space delimited parameters to a list of tuples.
771
    param_list = list();
772
    for param_string in re.findall(r'(\w+="[^"]*"|\w+=\S+|\w+)\s*',cmd[0][1]):
773
      if param_string == "help":
774
        exec('helpmsg = %s.__doc__' % peripheral);
775
        if not helpmsg:
776
          raise SSBCCException('No help for peripheral %s is provided' % fullperipheral);
777
        print;
778
        print 'Help message for peripheral:  %s' % peripheral;
779
        print 'Located at:  %s' % fullperipheral;
780
        print;
781
        print helpmsg;
782
        raise SSBCCException('Terminated by "help" for peripheral %s' % peripheral);
783
      ix = param_string.find('=');
784
      if param_string.find('="') > 0:
785
        param_list.append((param_string[:ix],param_string[ix+2:-1],));
786
      elif param_string.find('=') > 0:
787
        param_list.append((param_string[:ix],param_string[ix+1:],));
788
      else:
789
        param_list.append((param_string,None));
790
    # Add the peripheral to the micro controller configuration.
791
    exec('self.peripheral.append(%s(fullperipheral,self,param_list,loc));' % peripheral);
792
 
793
  def Set(self,name,value):
794
    """
795
    Create or override the specified attribute in the ssbccConfig object.
796
    """
797
    self.config[name] = value;
798
 
799
  def SetMemoryBlock(self,name,value,errorInfo):
800
    """
801
    Set an attribute in the ssbccConfig object for the specified memory with
802
    the specified memory architecture.\n
803
    "value" must be a string with the format "\d+" or "\d+*\d+" where "\d+" is
804
    an integer.  The first format specifies a single memory with the stated
805
    size and the size must be a power of two.  The second format specified
806
    allocation of multiple memory blocks where the size is given by the first
807
    integer and must be a power of 2 and the number of blocks is given by the
808
    second integer and doesn't need to be a power of 2.
809
    """
810
    findStar = value.find('*');
811
    if findStar == -1:
812
      blockSize = int(value);
813
      nBlocks = 1;
814
    else:
815
      blockSize = int(value[0:findStar]);
816
      nBlocks = int(value[findStar+1:]);
817
    nbits_blockSize = int(round(math.log(blockSize,2)));
818
    if blockSize != 2**nbits_blockSize:
819 3 sinclairrf
      raise SSBCCException('block size must be a power of 2 at %s: "%s"' % errorInfo);
820 2 sinclairrf
    nbits_nBlocks = CeilLog2(nBlocks);
821
    self.Set(name, dict(
822
                   length=blockSize*nBlocks,
823
                   nbits=nbits_blockSize+nbits_nBlocks,
824
                   blockSize=blockSize,
825
                   nbits_blockSize=nbits_blockSize,
826
                   nBlocks=nBlocks,
827
                   nbits_nBlocks=nbits_nBlocks));
828
 
829
  def SetMemoryParameters(self,memParam,values):
830
    """
831
    Record the body of the specified memory based on the assembler output.
832
    """
833
    index = memParam['index'];
834
    for field in values:
835
      if field not in self.memories:
836
        self.memories[field] = list();
837
        for ix in range(len(self.memories['name'])):
838
          self.memories[field].append(None);
839
      self.memories[field][index] = values[field];
840
 
841
  def SignalLengthList(self):
842
    """
843
    Generate a list of the I/O signals and their lengths.
844
    """
845
    outlist = list();
846
    for io in self.ios:
847
      if io[2] == 'comment':
848
        continue;
849
      outlist.append((io[0],io[1],));
850
    return outlist;

powered by: WebSVN 2.1.0

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