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

Subversion Repositories ssbcc

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

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