| 1 |
2 |
sinclairrf |
################################################################################
|
| 2 |
|
|
#
|
| 3 |
6 |
sinclairrf |
# Copyright 2012-2014, Sinclair R.F., Inc.
|
| 4 |
2 |
sinclairrf |
#
|
| 5 |
|
|
################################################################################
|
| 6 |
|
|
|
| 7 |
|
|
import math
|
| 8 |
|
|
import re
|
| 9 |
|
|
|
| 10 |
|
|
from ssbccPeripheral import SSBCCperipheral
|
| 11 |
|
|
from ssbccUtil import SSBCCException;
|
| 12 |
|
|
|
| 13 |
|
|
class monitor_stack(SSBCCperipheral):
|
| 14 |
|
|
"""
|
| 15 |
|
|
Simulation-specific peripheral to flag invalid stack operations and display
|
| 16 |
|
|
the execution history immediately before the invalid operation.\n
|
| 17 |
|
|
Invalid data stack operations are:
|
| 18 |
|
|
pushing onto a full data stack
|
| 19 |
|
|
dropping from an empty data stack
|
| 20 |
|
|
nipping from an almost empty data stack\n
|
| 21 |
|
|
Invalid return stack operations are:
|
| 22 |
|
|
pushing onto a full return stack
|
| 23 |
|
|
dropping values from an empty return stack
|
| 24 |
|
|
returns from a data entry on the return stack
|
| 25 |
|
|
non-return operations from an address entry on the return stack\n
|
| 26 |
|
|
Invalid data operations are:
|
| 27 |
|
|
swap on an empty or almost empty data stack
|
| 28 |
|
|
in-place operations on an empty or almost empty data stack\n
|
| 29 |
|
|
Usage:
|
| 30 |
|
|
PERIPHERAL monitor_stack \\
|
| 31 |
|
|
[history==n]\n
|
| 32 |
|
|
Where:
|
| 33 |
|
|
history=n
|
| 34 |
|
|
display the n most recent operations when a stack error is encountered
|
| 35 |
|
|
Note: Normally the last 50 instructions are displayed.
|
| 36 |
|
|
"""
|
| 37 |
|
|
|
| 38 |
|
|
def __init__(self,peripheralFile,config,param_list,loc):
|
| 39 |
|
|
# Use the externally provided file name for the peripheral
|
| 40 |
|
|
self.peripheralFile = peripheralFile;
|
| 41 |
|
|
# Get the parameters.
|
| 42 |
6 |
sinclairrf |
allowables = (
|
| 43 |
|
|
( 'history', r'[1-9]\d*$', int, ),
|
| 44 |
|
|
);
|
| 45 |
|
|
names = [a[0] for a in allowables];
|
| 46 |
|
|
for param_tuple in param_list:
|
| 47 |
|
|
param = param_tuple[0];
|
| 48 |
|
|
if param not in names:
|
| 49 |
|
|
raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,));
|
| 50 |
|
|
param_test = allowables[names.index(param)];
|
| 51 |
|
|
self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]);
|
| 52 |
2 |
sinclairrf |
# Set optional parameters.
|
| 53 |
|
|
if not hasattr(self,'history'):
|
| 54 |
|
|
self.history = 50;
|
| 55 |
|
|
# Configure the system for this peripheral.
|
| 56 |
|
|
config.functions['display_trace'] = True;
|
| 57 |
|
|
|
| 58 |
|
|
def GenVerilog(self,fp,config):
|
| 59 |
|
|
body = self.LoadCore(self.peripheralFile,'.v');
|
| 60 |
12 |
sinclairrf |
if not config.InterruptVector():
|
| 61 |
|
|
for replace in (r's_interrupt\b',r's_interrupted\b',):
|
| 62 |
|
|
body = re.sub(replace,'1\'b0',body);
|
| 63 |
2 |
sinclairrf |
outport_pure_strobe = '';
|
| 64 |
|
|
for ix in range(config.NOutports()):
|
| 65 |
|
|
thisPort = config.outports[ix][2:];
|
| 66 |
|
|
thisIsStrobe = True;
|
| 67 |
|
|
for jx in range(len(thisPort)):
|
| 68 |
|
|
signal = thisPort[jx];
|
| 69 |
|
|
signalType = signal[2];
|
| 70 |
|
|
if signalType == 'data':
|
| 71 |
|
|
thisIsStrobe = False;
|
| 72 |
|
|
elif signalType == 'strobe':
|
| 73 |
|
|
pass;
|
| 74 |
|
|
else:
|
| 75 |
|
|
raise Exception('Program Bug: Unrecognized outport signal type "%s"' % signalType);
|
| 76 |
|
|
if thisIsStrobe:
|
| 77 |
|
|
if len(outport_pure_strobe) > 0:
|
| 78 |
|
|
outport_pure_strobe += ' || ';
|
| 79 |
|
|
outport_pure_strobe += ('(s_T == 8\'h%02X)' % ix);
|
| 80 |
|
|
if len(outport_pure_strobe) == 0:
|
| 81 |
|
|
outport_pure_strobe = '1\'b0';
|
| 82 |
|
|
outport_pure_strobe = 'wire s__outport_pure_strobe = ' + outport_pure_strobe + ';';
|
| 83 |
6 |
sinclairrf |
for subpair in (
|
| 84 |
|
|
( r'\\bix__', 'ix__monitor_stack__', ),
|
| 85 |
|
|
( r'\\bs__', 's__monitor_stack__', ),
|
| 86 |
|
|
( r'@CORENAME@', config.Get('outCoreName'), ),
|
| 87 |
|
|
( r'@HISTORY@', str(self.history), ),
|
| 88 |
|
|
( r'@LAST_INPORT@', '9\'h%03X' % config.NInports(), ),
|
| 89 |
|
|
( r'@LAST_OUTPORT@', '9\'h%03X' % config.NOutports(), ),
|
| 90 |
|
|
( r'@NINSTRUCTIONS@', str(config.Get('nInstructions')['length']), ),
|
| 91 |
|
|
( r'@OUTPORT_PURE_STROBE@', outport_pure_strobe, ),
|
| 92 |
|
|
):
|
| 93 |
|
|
body = re.sub(subpair[0],subpair[1],body);
|
| 94 |
2 |
sinclairrf |
for ixBank in range(4):
|
| 95 |
|
|
memParam = config.GetMemoryByBank(ixBank);
|
| 96 |
|
|
if memParam:
|
| 97 |
|
|
maxLength = memParam['maxLength'];
|
| 98 |
|
|
else:
|
| 99 |
|
|
maxLength = 0;
|
| 100 |
|
|
body = re.sub('@MEM_LIMIT_%d@' % ixBank, str(maxLength), body);
|
| 101 |
|
|
fp.write(body);
|