Line 1... |
Line 1... |
################################################################################
|
################################################################################
|
#
|
#
|
# Copyright 2012, Sinclair R.F., Inc.
|
# Copyright 2012-2015, Sinclair R.F., Inc.
|
#
|
#
|
# Verilog generation functions.
|
# Verilog generation functions.
|
#
|
#
|
################################################################################
|
################################################################################
|
|
|
Line 17... |
Line 17... |
#
|
#
|
# Generate input and output core names.
|
# Generate input and output core names.
|
#
|
#
|
################################################################################
|
################################################################################
|
|
|
|
def doFillCommand(fillCommand,fpOutCore,config):
|
|
"""
|
|
Do core-specific fill commands for the "..@SSBCC@ <fillCommand>" lines.
|
|
"""
|
|
# functions and tasks
|
|
if fillCommand == "functions":
|
|
genFunctions(fpOutCore,config);
|
|
# inports
|
|
elif fillCommand == 'inports':
|
|
genInports(fpOutCore,config);
|
|
# interrupt conditionals
|
|
elif fillCommand == 'interrupt__s_math_rotate':
|
|
if config.InterruptVector():
|
|
fpOutCore.write(""" if (s_interrupt || s_interrupted)
|
|
s_math_rotate = s_T;
|
|
else""");
|
|
elif fillCommand == 'interrupt__s_opcode':
|
|
if config.InterruptVector():
|
|
fpOutCore.write(""" if (s_interrupted) begin
|
|
// nop
|
|
end else if (s_interrupt) begin
|
|
s_return = C_RETURN_INC;
|
|
end else""");
|
|
# localparam
|
|
elif fillCommand == 'localparam':
|
|
genLocalParam(fpOutCore,config);
|
|
# module
|
|
elif fillCommand == 'module':
|
|
genModule(fpOutCore,config);
|
|
# outports
|
|
elif fillCommand == 'outports':
|
|
genOutports(fpOutCore,config);
|
|
# "s_PC_next" body
|
|
elif fillCommand == 's_PC_next':
|
|
genSPCnext(fpOutCore,config);
|
|
# "s_R_pre" body
|
|
elif fillCommand == 's_R_pre':
|
|
genSRpre(fpOutCore,config);
|
|
# additional signals
|
|
elif fillCommand == 'signals':
|
|
genSignals(fpOutCore,config);
|
|
# error
|
|
else:
|
|
print 'WARNING: Unimplemented command ' + fillCommand;
|
|
|
def genCoreName():
|
def genCoreName():
|
"""
|
"""
|
Return the name of the file to use for the processor core.
|
Return the name of the file to use for the processor core.
|
"""
|
"""
|
return 'core.v';
|
return 'core.v';
|
Line 48... |
Line 93... |
on the ssbcc command line
|
on the ssbcc command line
|
display_opcode human-readable version of the opcode suitable for
|
display_opcode human-readable version of the opcode suitable for
|
waveform viewers
|
waveform viewers
|
display_trace when the trace or monitor_stack peripherals are included
|
display_trace when the trace or monitor_stack peripherals are included
|
"""
|
"""
|
|
def DisableInterrupt(body):
|
|
for replace in ('s_interrupt','s_interrupted',):
|
|
replace = '\(' + replace + '\)';
|
|
while re.search(replace,body):
|
|
body = re.sub(replace,'(1\'b0)',body);
|
|
return body;
|
if 'display_opcode' in config.functions:
|
if 'display_opcode' in config.functions:
|
displayOpcodePath = os.path.join(config.Get('corepath'),'display_opcode.v');
|
displayOpcodePath = os.path.join(config.Get('corepath'),'display_opcode.v');
|
fpDisplayOpcode = open(displayOpcodePath,'rt');
|
fpDisplayOpcode = open(displayOpcodePath,'rt');
|
if not fpDisplayOpcode:
|
if not fpDisplayOpcode:
|
raise Exception('Program Bug -- "%s" not found' % displayOpcodePath);
|
raise Exception('Program Bug -- "%s" not found' % displayOpcodePath);
|
body = fpDisplayOpcode.read();
|
body = fpDisplayOpcode.read();
|
fpDisplayOpcode.close();
|
fpDisplayOpcode.close();
|
|
if not config.InterruptVector():
|
|
body = DisableInterrupt(body);
|
fp.write(body);
|
fp.write(body);
|
if ('clog2' in config.functions) and config.Get('define_clog2'):
|
if ('clog2' in config.functions) and config.Get('define_clog2'):
|
fp.write("""
|
fp.write("""
|
// Use constant function instead of builtin $clog2.
|
// Use constant function instead of builtin $clog2.
|
function integer clog2;
|
function integer clog2;
|
Line 76... |
Line 129... |
fpDisplayTrace = open(displayTracePath,'rt');
|
fpDisplayTrace = open(displayTracePath,'rt');
|
if not fpDisplayTrace:
|
if not fpDisplayTrace:
|
raise Exception('Program Bug -- "%s" not found' % displayTracePath);
|
raise Exception('Program Bug -- "%s" not found' % displayTracePath);
|
body = fpDisplayTrace.read();
|
body = fpDisplayTrace.read();
|
fpDisplayTrace.close();
|
fpDisplayTrace.close();
|
|
if not config.InterruptVector():
|
|
body = DisableInterrupt(body);
|
fp.write(body);
|
fp.write(body);
|
|
|
def genInports(fp,config):
|
def genInports(fp,config):
|
"""
|
"""
|
Generate the logic for the input signals.
|
Generate the logic for the input signals.
|
Line 159... |
Line 214... |
|
|
def genLocalParam(fp,config):
|
def genLocalParam(fp,config):
|
"""
|
"""
|
Generate the localparams for implementation-specific constants.
|
Generate the localparams for implementation-specific constants.
|
"""
|
"""
|
fp.write('localparam C_PC_WIDTH = %4d;\n' % CeilLog2(config.Get('nInstructions')['length']));
|
pcWidth = CeilLog2(config.Get('nInstructions')['length']);
|
|
fp.write('localparam C_PC_WIDTH = %4d;\n' % pcWidth);
|
fp.write('localparam C_RETURN_PTR_WIDTH = %4d;\n' % CeilLog2(config.Get('return_stack')));
|
fp.write('localparam C_RETURN_PTR_WIDTH = %4d;\n' % CeilLog2(config.Get('return_stack')));
|
fp.write('localparam C_DATA_PTR_WIDTH = %4d;\n' % CeilLog2(config.Get('data_stack')));
|
fp.write('localparam C_DATA_PTR_WIDTH = %4d;\n' % CeilLog2(config.Get('data_stack')));
|
fp.write('localparam C_RETURN_WIDTH = (C_PC_WIDTH <= 8) ? 8 : C_PC_WIDTH;\n');
|
fp.write('localparam C_RETURN_WIDTH = (C_PC_WIDTH <= 8) ? 8 : C_PC_WIDTH;\n');
|
|
|
def genMemories(fp,fpMemFile,config,programBody):
|
def genMemories(fp,fpMemFile,config,programBody):
|
Line 748... |
Line 804... |
for jx in range(len(thisPort)):
|
for jx in range(len(thisPort)):
|
signal = thisPort[jx];
|
signal = thisPort[jx];
|
signalName = signal[0];
|
signalName = signal[0];
|
signalWidth = signal[1];
|
signalWidth = signal[1];
|
signalType = signal[2];
|
signalType = signal[2];
|
signalInit = '%d\'d0' % signalWidth if len(signal)==3 else signal[3];
|
signalInit = 0 if len(signal)==3 else signal[3];
|
|
signalInit = InitSignal(signalWidth,signalInit)
|
if signalType == 'data':
|
if signalType == 'data':
|
fp.write('initial %s = %s;\n' % (signalName,signalInit,));
|
fp.write('initial %s = %s;\n' % (signalName,signalInit,));
|
if bitWidth > 0:
|
if bitWidth > 0:
|
bitName += ', ';
|
bitName += ', ';
|
bitInit += ', '
|
bitInit += ', '
|
Line 805... |
Line 862... |
maxLength = len(signalName);
|
maxLength = len(signalName);
|
maxLength = maxLength + 12;
|
maxLength = maxLength + 12;
|
for thisSignal in config.signals:
|
for thisSignal in config.signals:
|
signalName = thisSignal[0];
|
signalName = thisSignal[0];
|
signalWidth = thisSignal[1];
|
signalWidth = thisSignal[1];
|
signalInit = "%d'd0" % signalWidth if len(thisSignal) < 3 else thisSignal[2];
|
signalInit = 0 if len(thisSignal)==2 else thisSignal[2];
|
outString = 'reg ';
|
outString = 'reg ';
|
if signalWidth == 1:
|
if signalWidth == 1:
|
outString += ' ';
|
outString += ' ';
|
elif signalWidth <= 10:
|
elif signalWidth <= 10:
|
outString += (' [%d:0] ' % (signalWidth-1));
|
outString += (' [%d:0] ' % (signalWidth-1));
|
else:
|
else:
|
outString += ('[%2d:0] ' % (signalWidth-1));
|
outString += ('[%2d:0] ' % (signalWidth-1));
|
outString += signalName;
|
outString += signalName;
|
if signalInit != None:
|
if signalInit != None:
|
outString += ' '*(maxLength-len(outString));
|
outString += ' '*(maxLength-len(outString));
|
outString += ' = ' + signalInit;
|
outString += ' = ' + InitSignal(signalWidth,signalInit);
|
outString += ';\n'
|
outString += ';\n'
|
fp.write(outString);
|
fp.write(outString);
|
|
|
|
def genSPCnext(fp,config):
|
|
"""
|
|
Write the logic to generate the next PC address.\n
|
|
Note: This signal depends on whether or not interrupts are enabled.
|
|
"""
|
|
pcWidth = CeilLog2(config.Get('nInstructions')['length']);
|
|
fp.write("reg [C_PC_WIDTH-1:0] s_PC_next;\n");
|
|
fp.write("always @ (*)\n");
|
|
if config.InterruptVector():
|
|
format_pc_addr = "%d\'h%%0%dx" % (pcWidth,(pcWidth+3)/4,);
|
|
fp.write(" if (s_interrupt)\n");
|
|
fp.write(" s_PC_next = %s;\n" % (format_pc_addr % config.InterruptVector()));
|
|
fp.write(" else");
|
|
fp.write(" case (s_bus_pc)\n");
|
|
fp.write(" C_BUS_PC_NORMAL:\n");
|
|
fp.write(" s_PC_next = s_PC_plus1;\n");
|
|
fp.write(" C_BUS_PC_JUMP:\n");
|
|
fp.write(" s_PC_next = s_PC_jump;\n");
|
|
fp.write(" C_BUS_PC_RETURN:\n");
|
|
fp.write(" s_PC_next = s_R[0+:C_PC_WIDTH];\n");
|
|
fp.write(" default:\n");
|
|
fp.write(" s_PC_next = s_PC_plus1;\n");
|
|
fp.write(" endcase\n");
|
|
|
|
def genSRpre(fp,config):
|
|
"""
|
|
Write the logic to select the value to be put onto the return stack.\n
|
|
Note: This also captures the pc value to be put onto the return stack as
|
|
part of interrupt handling.
|
|
"""
|
|
data_width = config.Get('data_width');
|
|
pcWidth = CeilLog2(config.Get('nInstructions')['length']);
|
|
if pcWidth <= data_width:
|
|
assignT = "s_T";
|
|
else:
|
|
assignT = "{ {(C_PC_WIDTH-%d){1'b0}}, s_T }" % data_width;
|
|
if pcWidth < data_width:
|
|
assignPC = "{ {(%d-C_PC_WIDTH){1'b0}}, %%s }" % data_width;
|
|
else:
|
|
assignPC = "%s";
|
|
if config.InterruptVector():
|
|
fp.write("reg [C_RETURN_WIDTH-1:0] s_PC_s = {(C_RETURN_WIDTH){1'b0}};\n");
|
|
fp.write("always @ (posedge i_clk)\n");
|
|
fp.write(" if (i_rst)\n");
|
|
fp.write(" s_PC_s <= {(C_RETURN_WIDTH){1'b0}};\n");
|
|
fp.write(" else\n");
|
|
fp.write(" s_PC_s <= s_PC;\n");
|
|
fp.write("\n");
|
|
fp.write("reg [C_RETURN_WIDTH-1:0] s_R_pre;\n");
|
|
fp.write("always @ (*)\n");
|
|
if config.InterruptVector():
|
|
fp.write(" if (s_interrupt)\n");
|
|
fp.write(" s_R_pre = %s;\n" % (assignPC % "s_PC_s"));
|
|
fp.write(" else");
|
|
fp.write(" case (s_bus_r)\n");
|
|
fp.write(" C_BUS_R_T:\n");
|
|
fp.write(" s_R_pre = %s;\n" % assignT);
|
|
fp.write(" C_BUS_R_PC:\n");
|
|
fp.write(" s_R_pre = %s;\n" % (assignPC % "s_PC_plus1"));
|
|
fp.write(" default:\n");
|
|
fp.write(" s_R_pre = %s;\n" % assignT);
|
|
fp.write(" endcase\n");
|
|
|
def genUserHeader(fp,user_header):
|
def genUserHeader(fp,user_header):
|
"""
|
"""
|
Copy the user header to the output module.
|
Copy the user header to the output module.
|
"""
|
"""
|
for ix in range(len(user_header)):
|
for ix in range(len(user_header)):
|