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

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [core/] [9x8/] [ssbccGenVerilog.py] - Blame information for rev 2

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

Line No. Rev Author Line
1 2 sinclairrf
################################################################################
2
#
3
# Copyright 2012, Sinclair R.F., Inc.
4
#
5
# Verilog generation functions.
6
#
7
################################################################################
8
 
9
import math
10
import os
11
import re
12
 
13
from ssbccUtil import *;
14
 
15
################################################################################
16
#
17
# Generate input and output core names.
18
#
19
################################################################################
20
 
21
def genCoreName():
22
  """
23
  Return the name of the file to use for the processor core.
24
  """
25
  return 'core.v';
26
 
27
def genOutName(rootName):
28
  """
29
  Return the name for the output micro controller module.
30
  """
31
  if re.match('.*\.v$',rootName):
32
    return rootName;
33
  else:
34
    return ("%s.v" % rootName);
35
 
36
################################################################################
37
#
38
# Generate the code to run the INPORT selection, the associated output
39
# strobes,and the set-reset latches.
40
#
41
################################################################################
42
 
43
def genFunctions(fp,config):
44
  """
45
  Output the optional bodies for the following functions and tasks:
46
    clog2               when $clog2 isn't available by commanding "--define_clog2"
47
                        on the ssbcc command line
48
    display_opcode      human-readable version of the opcode suitable for
49
                        waveform viewers
50
    display_trace       when the trace or monitor_stack peripherals are included
51
  """
52
  if 'display_opcode' in config.functions:
53
    displayOpcodePath = os.path.join(config.Get('corepath'),'display_opcode.v');
54
    fpDisplayOpcode = open(displayOpcodePath,'r');
55
    if not fpDisplayOpcode:
56
      raise Exception('Program Bug -- "%s" not found' % displayOpcodePath);
57
    body = fpDisplayOpcode.read();
58
    fpDisplayOpcode.close();
59
    fp.write(body);
60
  if ('clog2' in config.functions) and config.Get('define_clog2'):
61
    fp.write("""
62
// Use constant function instead of builtin $clog2.
63
function integer clog2;
64
  input integer value;
65
  integer temp;
66
  begin
67
    temp = value - 1;
68
    for (clog2=0; temp>0; clog2=clog2+1)
69
      temp = temp >> 1;
70
  end
71
endfunction
72
""");
73
  if 'display_trace' in config.functions:
74
    displayTracePath = os.path.join(config.Get('corepath'),'display_trace.v');
75
    fpDisplayTrace = open(displayTracePath,'r');
76
    if not fpDisplayTrace:
77
      raise Exception('Program Bug -- "%s" not found' % displayTracePath);
78
    body = fpDisplayTrace.read();
79
    fpDisplayTrace.close();
80
    fp.write(body);
81
 
82
def genInports(fp,config):
83
  """
84
  Generate the logic for the input signals.
85
  """
86
  if not config.inports:
87
    fp.write('// no input ports\n');
88
    return
89
  haveBitInportSignals = False;
90
  for ix in range(config.NInports()):
91
    thisPort = config.inports[ix][1:];
92
    for jx in range(len(thisPort)):
93
      signal = thisPort[jx];
94
      signalType = signal[2];
95
      if signalType in ('data','set-reset',):
96
        haveBitInportSignals = True;
97
  if haveBitInportSignals:
98
    fp.write('always @ (*)\n');
99
    fp.write('  case (s_T)\n');
100
  for ix in range(config.NInports()):
101
    thisPort = config.inports[ix][1:];
102
    nbits = 0;
103
    bitString = '';
104
    for jx in range(len(thisPort)):
105
      signal = thisPort[jx];
106
      signalName = signal[0];
107
      signalSize = signal[1];
108
      signalType = signal[2];
109
      if signalType == 'data':
110
        nbits = nbits + signalSize;
111
        if len(bitString)>0:
112
          bitString += ', ';
113
        bitString = bitString + signalName;
114
      if signalType == 'set-reset':
115
        fp.write('      8\'h%02X : s_T_inport = (%s || s_SETRESET_%s) ? 8\'hFF : 8\'h00;\n' % (ix, signalName, signalName));
116
    if nbits == 0:
117
      pass;
118
    elif nbits < 8:
119
      fp.write('      8\'h%02X : s_T_inport = { %d\'h0, %s };\n' % (ix,8-nbits,bitString));
120
    elif nbits == 8:
121
      fp.write('      8\'h%02X : s_T_inport = %s;\n' % (ix,bitString));
122
    else:
123
      fp.write('      8\'h%02X : s_T_inport = %s[0+:8];\n' % (ix,bitString));
124
  if haveBitInportSignals:
125
    fp.write('    default : s_T_inport = 8\'h00;\n');
126
    fp.write('  endcase\n');
127
    fp.write('\n');
128
  # Generate all the INPORT strobes.
129
  for ix in range(config.NInports()):
130
    thisPort = config.inports[ix][1:];
131
    for jx in range(len(thisPort)):
132
      signal = thisPort[jx];
133
      signalName = signal[0];
134
      signalType = signal[2];
135
      if signalType == 'strobe':
136
        fp.write('always @ (posedge i_clk)\n');
137
        fp.write('  if (i_rst)\n');
138
        fp.write('    %s <= 1\'b0;\n' % signalName);
139
        fp.write('  else if (s_inport)\n');
140
        fp.write('    %s <= (s_T == 8\'h%02X);\n' % (signalName,ix));
141
        fp.write('  else\n');
142
        fp.write('    %s <= 1\'b0;\n' % signalName);
143
        fp.write('\n');
144
  # Generate all the INPORT "set-reset"s.
145
  for ix in range(config.NInports()):
146
    thisPort = config.inports[ix][1:];
147
    if thisPort[0][2] == 'set-reset':
148
      signalName = thisPort[0][0];
149
      fp.write('always @(posedge i_clk)\n');
150
      fp.write('  if (i_rst)\n');
151
      fp.write('    s_SETRESET_%s <= 1\'b0;\n' % signalName);
152
      fp.write('  else if (s_inport && (s_T == 8\'h%02X))\n' % ix);
153
      fp.write('    s_SETRESET_%s <= 1\'b0;\n' % signalName);
154
      fp.write('  else if (%s)\n' % signalName);
155
      fp.write('    s_SETRESET_%s <= 1\'b1;\n' % signalName);
156
      fp.write('  else\n');
157
      fp.write('    s_SETRESET_%s <= s_SETRESET_%s;\n' % (signalName,signalName));
158
 
159
def genLocalParam(fp,config):
160
  """
161
  Generate the localparams for implementation-specific constants.
162
  """
163
  fp.write('localparam C_PC_WIDTH                              = %4d;\n' % CeilLog2(config.Get('nInstructions')['length']));
164
  fp.write('localparam C_RETURN_PTR_WIDTH                      = %4d;\n' % CeilLog2(config.Get('return_stack')));
165
  fp.write('localparam C_DATA_PTR_WIDTH                        = %4d;\n' % CeilLog2(config.Get('data_stack')));
166
  fp.write('localparam C_RETURN_WIDTH                          = (C_PC_WIDTH <= 8) ? 8 : C_PC_WIDTH;\n');
167
 
168
def genMemories(fp,fpMemFile,config,programBody):
169
  """
170
  Generate the memories for the instructions, data stack, return stack, and the
171
  memories and the operations to access these memories in this order.
172
  Initialize the instruction memory.\n
173
  fp            file handle for the output core
174
  fpMemFile     file handle for the memory initialization file
175
                Note:  This can be used to avoid running synthesis again.
176
  """
177
  combines = config.config['combine'];
178
  # Declare instruction ROM(s).
179
  instructionMemory = config.Get('nInstructions');
180
  instructionAddrWidth = (instructionMemory['nbits_blockSize']+3)/4;
181
  instructionNameIndexWidth = (instructionMemory['nbits_nBlocks']+3)/4;
182
  instructionMemNameFormat = 's_opcodeMemory_%%0%dX' % instructionNameIndexWidth;
183
  (combined,port,packing) = config.GetPacking('INSTRUCTION');
184
  instruction_mem_width = combined['memWidth'];
185
  for ixBlock in range(instructionMemory['nBlocks']):
186
    if instructionMemory['nBlocks'] == 1:
187
      memName = 's_opcodeMemory';
188
    else:
189
      memName = instructionMemNameFormat % ixBlock;
190
    fp.write('reg [%d:0] %s[%d:0];\n' % (instruction_mem_width-1,memName,instructionMemory['blockSize']-1,));
191
  # Declare data stack RAM and return stacks RAM if they aren't combined into other memories.
192
  for memType in ('DATA_STACK','RETURN_STACK',):
193
    (combined,port,packing) = config.GetPacking(memType);
194
    if combined['port'][0]['packing'][0]['name'] != memType:
195
      continue;
196
    fp.write('reg [%d:0] %s[%d:0];\n' % (combined['memWidth']-1,combined['memName'],combined['nWords']-1,));
197
  # Declare the memories.
198
  for combined in combines:
199
    if combined['mems'][0] in ('INSTRUCTION','DATA_STACK','RETURN_STACK',):
200
      continue;
201
    fp.write('reg [%d:0] %s[%d:0];\n' % (combined['memWidth']-1,combined['memName'],combined['nWords']-1,));
202
  # Vertical separation between declarations and first initialization.
203
  fp.write('\n');
204
  # Initialize the instruction memory.
205
  (combined,port,packing) = config.GetPacking('INSTRUCTION');
206
  fp.write('initial begin\n');
207
  ixRecordedBody = 0;
208
  nbits = combined['memWidth'];
209
  ixInstruction = 0;
210
  instructionBodyLength = packing['length'];
211
  for ixBlock in range(instructionMemory['nBlocks']):
212
    if instructionMemory['nBlocks'] == 1:
213
      memName = 's_opcodeMemory';
214
    else:
215
      memName = instructionMemNameFormat % ixBlock;
216
    if nbits == 9:
217
      formatp = '  %s[\'h%%0%dX] = { 1\'b1, %%s };' % (memName,instructionAddrWidth,);
218
      formatn = '  %s[\'h%%0%dX] = 9\'h%%s; // %%s\n' % (memName,instructionAddrWidth,);
219
      formate = '  %s[\'h%%0%dX] = 9\'h000;\n' % (memName,instructionAddrWidth,);
220
    else:
221
      formatp = '  %s[\'h%%0%dX] = { %d\'d0, 1\'b1, %%s };' % (memName,instructionAddrWidth,nbits-9,);
222
      formatn = '  %s[\'h%%0%dX] = { %d\'d0, 9\'h%%s }; // %%s\n' % (memName,instructionAddrWidth,nbits-9,);
223
      formate = '  %s[\'h%%0%dX] = { %d\'d0, 9\'h000 };\n' % (memName,instructionAddrWidth,nbits-9,);
224
    for ixMem in range(instructionMemory['blockSize']):
225
      memAddr = instructionMemory['blockSize']*ixBlock+ixMem;
226
      if ixRecordedBody < len(programBody):
227
        for ixRecordedBody in range(ixRecordedBody,len(programBody)):
228
          if programBody[ixRecordedBody][0] == '-':
229
            fp.write('  // %s\n' % programBody[ixRecordedBody][2:]);
230
          else:
231
            if programBody[ixRecordedBody][0] == 'p':
232
              (parameterString,parameterComment) = re.findall(r'(\S+)(.*)$',programBody[ixRecordedBody][2:])[0];
233
              fp.write(formatp % (ixMem,parameterString,));
234
              fpMemFile.write('@%04X %03X\n' % (memAddr,0x100 + config.GetParameterValue(parameterString)));
235
              if len(parameterComment) > 0:
236
                fp.write(' // %s' % parameterComment[1:]);
237
              fp.write('\n');
238
            else:
239
              fp.write(formatn % (ixMem,programBody[ixRecordedBody][0:3],programBody[ixRecordedBody][4:]));
240
              fpMemFile.write('@%04X %s\n' % (memAddr,programBody[ixRecordedBody][0:3],));
241
            break;
242
        ixRecordedBody = ixRecordedBody + 1;
243
      elif ixInstruction < instructionBodyLength:
244
        fp.write(formate % ixMem);
245
        fpMemFile.write('@%04X 000\n' % memAddr);
246
      else:
247
        break;
248
      ixInstruction = ixInstruction + 1;
249
    # Save the last memory name for memories combined at the end of the instruction memory.
250
    combined['memName'] = memName;
251
  if len(combined['port']) > 1:
252
    offset0 = instructionMemory['blockSize']*(instructionMemory['nBlocks']-1);
253
    combined['port'][1]['offset'] -= offset0;
254
    genMemories_init(fp,config,combined,fpMemFile=fpMemFile,memName=memName,memLength=instructionMemory['blockSize']);
255
  fp.write('end\n\n');
256
  # Initialize the data stack.
257
  for combined in [thisCombined for thisCombined in combines if thisCombined['port'][0]['packing'][0]['name'] == 'DATA_STACK']:
258
    fp.write('initial begin\n');
259
    genMemories_init(fp,config,combined);
260
    fp.write('end\n\n');
261
    break;
262
  # Initialize the return stack.
263
  for combined in [thisCombined for thisCombined in combines if thisCombined['port'][0]['packing'][0]['name'] == 'RETURN_STACK']:
264
    fp.write('initial begin\n');
265
    genMemories_init(fp,config,combined);
266
    fp.write('end\n\n');
267
    break;
268
  # Initialize the memories
269
  for combined in [thisCombined for thisCombined in combines if thisCombined['port'][0]['packing'][0]['name'] not in ('INSTRUCTION','DATA_STACK','RETURN_STACK',)]:
270
    fp.write('initial begin\n');
271
    genMemories_init(fp,config,combined);
272
    fp.write('end\n\n');
273
  # Generate the opcode read logic.
274
  fp.write('//\n');
275
  fp.write('// opcode read logic\n');
276
  fp.write('//\n');
277
  fp.write('\n');
278
  fp.write('initial s_opcode = 9\'h000;\n');
279
  if instruction_mem_width == 10:
280
    fp.write('reg not_used_s_opcode = 1\'b0;\n');
281
  elif instruction_mem_width > 10:
282
    fp.write('reg [%d:0] not_used_s_opcode = %d\'d0;\n' % (instruction_mem_width-10,instruction_mem_width-9,));
283
  fp.write('always @ (posedge i_clk)\n');
284
  fp.write('  if (i_rst) begin\n');
285
  fp.write('    s_opcode <= 9\'h000;\n');
286
  if instruction_mem_width > 9:
287
    fp.write('    not_used_s_opcode <= %d\'d0;\n' % (instruction_mem_width-9,));
288
  if instruction_mem_width == 9:
289
    instructionReadTarget = 's_opcode';
290
  else:
291
    instructionReadTarget = '{ not_used_s_opcode, s_opcode }';
292
  if instructionMemory['nBlocks'] == 1:
293
    fp.write('  end else\n');
294
    fp.write('    %s <= s_opcodeMemory[s_PC];\n' % instructionReadTarget);
295
  else:
296
    fp.write('  end else case (s_PC[%d+:%d])\n' % (instructionMemory['nbits_blockSize'],instructionMemory['nbits_nBlocks'],));
297
    for ixBlock in range(instructionMemory['nBlocks']):
298
      memName = instructionMemNameFormat % ixBlock;
299
      thisLine = '%d\'h%X : %s <= %s[s_PC[0+:%d]];\n' % (instructionMemory['nbits_nBlocks'],ixBlock,instructionReadTarget,memName,instructionMemory['nbits_blockSize'],);
300
      while thisLine.index(':') < 12:
301
        thisLine = ' ' + thisLine;
302
      fp.write(thisLine);
303
    fp.write('    default : %s <= %d\'h000;\n' % (instructionReadTarget,instruction_mem_width,));
304
    fp.write('  endcase\n');
305
  fp.write('\n');
306
  #
307
  # Generate the data_stack read and write logic.
308
  #
309
  fp.write('//\n// data stack read and write logic\n//\n\n');
310
  (combined,port,packing) = config.GetPacking('DATA_STACK');
311
  genMemories_stack(fp,combined,port,packing,'s_N','s_Np','s_stack == C_STACK_INC');
312
  #
313
  # Generate the return_stack read and write logic.
314
  #
315
  fp.write('//\n// return stack read and write logic\n//\n\n');
316
  (combined,port,packing) = config.GetPacking('RETURN_STACK');
317
  genMemories_stack(fp,combined,port,packing,'s_R_pre','s_R','s_return == C_RETURN_INC');
318
  #
319
  # Coalesce the memory bank indices and the corresponding memory names, offsets, lengths, etc.
320
  #
321
  lclMemName = [];
322
  lclMemParam = [];
323
  for ixBank in range(4):
324
    memParam = config.GetMemoryByBank(ixBank);
325
    if not memParam:
326
      continue;
327
    lclMemName.append(memParam['name']);
328
    lclMemParam.append(dict(bank=memParam['bank'],type=memParam['type']));
329
  for combined in combines:
330
    for port in combined['port']:
331
      if port['packing'][0]['name'] in ('INSTRUCTION','DATA_STACK','RETURN_STACK',):
332
        continue;
333
      for packing in port['packing']:
334
        if packing['name'] not in lclMemName:
335
          print 'WARNING:  Memory "%s" not used in program' % packing['name'];
336
          continue;
337
        ixLclMem = lclMemName.index(packing['name']);
338
        thisLclMemParam = lclMemParam[ixLclMem];
339
        thisLclMemParam['combined'] = combined;
340
        thisLclMemParam['port'] = port;
341
        thisLclMemParam['packing'] = packing;
342
  # Generate the memory read/write logic.
343
  if config.NMemories() == 0:
344
    fp.write('// no memories\n\n');
345
  else:
346
    # Compute the address string / address string format for each RAM/ROM port.
347
    for combined in combines:
348
      for port in combined['port']:
349
        addrWidth = CeilLog2(port['nWords'])-CeilLog2(port['ratio']);
350
        addrString = '';
351
        if len(combined['port']) > 1:
352
          addrString = '{' + addrString;
353
          nMajorAddressBits = CeilLog2(combined['nWords']) - CeilLog2(port['nWords']);
354
          addrString += '%d\'h%x,' % (nMajorAddressBits,port['offset']/port['nWords'],);
355
        addrString += 's_T[%d:0]' % (addrWidth-1,);
356
        if port['ratio'] > 1:
357
          if '{' not in addrString:
358
            addrString = '{' + addrString;
359
          addrString += ',%d\'d%%d' % (CeilLog2(port['ratio']),);
360
        if '{' in addrString:
361
          addrString += '}';
362
        port['addrString'] = addrString;
363
    # Generate the memory read logic.
364
    fp.write('//\n// memory read logic\n//\n\n');
365
    for combined in combines:
366
      if combined['memArch'] != 'sync':
367
        continue;
368
      memName = combined['memName'];
369
      memWidth = combined['memWidth'];
370
      for port in combined['port']:
371
        if port['packing'][0]['name'] in ('INSTRUCTION','DATA_STACK','RETURN_STACK',):
372
          continue;
373
        addrString = port['addrString'];
374
        totalWidth = memWidth * port['ratio'];
375
        if combined['memArch'] == 'sync':
376
          fp.write('reg [%d:0] %s_reg = %d\'h0;\n' % (totalWidth-1,memName,totalWidth,));
377
        if port['ratio'] == 1:
378
          fp.write('always @ (%s[%s])\n' % (memName,addrString,));
379
          fp.write('  %s_reg = %s[%s];\n' % (memName,memName,addrString,));
380
        else:
381
          fp.write('always @ (');
382
          for ratio in range(port['ratio']):
383
            if ratio != 0:
384
              fp.write(',');
385
            fp.write('%s[%s]' % (memName,(addrString % ratio),));
386
          fp.write(') begin\n');
387
          for ratio in range(port['ratio']):
388
            fp.write('  %s_reg[%d+:%d] = %s[%s];\n' % (memName,ratio*memWidth,memWidth,memName,(addrString % ratio),));
389
          fp.write('end\n');
390
    for ixLclMemParam in range(len(lclMemParam)):
391
      thisLclMemParam = lclMemParam[ixLclMemParam];
392
      combined = thisLclMemParam['combined'];
393
      if ixLclMemParam == 0:
394
        fp.write('assign s_memory = ');
395
      else:
396
        fp.write('                : ');
397
      fp.write('(s_opcode[0+:2] == 2\'d%d) ? ' % thisLclMemParam['bank']);
398
      if combined['memArch'] == 'LUT':
399
        fp.write('%s[%s]\n' % (combined['memName'],thisLclMemParam['port']['addrString'],));
400
      else:
401
        fp.write('%s_reg[%d+:8]\n' % (combined['memName'],combined['memWidth']*thisLclMemParam['packing']['lane'],));
402
    fp.write('                : 8\'d0;\n');
403
    fp.write('\n');
404
    # Generate the memory write logic.
405
    fp.write('//\n// memory write logic\n//\n\n');
406
    for combined in combines:
407
      for port in combined['port']:
408
        if port['packing'][0]['name'] in ('INSTRUCTION','DATA_STACK','RETURN_STACK',):
409
          continue;
410
        thisRams = [];
411
        for packing in port['packing']:
412
          memParam = config.GetMemoryByName(packing['name']);
413
          if not memParam:
414
            continue;
415
          if memParam['type'] != 'RAM':
416
            continue;
417
          thisRams.append({ 'memParam':memParam, 'packing':packing });
418
        if not thisRams:
419
          continue;
420
        fp.write('always @ (posedge i_clk) begin\n');
421
        for ram in thisRams:
422
          memParam = ram['memParam'];
423
          packing = ram['packing'];
424
          if combined['memArch'] == 'LUT':
425
            fp.write('  if (s_mem_wr && (s_opcode[0+:2] == 2\'d%d))\n' % memParam['bank']);
426
            fp.write('    %s[%s] <= s_N; // memory %s\n' % (combined['memName'],port['addrString'],packing['name'],));
427
          else:
428
            addrString = port['addrString'];
429
            if '%' in addrString:
430
              addrString = addrString % packing['lane'];
431
            fp.write('  if (s_mem_wr && (s_opcode[0+:2] == 2\'d%d))\n' % memParam['bank']);
432
            if combined['memWidth'] == 8:
433
              source = 's_N';
434
            else:
435
              source = '{ %d\'d0, s_N }' % (combined['memWidth']-8);
436
            fp.write('    %s[%s] <= %s; // memory %s\n' % (combined['memName'],addrString,source,packing['name'],));
437
        fp.write('end\n\n');
438
 
439
def genMemories_assign(fp,mode,combined,port,packing,addr,sigName):
440
  """
441
  Utility function for genMemories.\n
442
  Generate the logic to perform memory writes, including writes to multiple
443
  memory locations (for the return stack) and writing zeros to otherwise unused
444
  bits.
445
  """
446
  if mode not in ['write','read']:
447
    raise Exception('Program Bug: %s' % mode);
448
  memName = combined['memName'];
449
  memWidth = combined['memWidth'];
450
  ratio = packing['ratio']
451
  sigWidth = packing['nbits'];
452
  nbitsRatio = CeilLog2(ratio);
453
  notUsedWidth = ratio*memWidth - sigWidth;
454
  isLUT = (combined['memArch'] == 'LUT');
455
  if not isLUT and port['nWords'] != combined['nWords']:
456
    memAddrWidth = CeilLog2(combined['nWords']);
457
    thisAddrWidth = CeilLog2(packing['nWords']);
458
    nbitsOffset = memAddrWidth - thisAddrWidth;
459
    addr = '{%d\'h%%0%dx,%s}' % (nbitsOffset,(nbitsOffset+3)/4,addr,) % (port['offset']/2**thisAddrWidth,);
460
  for ixRatio in range(ratio):
461
    ix0 = ixRatio*memWidth;
462
    ix1 = ix0+memWidth;
463
    if ratio == 1:
464
      thisAddr = addr;
465
    else:
466
      thisAddr = '%s, %d\'h%%0%dx' % (addr,nbitsRatio,(nbitsRatio+3)/4,) % ixRatio;
467
    if thisAddr.find(',') != -1:
468
      thisAddr = '{ %s }' % thisAddr;
469
    if ix1 <= sigWidth:
470
      thisSignal = '%s[%d:%d]' % (sigName,ix1-1,ix0,);
471
    elif ix0 <= sigWidth:
472
      nEmpty = ix1-sigWidth;
473
      if mode == 'write':
474
        thisSignal = '{ %d\'d0, %s[%d:%d] }' % (nEmpty,sigName,sigWidth-1,ix0,);
475
      elif notUsedWidth == 1:
476
        thisSignal = '{ not_used_%s, %s[%d:%d] }' % (sigName,sigName,sigWidth-1,ix0,);
477
      else:
478
        thisSignal = '{ not_used_%s[%d:0], %s[%d:%d] }' % (sigName,ix1-sigWidth-1,sigName,sigWidth-1,ix0,);
479
    else:
480
      if mode == 'write':
481
        thisSignal = '%d\'0' % memWidth;
482
      else:
483
        thisSignal = 'not_used_%s[%d:%d]' % (sigName,ix1-sigWidth-1,ix0-sigWidth,);
484
    if mode == 'write' and isLUT:
485
      fp.write('    %s[%s] <= %s;\n' % (memName,thisAddr,thisSignal,));
486
    elif mode == 'write' and not isLUT:
487
      fp.write('    %s[%s] = %s; // coerce write-through\n' % (memName,thisAddr,thisSignal,));
488
    elif mode == 'read' and not isLUT:
489
      fp.write('  %s <= %s[%s];\n' % (thisSignal,memName,thisAddr,));
490
    elif mode == 'read' and isLUT:
491
      fp.write('always @ (%s[%s],%s)\n' % (memName,thisAddr,thisAddr,));
492
      fp.write('  %s = %s[%s];\n' % (thisSignal,memName,thisAddr,));
493
 
494
def genMemories_init(fp,config,combined,fpMemFile=None,memName=None,memLength=None):
495
  """
496
  Utility function for genMemories.\n
497
  Generate the logic to initialize memories based on the memory width and the
498
  initialization output from the assembler.
499
  """
500
  if not memName:
501
    memName = combined['memName'];
502
  if not memLength:
503
    memLength = combined['nWords'];
504
  memWidth = combined['memWidth'];
505
  # Compute the formatting for the initialization values
506
  nAddrBits = CeilLog2(memLength);
507
  if memWidth == 8:
508
    formatd = '%s[\'h%%0%dX] = 8\'h%%s;' % (memName,(nAddrBits+3)/4,);
509
  else:
510
    formatd = '%s[\'h%%0%dX] = { %d\'d0, 8\'h%%s };' % (memName,(nAddrBits+3)/4,memWidth-8,);
511
  formate = '%s[\'h%%0%dX] = %d\'h%s;' % (memName,(nAddrBits+3)/4,memWidth,'0'*((memWidth+3)/4),);
512
  # Create the list of initialization statements.
513
  for port in combined['port']:
514
    fills = list();
515
    values = list();
516
    if port['packing'][0]['name'] == 'INSTRUCTION':
517
      continue;
518
    for packing in port['packing']:
519
      thisMemName = packing['name'];
520
      if thisMemName in ('DATA_STACK','RETURN_STACK',):
521
        for thisRatio in range(port['ratio']):
522
          thisFill = list();
523
          fills.append(thisFill);
524
          thisValue = list();
525
          values.append(thisValue);
526
          curOffset = 0;
527
          while curOffset < port['packing'][0]['length']:
528
            addr = port['offset']+port['ratio']*curOffset+packing['lane']+thisRatio;
529
            thisFill.append({ 'assign':(formate % addr) });
530
            thisValue.append('0');
531
            curOffset += 1;
532
      else:
533
        memParam = config.GetMemoryByName(thisMemName);
534
        if not memParam:
535
          raise Exception('Program bug -- memory "%s" not found' % thisMemName);
536
        thisFill = list();
537
        fills.append(thisFill);
538
        thisValue = list();
539
        values.append(thisValue);
540
        curOffset = 0;
541
        if memParam['body'] != None:
542
          for line in memParam['body']:
543
            if line[0] == '-':
544
              varName = line[2:-1];
545
              continue;
546
            addr = port['offset']+port['ratio']*curOffset+packing['lane'];
547
            thisFill.append({ 'assign':(formatd % (addr,line[0:2],)) });
548
            thisFill[-1]['comment'] = varName if varName else '.';
549
            thisValue.append(line[0:2]);
550
            varName = None;
551
            curOffset += 1;
552
      if (curOffset > packing['nWords']):
553
        raise Exception('Program Bug -- memory body longer than allocated memory space');
554
      while curOffset < packing['length']:
555
        addr = port['ratio']*curOffset+port['offset'];
556
        thisFill.append({ 'assign':(formate % addr) });
557
        thisValue.append('0');
558
        curOffset += 1;
559
    endLength = port['nWords']/port['ratio'];
560
    for ixFill in range(len(fills)):
561
      thisFill = fills[ixFill];
562
      thisValue = values[ixFill];
563
      curOffset = len(thisFill);
564
      if curOffset < endLength:
565
        addr = port['ratio']*curOffset+port['offset']+ixFill;
566
        thisFill.append({ 'assign':(formate % addr), 'comment':'***' });
567
        thisValue.append('0');
568
        curOffset += 1;
569
        while curOffset < endLength:
570
          addr = port['ratio']*curOffset+port['offset']+ixFill;
571
          thisFill.append({ 'assign':(formate % addr) });
572
          thisValue.append('0');
573
          curOffset += 1;
574
    for thisFill in fills:
575
      commentLengths = [len(entry['comment']) for entry in thisFill if 'comment' in entry];
576
      if not commentLengths:
577
        formatc = '%s';
578
      elif len(fills) == 1:
579
        formatc = '%s // %s';
580
      else:
581
        formatc = '%%s /* %%-%ds */' % max(commentLengths);
582
      for entry in thisFill:
583
        if 'comment' in entry:
584
          entry['output'] = formatc % (entry['assign'],entry['comment'],);
585
        elif commentLengths:
586
          entry['output'] = formatc % (entry['assign'],'',);
587
        else:
588
          entry['output'] = entry['assign'];
589
    lens = [len(thisFill) for thisFill in fills];
590
    if min(lens) < max(lens):
591
      raise Exception('Program Bug -- unequal fill lengths');
592
    formatLine = ' ';
593
    for thisFill in fills:
594
      formatLine += ' %%-%ds' % len(thisFill[0]['output']);
595
    formatLine += '\n';
596
    names = [packing['name'] for packing in port['packing']];
597
    while len(names) < len(fills):
598
      names.append('');
599
    names[0] = '// '+names[0];
600
    fp.write(formatLine % tuple(names));
601
    for ixFill in range(lens[0]):
602
      fp.write(formatLine % tuple([thisFill[ixFill]['output'] for thisFill in fills]));
603
    if fpMemFile:
604
      for port in combined['port']:
605
        if port['packing'][0]['name'] != 'INSTRUCTION':
606
          break;
607
      else:
608
        raise Exception('Program Bug:  Should have had a start address here.');
609
      addr = port['offset'];
610
      for ixFill in range(lens[0]):
611
        for ixCol in range(len(lens)):
612
          fpMemFile.write('@%04X %03X\n' % (addr,values[ixCol][ixFill],));
613
          addr += 1;
614
 
615
def genMemories_stack(fp,combined,port,packing,inSignalName,outSignalName,muxTest):
616
  nbits = packing['nbits'];                             # number of bits in the signal
617
  totalWidth = packing['ratio'] * combined['memWidth']; # width of the [multi-]word memory access
618
  # Generate the core.
619
  if combined['memArch'] == 'sync':
620
    fp.write('reg [%d:0] %s_reg = %d\'d0;\n' % (nbits-1,outSignalName,nbits,));
621
  if totalWidth == nbits+1:
622
    fp.write('reg not_used_%s_reg = 1\'b0;\n' % outSignalName);
623
  elif totalWidth > nbits+1:
624
    fp.write('reg [%d:0] not_used_%s_reg = %d\'d0;\n' % (totalWidth-nbits-1,outSignalName,totalWidth-nbits,));
625
  fp.write('always @ (posedge i_clk) begin\n');
626
  fp.write('  if (%s) begin\n' % muxTest);
627
  genMemories_assign(fp,'write',combined,port,packing,outSignalName+'_stack_ptr_next',inSignalName);
628
  fp.write('  end\n');
629
  if combined['memArch'] == 'sync':
630
    genMemories_assign(fp,'read',combined,port,packing,outSignalName+'_stack_ptr_next',outSignalName+'_reg');
631
  fp.write('end\n');
632
  if combined['memArch'] == 'LUT':
633
    if totalWidth == nbits+1:
634
      fp.write('wire not_used_%s_reg;\n' % outSignalName);
635
    elif totalWidth > nbits+1:
636
      fp.write('wire [%d:0] not_used_%s_reg;\n' % (totalWidth-nbits-1,outSignalName,));
637
    genMemories_assign(fp,'read',combined,port,packing,outSignalName+'_stack_ptr',outSignalName);
638
  else:
639
    fp.write('initial %s = %d\'d0;\n' % (outSignalName,nbits,));
640
    fp.write('always @ (%s_reg)\n' % outSignalName);
641
    fp.write('  %s = %s_reg;\n' % (outSignalName,outSignalName,));
642
  fp.write('\n');
643
 
644
def genModule(fp,config):
645
  """
646
  Generate the body of the module declaration and the parameter and localparam
647
  declarations.
648
  """
649
  # Insert the always-there stuff at the start of the module.
650
  config.ios.insert(0,('synchronous reset and processor clock',None,'comment',));
651
  if config.Get('invertReset'):
652
    config.ios.insert(1,('i_rstn',1,'input',));
653
  else:
654
    config.ios.insert(1,('i_rst',1,'input',));
655
  config.ios.insert(2,('i_clk',1,'input',));
656
  # Starting from the end, determine the termination character for each line of
657
  # the module declaration
658
  signalFound = False;
659
  for ix in range(len(config.ios),0,-1):
660
    thisIOs = config.ios[ix-1];
661
    signalType = thisIOs[2];
662
    if signalType == 'comment' or not signalFound:
663
      thisIOs = thisIOs + ('\n',);
664
    else:
665
      thisIOs = thisIOs + (',\n',);
666
    if signalType != 'comment':
667
      signalFound = True;
668
    config.ios[ix-1] = thisIOs;
669
  # Write the module declaration.
670
  fp.write('module %s(\n' % config.Get('outCoreName'));
671
  if config.ios:
672
    for ix in range(len(config.ios)):
673
      signal = config.ios[ix];
674
      signalName = signal[0];
675
      signalWidth = signal[1];
676
      signalType = signal[2];
677
      signalLineEnd = signal[3];
678
      if signalType == 'comment':
679
        fp.write('  // %s' % signalName);
680
      elif signalType == 'input':
681
        if signalWidth == 1:
682
          fp.write('  input  wire           %s' % signalName);
683
        elif signalWidth <= 10:
684
          fp.write('  input  wire     [%d:0] %s' % (signalWidth-1,signalName));
685
        else:
686
          fp.write('  input  wire    [%2d:0] %s' % (signalWidth-1,signalName));
687
      elif signalType == 'output':
688
        if signalWidth == 1:
689
          fp.write('  output reg            %s' % signalName);
690
        elif signalWidth <= 10:
691
          fp.write('  output reg      [%d:0] %s' % (signalWidth-1,signalName));
692
        else:
693
          fp.write('  output reg     [%2d:0] %s' % (signalWidth-1,signalName));
694
      elif signalType == 'inout':
695
        if signalWidth == 1:
696
          fp.write('  inout  wire           %s' % signalName);
697
        elif signalWidth <= 10:
698
          fp.write('  inout  wire     [%d:0] %s' % (signalWidth-1,signalName));
699
        else:
700
          fp.write('  inout  wire    [%2d:0] %s' % (signalWidth-1,signalName));
701
      else:
702
        raise Exception('Program Bug -- unrecognized ios "%s"' % signalType);
703
      fp.write(signalLineEnd);
704
  fp.write(');\n');
705
  # Write parameter and localparam statements (with separating blank lines).
706
  if config.parameters:
707
    isfirst = True;
708
    for parameter in config.parameters:
709
      if parameter[0][0] == 'G':
710
        if isfirst:
711
          fp.write('\n');
712
          isfirst = False;
713
        fp.write('parameter %s = %s;\n' % (parameter[0],parameter[1]));
714
    isfirst = True;
715
    for parameter in config.parameters:
716
      if parameter[0][0] == 'L':
717
        if isfirst:
718
          fp.write('\n');
719
          isfirst = False;
720
        fp.write('localparam %s = %s;\n' % (parameter[0],parameter[1]));
721
  # If an inverted reset is supplied, invert it.
722
  if config.Get('invertReset'):
723
    fp.write('\n');
724
    fp.write('// Invert received active-low reset\n');
725
    fp.write('wire i_rst = ~i_rstn;\n');
726
 
727
def genOutports(fp,config):
728
  """
729
  Generate the logic for the output signals.\n
730
  Note:  Empty bodies are allowed for inport and outports (see for example
731
         big_outport generates the composite output signal instead of using the
732
         code that would have been auto-generated here).
733
  """
734
  if not config.outports:
735
    fp.write('// no output ports\n');
736
    return;
737
  for ix in range(config.NOutports()):
738
    thisPort = config.outports[ix][2:];
739
    if not thisPort:
740
      continue;
741
    bitWidth = 0;
742
    bitName = '';
743
    bitInit = '';
744
    for jx in range(len(thisPort)):
745
      signal = thisPort[jx];
746
      signalName = signal[0];
747
      signalWidth = signal[1];
748
      signalType = signal[2];
749
      signalInit = '%d\'d0' % signalWidth if len(signal)==3 else signal[3];
750
      if signalType == 'data':
751
        if bitWidth > 0:
752
          bitName += ', ';
753
          bitInit += ', '
754
        bitWidth = bitWidth + signalWidth;
755
        bitName += signalName;
756
        bitInit += signalInit;
757
    if bitWidth > 0:
758
      if ',' in bitName:
759
        bitName = '{ ' + bitName + ' }';
760
        bitInit = '{ ' + bitInit + ' }';
761
      fp.write('always @ (posedge i_clk)\n');
762
      fp.write('  if (i_rst)\n');
763
      fp.write('    %s <= %s;\n' % (bitName,bitInit,));
764
      fp.write('  else if (s_outport && (s_T == 8\'h%02X))\n' % ix);
765
      fp.write('    %s <= s_N[0+:%d];\n' % (bitName,bitWidth));
766
      fp.write('  else\n');
767
      fp.write('    %s <= %s;\n' % (bitName,bitName));
768
      fp.write('\n');
769
    for jx in range(len(thisPort)):
770
      signal = thisPort[jx];
771
      signalName = signal[0];
772
      signalType = signal[2];
773
      if signalType == 'data':
774
        pass;
775
      elif signalType == 'strobe':
776
        fp.write('always @ (posedge i_clk)\n');
777
        fp.write('  if (i_rst)\n');
778
        fp.write('    %s <= 1\'b0;\n' % signalName);
779
        fp.write('  else if (s_outport)\n');
780
        fp.write('    %s <= (s_T == 8\'h%02X);\n' % (signalName,ix));
781
        fp.write('  else\n');
782
        fp.write('    %s <= 1\'b0;\n' % signalName);
783
        fp.write('\n');
784
      else:
785
        raise Exception('Program Bug -- unrecognized signal type "%s"' % signalType);
786
 
787
def genSignals(fp,config):
788
  """
789
  Insert the definitions of additional signals for the module.\n
790
  These can be signals required communications between the core and peripherals.
791
  """
792
  if not config.signals:
793
    fp.write('// no additional signals\n');
794
    return;
795
  maxLength = 0;
796
  for ix in range(len(config.signals)):
797
    thisSignal = config.signals[ix];
798
    signalName = thisSignal[0];
799
    if len(signalName) > maxLength:
800
      maxLength = len(signalName);
801
  maxLength = maxLength + 12;
802
  for ix in range(len(config.signals)):
803
    thisSignal = config.signals[ix];
804
    signalName = thisSignal[0];
805
    signalWidth = thisSignal[1];
806
    signalInit = "%d'd0" % signalWidth if len(thisSignal) < 3 else thisSignal[2];
807
    outString = 'reg ';
808
    if signalWidth == 1:
809
      outString += '       ';
810
    elif signalWidth <= 10:
811
      outString += (' [%d:0] ' % (signalWidth-1));
812
    else:
813
      outString += ('[%2d:0] ' % (signalWidth-1));
814
    outString += signalName;
815
    if signalInit != None:
816
      outString += ' '*(maxLength-len(outString));
817
      outString += ' = ' + signalInit;
818
    outString += ';\n'
819
    fp.write(outString);
820
 
821
def genUserHeader(fp,user_header):
822
  """
823
  Copy the user header to the output module.
824
  """
825
  for ix in range(len(user_header)):
826
    fp.write('// %s\n' % user_header[ix]);

powered by: WebSVN 2.1.0

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