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

Subversion Repositories ssbcc

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

Details | Compare with Previous | View Log

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