URL
https://opencores.org/ocsvn/ssbcc/ssbcc/trunk
Subversion Repositories ssbcc
Compare Revisions
- This comparison shows the changes necessary to convert path
/ssbcc
- from Rev 11 to Rev 12
- ↔ Reverse comparison
Rev 11 → Rev 12
/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; |
/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. |
/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? |
/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 |
/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"; |
/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) interrupts are enabled, (2) an interrupt edge has occurred |
(and not be precluded by the interrupt mask, if any), and (3) 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 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 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 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 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) interrupts |
are enabled, (2) a rising edge has occured, and (3) interrupts are |
not disabled because the instruction pipeline is in the middle of a jump, |
call, or return.<br/><br/> |
A 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 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> .interrupt<br/></tt> |
<tt> .fetchvalue(interruptCount) 1+ .storevalue(interruptCount)<br/></tt> |
<tt> .returni<br/></tt><br/> |
If 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> PERIPHERAL interrupt insignal0=i_int0,C_INT0 \<br/></tt> |
<tt> insignal1=i_int1,C_INT1 \<br/></tt> |
<tt> inport=I_INTERRUPT \<br/></tt> |
<tt> ...<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> .interrupt<br/></tt> |
<tt> .inport(I_INTERRUPT)<br/></tt> |
<tt> dup C_INT0 & .callc(int0)<br/></tt> |
<tt> dup C_INT1 & .callc(int1)<br/></tt> |
<tt> drop<br/></tt> |
<tt> .returni<br/></tt><br/> |
</body> |
</html> |
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: trunk/core/9x8/tb/ifdef/run
===================================================================
--- trunk/core/9x8/tb/ifdef/run (revision 11)
+++ 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: trunk/core/9x8/tb/ifdef/uc.9x8
===================================================================
--- trunk/core/9x8/tb/ifdef/uc.9x8 (revision 11)
+++ 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
/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. |
/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 "; |
/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 |
|
/******************************************************************************* |
* |
/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. |
# |
/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 |
/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); |
/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, ), |
/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:]; |
/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 |
/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 |
/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 |
/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 |
/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 |
/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 |
/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 |
/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 |
/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; |
trunk/core/9x8/peripherals/tb/interrupt/run
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/core/9x8/peripherals/tb/interrupt/.gitignore
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/.gitignore (nonexistent)
+++ trunk/core/9x8/peripherals/tb/interrupt/.gitignore (revision 12)
@@ -0,0 +1,3 @@
+tb.out
+tb.sav
+tb_interrupt.v
Index: trunk/core/9x8/peripherals/tb/interrupt/tb_interrupt.9x8
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb_interrupt.9x8 (nonexistent)
+++ 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: trunk/core/9x8/peripherals/tb/interrupt/tb.v
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb.v (nonexistent)
+++ 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
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: trunk/core/9x8/peripherals/tb/interrupt/tb.good-10
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb.good-10 (nonexistent)
+++ 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: trunk/core/9x8/peripherals/tb/interrupt/tb.good-11
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb.good-11 (nonexistent)
+++ 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: trunk/core/9x8/peripherals/tb/interrupt/tb.good-22
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb.good-22 (nonexistent)
+++ 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: trunk/core/9x8/peripherals/tb/interrupt/tb.good-13
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb.good-13 (nonexistent)
+++ 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: trunk/core/9x8/peripherals/tb/interrupt/tb.good-14
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb.good-14 (nonexistent)
+++ 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: trunk/core/9x8/peripherals/tb/interrupt/tb.good-23
===================================================================
--- trunk/core/9x8/peripherals/tb/interrupt/tb.good-23 (nonexistent)
+++ 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: trunk/core/9x8/peripherals/tb/outFIFO_async/tb_outFIFO_async.9x8
===================================================================
--- trunk/core/9x8/peripherals/tb/outFIFO_async/tb_outFIFO_async.9x8 (revision 11)
+++ 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
/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) |
/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); |
/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; |
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: trunk/core/9x8/peripherals/UART.py
===================================================================
--- trunk/core/9x8/peripherals/UART.py (revision 11)
+++ 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):
/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 |
/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): |
/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 |
/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 |
/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 |
/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 |
trunk/example/interrupt/run
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/example/interrupt/.gitignore
===================================================================
--- trunk/example/interrupt/.gitignore (nonexistent)
+++ trunk/example/interrupt/.gitignore (revision 12)
@@ -0,0 +1,3 @@
+*.mem
+*_pkg.vhd
+dual_interrupt.v
Index: trunk/example/interrupt/dual_interrupt.9x8
===================================================================
--- trunk/example/interrupt/dual_interrupt.9x8 (nonexistent)
+++ 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: trunk/example/interrupt/tb.v
===================================================================
--- trunk/example/interrupt/tb.v (nonexistent)
+++ 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
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: trunk/README
===================================================================
--- trunk/README (revision 11)
+++ 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
================================================================================
/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) |