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

Subversion Repositories ssbcc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 11 to Rev 12
    Reverse comparison

Rev 11 → Rev 12

/ssbcc/trunk/ssbccPeripheral.py
1,11 → 1,10
################################################################################
#
# Copyright 2012-2014, Sinclair R.F., Inc.
#
################################################################################
# Copyright 2012-2015, Sinclair R.F., Inc.
# Base classes and utility function for generating general-purpose and interrupt
# peripherals.
 
import re
 
from ssbccUtil import IntValue
from ssbccUtil import IsIntExpr
from ssbccUtil import IsPosInt
from ssbccUtil import IsPowerOf2
172,6 → 171,11
raise SSBCCException('Cannot be more than %d' % highLimit);
return value;
 
def IntValueMethod(self,value):
"""
"""
return IntValue(value);
 
def RateMethod(self,config,value):
"""
Return the string to evaluate the provided value or ratio of two values.
227,3 → 231,54
if (highLimit != None) and (v > highLimit):
raise SSBCCException('%s must be %s or smaller' % (v,highLimit,));
return v;
 
################################################################################
#
# Base class for interrupt peripherals.
#
################################################################################
 
class SSBCCinterruptPeripheral(SSBCCperipheral):
"""
Base class for interrupt peripherals.
"""
 
instance = None;
 
def __init__(self,config,loc):
"""
Perform tasks common to all interrupt peripherals:
Ensure only one interrupt peripheral is defined.
Declare the O_INTERRUPT_DIS and O_INTERRUPT_ENA output ports.
These are set/reset outports and only require 2 instructions.
These 2-instruction sequences are automatically generated by the ".ena"
and ".dis" macros.
...\n
Note: The "param_list" normally part of a peripheral __init__ method is
missing. First, it isn't required here. Second, that helps ensure
that this class is not instantiated by itself as a peripheral.
"""
# Ensure only one interrupt peripheral gets defined.
if SSBCCinterruptPeripheral.instance:
raise SSBCCException('Interrupt peripheral already defined before line %d' % loc);
SSBCCinterruptPeripheral.instance = self;
# Add the signals required by the interrupt handler.
config.AddSignal('s_interrupt',1,loc);
config.AddSignal('s_interrupted',1,loc);
# Add the outports to disable and enable interrupts.
self.ix_outport_interrupt_dis = config.NOutports();
config.AddOutport(('O_INTERRUPT_DIS',True,),loc);
self.ix_outport_interrupt_ena = config.NOutports();
config.AddOutport(('O_INTERRUPT_ENA',True,),loc);
 
################################################################################
#
# Utilties for interrupt peripherals.
#
################################################################################
 
def InterruptPeripheralAssigned():
"""
Indicate whether or not an interrupt peripheral has been generated.
"""
return True if SSBCCinterruptPeripheral.instance else False;
/ssbcc/trunk/ssbccUtil.py
70,6 → 70,20
v %= 2**bL;
return v;
 
def InitSignal(nBits,v):
"""
Generate an initial value for a Verilog signal.
"""
if v == None:
return None;
elif type(v) == str:
return v;
elif type(v) == int:
format = '%d\'h%%0%dX' % (nBits,int((nBits+3)/4),);
return format % v;
else:
raise Exception('Program Bug: unrecognized signal type "%s"' % type(signalInit))
 
def IntValue(v):
"""
Convert a Verilog format integer into an integer value.
/ssbcc/trunk/todo
22,7 → 22,6
for dual-port memories in slave peripherals (i.e., registers readable by the bus master)
for peripherals such as adders where long chains of outputs and inports would have been required and .store+/- and .fetch+/- would be much more efficient code-wise
how to accommodate multiple "shared memory" peripherals?
finish interrupt handling, add monitor-interrupt peripheral to ensure correct re-enable from the interrupt handler
remove dead parameters and dead code
rework design as required to make it more robust
documentation
45,7 → 44,6
change "opcodes.html" to "instructions.html", ...
parameters
constants
interrupts
peripherals
running the test benches
core.v
62,8 → 60,6
avoid full parsing of false branches (accommodate other cores?)
add symbol for current core -- is9x8 (?)
peripherals
INTERRUPT
interrupt enable/disable (through INTERRUPT command)
multi-byte adder
multiplier
PICK -- emulate the Forth operator?
/ssbcc/trunk/core/9x8/asm
2,7 → 2,7
 
################################################################################
#
# Copyright 2012, Sinclair R.F., Inc.
# Copyright 2012-2015, Sinclair R.F., Inc.
#
# Assembler for SSBCC 9x8 processor
#
61,9 → 61,12
argListParser.add_argument('filename', metavar='filename', nargs='+', type=validateFile, help='required list of files');
argList = argListParser.parse_args();
 
# Determine whether or not interrupts are enabled
interruptsEnabled = True if argList.i else False;
 
# Construct the keyword parser
from asmDef_9x8 import asmDef_9x8
ad = asmDef_9x8();
ad = asmDef_9x8(interruptsEnabled);
 
# Record the constants in the program symbol table.
if argList.C:
84,7 → 87,7
if argList.D:
for name in argList.D:
if not re.match('D_',name):
raise SSBCCException('Bad define name "%s" should start with "D_"' % name);
raise asmDef.AsmException('Argument "%s" to "%s" should start with "D_"' % (name,sys.argv[0],));
ad.AddSymbol(name, 'define');
 
# Record the input names and values in the appropriate record type
/ssbcc/trunk/core/9x8/display_opcode.v
1,7 → 1,12
// Copyright 2013-2015, Sinclair R.F., Inc.
// short, human-readable versions of s_opcode suitable for waveform viewers
reg [3*8-1:0] s_opcode_name = "nop";
always @ (posedge i_clk)
casez (s_opcode)
if (s_interrupt)
s_opcode_name = "int"; // interrupt cycle
else if (s_interrupted)
s_opcode_name = "npi"; // nop induced by interrupt
else casez (s_opcode)
9'b00_0000_000 : s_opcode_name = "nop";
9'b00_0000_001 : s_opcode_name = "<<0";
9'b00_0000_010 : s_opcode_name = "<<1";
/ssbcc/trunk/core/9x8/doc/interrupt.html
0,0 → 1,147
<!-- Copyright 2015, Sinclair R.F., Inc. -->
<html>
<title>
macros
</title>
<body>
<h1>Interrupt handlers for the 9x8 micro controller</h1><br/>
Copyright 2012, Sinclair R.F., Inc.<br/><br/>
This document describes how to implement interrupt handlers for the 9x8 micro
controller.<br/><br/>
There is a single interrupt in the controller, although this interrupt can be
triggered by more than one signal. Implementing interrupts consists of two
actions: adding a single interrupt peripheral to the processor architecture
and adding a ".interrupt" body to the assembly source.<br/><br/>
The interrupt test bench illustrates how to add an interrupt for a single
external event and the design in <tt>example/interrupt</tt> illustrates how to
add an interrupt for two events, one external to the processor and one
internal to the processor.<br/><br/>
<h2>Theory of Operation</h2>
The interrupt peripheral creates two signals, <tt>s_interrupt</tt> and
<tt>s_interrupted</tt>, for the interrupt event and to disable normal
processor operation until the interrupt handler is running.<br/><br/>
Specifically, <tt>s_interrupt</tt> is a non-registered signal that is high
when (1)&nbsp;interrupts are enabled, (2)&nbsp;an interrupt edge has occurred
(and not be precluded by the interrupt mask, if any), and (3)&nbsp;the
processor is not in the middle of executing a jump, call, or return.<br/><br/>
When <tt>s_interrupt</tt> goes high, the processor pushes the PC address for
the current instruction onto the return stack, sets the next PC address to be
the interrupt handler start address (so that the interrupt handler will start
executing in 2&nbsp;instruction cycles), and otherwise performs a "nop."
Because of the piplined PC/opcode architecture, a delay register is required
for the current opcode PC address to be available.<br/><br/>
The instruction cycle after <tt>s_interrupt</tt> is high must perform a "nop."
This is done by using <tt>s_interrupted</tt> as a registered, delayed, version
of <tt>s_interrupt</tt>. When <tt>s_interrupted</tt> is high, the processor
core is coerced to perform a "nop" and the instruction pipeline architecture
starts fetching the second instruction in the interrupt handler.<br/><br/>
When the "return" opcode is performed by the interrupt handler, execution will
resume at the instruction that would have been performed when
<tt>s_interrupt</tt> was high. This instruction cannot be one immediately
after a <tt>jump</tt>, <tt>call</tt>, or <tt>return</tt> or one after a
<tt>jumpc</tt> or <tt>callc</tt> if the conditional was true, otherwise the
processor will not perform the desired jump, call, or return and will simply
start executing the code following the instruction after the jump, call, or
return.<br/><br/>
On&nbsp;return from the interrupt handler, the interrupts are enabled in a way
that precludes the interrupt handler from being interrupted again. This is
done with the three instruction sequence "<tt>O_INTERRUPT_ENA return
outport</tt>." The outport, as the instruction performed immediately after
the return, enables interrupts on the following instruction cycle, which will
be the first instruction cycle resuming the previous execution
sequence.<br/><br/>
The interrupt peripheral needs to generate the <tt>s_interrupt</tt> and
<tt>s_interrupted</tt> signals and the <tt>O_INTERRUPT_DIS</tt> and
<tt>O_INTERRUPT_ENA</tt> outport strobes; create signals for any interrupt
signals external to the processor; and instantiate the HDL for the
interrupt. Using the base class <tt>SSBCCinterruptPeripheral</tt> from
<tt>ssbccPeripheral</tt> ensures the <tt>s_interrupt</tt> and
<tt>s_interrupted</tt> signals are declared, although the code to generate
their values is not created, and it ensures the two outport strobes are
created.<br/><br/>
<h2>Example Implementation</h2>
The interrupt peripheral provided with the core provides an interface for one
to eight edge triggered interrupts. These interrupt sources can be external
to the processor or they can be signals from other peripherals. They are
normally rising edge triggered, but they can also be falling edge triggered.
The peripheral also provides an optional mask for the interrupt sources,
allowing it to be set, read, and initialized to a particular value.
Constants for bit maps for the interrupt signals can be defined as part of
selecting the signal for each of the one to eight interrupt signal
sources.<br/><br/>
The test bench for this interrupt peripheral illustrates a single, external,
rising-edge interrupt signal. The timing of the external interrupt was varied
to validate correct generation of the <tt>s_interrupt</tt> signal and return
from the interrupt handler (this was done by manually verifying the
displayed instruction sequences).<br/><br/>
An example interrupt controller for two interrupt signals, one external and
one internal, and one rising edge and one falled edge, along with a mask for
the interrupt signals, is also provided in
<tt>example/interrupt</tt>.<br/><br/>
<h2>Construction of Interrupt Peripherals</h2>
This discussion is based on the interrupt peripheral provided with the 9x8
processor core. It&nbsp;describes the HDL required to implement the interrupt
hardware.<br/><br/>
The processor core sets <tt>s_bus_pc</tt> to <tt>C_BUS_PC_JUMP</tt> when a
jump or call is performed and it sets it to <tt>C_BUS_PC_RETURN</tt> when a
return is being performed. When <tt>s_bus_pc</tt> is either one of these
values at the end of a processor clock cycle, then the instruction pipeline
will be in the middle of performing a jump, call, or return during the
following interval. During this subsequent interval, interrupts must be
disabled. This is done by capturing the status of <tt>s_bus_pc</tt> in the
register <tt>s_in_jump</tt> and prohibiting interrupts if <tt>s_in_jump</tt>
is high.<br/><br/>
The status of candidate interrupt signals is captured in
<tt>s_interrupt_raw</tt>. I.e., signal inversion is performed as required by
the peripheral architecture statement and masking is performed where the mask
is high if the signal is to be included as a candidate interrupt. The "raw"
interrupt triggers are then generated by looking for rising edges in this
signal as compared to the value(s) for the previous clock cycle.<br/><br/>
Two signals are then used to capture the trigger. The first,
<tt>s_interrupt_trigger</tt> records which enabled signals had a rising edge.
In&nbsp;order to reduced the depth of subsequent logic for the interrupt
signal itself, the single-bit signal <tt>s_interrupt_trigger_any</tt> records
whether or not any enabled signal had a rising edge. The history of both of
these signals is cleared if the processor reads the input port for
<tt>s_interrupt_trigger</tt>.<br/><br/>
The non-registered interrupt signal is then generated if (1)&nbsp;interrupts
are enabled, (2)&nbsp;a rising edge has occured, and (3)&nbsp;interrupts are
not disabled because the instruction pipeline is in the middle of a jump,
call, or return.<br/><br/>
A&nbsp;delayed version of <tt>s_interrupt</tt> is registed as
<tt>s_interrupted</tt> for generation of the interrupt-induced "nop"
instruction that must follow the interrupt.<br/><br/>
Finally, the interrupt enable signal is generated. Interrupts are initially
disabled (so that the processor can perform its initialization without
spurious stated induced by premature interrupts). Interrupts are then
disabled when an interrupt occurs or when the <tt>O_INTERRUPT_DIS</tt> strobe
is received. Interrupts are only enabled when the <tt>O_INTERRUPT_ENA</tt>
strobe is received.<br/><br/>
<h2>Construction of Interrupt Handlers</h2>
If&nbsp;there is only one signal that can produce an interrupt (as set in the
peripheral architecture statement), then the interrupt handler simply
processed the interrupt and exits using the <tt>.returni</tt> macro. For
example, the following code simply counts the number of interrupts received
(provided that they don't occur so fast that the interrupt handler isn't
called as fast as the interrupts occur):<br/><br/>
<tt>&nbsp;&nbsp;.interrupt<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;.fetchvalue(interruptCount) 1+ .storevalue(interruptCount)<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;.returni<br/></tt><br/>
If&nbsp;there is more than one signal that can produce an interrupt, then the
construction of the interrupt handler is slightly more complicated. Suppose
the interrupt peripheral architecture statement is:<br/><br/>
<tt>&nbsp;&nbsp;PERIPHERAL&nbsp;interrupt&nbsp;insignal0=i_int0,C_INT0&nbsp;\<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;insignal1=i_int1,C_INT1&nbsp;\<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inport=I_INTERRUPT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br/></tt><br/>
The interrupt handler then reads the interrupt trigger, conditionally calls
subroutines for the appropriate interrupt, clears the trigger from the data
stack, and returns as follows:<br/><br/>
<tt>&nbsp;&nbsp;.interrupt<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;.inport(I_INTERRUPT)<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;dup C_INT0 &amp; .callc(int0)<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;dup C_INT1 &amp; .callc(int1)<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;drop<br/></tt>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;.returni<br/></tt><br/>
</body>
</html>
ssbcc/trunk/core/9x8/doc/interrupt.html Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/html \ No newline at end of property Index: ssbcc/trunk/core/9x8/tb/ifdef/run =================================================================== --- ssbcc/trunk/core/9x8/tb/ifdef/run (revision 11) +++ ssbcc/trunk/core/9x8/tb/ifdef/run (revision 12) @@ -9,10 +9,10 @@ for INCLUDE_I2C in false true; do FLAGS=""; if ${INCLUDE_UART}; then - FLAGS+=" -D INCLUDE_UART"; + FLAGS+=" -D D_INCLUDE_UART"; fi if ${INCLUDE_I2C}; then - FLAGS+=" -D INCLUDE_I2C"; + FLAGS+=" -D D_INCLUDE_I2C"; fi ssbcc -q ${FLAGS} uc.9x8 || { echo "FATAL ERROR: ssbcc failed" > /dev/stderr; exit 1; } FAILED=false; Index: ssbcc/trunk/core/9x8/tb/ifdef/uc.9x8 =================================================================== --- ssbcc/trunk/core/9x8/tb/ifdef/uc.9x8 (revision 11) +++ ssbcc/trunk/core/9x8/tb/ifdef/uc.9x8 (revision 12) @@ -10,7 +10,7 @@ PARAMETER G_CLK_FREQ_HZ 50_000_000 -.IFDEF INCLUDE_UART +.IFDEF D_INCLUDE_UART PORTCOMMENT UART PERIPHERAL UART_Tx outport=O_UART_TX \ outstatus=I_UART_TX_BUSY \ @@ -18,7 +18,7 @@ outsignal=o_uart_tx .ENDIF -.IFNDEF INCLUDE_I2C +.IFNDEF D_INCLUDE_I2C PORTCOMMENT WARNING -- NO I2C BUS .ELSE PORTCOMMENT I2C bus
/ssbcc/trunk/core/9x8/ssbccGenVerilog.py
1,6 → 1,6
################################################################################
#
# Copyright 2012, Sinclair R.F., Inc.
# Copyright 2012-2015, Sinclair R.F., Inc.
#
# Verilog generation functions.
#
19,6 → 19,51
#
################################################################################
 
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():
"""
Return the name of the file to use for the processor core.
50,6 → 95,12
waveform viewers
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:
displayOpcodePath = os.path.join(config.Get('corepath'),'display_opcode.v');
fpDisplayOpcode = open(displayOpcodePath,'rt');
57,6 → 108,8
raise Exception('Program Bug -- "%s" not found' % displayOpcodePath);
body = fpDisplayOpcode.read();
fpDisplayOpcode.close();
if not config.InterruptVector():
body = DisableInterrupt(body);
fp.write(body);
if ('clog2' in config.functions) and config.Get('define_clog2'):
fp.write("""
78,6 → 131,8
raise Exception('Program Bug -- "%s" not found' % displayTracePath);
body = fpDisplayTrace.read();
fpDisplayTrace.close();
if not config.InterruptVector():
body = DisableInterrupt(body);
fp.write(body);
 
def genInports(fp,config):
161,7 → 216,8
"""
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_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');
750,7 → 806,8
signalName = signal[0];
signalWidth = signal[1];
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':
fp.write('initial %s = %s;\n' % (signalName,signalInit,));
if bitWidth > 0:
807,7 → 864,7
for thisSignal in config.signals:
signalName = thisSignal[0];
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 ';
if signalWidth == 1:
outString += ' ';
818,10 → 875,73
outString += signalName;
if signalInit != None:
outString += ' '*(maxLength-len(outString));
outString += ' = ' + signalInit;
outString += ' = ' + InitSignal(signalWidth,signalInit);
outString += ';\n'
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):
"""
Copy the user header to the output module.
/ssbcc/trunk/core/9x8/display_trace.v
1,5 → 1,8
// Copyright 2013-2015, Sinclair R.F., Inc.
// Display micro controller PC, opcode, and stacks.
localparam L__TRACE_SIZE = C_PC_WIDTH // pc width
localparam L__TRACE_SIZE = 1 // s_interrupt
+ 1 // s_interrupted
+ C_PC_WIDTH // pc width
+ 9 // opcode width
+ C_DATA_PTR_WIDTH // data stack pointer width
+ 1 // s_N_valid
12,6 → 15,8
;
task display_trace;
input [L__TRACE_SIZE-1:0] s_raw;
reg s_interrupt;
reg s_interrupted;
reg [C_PC_WIDTH-1:0] s_PC;
reg [8:0] s_opcode;
reg [C_DATA_PTR_WIDTH-1:0] s_Np_stack_ptr;
24,8 → 29,12
reg [C_RETURN_PTR_WIDTH-1:0] s_Rw_ptr;
reg [7*8-1:0] s_opcode_name;
begin
{ s_PC, s_opcode, s_Np_stack_ptr, s_N_valid, s_N, s_T_valid, s_T, s_R_valid, s_R, s_Rw_ptr } = s_raw;
casez (s_opcode)
{ s_interrupt, s_interrupted, s_PC, s_opcode, s_Np_stack_ptr, s_N_valid, s_N, s_T_valid, s_T, s_R_valid, s_R, s_Rw_ptr } = s_raw;
if (s_interrupt)
s_opcode_name = "int ";
else if (s_interrupted)
s_opcode_name = "nop_int";
else casez (s_opcode)
9'b00_0000_000 : s_opcode_name = "nop ";
9'b00_0000_001 : s_opcode_name = "<<0 ";
9'b00_0000_010 : s_opcode_name = "<<1 ";
/ssbcc/trunk/core/9x8/core.v
1,6 → 1,6
/*******************************************************************************
*
* Copyright 2012-2014, Sinclair R.F., Inc.
* Copyright 2012-2015, Sinclair R.F., Inc.
*
* SSBCC.9x8 -- Small Stack Based Computer Compiler, 9-bit opcode, 8-bit data.
*
50,6 → 50,7
// 6-input LUT formulation -- 3-bit opcode, 3 bits of T centered at current bit
reg [7:0] s_math_rotate;
always @ (s_T,s_opcode)
//@SSBCC@ interrupt__s_math_rotate
case (s_opcode[0+:3])
3'b000 : s_math_rotate = s_T; // nop
3'b001 : s_math_rotate = { s_T[0+:7], 1'b0 }; // <<0
203,6 → 204,7
s_inport = 1'b0;
s_outport = 1'b0;
s_mem_wr = 1'b0;
//@SSBCC@ interrupt__s_opcode
if (s_opcode[8] == 1'b1) begin // push
s_bus_t = C_BUS_T_OPCODE;
s_bus_n = C_BUS_N_T;
303,54 → 305,10
******************************************************************************/
 
// non-clocked PC required for shadow register in SRAM blocks
reg [C_PC_WIDTH-1:0] s_PC_next;
always @ (*)
case (s_bus_pc)
C_BUS_PC_NORMAL:
s_PC_next = s_PC_plus1;
C_BUS_PC_JUMP:
s_PC_next = s_PC_jump;
C_BUS_PC_RETURN:
s_PC_next = s_R[0+:C_PC_WIDTH];
default:
s_PC_next = s_PC_plus1;
endcase
//@SSBCC@ s_PC_next
 
// Return stack candidate
reg [C_RETURN_WIDTH-1:0] s_R_pre;
generate
if (C_PC_WIDTH < 8) begin : gen_r_narrow
always @ (*)
case (s_bus_r)
C_BUS_R_T:
s_R_pre = s_T;
C_BUS_R_PC:
s_R_pre = { {(8-C_PC_WIDTH){1'b0}}, s_PC_plus1 };
default:
s_R_pre = s_T;
endcase
end else if (C_PC_WIDTH == 8) begin : gen_r_same
always @ (*)
case (s_bus_r)
C_BUS_R_T:
s_R_pre = s_T;
C_BUS_R_PC:
s_R_pre = s_PC_plus1;
default:
s_R_pre = s_T;
endcase
end else begin : gen_r_wide
always @ (*)
case (s_bus_r)
C_BUS_R_T:
s_R_pre = { {(C_PC_WIDTH-8){1'b0}}, s_T };
C_BUS_R_PC:
s_R_pre = s_PC_plus1;
default:
s_R_pre = { {(C_PC_WIDTH-8){1'b0}}, s_T };
endcase
end
endgenerate
//@SSBCC@ s_R_pre
 
/*******************************************************************************
*
/ssbcc/trunk/core/9x8/asmDef_9x8.py
1,6 → 1,6
################################################################################
#
# Copyright 2012-2014, Sinclair R.F., Inc.
# Copyright 2012-2015, Sinclair R.F., Inc.
#
# Assembly language definitions for SSBCC 9x8.
#
439,10 → 439,23
if firstToken['value'] == '.main':
if (lastToken['type'] != 'macro') or (lastToken['value'] != '.jump'):
raise asmDef.AsmException('.main body does not end in ".jump" at %s' % lastToken['loc']);
# Ensure functions and interrupts end in a ".jump" or ".return".
if firstToken['value'] in ('.function','.interrupt',):
# Ensure the interrupt body contains a ".returni" and does not contain any ".return"s.
if firstToken['value'] == '.interrupt':
for token in [token for token in rawTokens if (token['type'] == 'macro') and (token['value'] == '.return')]:
raise asmDef.AsmException('".return" macro prohibited in .interrupt at %s' % token['loc']);
foundReturni = [token for token in rawTokens if (token['type'] == 'macro') and (token['value'] == '.returni')];
if not foundReturni:
raise asmDef.AsmException('.returni missing in .interrupt body at %s' % rawTokens[0]['loc']);
if (lastToken['type'] != 'macro') or (lastToken['value'] not in ('.jump','.returni',)):
raise asmDef.AsmException('.interrupt must end in .jump or .returni instead of "%s" at %s' % (lastToken['value'],lastToken['loc'],));
# Ensure functions end in a ".jump" or ".return".
if firstToken['value'] == '.function':
if (lastToken['type'] != 'macro') or (lastToken['value'] not in ('.jump','.return',)):
raise asmDef.AsmException('Last entry in ".function" or ".interrupt" must be a ".jump" or ".return" at %s' % lastToken['loc']);
raise asmDef.AsmException('function "%s" must end in .jump or .return instead of "%s" at %s' % (firstToken['value'],lastToken['value'],lastToken['loc'],));
# Ensure that .main and normal functions do not use ".returni".
if firstToken['value'] in ('.main','.function',):
for token in [token for token in rawTokens if (token['type'] == 'macro') and (token['value'] == '.returni')]:
raise asmDef.AsmException('.returni prohibited outside .interrupt at %s' % token['loc']);
 
################################################################################
#
739,6 → 752,16
"""
self.functionEvaluation = dict(list=list(), length=list(), body=list(), address=list());
nextStart = 0;
# ".interrupt" is optionally required (and is sure to exist by this
# function call if it is required). The interrupt handler always starts at
# address 3 so that address 0 can be a jump to ".main".
if self.interrupt:
nextStart = 3;
self.functionEvaluation['list'].append('.interrupt');
self.functionEvaluation['length'].append(self.interrupt['length']);
self.functionEvaluation['body'].append(self.interrupt['tokens']);
self.functionEvaluation['address'].append(nextStart);
nextStart = nextStart + self.functionEvaluation['length'][-1];
# ".main" is always required.
self.functionEvaluation['list'].append('.main');
self.functionEvaluation['length'].append(self.main['length']);
745,14 → 768,6
self.functionEvaluation['body'].append(self.main['tokens']);
self.functionEvaluation['address'].append(nextStart);
nextStart = nextStart + self.functionEvaluation['length'][-1];
# ".interrupt" is optionally required (and is sure to exist by this function
# call if it is required).
if self.interrupt:
self.functionEvaluation['list'].append('.interrupt');
self.functionEvaluation['length'].append(self.interrupt['length']);
self.functionEvaluation['body'].append(self.interrupt['tokens']);
self.functionEvaluation['address'].append(nextStart);
nextStart = nextStart + self.functionEvaluation['length'][-1];
# Loop through the required function bodies as they are identified.
ix = 0;
while ix < len(self.functionEvaluation['body']):
1065,6 → 1080,20
self.EmitPush(fp,token['address'] & 0xFF,'');
self.EmitOpcode(fp,self.specialInstructions['callc'] | (token['address'] >> 8),'callc '+token['argument'][0]['value']);
self.EmitOptArg(fp,token['argument'][1]);
# .dis
elif token['value'] == '.dis':
if not self.interruptsEnabled:
raise Exception('Program Bug -- interrupts not enabled');
dis_outport = self.interrupt_dis_outport;
self.EmitPush(fp,self.OutportAddress(dis_outport),dis_outport);
self.EmitOpcode(fp,self.InstructionOpcode('outport'),'outport (.dis)');
# .ena
elif token['value'] == '.ena':
if not self.interruptsEnabled:
raise Exception('Program Bug -- interrupts not enabled');
ena_outport = self.interrupt_ena_outport;
self.EmitPush(fp,self.OutportAddress(ena_outport),ena_outport);
self.EmitOpcode(fp,self.InstructionOpcode('outport'),'outport (.ena)');
# .fetch
elif token['value'] == '.fetch':
name = token['argument'][0]['value'];
1094,6 → 1123,14
elif token['value'] == '.return':
self.EmitOpcode(fp,self.specialInstructions['return'],'return');
self.EmitOptArg(fp,token['argument'][0]);
# .returni
elif token['value'] == '.returni':
if not self.interruptsEnabled:
raise Exception('Program Bug -- interrupts not enabled');
ena_outport = self.interrupt_ena_outport;
self.EmitPush(fp,self.OutportAddress(ena_outport),ena_outport);
self.EmitOpcode(fp,self.specialInstructions['return'],'return');
self.EmitOpcode(fp,self.InstructionOpcode('outport'),'outport (.ena)');
# .store
elif token['value'] == '.store':
name = token['argument'][0]['value'];
1146,14 → 1183,21
# Write the program marker, address of .main, address or "[]" of .interrupt,
# and the total program length.
fp.write(':program');
fp.write(' %d' % self.functionEvaluation['address'][0]);
if self.interrupt:
fp.write(' %d' % self.functionEvaluation['address'][1]);
fp.write(' %d' % self.functionEvaluation['address'][1]); # .main
fp.write(' %d' % self.functionEvaluation['address'][0]); # .interrupt
else:
fp.write(' []');
fp.write(' %d' % self.functionEvaluation['address'][0]); # .main
fp.write(' []'); # no .interrupt
fp.write(' %d' % (self.functionEvaluation['address'][-1] + self.functionEvaluation['length'][-1]));
fp.write('\n');
# Emit the bodies
if self.interrupt:
self.emitLabelList = '';
mainAddress = self.functionEvaluation['address'][1];
self.EmitPush(fp,mainAddress & 0xFF,name='');
self.EmitOpcode(fp,self.specialInstructions['jump'] | (mainAddress >> 8),'jump .main');
self.EmitOpcode(fp,self.InstructionOpcode('nop'),'nop');
for ix in range(len(self.functionEvaluation['list'])):
fp.write('- %s\n' % self.functionEvaluation['list'][ix]);
self.emitLabelList = '';
1194,7 → 1238,7
#
################################################################################
 
def __init__(self):
def __init__(self,enableInterrupts):
"""
Initialize the tables definining the following:
directly invokable instruction mnemonics and the associated opcodes
1206,7 → 1250,10
restrictions for optional arguments\n
Initialize lists and members to record memory attributes, stack lengths,
body of the .main function, body of the optional .interrupt function,
current memory for variable definitions, etc.
current memory for variable definitions, etc.\n
If enableInterrupts is True, then also define the ".ena", ".dis", and
".returni" macros to enable and disable interrupts and to return from the
interrupt handler.
"""
 
#
1249,10 → 1296,8
self.AddInstruction('<<msb', 0x003);
self.AddInstruction('>r', 0x040);
self.AddInstruction('^', 0x052);
#self.AddInstruction('dis', 0x01C);
self.AddInstruction('drop', 0x054);
self.AddInstruction('dup', 0x008);
#self.AddInstruction('ena', 0x019);
self.AddInstruction('inport', 0x030);
self.AddInstruction('lsb>>', 0x007);
self.AddInstruction('msb>>', 0x006);
1336,6 → 1381,20
self.stackLength = dict();
 
#
# Conditional implementation of interrupts.
#
 
if type(enableInterrupts) != bool:
raise Exception('Program Bug -- enableInterrupts must be a boolean');
self.interruptsEnabled = enableInterrupts;
if enableInterrupts:
self.interrupt_dis_outport = 'O_INTERRUPT_DIS';
self.interrupt_ena_outport = 'O_INTERRUPT_ENA';
self.AddMacro('.dis', 2, []);
self.AddMacro('.ena', 2, []);
self.AddMacro('.returni', 3, []);
 
#
# Configure the containers for the expanded main, interrupt, function,
# macro, etc. definitions.
#
/ssbcc/trunk/core/9x8/peripherals/monitor_stack.v
1,6 → 1,6
//
// monitor_stack peripheral
// Copyright 2013, Sinclair R.F., Inc.
// Copyright 2013-2015, Sinclair R.F., Inc.
//
// Note: The validity of N and T are not monitored for invalid operations. For
// example, if N is not valid and a "swap" is performed, then the data
25,6 → 25,8
always @ (posedge i_clk)
if (i_rst)
s__T_valid <= 1'b0;
else if (s_interrupt || s_interrupted)
s__T_valid <= s__T_valid;
else case (s_bus_t)
C_BUS_T_OPCODE: s__T_valid <= 1'b1;
C_BUS_T_N: s__T_valid <= s__N_valid;
89,7 → 91,9
$display("%12d : Malformed next-to-top-of-data-stack validity in @CORENAME@", $time);
s__data_stack_error <= 1'b1;
end
case (s_bus_t)
if (s_interrupt || s_interrupted)
; // do nothing
else case (s_bus_t)
C_BUS_T_MATH_ROTATE:
if (!s__T_valid && (s_opcode[0+:3] != 3'h0)) begin
$display("%12d : Illegal rotate on invalid top of data stack in @CORENAME@", $time);
138,7 → 142,9
default:
;
endcase
if ((s_opcode == 9'b00_0111_000) && !s__T_valid) begin
if (s_interrupt || s_interrupted)
; // do nothing
else if ((s_opcode == 9'b00_0111_000) && !s__T_valid) begin
$display("%12d : Outport with invalid top-of-data-stack in @CORENAME@", $time);
s__data_stack_error <= 1'b1;
end
193,7 → 199,7
s__R_is_address <= 1'b0;
s__return_is_address <= {(2**C_RETURN_PTR_WIDTH){1'b0}};
end else if (s_return == C_RETURN_INC) begin
s__R_is_address <= (s_bus_r == C_BUS_R_PC);
s__R_is_address <= s_interrupt || (s_bus_r == C_BUS_R_PC);
s__return_is_address[s_R_stack_ptr_next] <= s__R_is_address;
end else if (s_return == C_RETURN_DEC) begin
s__R_is_address <= s__return_is_address[s_R_stack_ptr];
206,7 → 212,9
$display("%12d : Non-address by return instruction in @CORENAME@", $time);
s__R_address_error <= 1'b1;
end
if (((s_opcode == 9'b00_0001_001) || (s_opcode == 9'b00_1001_001)) && s__R_is_address) begin
if (s_interrupt || s_interrupted)
; // do nothing
else if (((s_opcode == 9'b00_0001_001) || (s_opcode == 9'b00_1001_001)) && s__R_is_address) begin
$display("%12d : Copied address to data stack in @CORENAME@", $time);
s__R_address_error <= 1'b1;
end
221,7 → 229,9
s__mem_address_limit[3] = @MEM_LIMIT_3@;
end
always @ (posedge i_clk)
if ((s_opcode[3+:6] == 6'b000110) && ({ 1'b0, s_T } >= @LAST_INPORT@)) begin
if (s_interrupt || s_interrupted) begin
// do nothing
end else if ((s_opcode[3+:6] == 6'b000110) && ({ 1'b0, s_T } >= @LAST_INPORT@)) begin
$display("%12d : Range error on inport in @CORENAME@", $time);
s__range_error <= 1'b1;
end else if ((s_opcode[3+:6] == 6'b000111) && ({ 1'b0, s_T } >= @LAST_OUTPORT@)) begin
235,6 → 245,8
reg [L__TRACE_SIZE-1:0] s__history[@HISTORY@-1:0];
reg [8:0] s__opcode_s = 9'b0;
reg [C_PC_WIDTH-1:0] s__PC_s[1:0];
reg s__interrupt_s = 1'b0;
reg s__interrupted_s = 1'b0;
integer ix__history;
initial begin
for (ix__history=0; ix__history<@HISTORY@; ix__history=ix__history+1)
245,16 → 257,18
always @ (posedge i_clk) begin
s__PC_s[1] <= s__PC_s[0];
s__PC_s[0] <= s_PC;
s__interrupt_s <= s_interrupt;
s__interrupted_s <= s_interrupted;
s__opcode_s <= s_opcode;
for (ix__history=1; ix__history<@HISTORY@; ix__history=ix__history+1)
s__history[ix__history-1] <= s__history[ix__history];
s__history[@HISTORY@-1] <= { s__PC_s[1], s__opcode_s, s_Np_stack_ptr, s__N_valid, s_N, s__T_valid, s_T, s__R_valid, s_R, s_R_stack_ptr };
s__history[@HISTORY@-1] <= { s__interrupt_s, s__interrupted_s, s__PC_s[1], s__opcode_s, s_Np_stack_ptr, s__N_valid, s_N, s__T_valid, s_T, s__R_valid, s_R, s_R_stack_ptr };
end
wire s_terminate = s__PC_error || s__data_stack_error || s__return_stack_error || s__R_address_error || s__range_error;
always @ (posedge s_terminate) begin
for (ix__history=0; ix__history<@HISTORY@; ix__history=ix__history+1)
display_trace(s__history[ix__history]);
display_trace({ s__PC_s[1], s__opcode_s, s_Np_stack_ptr, s__N_valid, s_N, s__T_valid, s_T, s__R_valid, s_R, s_R_stack_ptr });
display_trace({ s_interrupt, s_interrupted, s__PC_s[1], s__opcode_s, s_Np_stack_ptr, s__N_valid, s_N, s__T_valid, s_T, s__R_valid, s_R, s_R_stack_ptr });
$finish;
end
endgenerate
/ssbcc/trunk/core/9x8/peripherals/interrupt.py
0,0 → 1,207
################################################################################
#
# Copyright 2015, Sinclair R.F., Inc.
#
################################################################################
 
from ssbccPeripheral import SSBCCinterruptPeripheral
from ssbccUtil import SSBCCException
 
class interrupt(SSBCCinterruptPeripheral):
"""
Interrupt peripheral for 1 to 8 interrupt inputs.\n
This implements a variable-width interrupt input of up to 8 bits and
generates an interrupt when one of these goes from low to high, provided that
an interrupt is not already in progress.\n
Usage:
PERIPHERAL interrupt insignal<N>=[!]{i_name|s__name}[,C_NAME] \\
[inport=I_NAME] \\
[outmaskport=O_NAME] \\
[inmaskport=I_NAME] \\
[initmask=<value>]\n
Where:
insignal<N>={i_name|s__name}[,C_NAME]
specifies one of the eight possible single-bit signal that will trigger
the interrupt and optionally specify a constant defined by the interrupt
bit position
Note: Replace <N> with 0, 1, ..., 7
Note: If the signal name starts with "i_" it will be added as a single
bit wide input to the processor. If the signal name starts with
"s__" it must be a signal from another peripheral with the given
name.
Note: If the signal name is preceded by a an exclamation mark, i.e., a
"!", then the signal will be treated as falling-edge triggered
instead of rising edge triggered.
Note: External signals may need to be synchronized to the micro
controller clock.
inport=I_NAME
provide the input port name to read the interrupt signal
Note: This port is prohibited if there is only one interrupt signal and
it is required if there is more than one interrupt signal.
outmaskport=O_NAME
optionally specifies a port to provide an enable/disable mask to
the interrupt signals
inmaskport=I_NAME
optionally specifies a port to read the current enable/disable mask
Note: This cannot be used if outmaskport is not specified.
initmask=<value>
optionally specifies the initial value of the mask
Note: This cannot be used if outmaskport is not specified.
Note: The value is either a Verilog format value or a decimal value.
Note: If this is not specified then all interrupt bits will be enabled.\n
Example: Trigger an interrupt when a 1 clock wide strobe is received from an
external timer.\n
# In the architecture file
PERIPHERAL interrupt insignal0=i_timer_strobe\n
; In the assembly file
.interrupt
; Do the timer event.
...
; Return from the interrupt.
.returni\n
Example: Monitor an external timer strobe and a FIFO empty flag (which is
high when the FIFO is empty).\n
# In the architecture file
PERIPHERAL outFIFO_async data=o_fifo ... outempty=I_EMPTY
PERIPHERAL interrupt insignal0=!s__o_fifo__outempty_in,C_INTERRUPT_MASK_FIFO \\
insignal1=i_timer_strobe,C_INTERRUPT_MASK_TIMER \\
inport=I_INTERRUPT\n
; In the assembly file
.interrupt
; Read the interrupt condition.
.inport(I_INTERRUPT)
; If the interrupt was triggered by the timer, then handle the
; timer event (but don't throw away the rest of the interrupt
; condition).
dup C_INTERRUPT_MASK_TIMER & .callc(...)
; If the interrupt was triggered by the FIFO becoming empty, then
; do whatever's appropriate (and throw away the interrupt
; condition).
C_INTERRUPT_MASK_FIFO & .callc(...)
; Return from the interrupt.
.returni\n
WARNING: Setting the interrupt mask does not disable interrupts occuring
before a bit in the mask is cleared. I.e., if a particular
interrupt bit is disabled by a new interrupt mask, but an interrupt
for that bit occured before the mask bit was cleared, then that
interrupt bit will still have caused a pending interrupt. This is
particularly important when the processor is starting.\n
This can be resolved in part by using the following code at the top
of the interrupt handler:\n
.inport(I_INTERRUPT) .inport(I_INTERRUPT_MASK) &
where .inport(I_INTERRUPT) gets the interrupt event(s) and
.inport(I_INTERRUPT_MASK) gets the current interrupt mask.
"""
 
def __init__(self,peripheralFile,config,param_list,loc):
"""
Configure this peripheral as an interrupt peripheral.
"""
# Invoke the base class __init__ function before doing anything else.
SSBCCinterruptPeripheral.__init__(self,config,loc)
# Use the externally provided file name for the peripheral
self.peripheralFile = peripheralFile
# Get the parameters.
allowables = (
( 'initmask', r'\S+$', lambda v : self.IntValueMethod(v), ),
( 'inmaskport', r'I_\w+$', None, ),
( 'inport', r'I_\w+$', None, ),
( 'outmaskport', r'O_\w+$', None, ),
)
names = [a[0] for a in allowables]
self.insignal = [None for ix in range(config.Get('data_width'))]
self.invert = 0
for param_tuple in param_list:
param = param_tuple[0]
if re.match(r'insignal[0-7]$',param):
if param_tuple[1] == None:
raise SSBCCException('"%s" missing value at %s' % (param,loc,))
ix = int(param[-1])
if self.insignal[ix]:
raise SSBCCException('%s already specified at %s' % (param,loc,))
pars = re.findall(r'(!?)(i_\w+|s__\w+)(,C_\w+)?$',param_tuple[1])
if not pars or not pars[0][1]:
raise SSBCCException('I/O symbol at %s does not match required format "[!]{i_name|s__name}[,C_name]": "%s"' % (loc,param_tuple[1],))
pars = pars[0]
if pars[0]:
self.invert |= 2**ix
self.insignal[ix] = pars[1]
if pars[2]:
config.AddConstant(pars[2][1:],2**ix,loc)
elif param in names:
param_test = allowables[names.index(param)]
self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2])
else:
raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,))
# Ensure the required parameters are set.
if not any(self.insignal):
raise SSBCCException('Required parameter insignal<N> missing at %s' % loc)
self.width = sum(1 for ix in range(len(self.insignal)) if self.insignal[ix])
ixMissing = [ix for ix in range(self.width) if not self.insignal[ix]]
if ixMissing:
raise SSBCCException('insignal%d missing at %s' % (ixMissing[0],loc,))
if self.width == 1:
if hasattr(self,'inport'):
raise SSBCCException('Parameter "inport" is prohibited when there is only one interrupt signal at %s' % loc)
else:
if not hasattr(self,'inport'):
raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,))
# Ensure optional parameters are consistent.
for opt in ('inmaskport','initmask',):
if hasattr(self,opt) and not hasattr(self,'outmaskport'):
raise SSBCCException('Optional parameter "%s" requires "outmaskport" at %s' % (opt,loc,))
if hasattr(self,'initmask'):
if self.initmask >= 2**self.width:
raise SSBCCException('Value of "initmask" exceeds interrupt width at %s' % loc)
# Create the signal for the triggering interrupt source.
config.AddSignal('s_interrupt_trigger',self.width,loc)
# Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
for ix in [ix for ix in range(self.width) if re.match(r'i_',self.insignal[ix])]:
config.AddIO(self.insignal[ix],1,'input',loc)
if hasattr(self,'inport'):
self.ix_inport = config.NInports()
config.AddInport((self.inport,
('s_interrupt_trigger',self.width,'data',),
),
loc)
if not hasattr(self,'initmask'):
self.initmask= '%d\'h%X' % (self.width,2**self.width-1,)
if hasattr(self,'outmaskport'):
self.masksignal = 's_interrupt_mask'
config.AddSignalWithInit(self.masksignal,self.width,None,loc)
config.AddOutport((self.outmaskport,False,
(self.masksignal,self.width,'data',self.initmask,),
),
loc)
if hasattr(self,'inmaskport'):
config.AddInport((self.inmaskport,
(self.masksignal,self.width,'data',),
),
loc)
else:
self.masksignal = self.initmask
 
def GenVerilog(self,fp,config):
body = self.LoadCore(self.peripheralFile,'.v');
if self.width == 1:
body = re.sub(r'reg s_interrupt_trigger_any.*?\n','',body);
while re.search(r' {4,}s_interrupt_trigger_any',body):
body = re.sub(r' {4,}s_interrupt_trigger_any.*?\n','',body);
body = re.sub(r's_interrupt_trigger_any','s_interrupt_trigger',body);
if not hasattr(self,'inport'):
clear_trigger = 's_interrupt';
else:
clear_trigger = 's_inport && (s_T == %d)' % self.ix_inport;
for subpair in (
( r'@CLEAR_TRIGGER@', clear_trigger, ),
( r'@IX_OUTPORT_DIS@', '8\'h%02X' % self.ix_outport_interrupt_dis, ),
( r'@IX_OUTPORT_ENA@', '8\'h%02X' % self.ix_outport_interrupt_ena, ),
( r'@INSIGNAL@', '{ %s }' % ', '.join(self.insignal[ix] for ix in range(self.width-1,-1,-1)), ),
( r'@INVERT@', '%d\'h%X' % (self.width,self.invert,), ),
( r'@MASK@', self.masksignal, ),
( r'@WIDTH@ ', '' if self.width==1 else '[%d:0] ' % (self.width-1,), ),
( r'@ZERO@', '%d\'h0' % self.width, ),
):
body = re.sub(subpair[0],subpair[1],body);
body = self.GenVerilogFinal(config,body);
fp.write(body);
/ssbcc/trunk/core/9x8/peripherals/outFIFO_async.py
22,7 → 22,8
data_empty=<o_data_empty> \\
outport=<O_data> \\
infull=<I_full> \\
depth=<N> \n
depth=<N> \\
[outempty=I_empty] \n
Where:
outclk=<i_clock>
specifies the name of the asynchronous read clock
39,7 → 40,10
status of the FIFO
depth=<N>
specifies the depth of the FIFO
Note: N must be a power of 2 and must be at least 16.\n
Note: N must be a power of 2 and must be at least 16.
outempty=O_empty
optionally specifies the name of an input port for the processor to access
the "empty" status of the FIFO\n
Example: Provide a FIFO to an external device or IP.\n
The PERIPHERAL statement would be:\n
PERIPHERAL outFIFO_async outclk=i_dev_clk \\
54,7 → 58,11
:loop
.inport(I_DATA_FIFO_FULL) .jumpc(loop)
.outport(O_DATA_FIFO)
.jumpc(loop,nop)
.jumpc(loop,nop)\n
Interrupt handler: "!s__<data>__outempty_in" is is suitable input to an
interrupt handler where "<data>" is the name assigned to "data". This signal
is high when the FIFO is empty, so a falling edge (the leading "!") is a
suitable condition for the interrupt to occur.
"""
 
def __init__(self,peripheralFile,config,param_list,loc):
69,6 → 77,7
('outport', r'O_\w+$', None, ),
('infull', r'I_\w+$', None, ),
('depth', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v,lowLimit=16), ),
('outempty', r'I_\w+$', None, ),
);
names = [a[0] for a in allowables];
for param_tuple in param_list:
79,6 → 88,8
self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]);
# Ensure the required parameters are provided.
for paramname in names:
if paramname in ('outempty',):
continue;
if not hasattr(self,paramname):
raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,));
# Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
95,9 → 106,25
('s__%s__full' % self.data,1,'data',),
),loc);
 
if hasattr(self,'outempty'):
self.outempty_name = 's__%s__outempty_in' % self.data;
config.AddSignalWithInit(self.outempty_name,1,'1\'b1',loc);
self.ix_outempty = config.NInports();
config.AddInport((self.outempty,
(self.outempty_name,1,'data',),
),loc);
 
def GenVerilog(self,fp,config):
body = self.LoadCore(self.peripheralFile,'.v');
if hasattr(self,'outempty'):
body_outempty = """\
always @ (posedge i_clk)
s__outempty_in <= (s__delta_clk == @DEPTH_NBITS@'d0);
"""
else:
body_outempty = '';
for subpair in (
( r'@OUTEMPTY@\n', body_outempty, ),
( r'@DATA@', self.data, ),
( r'@DATA_EMPTY@', self.data_empty, ),
( r'@DATA_RD@', self.data_rd, ),
/ssbcc/trunk/core/9x8/peripherals/monitor_stack.py
57,6 → 57,9
 
def GenVerilog(self,fp,config):
body = self.LoadCore(self.peripheralFile,'.v');
if not config.InterruptVector():
for replace in (r's_interrupt\b',r's_interrupted\b',):
body = re.sub(replace,'1\'b0',body);
outport_pure_strobe = '';
for ix in range(config.NOutports()):
thisPort = config.outports[ix][2:];
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-16
0,0 → 1,51
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 106 push : e 00 06 : 00 f
01 080 jump : d 00 00 : 00 f
02 000 nop : d 00 00 : 00 f
06 101 push : e 00 01 : 00 f
07 038 outport : d 00 00 : 00 f
08 101 push : e 00 01 : 00 f
09 115 push : f 01 15 : 00 f
0a 0e0 callc : e 00 01 : 0c 0
0b 000 nop : e 00 01 : 0c 0
15 028 return : e 00 01 : 00 f
16 000 nop : e 00 01 : 00 f
0c 109 push : f 01 09 : 00 f
0d 0a0 jumpc : e 00 01 : 00 f
0e 05c 1- : e 00 00 : 00 f
09 115 push : f 00 15 : 00 f
0a 0e0 callc : e 00 00 : 00 f
0b 000 int : e 00 00 : 0b 0
0c 109 nop_int : e 00 00 : 0b 0
03 101 push : f 00 01 : 0b 0
04 028 return : f 00 01 : 00 f
05 038 outport : e 00 00 : 00 f
0b 000 nop : e 00 00 : 00 f
0c 109 push : f 00 09 : 00 f
0d 0a0 jumpc : e 00 00 : 00 f
0e 05c 1- : e 00 ff : 00 f
0f 054 drop : d 00 00 : 00 f
10 100 push : e 00 00 : 00 f
11 038 outport : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb_interrupt.s
0,0 → 1,25
; Copyright 2015, Sinclair R.F., Inc.
; Test bench for interrupt peripheral.
 
.main
 
; Enable the interrupts.
.ena
 
; Test conditional calls and jumps.
${2-1} :loop_test
.callc(test_call,nop)
.jumpc(loop_test,1-) drop
 
; Test against interrupt disable instruction.
.dis
 
; Wait forever.
:infinite .jump(infinite)
 
.interrupt
; Return from the interrupt handler.
.returni
 
.function test_call
.return
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-19
0,0 → 1,51
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 106 push : e 00 06 : 00 f
01 080 jump : d 00 00 : 00 f
02 000 nop : d 00 00 : 00 f
06 101 push : e 00 01 : 00 f
07 038 outport : d 00 00 : 00 f
08 101 push : e 00 01 : 00 f
09 115 push : f 01 15 : 00 f
0a 0e0 callc : e 00 01 : 0c 0
0b 000 nop : e 00 01 : 0c 0
15 028 return : e 00 01 : 00 f
16 000 nop : e 00 01 : 00 f
0c 109 push : f 01 09 : 00 f
0d 0a0 jumpc : e 00 01 : 00 f
0e 05c 1- : e 00 00 : 00 f
09 115 push : f 00 15 : 00 f
0a 0e0 callc : e 00 00 : 00 f
0b 000 nop : e 00 00 : 00 f
0c 109 push : f 00 09 : 00 f
0d 0a0 jumpc : e 00 00 : 00 f
0e 05c int : e 00 00 : 0e 0
0f 054 nop_int : e 00 00 : 0e 0
03 101 push : f 00 01 : 0e 0
04 028 return : f 00 01 : 00 f
05 038 outport : e 00 00 : 00 f
0e 05c 1- : e 00 ff : 00 f
0f 054 drop : d 00 00 : 00 f
10 100 push : e 00 00 : 00 f
11 038 outport : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-5
0,0 → 1,51
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 106 push : e 00 06 : 00 f
01 080 jump : d 00 00 : 00 f
02 000 nop : d 00 00 : 00 f
06 101 push : e 00 01 : 00 f
07 038 outport : d 00 00 : 00 f
08 101 int : d 00 00 : 08 0
09 115 nop_int : d 00 00 : 08 0
03 101 push : e 00 01 : 08 0
04 028 return : e 00 01 : 00 f
05 038 outport : d 00 00 : 00 f
08 101 push : e 00 01 : 00 f
09 115 push : f 01 15 : 00 f
0a 0e0 callc : e 00 01 : 0c 0
0b 000 nop : e 00 01 : 0c 0
15 028 return : e 00 01 : 00 f
16 000 nop : e 00 01 : 00 f
0c 109 push : f 01 09 : 00 f
0d 0a0 jumpc : e 00 01 : 00 f
0e 05c 1- : e 00 00 : 00 f
09 115 push : f 00 15 : 00 f
0a 0e0 callc : e 00 00 : 00 f
0b 000 nop : e 00 00 : 00 f
0c 109 push : f 00 09 : 00 f
0d 0a0 jumpc : e 00 00 : 00 f
0e 05c 1- : e 00 ff : 00 f
0f 054 drop : d 00 00 : 00 f
10 100 push : e 00 00 : 00 f
11 038 outport : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-6
0,0 → 1,51
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 106 push : e 00 06 : 00 f
01 080 jump : d 00 00 : 00 f
02 000 nop : d 00 00 : 00 f
06 101 push : e 00 01 : 00 f
07 038 outport : d 00 00 : 00 f
08 101 push : e 00 01 : 00 f
09 115 int : e 00 01 : 09 0
0a 0e0 nop_int : e 00 01 : 09 0
03 101 push : f 01 01 : 09 0
04 028 return : f 01 01 : 00 f
05 038 outport : e 00 01 : 00 f
09 115 push : f 01 15 : 00 f
0a 0e0 callc : e 00 01 : 0c 0
0b 000 nop : e 00 01 : 0c 0
15 028 return : e 00 01 : 00 f
16 000 nop : e 00 01 : 00 f
0c 109 push : f 01 09 : 00 f
0d 0a0 jumpc : e 00 01 : 00 f
0e 05c 1- : e 00 00 : 00 f
09 115 push : f 00 15 : 00 f
0a 0e0 callc : e 00 00 : 00 f
0b 000 nop : e 00 00 : 00 f
0c 109 push : f 00 09 : 00 f
0d 0a0 jumpc : e 00 00 : 00 f
0e 05c 1- : e 00 ff : 00 f
0f 054 drop : d 00 00 : 00 f
10 100 push : e 00 00 : 00 f
11 038 outport : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-7
0,0 → 1,51
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 106 push : e 00 06 : 00 f
01 080 jump : d 00 00 : 00 f
02 000 nop : d 00 00 : 00 f
06 101 push : e 00 01 : 00 f
07 038 outport : d 00 00 : 00 f
08 101 push : e 00 01 : 00 f
09 115 push : f 01 15 : 00 f
0a 0e0 int : f 01 15 : 0a 0
0b 000 nop_int : f 01 15 : 0a 0
03 101 push : 0 15 01 : 0a 0
04 028 return : 0 15 01 : 00 f
05 038 outport : f 01 15 : 00 f
0a 0e0 callc : e 00 01 : 0c 0
0b 000 nop : e 00 01 : 0c 0
15 028 return : e 00 01 : 00 f
16 000 nop : e 00 01 : 00 f
0c 109 push : f 01 09 : 00 f
0d 0a0 jumpc : e 00 01 : 00 f
0e 05c 1- : e 00 00 : 00 f
09 115 push : f 00 15 : 00 f
0a 0e0 callc : e 00 00 : 00 f
0b 000 nop : e 00 00 : 00 f
0c 109 push : f 00 09 : 00 f
0d 0a0 jumpc : e 00 00 : 00 f
0e 05c 1- : e 00 ff : 00 f
0f 054 drop : d 00 00 : 00 f
10 100 push : e 00 00 : 00 f
11 038 outport : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-8
0,0 → 1,51
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 106 push : e 00 06 : 00 f
01 080 jump : d 00 00 : 00 f
02 000 nop : d 00 00 : 00 f
06 101 push : e 00 01 : 00 f
07 038 outport : d 00 00 : 00 f
08 101 push : e 00 01 : 00 f
09 115 push : f 01 15 : 00 f
0a 0e0 callc : e 00 01 : 0c 0
0b 000 nop : e 00 01 : 0c 0
15 028 int : e 00 01 : 15 1
16 000 nop_int : e 00 01 : 15 1
03 101 push : f 01 01 : 15 1
04 028 return : f 01 01 : 0c 0
05 038 outport : e 00 01 : 0c 0
15 028 return : e 00 01 : 00 f
16 000 nop : e 00 01 : 00 f
0c 109 push : f 01 09 : 00 f
0d 0a0 jumpc : e 00 01 : 00 f
0e 05c 1- : e 00 00 : 00 f
09 115 push : f 00 15 : 00 f
0a 0e0 callc : e 00 00 : 00 f
0b 000 nop : e 00 00 : 00 f
0c 109 push : f 00 09 : 00 f
0d 0a0 jumpc : e 00 00 : 00 f
0e 05c 1- : e 00 ff : 00 f
0f 054 drop : d 00 00 : 00 f
10 100 push : e 00 00 : 00 f
11 038 outport : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-9
0,0 → 1,51
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 000 nop : d 00 00 : 00 f
00 106 push : e 00 06 : 00 f
01 080 jump : d 00 00 : 00 f
02 000 nop : d 00 00 : 00 f
06 101 push : e 00 01 : 00 f
07 038 outport : d 00 00 : 00 f
08 101 push : e 00 01 : 00 f
09 115 push : f 01 15 : 00 f
0a 0e0 callc : e 00 01 : 0c 0
0b 000 nop : e 00 01 : 0c 0
15 028 int : e 00 01 : 15 1
16 000 nop_int : e 00 01 : 15 1
03 101 push : f 01 01 : 15 1
04 028 return : f 01 01 : 0c 0
05 038 outport : e 00 01 : 0c 0
15 028 return : e 00 01 : 00 f
16 000 nop : e 00 01 : 00 f
0c 109 push : f 01 09 : 00 f
0d 0a0 jumpc : e 00 01 : 00 f
0e 05c 1- : e 00 00 : 00 f
09 115 push : f 00 15 : 00 f
0a 0e0 callc : e 00 00 : 00 f
0b 000 nop : e 00 00 : 00 f
0c 109 push : f 00 09 : 00 f
0d 0a0 jumpc : e 00 00 : 00 f
0e 05c 1- : e 00 ff : 00 f
0f 054 drop : d 00 00 : 00 f
10 100 push : e 00 00 : 00 f
11 038 outport : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
12 112 push : e 00 12 : 00 f
13 080 jump : d 00 00 : 00 f
14 000 nop : d 00 00 : 00 f
/ssbcc/trunk/core/9x8/peripherals/tb/interrupt/run
0,0 → 1,19
#!/bin/bash
#
# Copyright 2015, Sinclair R.F., Inc.
 
NAME=interrupt
 
../../../../../ssbcc -q -P monitor_stack tb_${NAME}.9x8 || { echo "${NAME} compile failed" > /dev/stderr; exit 1; }
for INT_DELAY in 5 6 7 8 9 10 11 13 14 16 19 22 23; do
iverilog -D INT_DELAY=${INT_DELAY} -o tb tb.v tb_${NAME}.v \
|| { echo "${NAME} build failed" > /dev/stderr; exit 1; }
./tb > tb.out;
if ! cmp -s tb.out tb.good-${INT_DELAY}; then
echo "${NAME} failed on INT_DELAY=${INT_DELAY}" > /dev/stderr;
exit 1;
fi
done
 
echo "Passed: ${NAME}";
exit 0;
ssbcc/trunk/core/9x8/peripherals/tb/interrupt/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/.gitignore =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/.gitignore (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/.gitignore (revision 12) @@ -0,0 +1,3 @@ +tb.out +tb.sav +tb_interrupt.v Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb_interrupt.9x8 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb_interrupt.9x8 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb_interrupt.9x8 (revision 12) @@ -0,0 +1,14 @@ +# Copyright 2015, Sinclair R.F., Inc. +# Test bench for interrupt peripheral. + +ARCHITECTURE core/9x8 Verilog +ASSEMBLY tb_interrupt.s + +INSTRUCTION 256 +DATA_STACK 16 +RETURN_STACK 16 + +PERIPHERAL trace + +PORTCOMMENT external interrupt +PERIPHERAL interrupt insignal0=i_interrupt Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.v =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.v (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.v (revision 12) @@ -0,0 +1,49 @@ +/******************************************************************************* + * + * Copyright 2015, Sinclair R.F., Inc. + * + * Test bench for the servo_motor peripheral. + * + ******************************************************************************/ + +`timescale 1ns/1ps + +module tb; + +// 10 MHz clock +reg s_clk = 1'b1; +always @ (s_clk) + s_clk <= #50 ~s_clk; + +reg s_rst = 1'b1; +initial begin + repeat (5) @ (posedge s_clk); + s_rst = 1'b0; +end + +reg s_interrupt = 1'b0; +initial begin + @ (negedge s_rst); + repeat(`INT_DELAY) @ (posedge s_clk); + s_interrupt = 1'b1; + @ (posedge s_clk); + s_interrupt = 1'b0; +end + +tb_interrupt uut( + // synchronous reset and processor clock + .i_rst (s_rst), + .i_clk (s_clk), + // external interrupt + .i_interrupt (s_interrupt) +); + +initial begin +// $dumpfile("tb.vcd"); +// $dumpvars(); + repeat(50) @ (posedge s_clk); + @ (negedge s_clk); + $finish; +end + +endmodule
ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.v Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-10 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-10 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-10 (revision 12) @@ -0,0 +1,51 @@ +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 106 push : e 00 06 : 00 f +01 080 jump : d 00 00 : 00 f +02 000 nop : d 00 00 : 00 f +06 101 push : e 00 01 : 00 f +07 038 outport : d 00 00 : 00 f +08 101 push : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 int : e 00 02 : 0c 0 +0d 0a0 nop_int : e 00 02 : 0c 0 +03 101 push : f 02 01 : 0c 0 +04 028 return : f 02 01 : 00 f +05 038 outport : e 00 02 : 00 f +0c 109 push : f 02 09 : 00 f +0d 0a0 jumpc : e 00 02 : 00 f +0e 05c 1- : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 push : f 01 09 : 00 f +0d 0a0 jumpc : e 00 01 : 00 f +0e 05c 1- : e 00 00 : 00 f +09 115 push : f 00 15 : 00 f +0a 0e0 callc : e 00 00 : 00 f +0b 000 nop : e 00 00 : 00 f +0c 109 push : f 00 09 : 00 f +0d 0a0 jumpc : e 00 00 : 00 f +0e 05c 1- : e 00 ff : 00 f +0f 054 drop : d 00 00 : 00 f +10 100 push : e 00 00 : 00 f +11 038 outport : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-11 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-11 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-11 (revision 12) @@ -0,0 +1,51 @@ +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 106 push : e 00 06 : 00 f +01 080 jump : d 00 00 : 00 f +02 000 nop : d 00 00 : 00 f +06 101 push : e 00 01 : 00 f +07 038 outport : d 00 00 : 00 f +08 101 push : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 int : e 00 02 : 0c 0 +0d 0a0 nop_int : e 00 02 : 0c 0 +03 101 push : f 02 01 : 0c 0 +04 028 return : f 02 01 : 00 f +05 038 outport : e 00 02 : 00 f +0c 109 push : f 02 09 : 00 f +0d 0a0 jumpc : e 00 02 : 00 f +0e 05c 1- : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 push : f 01 09 : 00 f +0d 0a0 jumpc : e 00 01 : 00 f +0e 05c 1- : e 00 00 : 00 f +09 115 push : f 00 15 : 00 f +0a 0e0 callc : e 00 00 : 00 f +0b 000 nop : e 00 00 : 00 f +0c 109 push : f 00 09 : 00 f +0d 0a0 jumpc : e 00 00 : 00 f +0e 05c 1- : e 00 ff : 00 f +0f 054 drop : d 00 00 : 00 f +10 100 push : e 00 00 : 00 f +11 038 outport : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-22 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-22 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-22 (revision 12) @@ -0,0 +1,51 @@ +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 106 push : e 00 06 : 00 f +01 080 jump : d 00 00 : 00 f +02 000 nop : d 00 00 : 00 f +06 101 push : e 00 01 : 00 f +07 038 outport : d 00 00 : 00 f +08 101 push : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 push : f 01 09 : 00 f +0d 0a0 jumpc : e 00 01 : 00 f +0e 05c 1- : e 00 00 : 00 f +09 115 push : f 00 15 : 00 f +0a 0e0 callc : e 00 00 : 00 f +0b 000 nop : e 00 00 : 00 f +0c 109 push : f 00 09 : 00 f +0d 0a0 jumpc : e 00 00 : 00 f +0e 05c 1- : e 00 ff : 00 f +0f 054 drop : d 00 00 : 00 f +10 100 push : e 00 00 : 00 f +11 038 int : e 00 00 : 11 0 +12 112 nop_int : e 00 00 : 11 0 +03 101 push : f 00 01 : 11 0 +04 028 return : f 00 01 : 00 f +05 038 outport : e 00 00 : 00 f +11 038 outport : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-13 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-13 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-13 (revision 12) @@ -0,0 +1,51 @@ +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 106 push : e 00 06 : 00 f +01 080 jump : d 00 00 : 00 f +02 000 nop : d 00 00 : 00 f +06 101 push : e 00 01 : 00 f +07 038 outport : d 00 00 : 00 f +08 101 push : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 push : f 01 09 : 00 f +0d 0a0 jumpc : e 00 01 : 00 f +0e 05c 1- : e 00 00 : 00 f +09 115 int : e 00 00 : 09 0 +0a 0e0 nop_int : e 00 00 : 09 0 +03 101 push : f 00 01 : 09 0 +04 028 return : f 00 01 : 00 f +05 038 outport : e 00 00 : 00 f +09 115 push : f 00 15 : 00 f +0a 0e0 callc : e 00 00 : 00 f +0b 000 nop : e 00 00 : 00 f +0c 109 push : f 00 09 : 00 f +0d 0a0 jumpc : e 00 00 : 00 f +0e 05c 1- : e 00 ff : 00 f +0f 054 drop : d 00 00 : 00 f +10 100 push : e 00 00 : 00 f +11 038 outport : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-14 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-14 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-14 (revision 12) @@ -0,0 +1,51 @@ +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 106 push : e 00 06 : 00 f +01 080 jump : d 00 00 : 00 f +02 000 nop : d 00 00 : 00 f +06 101 push : e 00 01 : 00 f +07 038 outport : d 00 00 : 00 f +08 101 push : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 push : f 01 09 : 00 f +0d 0a0 jumpc : e 00 01 : 00 f +0e 05c 1- : e 00 00 : 00 f +09 115 int : e 00 00 : 09 0 +0a 0e0 nop_int : e 00 00 : 09 0 +03 101 push : f 00 01 : 09 0 +04 028 return : f 00 01 : 00 f +05 038 outport : e 00 00 : 00 f +09 115 push : f 00 15 : 00 f +0a 0e0 callc : e 00 00 : 00 f +0b 000 nop : e 00 00 : 00 f +0c 109 push : f 00 09 : 00 f +0d 0a0 jumpc : e 00 00 : 00 f +0e 05c 1- : e 00 ff : 00 f +0f 054 drop : d 00 00 : 00 f +10 100 push : e 00 00 : 00 f +11 038 outport : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f Index: ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-23 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-23 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/interrupt/tb.good-23 (revision 12) @@ -0,0 +1,51 @@ +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 000 nop : d 00 00 : 00 f +00 106 push : e 00 06 : 00 f +01 080 jump : d 00 00 : 00 f +02 000 nop : d 00 00 : 00 f +06 101 push : e 00 01 : 00 f +07 038 outport : d 00 00 : 00 f +08 101 push : e 00 01 : 00 f +09 115 push : f 01 15 : 00 f +0a 0e0 callc : e 00 01 : 0c 0 +0b 000 nop : e 00 01 : 0c 0 +15 028 return : e 00 01 : 00 f +16 000 nop : e 00 01 : 00 f +0c 109 push : f 01 09 : 00 f +0d 0a0 jumpc : e 00 01 : 00 f +0e 05c 1- : e 00 00 : 00 f +09 115 push : f 00 15 : 00 f +0a 0e0 callc : e 00 00 : 00 f +0b 000 nop : e 00 00 : 00 f +0c 109 push : f 00 09 : 00 f +0d 0a0 jumpc : e 00 00 : 00 f +0e 05c 1- : e 00 ff : 00 f +0f 054 drop : d 00 00 : 00 f +10 100 push : e 00 00 : 00 f +11 038 outport : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f +14 000 nop : d 00 00 : 00 f +12 112 push : e 00 12 : 00 f +13 080 jump : d 00 00 : 00 f Index: ssbcc/trunk/core/9x8/peripherals/tb/outFIFO_async/tb_outFIFO_async.9x8 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/outFIFO_async/tb_outFIFO_async.9x8 (revision 11) +++ ssbcc/trunk/core/9x8/peripherals/tb/outFIFO_async/tb_outFIFO_async.9x8 (revision 12) @@ -16,11 +16,9 @@ data_empty=o_data_empty \ outport=O_DATA \ infull=I_FULL \ - depth=32 + depth=32 \ + outempty=I_EMPTY -PORTCOMMENT feed-back empty condition -INPORT 1-bit i_empty I_EMPTY - PORTCOMMENT termination signal OUTPORT 1-bit o_done O_DONE
/ssbcc/trunk/core/9x8/peripherals/tb/outFIFO_async/tb.v
43,7 → 43,6
wire s_done;
 
wire s_diag_rd = ~s_empty && s_readout_en;
reg s_empty_clk = 1'b0;
 
tb_outFIFO_async uut(
// synchronous reset and processor clock
54,15 → 53,10
.o_data (s_diag),
.i_data_rd (s_diag_rd),
.o_data_empty (s_empty),
// feed-back empty condition
.i_empty (s_empty_clk),
// termination signal
.o_done (s_done)
);
 
always @ (posedge s_clk)
s_empty_clk <= s_empty;
 
// validation output
always @ (posedge s_fast_clk)
if (s_diag_rd)
/ssbcc/trunk/core/9x8/peripherals/trace.py
1,6 → 1,6
################################################################################
#
# Copyright 2012-2013, Sinclair R.F., Inc.
# Copyright 2012-2015, Sinclair R.F., Inc.
#
################################################################################
 
45,6 → 45,8
reg [C_PC_WIDTH-1:0] s__PC_s[1:0];
reg [8:0] s__opcode_s = 9'h000;
reg [7*8-1:0] s__opcode_name;
reg s__interrupt_s = 1'b0;
reg s__interrupted_s = 1'b0;
initial begin
s__PC_s[0] = {(C_PC_WIDTH){1'b0}};
s__PC_s[1] = {(C_PC_WIDTH){1'b0}};
52,10 → 54,15
always @ (posedge i_clk) begin
s__PC_s[0] <= s_PC;
s__PC_s[1] <= s__PC_s[0];
s__interrupt_s <= s_interrupt;
s__interrupted_s <= s_interrupted;
s__opcode_s <= s_opcode;
display_trace({ s__PC_s[1], s__opcode_s, s_Np_stack_ptr, 1'b1, s_N, 1'b1, s_T, 1'b1, s_R, s_R_stack_ptr });
display_trace({ s__interrupt_s, s__interrupted_s, s__PC_s[1], s__opcode_s, s_Np_stack_ptr, 1'b1, s_N, 1'b1, s_T, 1'b1, s_R, s_R_stack_ptr });
end
endgenerate
""";
if not config.InterruptVector():
for replace in ('s_interrupt','s_interrupted',):
body = re.sub(replace+';','1\'b0;',body);
body = re.sub(r'\bs__','s__trace__',body);
fp.write(body);
/ssbcc/trunk/core/9x8/peripherals/interrupt.v
0,0 → 1,50
//
// PERIPHERAL interrupt
// Copyright 2015, Sinclair R.F., Inc.
//
reg s_in_jump = 1'b0;
always @ (posedge i_clk)
if (i_rst)
s_in_jump <= 1'b0;
else
s_in_jump <= (s_bus_pc == C_BUS_PC_JUMP) || (s_bus_pc == C_BUS_PC_RETURN);
wire @WIDTH@ s_interrupt_raw = ( @INVERT@ ^ @INSIGNAL@ ) & @MASK@;
reg @WIDTH@ s_interrupt_raw_s = @INVERT@;
always @ (posedge i_clk)
if (i_rst)
s_interrupt_raw_s <= @INVERT@;
else
s_interrupt_raw_s <= s_interrupt_raw;
wire @WIDTH@ s_interrupt_trigger_raw = s_interrupt_raw & ~s_interrupt_raw_s;
reg s_interrupt_trigger_any = 1'b0;
always @ (posedge i_clk)
if (i_rst) begin
s_interrupt_trigger <= @ZERO@;
s_interrupt_trigger_any <= 1'b0;
end else if (@CLEAR_TRIGGER@) begin
s_interrupt_trigger <= s_interrupt_trigger_raw;
s_interrupt_trigger_any <= |s_interrupt_trigger_raw;
end else begin
s_interrupt_trigger <= s_interrupt_trigger | s_interrupt_trigger_raw;
s_interrupt_trigger_any <= s_interrupt_trigger_any || (|s_interrupt_trigger_raw);
end
reg s_interrupt_ena;
always @ (*)
s_interrupt = s_interrupt_ena && s_interrupt_trigger_any && ~s_in_jump;
always @ (posedge i_clk)
if (i_rst)
s_interrupted <= 1'b0;
else
s_interrupted <= s_interrupt;
initial s_interrupt_ena = 1'b0;
always @ (posedge i_clk)
if (i_rst)
s_interrupt_ena <= 1'b0;
else if (s_interrupt)
s_interrupt_ena <= 1'b0;
else if (s_outport && (s_T == @IX_OUTPORT_ENA@))
s_interrupt_ena <= 1'b1;
else if (s_outport && (s_T == @IX_OUTPORT_DIS@))
s_interrupt_ena <= 1'b0;
else
s_interrupt_ena <= s_interrupt_ena;
ssbcc/trunk/core/9x8/peripherals/interrupt.v Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/UART.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/UART.py (revision 11) +++ ssbcc/trunk/core/9x8/peripherals/UART.py (revision 12) @@ -179,7 +179,12 @@ Use the following assembly code to transmit the message "Hello World!". This transmits the entire message whether or not the peripheral has a FIFO.\n N"Hello World!\\r\\n" - :loop .outport(O_UART_TX) :wait .inport(I_UART_TX_BUSY) .jumpc(wait) .jumpc(loop,nop) drop + :loop .outport(O_UART_TX) :wait .inport(I_UART_TX_BUSY) .jumpc(wait) .jumpc(loop,nop) drop\n + Interrupt handler: "!s____TX_uart_busy" is is suitable input to + an interrupt handler where "" is the name assigned to "outsignal". + This signal is low when the peripheral is not transmitting data and there is + no output FIFO and can be used as an indication that the peripheral is ready + for a new byte to transmit. """ def __init__(self,peripheralFile,config,param_list,loc):
/ssbcc/trunk/core/9x8/peripherals/outFIFO_async.v
72,4 → 72,5
s__delta_clk <= s__ix_in - s__ix_out_clk;
always @ (posedge i_clk)
s__full <= &s__delta_clk[@DEPTH_NBITS-1@:2];
@OUTEMPTY@
endgenerate
/ssbcc/trunk/core/9x8/peripherals/UART_Tx.py
105,7 → 105,12
Use the following assembly code to transmit the message "Hello World!".
This transmits the entire message whether or not the peripheral has a FIFO.\n
N"Hello World!\\r\\n"
:loop .outport(O_UART_TX) :wait .inport(I_UART_TX_BUSY) .jumpc(wait) .jumpc(loop,nop) drop
:loop .outport(O_UART_TX) :wait .inport(I_UART_TX_BUSY) .jumpc(wait) .jumpc(loop,nop) drop\n
Interrupt handler: "!s__<outsignal>__TX_uart_busy" is is suitable input to
an interrupt handler where "<outsignal>" is the name assigned to "outsignal".
This signal is low when the peripheral is not transmitting data and there is
no output FIFO and can be used as an indication that the peripheral is ready
for a new byte to transmit.
"""
 
def __init__(self,peripheralFile,config,param_list,loc):
/ssbcc/trunk/ssbccConfig.py
1,10 → 1,5
################################################################################
#
# Copyright 2012-2013, Sinclair R.F., Inc.
#
# Utilities required by ssbcc
#
################################################################################
# Copyright 2012-2015, Sinclair R.F., Inc.
# Utilities required by ssbcc.
 
import math
import os
11,6 → 6,7
import re
import sys
 
from ssbccPeripheral import SSBCCinterruptPeripheral
from ssbccUtil import *
 
class SSBCCconfig():
63,7 → 59,7
self.AddSymbol(name,loc);
if name in self.constants:
raise SSBCCException('CONSTANT "%s" already declared at %s' % (name,loc,));
if not IsIntExpr(value):
if not ((type(value) == int) or IsIntExpr(value)):
raise SSBCCException('Could not evaluate expression "%s" for constant at %s' % (value,loc,));
self.constants[name] = ParseIntExpr(value);
 
122,7 → 118,7
Add an OUTPORT symbol to the processor.\n
port tuple as follows:
port[0] - name of the OUTPORT symbol
port[1] - True if the outport is a strobe-only outport, false
port[1] - True if the outport is a strobe-only outport, False
otherwise
port[2:] - zero or more tuples as follows:
(o_signal,width,type,[initialization],)
334,6 → 330,21
"""
self.peripheralpaths.insert(-1,path);
 
def InterruptVector(self):
"""
Indicate whether or not interrupts have been enabled and, if so, what the
interrupt address is.\n
Note: The interrupt address cannot be zero because .main starts at address
0 and it must have a non-empty body.\n
Note: Returning "None" when there is not interrupt address ensures both a
"False" evaluation and that the value cannot be turned into an
integer for an address.
"""
if not self.Exists('interruptAddress'):
return None;
else:
return self.Get('interruptAddress');
 
def IsCombined(self,name):
"""
Indicate whether or not the specified memory type has already been listed
/ssbcc/trunk/example/interrupt/tb.gtkw
0,0 → 1,49
[*]
[*] GTKWave Analyzer v3.3.34 (w)1999-2012 BSI
[*] Sat Jun 20 01:50:44 2015
[*]
[dumpfile] "/home/rsinclair/Projects/ssbcc-interrupt/example/interrupt/tb.vcd"
[dumpfile_mtime] "Sat Jun 20 01:39:12 2015"
[dumpfile_size] 2501556
[savefile] "/home/rsinclair/Projects/ssbcc-interrupt/example/interrupt/tb.gtkw"
[timestart] 0
[size] 959 576
[pos] -1 -1
*-26.975466 8500000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] tb.
[treeopen] tb.uut.
[sst_width] 43
[signals_width] 218
[sst_expanded] 0
[sst_vpaned_height] 151
@28
tb.s_rst
tb.s_clk
tb.s_interrupt
tb.s_UART_Tx
tb.uut.s__o_uart_tx__Tx_busy
@200
-
@28
tb.uut.s_interrupt
@22
>200000
tb.uut.s_PC[9:0]
>100000
tb.uut.s_opcode[8:0]
@820
>0
tb.uut.s_opcode_name[23:0]
@22
tb.uut.s_R_stack_ptr[3:0]
tb.uut.s_R[9:0]
tb.uut.s_T[7:0]
tb.uut.s_N[7:0]
tb.uut.s_Np_stack_ptr[3:0]
@29
tb.uut.s_interrupt_ena
@28
tb.uut.s_interrupt_mask[1:0]
tb.uut.s_interrupt_raw[1:0]
[pattern_trace] 1
[pattern_trace] 0
/ssbcc/trunk/example/interrupt/dual_interrupt.s
0,0 → 1,53
; Copyright 2015, Sinclair R.F., Inc.
; demonstrate dual interrupt peripheral
 
.memory ROM myrom
.variable msg N"INT\n"
 
.memory RAM myram
.variable ixMsg 0
 
.main
; Mask all but the external interrupt and then enable interrupts.
C_INTERRUPT .outport(O_INTERRUPT_MASK)
.ena
 
; Sit in an infinite loop while the interrupt handler does everything else.
:infinite .jump(infinite)
 
.interrupt
; Get the interrupt event(s).
; ( - u_int )
.inport(I_INTERRUPT)
 
; Test for the external interrupt.
; ( u_int - u_int )
dup C_INTERRUPT & 0= .jumpc(not_external)
; Set the index into the output message.
msg .storevalue(ixMsg)
; Enable the UART_Tx interrupt.
.inport(I_INTERRUPT_MASK) C_UART_TX_INTERRUPT or .outport(O_INTERRUPT_MASK)
:not_external
 
; Test for the UART_Tx not_busy interrupt.
; ( u_int - u_int )
dup C_UART_TX_INTERRUPT & 0= .jumpc(not_uart)
; Get the next character to transmit and move the pointer to the next
; character.
; ( - u_char )
.fetchvalue(ixMsg) .fetch+(myrom) .storevalue(ixMsg)
; If the character is a terminating null character then discard it and
; disable this part of the interrupt, otherwise output it.
.jumpc(not_null,nop)
; ( u_char - )
drop
.inport(I_INTERRUPT_MASK) ${~C_UART_TX_INTERRUPT} & .outport(O_INTERRUPT_MASK)
.jump(not_uart)
:not_null
; ( u_char - )
.outport(O_UART_TX)
:not_uart
 
; Drop the interrupt event from the data stack and return from the interrupt.
; ( u_int - )
drop .returni
/ssbcc/trunk/example/interrupt/run
0,0 → 1,11
#!/bin/bash
# Copyright 2015, Sinclair R.F., Inc.
 
NAME=dual_interrupt
 
../../ssbcc -q --display-opcode -P monitor_stack ${NAME}.9x8 \
|| { echo "${NAME} compile failed" > /dev/stderr; exit 1; }
 
iverilog -o tb tb.v ${NAME}.v \
|| { echo "${NAME} build failed" > /dev/stderr; exit 1; }
./tb
ssbcc/trunk/example/interrupt/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ssbcc/trunk/example/interrupt/.gitignore =================================================================== --- ssbcc/trunk/example/interrupt/.gitignore (nonexistent) +++ ssbcc/trunk/example/interrupt/.gitignore (revision 12) @@ -0,0 +1,3 @@ +*.mem +*_pkg.vhd +dual_interrupt.v Index: ssbcc/trunk/example/interrupt/dual_interrupt.9x8 =================================================================== --- ssbcc/trunk/example/interrupt/dual_interrupt.9x8 (nonexistent) +++ ssbcc/trunk/example/interrupt/dual_interrupt.9x8 (revision 12) @@ -0,0 +1,29 @@ +# Copyright 2015, Sinclair R.F., Inc. +# Demonstrate dual interrupt peripheral. + +ARCHITECTURE core/9x8 Verilog +ASSEMBLY dual_interrupt.s + +INSTRUCTION 1024 +DATA_STACK 16 +RETURN_STACK 16 +MEMORY ROM myrom 16 +MEMORY RAM myram 16 + +CONSTANT C_CLOCK_HZ 10_000_000 +CONSTANT C_UART_BAUD 119_200 + +PORTCOMMENT transmit-only UART +PERIPHERAL UART_Tx outport=O_UART_TX \ + outstatus=I_UART_TX_BUSY \ + baudmethod=C_CLOCK_HZ/C_UART_BAUD \ + outsignal=o_uart_tx \ + noOutFIFO + +PORTCOMMENT interrupts +PERIPHERAL interrupt insignal0=i_interrupt,C_INTERRUPT \ + insignal1=!s__o_uart_tx__Tx_uart_busy,C_UART_TX_INTERRUPT \ + inport=I_INTERRUPT \ + outmaskport=O_INTERRUPT_MASK \ + inmaskport=I_INTERRUPT_MASK \ + initmask=2'b01 Index: ssbcc/trunk/example/interrupt/tb.v =================================================================== --- ssbcc/trunk/example/interrupt/tb.v (nonexistent) +++ ssbcc/trunk/example/interrupt/tb.v (revision 12) @@ -0,0 +1,69 @@ +/******************************************************************************* + * + * Copyright 2015, Sinclair R.F., Inc. + * + * Test bench for two-interrupt peripheral. + * + ******************************************************************************/ + +`timescale 1ns/1ps + +module tb; + +// 10 MHz clock +reg s_clk = 1'b1; +always @ (s_clk) s_clk <= #50 ~s_clk; + +reg s_rst = 1'b1; +initial begin + repeat (5) @ (posedge s_clk); + s_rst <= 1'b0; +end + +reg s_interrupt = 1'b0; +initial begin + repeat (50) @ (posedge s_clk); + s_interrupt = 1'b1; + @ (posedge s_clk) + s_interrupt = 1'b0; +end + +wire s_UART_Tx; +dual_interrupt uut( + // synchronous reset and processor clock + .i_rst (s_rst), + .i_clk (s_clk), + // transmit-only UART + .o_uart_tx (s_UART_Tx), + // interrupts + .i_interrupt (s_interrupt) +); + +localparam baud = 115200; +localparam dt_baud = 1.0e9/baud; +reg [8:0] deser = 9'h1FF; +initial forever begin + @ (negedge s_UART_Tx); + #(dt_baud/2.0); + repeat (9) begin + #dt_baud; + deser = { s_UART_Tx, deser[1+:8] }; + end + if (deser[8] != 1'b1) + $display("%13d : Malformed UART transmition", $time); + else if ((8'h20 <= deser[0+:8]) && (deser[0+:8]<=8'h80)) + $display("%13d : Sent 0x%02H : %c", $time, deser[0+:8], deser[0+:8]); + else + $display("%13d : Sent 0x%02H", $time, deser[0+:8]); + if (deser[0+:8] == 8'h0A) begin + @ (negedge s_clk) + $finish; + end +end + +initial begin + $dumpfile("tb.vcd"); + $dumpvars(); +end + +endmodule
ssbcc/trunk/example/interrupt/tb.v Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: ssbcc/trunk/README =================================================================== --- ssbcc/trunk/README (revision 11) +++ ssbcc/trunk/README (revision 12) @@ -25,6 +25,7 @@ - automatic generation of I/O ports - configurable instruction, data stack, return stack, and memory utilization - extensible set of peripherals (I2C busses, UARTs, AXI4-Lite busses, etc.) +- optional interrupt peripheral and interrupt handler - extensible set of macros - memory initialization file to facilitate code development without rebuilds - simulation diagnostics to facilitate identifying code errors @@ -680,6 +681,38 @@ or a subdirectory named "peripherals". +INTERRUPTS +================================================================================ + +Interrupts are enabled by including an interrupt peripheral in the architecture +file and an interrupt handler in the assembly code. + +Incorporating an interrupt adds the following output ports as strobes: + + O_INTERRUPT_DIS disable interrupts + O_INTERRUPT_ENA enable interrupts + +and the following 3 macros + + .dis disable interrupts + Note: This is equivalent to .outstrobe(O_INTERRUPT_DIS) + .ena enable interrupts + Note: This is equivalent to .outstrobe(O_INTERRUPT_ENA) + .returni return from interrupt handler and enable interrupts + Note: This is equivalent to the 3 instruction sequence + "O_INTERRUPT_ENA return outport" + Note: The assembler prohibits the ".return" macro in the + interrupt handler and the ".returni" macro anywhere other + than the interrupt handler. + +See examples/interrupt for a demonstration of an interrupt handler for two +events, one external to the processor and one internal to the processor. + +The interrupt handler included in core/9x8/peripherals handles one to eight +interrupt sources. See core/9x8/doc/interrupt.html for instructions on creating +custom interrupt peripherals, possibly with more interrupt sources. + + PARAMETER and LOCALPARAM ================================================================================
/ssbcc/trunk/ssbcc
1,12 → 1,7
#!/usr/bin/python2.7
 
################################################################################
#
# Copyright 2012, Sinclair R.F., Inc.
#
# Copyright 2012-2015, Sinclair R.F., Inc.
# Build an SSBCC system.
#
################################################################################
 
import math
import os
16,6 → 11,7
 
from ssbccUtil import *;
from ssbccConfig import SSBCCconfig;
from ssbccPeripheral import InterruptPeripheralAssigned;
 
################################################################################
#
78,7 → 74,7
if argList.D:
for name in argList.D:
if not re.match('D_',name):
raise SSBCCException('Bad define name "%s" should start with "D_"' % name);
raise SSBCCException('Argument "%s" to %s should start with "D_"' % (name,sys.argv[0],));
config.AddDefine(name);
 
if argList.I:
385,6 → 381,8
cmd += ' --help-macro %s' % argList.help_macro
if argList.list_macros:
cmd += ' --list-macros'
if InterruptPeripheralAssigned():
cmd += ' -i';
for name in config.constants:
cmd += (' -C %s=%s' % (name,config.constants[name],));
for name in config.defines:
456,10 → 454,8
elif re.match(':program',line):
cmd = re.findall(':program (\d+) (\S+) (\d+)',line);
mainStart = int(cmd[0][0]);
if cmd[0][1] == '[]':
interruptStart = -1;
else:
interruptStart = int(cmd[0][1]);
if cmd[0][1] != '[]':
config.Set('interruptAddress',int(cmd[0][1]));
mainLength = int(cmd[0][2]);
for line in fpAssemberOutput:
ixLine = ixLine + 1;
484,6 → 480,13
#
################################################################################
 
# Ensure consistent implementation of an interrupt peripheral and an interrupt
# handler in the source assembly.
if InterruptPeripheralAssigned() and not config.InterruptVector():
raise SSBCCException('Interrupt peripheral defined but no .interrupt function defined');
if config.InterruptVector() and not InterruptPeripheralAssigned():
raise ssbccPeripheral('.interrupt function defined but no interrupt peripheral defined');
 
# Ensure all memories are used.
for ixMem in range(config.NMemories()):
memParam = config.GetMemoryParameters(ixMem);
536,24 → 539,9
fpOutCore.write(line);
continue;
fillCommand = re.findall(r'..@SSBCC@\s+(\S+)',line)[0];
# functions and tasks
if fillCommand == "functions":
genFunctions(fpOutCore,config);
# inports
elif fillCommand == 'inports':
genInports(fpOutCore,config);
# localparam
elif fillCommand == 'localparam':
genLocalParam(fpOutCore,config);
# memories
elif fillCommand == 'memories':
if fillCommand == 'memories':
genMemories(fpOutCore,fpMemFile,config,programBody);
# module
elif fillCommand == 'module':
genModule(fpOutCore,config);
# outports
elif fillCommand == 'outports':
genOutports(fpOutCore,config);
# peripherals
elif fillCommand == 'peripherals':
if not config.peripheral:
568,9 → 556,6
fpOutCore.write('wire [7:0] s_memory = 8\'h00;\n');
else:
fpOutCore.write('wire [7:0] s_memory;\n');
# additional signals
elif fillCommand == 'signals':
genSignals(fpOutCore,config);
# user_header
elif fillCommand == 'user_header':
genUserHeader(fpOutCore,user_header);
580,9 → 565,9
fpOutCore.write('/* verilator tracing_on */\n');
else:
fpOutCore.write('/* verilator tracing_off */\n');
# error
# All others are specific to the core.
else:
print 'WARNING: Unimplemented command ' + fillCommand;
doFillCommand(fillCommand,fpOutCore,config);
 
#
# Write package file (for use in VHDL or mixed-language projects)

powered by: WebSVN 2.1.0

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