URL
https://opencores.org/ocsvn/ssbcc/ssbcc/trunk
Subversion Repositories ssbcc
Compare Revisions
- This comparison shows the changes necessary to convert path
/ssbcc/trunk/core/9x8
- from Rev 2 to Rev 3
- ↔ Reverse comparison
Rev 2 → Rev 3
/asm
47,6 → 47,7
argListParser.add_argument('-G', metavar='parametername', action='append', help='parameter names'); |
argListParser.add_argument('-I', metavar='PORT=index', action='append', help='Input port names'); |
argListParser.add_argument('-L', metavar='librarypath', action='append', help='Library search path'); |
argListParser.add_argument('-M', metavar='macropath', action='append', help='Macro search path'); |
argListParser.add_argument('-O', metavar='PORT=index', action='append', help='Output port names'); |
argListParser.add_argument('-R', metavar='PORT=index', action='append', help='Strobe-only output port names'); |
argListParser.add_argument('-S', metavar='MEMORY=length', action='append', help='Memory length'); |
140,10 → 141,17
|
# Construct the iterator that loops through the code bodies. |
fbi = asmDef.FileBodyIterator(argList.filename,ad); |
|
# Add paths for the ".include" directive. |
if argList.L: |
for path in argList.L: |
fbi.AddSearchPath(path); |
|
# Add paths for the ".macro" directive. |
if argList.M: |
for path in argList.M: |
ad.AddMacroSearchPath(path); |
|
################################################################################ |
# |
# Stage 1: Parse the files. |
/macros/storevalue.py
0,0 → 1,31
# Copyright 2014, Sinclair R.F., Inc. |
|
def storevalue(ad): |
""" |
Built-in macro to store the top of the data stack in the specified |
variable.\n |
<v> .storevalue(variable[,op]) |
where: |
<v> is the value to be stored from the next-to-top of the data |
stack |
variable is the name of the variable |
op is an optional instruction to override the default "drop" |
instruction at the end of the instruction sequence\n |
The effect is: variable = v\n |
( u_value - ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.storevalue', 3, [ |
['','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
name = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(name); |
ad.EmitPush(fp,addr,ad.Emit_String(name),argument[0]['loc']); |
ad.EmitOpcode(fp,ad.specialInstructions['store'] | ixBank,'store '+bankName); |
ad.EmitOptArg(fp,argument[1]); |
ad.EmitFunction['.storevalue'] = emitFunction; |
/macros/fetchindexed.py
0,0 → 1,26
# Copyright 2014, Sinclair R.F., Inc. |
|
def fetchindexed(ad): |
""" |
Built-in macro to the N'th byte from a variable where N is specified by the |
top of the data stack.\n |
Usage: |
<N> .fetchindexed(variable) |
where |
<N> represents a value of the top of the data stack |
variable is a variable\n |
The effect is: T = variable[n]\n |
( u_offset - u_mem ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.fetchindexed', 3, [ ['','symbol'] ]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
variableName = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(variableName); |
ad.EmitPush(fp,addr,ad.Emit_String(variableName),argument[0]['loc']); |
ad.EmitOpcode(fp,ad.InstructionOpcode('+'),'+'); |
ad.EmitOpcode(fp,ad.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
ad.EmitFunction['.fetchindexed'] = emitFunction; |
/macros/inport.py
0,0 → 1,25
# Copyright 2014, Sinclair R.F., Inc. |
|
def inport(ad): |
""" |
Built-in macro to read the specified input port and save the value on the |
top of the data stack.\n |
Usage: |
.inport(I_name) |
where |
I_name is the name of the input port.\n |
The effect is: T = <value from the specified input port>\n |
( - u ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.inport', 2, [ ['','symbol'] ]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
if not ad.IsInport(argument[0]['value']): |
raise asmDef.AsmException('Symbol "%s is not an input port at %s' % (argument[0]['value'],argument[0]['loc'])); |
name = argument[0]['value']; |
ad.EmitPush(fp,ad.InportAddress(name) & 0xFF,name); |
ad.EmitOpcode(fp,ad.InstructionOpcode('inport'),'inport'); |
ad.EmitFunction['.inport'] = emitFunction; |
/macros/fetchvector.py
0,0 → 1,36
# Copyright 2014, Sinclair R.F., Inc. |
|
def fetchvector(ad): |
""" |
Built-in macro to move multiple bytes from memory to the data stack. The byte |
at the specified memory address is stored at the top of the data stack with |
subsequent bytes store below it.\n |
Usage: |
.fetchvector(variable,N) |
where |
variable is the name of a variable |
N is the constant number of bytes to transfer\n |
The effect is to push the values u_LSB=variable[N-1], ..., u_msb=variable[0] |
onto the data stack.\n |
( - u_LSB ... u_MSB ) |
""" |
|
def length(ad,argument): |
return int(argument[1]['value']) + 1; |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.fetchvector', length, [ |
['','symbol'], |
['','singlevalue','symbol'] |
]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
variableName = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(variableName); |
N = int(argument[1]['value']); |
ad.EmitPush(fp,addr+N-1,'%s+%d' % (variableName,N-1)); |
for dummy in range(N-1): |
ad.EmitOpcode(fp,ad.specialInstructions['fetch-'] | ixBank,'fetch- '+bankName); |
ad.EmitOpcode(fp,ad.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
ad.EmitFunction['.fetchvector'] = emitFunction; |
/macros/outport.py
0,0 → 1,31
# Copyright 2014, Sinclair R.F., Inc. |
|
def outport(ad): |
""" |
Built-in macro to write the top of the data stack to the specified output |
port.\n |
Usage: |
.outport(O_name[,op]) |
where |
O_name is the name of the output port |
op is an optional argument to override the default "drop" |
instruction\n |
The effect is: Write T to the specified output port.\n |
( u - ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.outport', 3, [ |
['','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
outportName = argument[0]['value']; |
if not ad.IsOutport(outportName): |
raise asmDef.AsmException('Symbol "%s" is either not an output port or is a strobe-only outport at %s' % (outportName,argument[0]['loc'])); |
ad.EmitPush(fp,ad.OutportAddress(outportName) & 0xFF,outportName); |
ad.EmitOpcode(fp,ad.InstructionOpcode('outport'),'outport'); |
ad.EmitOptArg(fp,argument[1]); |
ad.EmitFunction['.outport'] = emitFunction; |
/macros/storeindexed.py
0,0 → 1,34
# Copyright 2014, Sinclair R.F., Inc. |
|
def storeindexed(ad): |
""" |
Built-in macro to store the next-to-top of the data stack at the |
offset into variable specified by the top of the data stack.\n |
Usage: |
<v> <ix> .storeindexed(variable[,op]) |
where: |
<v> is the value to be stored from the next-to-top of the data |
stack |
<ix> is the index into the variable |
variable is the name of the variable |
op is an optional instruction to override the default "drop" |
instruction at the end of the instruction sequence\n |
The effect is: variable[ix] = v\n |
( u_value u_ix - ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.storeindexed', 4, [ |
['','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
variableName = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(variableName); |
ad.EmitPush(fp,addr,ad.Emit_String(variableName),argument[0]['loc']); |
ad.EmitOpcode(fp,ad.InstructionOpcode('+'),'+'); |
ad.EmitOpcode(fp,ad.specialInstructions['store'] | ixBank,'store '+bankName); |
ad.EmitOptArg(fp,argument[1]); |
ad.EmitFunction['.storeindexed'] = emitFunction; |
/macros/storevector.py
0,0 → 1,35
# Copyright 2014, Sinclair R.F., Inc. |
|
def storevector(ad): |
""" |
Built-in macro to move multiple bytes from the data stack to memory. The MSB |
(top of the data stack) is store at the specified memory location with |
subsequent bytes stored at subsequent memory locations.\n |
Usage: |
.storevector(variable,N) |
where |
variable is the name of a variable |
N is the constant number of bytes to transfer\n |
The effect is: variable[0]=u_MSB, ..., variable[N-1]=u_LSB\n |
( u_LSB ... u_MSB - ) |
""" |
|
def length(ad,argument): |
return int(argument[1]['value']) + 2; |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.storevector', length, [ |
['','symbol'], |
['','singlevalue','symbol'], |
]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
variableName = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(variableName); |
N = int(argument[1]['value']); |
ad.EmitPush(fp,addr,argument[0]['value']); |
for dummy in range(N): |
ad.EmitOpcode(fp,ad.specialInstructions['store+'] | ixBank,'store+ '+bankName); |
ad.EmitOpcode(fp,ad.InstructionOpcode('drop'),'drop -- .storevector(%s,%d)' % (variableName,N,) ); |
ad.EmitFunction['.storevector'] = emitFunction; |
/macros/fetchoffset.py
0,0 → 1,29
# Copyright 2014, Sinclair R.F., Inc. |
|
def fetchoffset(ad): |
""" |
Built-in macro to copy the value at the specified offset into the specified |
variable to the top of the data stack.\n |
Usage: |
.fetchoffset(variable,ix) |
where |
variable is a variable |
ix is the index into the variable\n |
The effect is: T = variable[ix]\n |
( - u_mem ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.fetchoffset', 2, [ |
['','symbol'], |
['','singlevalue','symbol'] |
]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
name = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(name); |
offset = ad.Emit_EvalSingleValue(argument[1]); |
ad.EmitPush(fp,addr+offset,ad.Emit_String('%s+%s' % (name,offset,)),argument[0]['loc']); |
ad.EmitOpcode(fp,ad.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
ad.EmitFunction['.fetchoffset'] = emitFunction; |
/macros/storeoffset.py
0,0 → 1,34
# Copyright 2014, Sinclair R.F., Inc. |
|
def storeoffset(ad): |
""" |
Built-in macro to store the top of the data stack at the specified offset |
into the specified variable.\n |
Usage: |
<v> .storeoffset(variable,ix[,op]) |
where: |
<v> is the value to be stored |
variable is the name of the variable |
ix is the index into the variable |
op is an optional instruction to override the default "drop" |
instruction at the end of the instruction sequence\n |
The effect is: variable[ix] = v\n |
( v - ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.storeoffset', 3, [ |
['','symbol'], |
['','singlevalue','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
variableName = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(variableName); |
offset = ad.Emit_EvalSingleValue(argument[1]); |
ad.EmitPush(fp,addr+offset,ad.Emit_String('%s+%s' % (variableName,offset,)),argument[0]['loc']); |
ad.EmitOpcode(fp,ad.specialInstructions['store'] | ixBank,'store '+bankName); |
ad.EmitOptArg(fp,argument[2]); |
ad.EmitFunction['.storeoffset'] = emitFunction; |
/macros/fetchvalue.py
0,0 → 1,24
# Copyright 2014, Sinclair R.F., Inc. |
|
def fetchvalue(ad): |
""" |
Built-in macro to copy the value from the specified variable to the top of the |
data stack.\n |
Usage: |
.fetchvalue(variable) |
where |
variable is a variable\n |
The effect is: T = variable\n |
( - u_mem ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.fetchvalue', 2, [ ['','symbol'] ]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
variableName = argument[0]['value']; |
(addr,ixBank,bankName) = ad.Emit_GetAddrAndBank(variableName); |
ad.EmitPush(fp,addr,ad.Emit_String(variableName),argument[0]['loc']); |
ad.EmitOpcode(fp,ad.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
ad.EmitFunction['.fetchvalue'] = emitFunction; |
/macros/outstrobe.py
0,0 → 1,24
# Copyright 2014, Sinclair R.F., Inc. |
|
def outstrobe(ad): |
""" |
Built-in macro to send strobes to the specified strobe-only output port.\n |
Usage: |
.outstrobe(O_name) |
where |
O_name is the name of the output port\n |
The effect is: To active the strobe at the specified output port.\n |
( - ) |
""" |
|
# Add the macro to the list of recognized macros. |
ad.AddMacro('.outstrobe', 2, [ ['','symbol'] ]); |
|
# Define the macro functionality. |
def emitFunction(ad,fp,argument): |
if not ad.IsOutstrobe(argument[0]['value']): |
raise asmDef.AsmException('Symbol "%s" is not a strobe-only output port at %s' % (argument[0]['value'],argument[0]['loc'])); |
name = argument[0]['value']; |
ad.EmitPush(fp,ad.OutportAddress(name) & 0xFF,name); |
ad.EmitOpcode(fp,ad.InstructionOpcode('outport'),'outport'); |
ad.EmitFunction['.outstrobe'] = emitFunction; |
/tb/.gitignore
0,0 → 1,2
*.mem |
*_pkg.vhd |
/asmDef.py
105,8 → 105,6
# Don't open the include file until all previous content has been emitted. |
if self.current: |
return self.current; |
if self.pendingInclude in self.included: |
raise AsmException('File "%s" already included' % self.pendingInclude); |
self.included.append(self.pendingInclude); |
fp_pending = None; |
for path in self.searchPaths: |
352,7 → 350,7
tValue.append(tParseNumber); |
return dict(type='value', value=tValue, loc=flc_loc); |
# look for a single-byte numeric value |
a = re.match(r'(0|[+\-]?[1-9]\d*|0[07]+|0x[0-9A-Fa-f]{1,2})$',raw); |
a = re.match(r'(0|[+\-]?[1-9]\d*|0[07]+|0x[0-9A-Fa-f]+)$',raw); |
if a: |
if 'singlevalue' not in allowed: |
raise AsmException('Value not allowed at %s' % flc_loc); |
/ssbccGenVerilog.py
8,6 → 8,7
|
import math |
import os |
import random |
import re |
|
from ssbccUtil import *; |
187,6 → 188,8
memName = 's_opcodeMemory'; |
else: |
memName = instructionMemNameFormat % ixBlock; |
if config.Get('synth_instr_mem'): |
fp.write('%s ' % config.Get('synth_instr_mem')); |
fp.write('reg [%d:0] %s[%d:0];\n' % (instruction_mem_width-1,memName,instructionMemory['blockSize']-1,)); |
# Declare data stack RAM and return stacks RAM if they aren't combined into other memories. |
for memType in ('DATA_STACK','RETURN_STACK',): |
216,11 → 219,12
if nbits == 9: |
formatp = ' %s[\'h%%0%dX] = { 1\'b1, %%s };' % (memName,instructionAddrWidth,); |
formatn = ' %s[\'h%%0%dX] = 9\'h%%s; // %%s\n' % (memName,instructionAddrWidth,); |
formate = ' %s[\'h%%0%dX] = 9\'h000;\n' % (memName,instructionAddrWidth,); |
formate = ' %s[\'h%%0%dX] = 9\'h%%03x;\n' % (memName,instructionAddrWidth,); |
else: |
formatp = ' %s[\'h%%0%dX] = { %d\'d0, 1\'b1, %%s };' % (memName,instructionAddrWidth,nbits-9,); |
formatn = ' %s[\'h%%0%dX] = { %d\'d0, 9\'h%%s }; // %%s\n' % (memName,instructionAddrWidth,nbits-9,); |
formate = ' %s[\'h%%0%dX] = { %d\'d0, 9\'h000 };\n' % (memName,instructionAddrWidth,nbits-9,); |
formate = ' %s[\'h%%0%dX] = { %d\'d0, 9\'h%%03x };\n' % (memName,instructionAddrWidth,nbits-9,); |
rand_instr_mem = config.Get('rand_instr_mem'); |
for ixMem in range(instructionMemory['blockSize']): |
memAddr = instructionMemory['blockSize']*ixBlock+ixMem; |
if ixRecordedBody < len(programBody): |
241,7 → 245,7
break; |
ixRecordedBody = ixRecordedBody + 1; |
elif ixInstruction < instructionBodyLength: |
fp.write(formate % ixMem); |
fp.write(formate % (ixMem,0 if not rand_instr_mem else random.randint(0,2**9-1),)); |
fpMemFile.write('@%04X 000\n' % memAddr); |
else: |
break; |
527,7 → 531,7
while curOffset < port['packing'][0]['length']: |
addr = port['offset']+port['ratio']*curOffset+packing['lane']+thisRatio; |
thisFill.append({ 'assign':(formate % addr) }); |
thisValue.append('0'); |
thisValue.append(0); |
curOffset += 1; |
else: |
memParam = config.GetMemoryByName(thisMemName); |
546,7 → 550,7
addr = port['offset']+port['ratio']*curOffset+packing['lane']; |
thisFill.append({ 'assign':(formatd % (addr,line[0:2],)) }); |
thisFill[-1]['comment'] = varName if varName else '.'; |
thisValue.append(line[0:2]); |
thisValue.append(int(line[0:2],16)); |
varName = None; |
curOffset += 1; |
if (curOffset > packing['nWords']): |
554,7 → 558,7
while curOffset < packing['length']: |
addr = port['ratio']*curOffset+port['offset']; |
thisFill.append({ 'assign':(formate % addr) }); |
thisValue.append('0'); |
thisValue.append(0); |
curOffset += 1; |
endLength = port['nWords']/port['ratio']; |
for ixFill in range(len(fills)): |
564,12 → 568,12
if curOffset < endLength: |
addr = port['ratio']*curOffset+port['offset']+ixFill; |
thisFill.append({ 'assign':(formate % addr), 'comment':'***' }); |
thisValue.append('0'); |
thisValue.append(0); |
curOffset += 1; |
while curOffset < endLength: |
addr = port['ratio']*curOffset+port['offset']+ixFill; |
thisFill.append({ 'assign':(formate % addr) }); |
thisValue.append('0'); |
thisValue.append(0); |
curOffset += 1; |
for thisFill in fills: |
commentLengths = [len(entry['comment']) for entry in thisFill if 'comment' in entry]; |
/asmDef_9x8.py
1,6 → 1,6
################################################################################ |
# |
# Copyright 2012, Sinclair R.F., Inc. |
# Copyright 2012-2014, Sinclair R.F., Inc. |
# |
# Assembly language definitions for SSBCC 9x8. |
# |
7,7 → 7,11
################################################################################ |
|
import copy |
import os |
import re |
import string |
import sys |
import types |
|
import asmDef |
|
114,6 → 118,36
raise Exception('Program Bug -- Only the last macro argument can be optional'); |
self.macros['nArgs'].append(range(nRequired,len(args)+1)); |
|
def AddMacroSearchPath(self,path): |
self.macroSearchPaths.append(path); |
|
def AddUserMacro(self,macroName,macroSearchPaths=None): |
""" |
Add a user-defined macro by processing the associated Python script. |
macroName name of the macro |
The associated Python script must be named |
<macroName>.py and must be in the project directory, an |
included directory, or must be one of the macros |
provided in "macros" subdirectory of this directory. |
""" |
if not macroSearchPaths: |
macroSearchPaths = self.macroSearchPaths; |
for testPath in macroSearchPaths: |
fullMacro = os.path.join(testPath,'%s.py' % macroName); |
if os.path.isfile(fullMacro): |
break; |
else: |
raise asmDef.AsmException('Definition for macro "%s" not found' % macroName); |
execfile(fullMacro); |
exec('%s(self)' % macroName); |
|
def IsBuiltInMacro(self,name): |
""" |
Indicate if the macro is built-in to the assembler or is taken from the |
./macros directory. |
""" |
return name in self.macros['builtIn']; |
|
def IsMacro(self,name): |
""" |
Indicate whether or not the string "name" is a recognized macro. |
150,21 → 184,18
def MacroLength(self,token): |
""" |
Return the length of fixed-length macros or compute and return the length |
of variable-length macros.\n |
Note: The only variable length macros recognized are fetchvector and |
storevector. |
of variable-length macros. |
""" |
if token['value'] not in self.macros['list']: |
raise Exception('Program Bug -- name "%s" is not a macro' % token['value']); |
ix = self.macros['list'].index(token['value']); |
length = self.macros['length'][ix]; |
if length >= 0: |
if type(length) == int: |
return length; |
if token['value'] == '.fetchvector': |
return int(token['argument'][1]['value']) + 1; |
if token['value'] == '.storevector': |
return int(token['argument'][1]['value']) + 2; |
raise Exception('Program Bug -- Unrecognized variable length macro "%s"' % token['value']); |
elif type(length) == types.FunctionType: |
return length(self,token['argument']); |
else: |
raise Exception('Program Bug -- Unrecognized variable length macro "%s"' % token['value']); |
|
def MacroNumberArgs(self,name): |
""" |
352,6 → 383,8
# Ensure the directive bodies are not too short. |
if (firstToken['value'] in ('.main','.interrupt',)) and not (len(rawTokens) > 1): |
raise asmDef.AsmException('"%s" missing body at %s' % (firstToken['value'],firstToken['loc'],)); |
if (firstToken['value'] in ('.macro',)) and not (len(rawTokens) == 2): |
raise asmDef.AsmException('body for "%s" directive must have exactly one argument at %s' % (firstToken['value'],firstToken['loc'],)); |
if (firstToken['value'] in ('.constant','.function','.memory','.variable',)) and not (len(rawTokens) >= 3): |
raise asmDef.AsmException('body for "%s" directive too short at %s' % (firstToken['value'],firstToken['loc'],)); |
# Ensure the main body ends in a ".jump". |
389,17 → 422,6
labelsUnused = set(labelDefs) - set(labelsUsed); |
if labelsUnused: |
raise asmDef.AsmException('Unused label(s) %s in body %s' % (labelsUnused,firstToken['loc'])); |
# Ensure symbols referenced by ".input", ".outport", and ".outstrobe" are defined. |
for token in rawTokens: |
if (token['type'] == 'macro') and (token['value'] == '.inport'): |
if not self.IsInport(token['argument'][0]['value']): |
raise asmDef.AsmException('Symbol "%s is not an input port at %s' % (token['argument'][0]['value'],token['loc'])); |
if (token['type'] == 'macro') and (token['value'] == '.outport'): |
if not self.IsOutport(token['argument'][0]['value']): |
raise asmDef.AsmException('Symbol "%s" is either not an output port or is a strobe-only outport at %s' % (token['argument'][0]['value'],token['loc'])); |
if (token['type'] == 'macro') and (token['value'] == '.outstrobe'): |
if not self.IsOutstrobe(token['argument'][0]['value']): |
raise asmDef.AsmException('Symbol "%s" is not a strobe-only output port at %s' % (token['argument'][0]['value'],token['loc'])); |
# Ensure referenced symbols are already defined (other than labels and |
# function names for call and jump macros). |
checkBody = False; |
555,6 → 577,7
.function add the function and its body, along with the relative |
addresses, to the list of symbols |
.interrupt record the function body and relative addresses |
.macro register the user-defined macro |
.main record the function body and relative addresses |
.memory record the definition of the memory and make it current |
for subsequent variable definitions. |
581,6 → 604,18
if self.interrupt: |
raise asmDef.AsmException('Second definition of ".interrupt" at %s' % firstToken['loc']); |
self.interrupt = self.ExpandTokens(rawTokens[1:]); |
# Process user-defined macros (the ".macro XXX" directive can be repeated for non-built-in macros). |
elif firstToken['value'] == '.macro': |
macroName = secondToken['value']; |
fullMacroName = '.' + macroName; |
if fullMacroName in self.directives: |
raise asmDef.AsmException('Macro "%s" is a directive at %s' % (fullMacroName,secondToken['loc'],)); |
if fullMacroName in self.instructions: |
raise asmDef.AsmException('Macro "%s" is an instruction at %s' % (fullMacroName,secondToken['loc'],)); |
if self.IsBuiltInMacro(fullMacroName): |
raise asmDef.AsmException('Macro "%s" is a built-in macro at %s' % (fullMacroName,secondToken['loc'],)); |
if fullMacroName not in self.macros['list']: |
self.AddUserMacro(macroName); |
# Process ".main" definition. |
elif firstToken['value'] == '.main': |
if self.main: |
834,7 → 869,8
For the specified variable, return an ordered tuple of the memory address |
within its bank, the corresponding bank index, and the corresponding bank |
name.\n |
Note: This is used for the .fetchvector and .storevector macro generation. |
Note: This is used by several user-defined macros that fetch from or store |
to variables. |
""" |
if not self.IsSymbol(name): |
raise asmDef.AsmException('"%s" is not a recognized symbol' % name); |
849,7 → 885,7
def Emit_GetBank(self,name): |
""" |
For the specified variable, return the memory bank index.\n |
Note: This is used for the .fetch, .fetch+, .fetch-, .store, .store+, and |
Note: This is used by the .fetch, .fetch+, .fetch-, .store, .store+, and |
.store- macros. |
""" |
if name not in self.memories['list']: |
983,7 → 1019,8
|
def EmitMacro(self,fp,token): |
""" |
Write the metacode for a macro. |
Write the metacode for a macro.\n |
The macros coded here are required to access intrinsics. |
""" |
# .call |
if token['value'] == '.call': |
1010,40 → 1047,6
name = token['argument'][0]['value']; |
ixBank = self.Emit_GetBank(name); |
self.EmitOpcode(fp,self.specialInstructions['fetch-'] | ixBank,'fetch-('+name+')'); |
# .fetchindexed |
elif token['value'] == '.fetchindexed': |
name = token['argument'][0]['value']; |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name); |
self.EmitPush(fp,addr,self.Emit_String(name),token['loc']); |
self.EmitOpcode(fp,self.InstructionOpcode('+'),'+'); |
self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
# .fetchoffset |
elif token['value'] == '.fetchoffset': |
name = token['argument'][0]['value']; |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name); |
offset = self.Emit_EvalSingleValue(token['argument'][1]); |
self.EmitPush(fp,addr+offset,self.Emit_String('%s+%s' % (name,offset,)),token['loc']); |
self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
# .fetchvalue |
elif token['value'] == '.fetchvalue': |
name = token['argument'][0]['value']; |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name); |
self.EmitPush(fp,addr,self.Emit_String(name),token['loc']); |
self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
# .fetchvector |
elif token['value'] == '.fetchvector': |
name = token['argument'][0]['value']; |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name); |
N = int(token['argument'][1]['value']); |
self.EmitPush(fp,addr+N-1,'%s+%d' % (name,N-1)); |
for dummy in range(N-1): |
self.EmitOpcode(fp,self.specialInstructions['fetch-'] | ixBank,'fetch- '+bankName); |
self.EmitOpcode(fp,self.specialInstructions['fetch'] | ixBank,'fetch '+bankName); |
# .inport |
elif token['value'] == '.inport': |
name = token['argument'][0]['value']; |
self.EmitPush(fp,self.InportAddress(name) & 0xFF,name); |
self.EmitOpcode(fp,self.InstructionOpcode('inport'),'inport'); |
# .jump |
elif token['value'] == '.jump': |
self.EmitPush(fp,token['address'] & 0xFF,''); |
1054,17 → 1057,6
self.EmitPush(fp,token['address'] & 0xFF,''); |
self.EmitOpcode(fp,self.specialInstructions['jumpc'] | (token['address'] >> 8),'jumpc '+token['argument'][0]['value']); |
self.EmitOptArg(fp,token['argument'][1]); |
# .outport |
elif token['value'] == '.outport': |
name = token['argument'][0]['value']; |
self.EmitPush(fp,self.OutportAddress(name) & 0xFF,name); |
self.EmitOpcode(fp,self.InstructionOpcode('outport'),'outport'); |
self.EmitOptArg(fp,token['argument'][1]); |
# .outstrobe |
elif token['value'] == '.outstrobe': |
name = token['argument'][0]['value']; |
self.EmitPush(fp,self.OutportAddress(name) & 0xFF,name); |
self.EmitOpcode(fp,self.InstructionOpcode('outport'),'outport'); |
# .return |
elif token['value'] == '.return': |
self.EmitOpcode(fp,self.specialInstructions['return'],'return'); |
1084,37 → 1076,9
name = token['argument'][0]['value']; |
ixBank = self.Emit_GetBank(name); |
self.EmitOpcode(fp,self.specialInstructions['store-'] | ixBank,'store- '+name); |
# .storeindexed |
elif token['value'] == '.storeindexed': |
name = token['argument'][0]['value']; |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name); |
self.EmitPush(fp,addr,self.Emit_String(name),token['loc']); |
self.EmitOpcode(fp,self.InstructionOpcode('+'),'+'); |
self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+bankName); |
self.EmitOptArg(fp,token['argument'][1]); |
# .storeoffset |
elif token['value'] == '.storeoffset': |
name = token['argument'][0]['value']; |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name); |
offset = self.Emit_EvalSingleValue(token['argument'][1]); |
self.EmitPush(fp,addr+offset,self.Emit_String('%s+%s' % (name,offset,)),token['loc']); |
self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+bankName); |
self.EmitOptArg(fp,token['argument'][2]); |
# .storevalue |
elif token['value'] == '.storevalue': |
name = token['argument'][0]['value']; |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(name); |
self.EmitPush(fp,addr,self.Emit_String(name),token['loc']); |
self.EmitOpcode(fp,self.specialInstructions['store'] | ixBank,'store '+bankName); |
self.EmitOptArg(fp,token['argument'][1]); |
# .storevector |
elif token['value'] == '.storevector': |
(addr,ixBank,bankName) = self.Emit_GetAddrAndBank(token['argument'][0]['value']); |
N = int(token['argument'][1]['value']); |
self.EmitPush(fp,addr,token['argument'][0]['value']); |
for dummy in range(N): |
self.EmitOpcode(fp,self.specialInstructions['store+'] | ixBank,'store+ '+bankName); |
self.EmitOpcode(fp,self.InstructionOpcode('drop'),'drop'); |
# user-defined macro |
elif token['value'] in self.EmitFunction: |
self.EmitFunction[token['value']](self,fp,token['argument']); |
# error |
else: |
raise Exception('Program Bug -- Unrecognized macro "%s"' % token['value']); |
1213,6 → 1177,22
""" |
|
# |
# Enumerate the directives |
# Note: The ".include" directive is handled within asmDef.FileBodyIterator. |
# |
|
self.directives = dict(); |
|
self.directives['list']= list(); |
self.directives['list'].append('.constant'); |
self.directives['list'].append('.function'); |
self.directives['list'].append('.interrupt'); |
self.directives['list'].append('.macro'); |
self.directives['list'].append('.main'); |
self.directives['list'].append('.memory'); |
self.directives['list'].append('.variable'); |
|
# |
# Configure the instructions. |
# |
|
1263,22 → 1243,6
self.specialInstructions['store-'] = 0x074; |
|
# |
# Enumerate the directives |
# Note: The ".include" directive is handled within asmDef.FileBodyIterator. |
# |
|
self.directives = dict(); |
|
self.directives['list']= list(); |
self.directives['list'].append('.constant'); |
self.directives['list'].append('.function'); |
self.directives['list'].append('.interrupt'); |
self.directives['list'].append('.main'); |
self.directives['list'].append('.memory'); |
self.directives['list'].append('.variable'); |
|
# |
# |
# Configure the pre-defined macros |
# Note: 'symbol' is a catch-call for functions, labels, variables, etc. |
# These are restricted to the appropriate types when the macros are |
1285,7 → 1249,10
# expanded. |
# |
|
self.macros = dict(list=list(), length=list(), args=list(), nArgs=list()); |
self.macros = dict(list=list(), length=list(), args=list(), nArgs=list(), builtIn = list()); |
self.EmitFunction = dict(); |
|
# Macros built in to the assembler (to access primitives). |
self.AddMacro('.call', 3, [ |
['','symbol'], |
['nop','instruction','singlemacro','singlevalue','symbol'] |
1297,17 → 1264,6
self.AddMacro('.fetch', 1, [ ['','symbol'] ]); |
self.AddMacro('.fetch+', 1, [ ['','symbol'] ]); |
self.AddMacro('.fetch-', 1, [ ['','symbol'] ]); |
self.AddMacro('.fetchindexed', 3, [ ['','symbol'] ]); |
self.AddMacro('.fetchoffset', 2, [ |
['','symbol'], |
['','singlevalue','symbol'] |
]); |
self.AddMacro('.fetchvalue', 2, [ ['','symbol'] ]); |
self.AddMacro('.fetchvector', -1, [ |
['','symbol'], |
['','singlevalue','symbol'] |
]); |
self.AddMacro('.inport', 2, [ ['','symbol'] ]); |
self.AddMacro('.jump', 3, [ |
['','symbol'], |
['nop','instruction','singlemacro','singlevalue','symbol'] |
1316,33 → 1272,20
['','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
self.AddMacro('.outport', 3, [ |
['','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
self.AddMacro('.outstrobe', 2, [ ['','symbol'] ]); |
self.AddMacro('.return', 2, [ ['nop','instruction','singlevalue','symbol'] ]); |
self.AddMacro('.store', 1, [ ['','symbol'] ]); |
self.AddMacro('.store+', 1, [ ['','symbol'] ]); |
self.AddMacro('.store-', 1, [ ['','symbol'] ]); |
self.AddMacro('.storeindexed', 4, [ |
['','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
self.AddMacro('.storeoffset', 3, [ |
['','symbol'], |
['','singlevalue','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
self.AddMacro('.storevalue', 3, [ |
['','symbol'], |
['drop','instruction','singlemacro','singlevalue','symbol'] |
]); |
self.AddMacro('.storevector', -1, [ |
['','symbol'], |
['','singlevalue','symbol'], |
]); |
|
# User-defined macros in ./macros that are "built in" to the assembler. |
macroSearchPath = os.path.join(sys.path[0],'macros'); |
for macroName in os.listdir(macroSearchPath): |
if not re.match(r'.*\.py$',macroName): |
continue; |
self.AddUserMacro(macroName[:-3],macroSearchPaths=[macroSearchPath]); |
for macroName in self.macros['list']: |
self.macros['builtIn'].append(macroName); |
|
# |
# List the macros that have special symbols for their first argument. |
# |
1361,7 → 1304,8
# macro, etc. definitions. |
# |
|
self.currentMemory = None; |
self.interrupt = None; |
self.main = None; |
self.macroSearchPaths = ['.','./macros']; |
self.symbols = dict(list=list(), type=list(), body=list()); |
self.currentMemory = None; |
/peripherals/big_inport.py
48,8 → 48,6
""" |
|
def __init__(self,peripheralFile,config,param_list,loc): |
# Use the externally provided file name for the peripheral |
self.peripheralFile = peripheralFile; |
# Get the parameters. |
allowables = ( |
('outlatch', r'O_\w+$', None, ), |
/peripherals/AXI4_Lite_Master.py
17,18 → 17,18
endian format (i.e., the LSB of the 32-bit word is stored in the lowest |
numbered address).\n |
Usage: |
PERIPHERAL AXI4_Lite_Master \\ |
basePortName=<name> \\ |
address=<O_address> \\ |
data=<O_data> \\ |
write_enable=<O_write_enable> \\ |
command_read=<O_command_read> \\ |
command_write=<O_command_write> \\ |
busy=<I_busy> \\ |
error=<I_error> \\ |
read=<I_read> \\ |
address_width=<N> \\ |
synchronous={True|False} |
PERIPHERAL AXI4_Lite_Master \\ |
basePortName=<name> \\ |
address=<O_address> \\ |
data=<O_data> \\ |
command_read=<O_command_read> \\ |
command_write=<O_command_write> \\ |
busy=<I_busy> \\ |
error=<I_error> \\ |
read=<I_read> \\ |
address_width=<N> \\ |
synchronous={True|False} \\ |
write_enable=<O_write_enable>|noWSTRB\n |
Where: |
basePortName=<name> |
specifies the name used to construct the multiple AXI4-Lite signals |
47,8 → 47,6
Note: Four outputs to this address are required, starting with the MSB of |
the 32-bit value, See the examples for illustrations of how this |
works. |
write_enable=<O_write_enable> |
specifies the symbol used to set the 4 write enable bits |
command_read=<O_command_read> |
specifies the symbol used to start the AXI4-Lite master core to issue a |
read and store the received data |
72,6 → 70,17
synchronous={True|False} |
indicates whether or not he micro controller clock and the AXI4-Lite bus |
are synchronous |
write_enable=<O_write_enable> |
optionally specify the symbol used to set the 4 write enable bits |
Note: This must be used if one or more of the slaves includes the |
optional WSTRB signals. |
noWSTRB |
indicates that the optional WSTRB signal should not be included |
Note: This must be specified if write_enable is not specified.\n |
Vivado Users: |
The peripheral creates a TCL script to facilitate turning the micro |
controller into an IP core. Look for a file with the name |
"vivado_<basePortName>.tcl".\n |
Example: Xilinx' AXI_DMA core has a 7-bit address range for its register |
address map. The PERIPHERAL configuration statement to interface to this |
core would be:\n |
79,7 → 88,6
basePortName=myAxiDmaDevice \ |
address=O_myAxiDmaDevice_address \ |
data=O_myAxiDmaDevice_data \ |
write_enable=O_myAxiDmaDevice_wen \ |
command_read=O_myAxiDmaDevice_cmd_read \ |
command_write=O_myAxiDmaDevice_cmd_write \ |
busy=I_myAxiDmaDevice_busy \ |
86,7 → 94,8
error=I_myAxiDmaDevice_error \ |
read=I_myAxiDmaDevice_read \ |
address_width=7 \ |
synchronous=True\n |
synchronous=True \\ |
write_enable=O_myAxiDmaDevice_wen\n |
To write to the memory master to slave start address, use the |
following, where "start_address" is a 4-byte variable set elsewhere in the |
program:\n |
166,6 → 175,7
('read', r'I_\w+$', None, ), |
('busy', r'I_\w+$', None, ), |
('error', r'I_\w+$', None, ), |
('noWSTRB', None, None, ), |
('synchronous', r'(True|False)$', bool, ), |
('write_enable', r'O_\w+$', None, ), |
); |
176,11 → 186,27
raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,)); |
param_test = allowables[names.index(param)]; |
self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]); |
# Ensure the required parameters are provided (all parameters are required). |
for paramname in names: |
# Ensure the required parameters are provided. |
for paramname in ( |
'address', |
'address_width', |
'basePortName', |
'command_read', |
'command_write', |
'data', |
'read', |
'busy', |
'error', |
'synchronous', |
): |
if not hasattr(self,paramname): |
raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,)); |
# There are no optional parameters. |
# Ensure one and only one of the complementary optional values are set. |
if not hasattr(self,'write_enable') and not hasattr(self,'noWSTRB'): |
raise SSBCCException('One of "write_enable" or "noWSTRB" must be set at %s' % loc); |
if hasattr(self,'write_enable') and hasattr(self,'noWSTRB'): |
raise SSBCCException('Only one of "write_enable" or "noWSTRB" can be set at %s' % loc); |
self.noWSTRB = hasattr(self,'noWSTRB'); |
# Temporary: Warning message |
if not self.synchronous: |
raise SSBCCException('synchronous=False has not been validated yet'); |
194,7 → 220,7
( 'o_%s_wvalid', 1, 'output', ), |
( 'i_%s_wready', 1, 'input', ), |
( 'o_%s_wdata', 32, 'output', ), |
( 'o_%s_wstrb', 4, 'output', ), |
( 'o_%s_wstrb', 4, 'output', ) if not self.noWSTRB else None, |
( 'i_%s_bresp', 2, 'input', ), |
( 'i_%s_bvalid', 1, 'input', ), |
( 'o_%s_bready', 1, 'output', ), |
206,6 → 232,8
( 'i_%s_rdata', 32, 'input', ), |
( 'i_%s_rresp', 2, 'input', ), |
): |
if not signal: |
continue |
thisName = signal[0] % self.basePortName; |
config.AddIO(thisName,signal[1],signal[2],loc); |
config.AddSignal('s__%s__address' % self.basePortName, self.address_width, loc); |
222,7 → 250,8
config.AddOutport((self.data,False, |
# empty list -- disable normal output port signal generation |
),loc); |
config.AddOutport((self.write_enable,False, |
if not self.noWSTRB: |
config.AddOutport((self.write_enable,False, |
('o_%s_wstrb' % self.basePortName, 4, 'data', ), |
),loc); |
config.AddOutport((self.command_read,True, |
266,3 → 295,8
body = re.sub(subpair[0],subpair[1],body); |
body = self.GenVerilogFinal(config,body); |
fp.write(body); |
|
# Write the TCL script to facilitate creating Vivado IP for the port. |
vivadoFile = os.path.join(os.path.dirname(self.peripheralFile),'vivado_AXI4_Lite_Bus.py'); |
execfile(vivadoFile,globals()); |
WriteTclScript('master',self.basePortName,self.address_width,noWSTRB=self.noWSTRB); |
/peripherals/big_outport.py
56,8 → 56,6
""" |
|
def __init__(self,peripheralFile,config,param_list,loc): |
# Use the externally provided file name for the peripheral |
self.peripheralFile = peripheralFile; |
# Get the parameters. |
allowables = ( |
('outport', r'O_\w+$', None, ), |
/peripherals/vivado_AXI4_Lite_Bus.py
0,0 → 1,132
################################################################################ |
# |
# Copyright 2014, Sinclair R.F., Inc. |
# |
################################################################################ |
|
import re |
|
def WriteTclScript(mode,basePortName,addrWidth,noWSTRB=False): |
""" |
Write a TCL script to facilitate generating IP for micro controller |
configurations with AXI4-List master or slave busses.\n |
Usage: |
This method should be called by the python scripts creating AXI4-Lite |
peripherals as follows:\n |
import vivado_AXI4_Lite_Bus |
vivado_AXI4_Lite_Bus.WriteTclScript(mode,basePortName);\n |
where: |
mode is either 'master' or 'slave' |
basePortName |
is the string used for the basePortName by the peripheral |
""" |
|
# |
# Validate the arguments. |
# |
|
if mode not in ('master','slave',): |
raise Exception('Program Bug: Mode "%s" should be either "master" or "slave"' % mode); |
|
if type(basePortName) != str: |
raise Exception('Program Bug: basePortName must be an "str", not a "%s"', type(basePortName)); |
|
# |
# Write the TCL script. |
# |
|
body = """# Auto-generated TCL script to configure the @MODE@ AXI4-Lite port "@BASEPORTNAME@" |
# Usage: source vivado_@BASEPORTNAME@.tcl |
|
# Remove the AXI port maps auto-generated by Vivado 2013.3. |
ipx::remove_address_space {i_@BASEPORTNAME@} [ipx::current_core] |
ipx::remove_address_space {o_@BASEPORTNAME@} [ipx::current_core] |
ipx::remove_bus_interface {i_@BASEPORTNAME@} [ipx::current_core] |
ipx::remove_bus_interface {o_@BASEPORTNAME@} [ipx::current_core] |
ipx::remove_bus_interface {i_@BASEPORTNAME@_signal_reset} [ipx::current_core] |
ipx::remove_bus_interface {i_@BASEPORTNAME@_signal_clock} [ipx::current_core] |
|
# Create the AXI4-Lite port. |
ipx::add_bus_interface {@BASEPORTNAME@} [ipx::current_core] |
set_property abstraction_type_vlnv {xilinx.com:interface:aximm_rtl:1.0} [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]] |
set_property bus_type_vlnv {xilinx.com:interface:aximm:1.0} [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]] |
set_property interface_mode {@MODE@} [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]] |
set_property display_name {@BASEPORTNAME@} [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]] |
set_property description {AXI4-Lite bus for @BASEPORTNAME@} [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]] |
|
# Add the signals to the AXI4-Lite port |
"""; |
|
# mode-dependent directions for signals |
mo = 'o' if mode == 'master' else 'i'; |
mi = 'i' if mode == 'master' else 'o'; |
|
for pairs in [ |
('ARADDR', 'araddr', mo, ), |
('ARREADY', 'arready', mi, ), |
('ARVALID', 'arvalid', mo, ), |
('AWADDR', 'awaddr', mo, ), |
('AWREADY', 'awready', mi, ), |
('AWVALID', 'awvalid', mo, ), |
('BREADY', 'bready', mo, ), |
('BRESP', 'bresp', mi, ), |
('BVALID', 'bvalid', mi, ), |
('RDATA', 'rdata', mi, ), |
('RREADY', 'rready', mo, ), |
('RRESP', 'rresp', mi, ), |
('RVALID', 'rvalid', mi, ), |
('WDATA', 'wdata', mo, ), |
('WREADY', 'wready', mi, ), |
('WSTRB', 'wstrb', mo, ) if not noWSTRB else None, |
('WVALID', 'wvalid', mo, ), |
]: |
if not pairs: |
continue; |
body += "ipx::add_port_map {%s} [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]]\n" % pairs[0]; |
body += "set_property physical_name {%s_@BASEPORTNAME@_%s} [ipx::get_port_map %s [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]]]\n" % (pairs[2],pairs[1],pairs[0],); |
|
body += """ |
# Fix the address space |
ipx::add_address_space {@BASEPORTNAME@} [ipx::current_core] |
set_property master_address_space_ref {@BASEPORTNAME@} [ipx::get_bus_interface @BASEPORTNAME@ [ipx::current_core]] |
set_property range {@ADDR_WIDTH@} [ipx::get_address_space @BASEPORTNAME@ [ipx::current_core]] |
set_property width {32} [ipx::get_address_space @BASEPORTNAME@ [ipx::current_core]] |
"""; |
|
body += """ |
# Fix the reset port definition |
ipx::add_bus_interface {@BASEPORTNAME@_aresetn} [ipx::current_core] |
set_property abstraction_type_vlnv {xilinx.com:signal:reset_rtl:1.0} [ipx::get_bus_interface @BASEPORTNAME@_aresetn [ipx::current_core]] |
set_property bus_type_vlnv {xilinx.com:signal:reset:1.0} [ipx::get_bus_interface @BASEPORTNAME@_aresetn [ipx::current_core]] |
set_property display_name {@BASEPORTNAME@_aresetn} [ipx::get_bus_interface @BASEPORTNAME@_aresetn [ipx::current_core]] |
ipx::add_port_map {RST} [ipx::get_bus_interface @BASEPORTNAME@_aresetn [ipx::current_core]] |
set_property physical_name {i_@BASEPORTNAME@_aresetn} [ipx::get_port_map RST [ipx::get_bus_interface @BASEPORTNAME@_aresetn [ipx::current_core]]] |
ipx::add_bus_parameter {POLARITY} [ipx::get_bus_interface @BASEPORTNAME@_aresetn [ipx::current_core]] |
set_property value {ACTIVE_LOW} [ipx::get_bus_parameter POLARITY [ipx::get_bus_interface @BASEPORTNAME@_aresetn [ipx::current_core]]] |
"""; |
|
body += """ |
# Fix the clock port definition |
ipx::add_bus_interface {@BASEPORTNAME@_aclk} [ipx::current_core] |
set_property abstraction_type_vlnv {xilinx.com:signal:clock_rtl:1.0} [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]] |
set_property bus_type_vlnv {xilinx.com:signal:clock:1.0} [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]] |
set_property display_name {@BASEPORTNAME@_aclk} [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]] |
ipx::add_port_map {CLK} [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]] |
set_property physical_name {i_@BASEPORTNAME@_aclk} [ipx::get_port_map CLK [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]]] |
ipx::add_bus_parameter {ASSOCIATED_BUSIF} [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]] |
set_property value {@BASEPORTNAME@} [ipx::get_bus_parameter ASSOCIATED_BUSIF [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]]] |
ipx::add_bus_parameter {ASSOCIATED_RESET} [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]] |
set_property value {i_@BASEPORTNAME@_aresetn} [ipx::get_bus_parameter ASSOCIATED_RESET [ipx::get_bus_interface @BASEPORTNAME@_aclk [ipx::current_core]]] |
"""; |
|
addrWidth = max(addrWidth,12); |
for subpair in [ |
('@ADDR_WIDTH@', str(2**addrWidth), ), |
('@BASEPORTNAME@', basePortName, ), |
('@MODE@', mode, ), |
]: |
body = re.sub(subpair[0],subpair[1],body); |
|
fp = open('vivado_%s.tcl' % basePortName, 'wt'); |
fp.write(body); |
fp.close(); |
/peripherals/wide_strobe.py
0,0 → 1,85
################################################################################ |
# |
# Copyright 2014, Sinclair R.F., Inc. |
# |
################################################################################ |
|
import re; |
|
from ssbccPeripheral import SSBCCperipheral |
from ssbccUtil import SSBCCException; |
|
class wide_strobe(SSBCCperipheral): |
""" |
Generate more than one simultaneous strobe.\n |
Usage: |
PERIPHERAL wide_strobe \\ |
outport=O_name \\ |
outsignal=o_name \\ |
width=<N>\n |
Where: |
outport=O_name |
specifies the symbol used to write to the output port |
outsignal=o_name |
specifies the name of the signal output from the module |
width=<N> |
specifies the width of the I/O |
Note: N must be between 1 and 8 inclusive.\n |
Example: Generate up to 4 simultaneous strobes.\n |
PORTCOMMENT 4 bit wide strobe |
PERIPHERAL wide_strobe \\ |
outport=O_4BIT_STROBE \\ |
outsignal=o_4bit_strobe \\ |
width=4\n |
Send strobes on bits 1 and 3 of the wide strobe as follows:\n |
${2**1|2**3} .outport(O_4BIT_STROBE) |
""" |
|
def __init__(self,peripheralFile,config,param_list,loc): |
# Get the parameters. |
allowables = ( |
('outport', r'O_\w+$', None, ), |
('outsignal', r'o_\w+$', None, ), |
('width', r'(9|[1-9]\d*)$', int, ), |
); |
names = [a[0] for a in allowables]; |
for param_tuple in param_list: |
param = param_tuple[0]; |
if param not in names: |
raise SSBCCException('Unrecognized parameter "%s" at %s' % (param,loc,)); |
param_test = allowables[names.index(param)]; |
self.AddAttr(config,param,param_tuple[1],param_test[1],loc,param_test[2]); |
# Ensure the required parameters are provided (all parameters are required). |
for paramname in names: |
if not hasattr(self,paramname): |
raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,)); |
# There are no optional parameters. |
# Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral. |
config.AddIO(self.outsignal,self.width,'output',loc); |
self.ix_outport = config.NOutports(); |
config.AddOutport((self.outport,False, |
# empty list |
), |
loc); |
|
def GenVerilog(self,fp,config): |
body = """// |
// PERIPHERAL wide_strobe: @NAME@ |
// |
initial @NAME@ = @WIDTH@'d0; |
always @ (posedge i_clk) |
if (i_rst) |
@NAME@ <= @WIDTH@'d0; |
else if (s_outport && (s_T == @IX_OUTPORT@)) |
@NAME@ <= s_N[0+:@WIDTH@]; |
else |
@NAME@ <= @WIDTH@'d0; |
""" |
for subpair in ( |
(r'@IX_OUTPORT@', "8'd%d" % self.ix_outport, ), |
(r'@WIDTH@', str(self.width), ), |
(r'@NAME@', self.outsignal, ), |
): |
body = re.sub(subpair[0],subpair[1],body); |
body = self.GenVerilogFinal(config,body); |
fp.write(body); |
/peripherals/tb/AXI4_Lite_Slave_DualPortRAM/.gitignore
1,3 → 1,4
*.9x8 |
*.tcl |
tb.out |
tb_*.v |
/peripherals/tb/big_inport/tb_big_inport.9x8
1,7 → 1,7
# |
# Copyright 2013, Sinclair R.F., Inc. |
# Copyright 2013-2014, Sinclair R.F., Inc. |
# |
# Test bench for PWM_8bit peripheral. |
# Test bench for big_inport peripheral. |
# |
|
ARCHITECTURE core/9x8 Verilog |
/peripherals/tb/AXI4_Lite_Master/.gitignore
1,2 → 1,3
*.tcl |
tb.out |
tb_*.v |
/peripherals/tb/big_outport/tb_big_outport.9x8
1,7 → 1,7
# |
# Copyright 2013, Sinclair R.F., Inc. |
# Copyright 2013-2014, Sinclair R.F., Inc. |
# |
# Test bench for PWM_8bit peripheral. |
# Test bench for big_outport peripheral. |
# |
|
ARCHITECTURE core/9x8 Verilog |
/peripherals/tb/wide_strobe/tb_wide_strobe.9x8
0,0 → 1,30
# |
# Copyright 2014, Sinclair R.F., Inc. |
# |
# Test bench for wide_strobe peripheral. |
# |
|
ARCHITECTURE core/9x8 Verilog |
INSTRUCTION 64 |
DATA_STACK 32 |
RETURN_STACK 16 |
|
PORTCOMMENT narrow strobe bus |
PERIPHERAL wide_strobe outport=O_MIN \ |
outsignal=o_min \ |
width=1 |
|
PORTCOMMENT medium-width strobe bus |
PERIPHERAL wide_strobe outport=O_MED \ |
outsignal=o_med \ |
width=4 |
|
PORTCOMMENT maximum-width strobe bus |
PERIPHERAL wide_strobe outport=O_MAX \ |
outsignal=o_max \ |
width=8 |
|
PORTCOMMENT termination signal |
OUTPORT 1-bit o_done O_DONE |
|
ASSEMBLY tb_wide_strobe.s |
/peripherals/tb/wide_strobe/run
0,0 → 1,18
#!/bin/bash |
# |
# Copyright 2013, Sinclair R.F., Inc. |
|
NAME=wide_strobe |
|
../../../../../ssbcc -q -P monitor_stack tb_${NAME}.9x8 || { echo "${NAME} compile failed" > /dev/stderr; exit 1; } |
iverilog -o tb tb.v tb_${NAME}.v || { echo "${NAME} build failed" > /dev/stderr; exit 1; } |
./tb > tb.out; |
|
T="`md5sum -c md5sums 2>&1 | sed '/: OK$/d'`"; |
if [ -n "${T}" ]; then |
echo "${NAME} failed" > /dev/stderr; |
exit 1; |
fi |
|
echo "Passed: ${NAME}"; |
exit 0; |
peripherals/tb/wide_strobe/run
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: peripherals/tb/wide_strobe/.gitignore
===================================================================
--- peripherals/tb/wide_strobe/.gitignore (nonexistent)
+++ peripherals/tb/wide_strobe/.gitignore (revision 3)
@@ -0,0 +1,2 @@
+tb.out
+tb_wide_strobe.v
Index: peripherals/tb/wide_strobe/tb.v
===================================================================
--- peripherals/tb/wide_strobe/tb.v (nonexistent)
+++ peripherals/tb/wide_strobe/tb.v (revision 3)
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ *
+ * Copyright 2013, Sinclair R.F., Inc.
+ *
+ * Test bench for big_outport peripheral.
+ *
+ ******************************************************************************/
+
+`timescale 1ns/1ps
+
+module tb;
+
+// 100 MHz clock
+reg s_clk = 1'b1;
+always @ (s_clk)
+ s_clk <= #5 ~s_clk;
+
+reg s_rst = 1'b1;
+initial begin
+ repeat (5) @ (posedge s_clk);
+ s_rst = 1'b0;
+end
+
+wire s_min;
+wire [3:0] s_med;
+wire [7:0] s_max;
+wire s_done;
+tb_wide_strobe uut(
+ // synchronous reset and processor clock
+ .i_rst (s_rst),
+ .i_clk (s_clk),
+ // narrow strobe bus
+ .o_min (s_min),
+ // medium-width strobe bus
+ .o_med (s_med),
+ // maximum-width strobe bus
+ .o_max (s_max),
+ // termination signal
+ .o_done (s_done)
+);
+
+always @ (posedge s_clk) begin
+ if ( s_min) $display("%12d : %d", $time, s_min);
+ if (|s_med) $display("%12d : %h", $time, s_med);
+ if (|s_max) $display("%12d : %h", $time, s_max);
+end
+
+always @ (posedge s_clk)
+ if (s_done)
+ $finish;
+
+endmodule
peripherals/tb/wide_strobe/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: peripherals/tb/wide_strobe/tb_wide_strobe.s
===================================================================
--- peripherals/tb/wide_strobe/tb_wide_strobe.s (nonexistent)
+++ peripherals/tb/wide_strobe/tb_wide_strobe.s (revision 3)
@@ -0,0 +1,25 @@
+; Copyright 2014, Sinclair R.F., Inc.
+;
+; Test bench for wide_strobe peripheral.
+
+.main
+
+ ; Wait a while
+ ${25-1} :wait_startup .jumpc(wait_startup,1-) drop
+
+ ; Exercise the minimum-width peripheral
+ 0x00 .outport(O_MIN)
+ 0x01 .outport(O_MIN)
+
+ ; Exercise the medium-width peripheral
+ ${2**4-1} :loop_medium O_MED outport .jumpc(loop_medium,1-) drop
+
+ ; Exercise the maximum-width peripheral
+ 0x03 ${12-1} :loop_maximum >r O_MAX outport < .jumpc(loop_maximum,1-) drop drop
+
+ ; Wait a few clock cycles.
+ ${3-1} :wait_end .jumpc(wait_end,1-) drop
+
+ ; Send the termination signal and then enter an infinite loop.
+ 1 .outport(O_DONE)
+ :infinite .jump(infinite)
Index: peripherals/tb/wide_strobe/md5sums
===================================================================
--- peripherals/tb/wide_strobe/md5sums (nonexistent)
+++ peripherals/tb/wide_strobe/md5sums (revision 3)
@@ -0,0 +1 @@
+77b52028b0a44699738498289d9045c9 tb.out
Index: peripherals/tb/inFIFO_async/tb_inFIFO_async.9x8
===================================================================
--- peripherals/tb/inFIFO_async/tb_inFIFO_async.9x8 (revision 2)
+++ peripherals/tb/inFIFO_async/tb_inFIFO_async.9x8 (revision 3)
@@ -1,7 +1,7 @@
#
-# Copyright 2013, Sinclair R.F., Inc.
+# Copyright 2013-2014, Sinclair R.F., Inc.
#
-# Test bench for PWM_8bit peripheral.
+# Test bench for inFIFO_async peripheral.
#
ARCHITECTURE core/9x8 Verilog
/peripherals/tb/outFIFO_async/tb_outFIFO_async.9x8
1,7 → 1,7
# |
# Copyright 2013, Sinclair R.F., Inc. |
# Copyright 2013-2014, Sinclair R.F., Inc. |
# |
# Test bench for PWM_8bit peripheral. |
# Test bench for outFIFO_async peripheral. |
# |
|
ARCHITECTURE core/9x8 Verilog |
/peripherals/AXI4_Lite_Slave_DualPortRAM.py
47,7 → 47,11
Note: This is the default |
ram32 |
optionally specifies using a 32-bit RAM for the dual-port memrory instantiation |
Note: This is required for Vivado 2013.3. |
Note: This is required for Vivado 2013.3.\n |
Vivado Users: |
The peripheral creates a TCL script to facilitate turning the micro |
controller into an IP core. Look for a file with the name |
"vivado_<basePortName>.tcl".\n |
Example: The code fragments |
<addr> .outport(O_address) .inport(I_read) |
and |
154,12 → 158,13
# Set the string used to identify signals associated with this peripheral. |
self.namestring = self.basePortName; |
# Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral. |
self.address_width = int(math.log(self.size,2)); |
for signal in ( |
( 'i_%s_aresetn', 1, 'input', ), |
( 'i_%s_aclk', 1, 'input', ), |
( 'i_%s_awvalid', 1, 'input', ), |
( 'o_%s_awready', 1, 'output', ), |
( 'i_%s_awaddr', math.log(self.size,2), 'input', ), |
( 'i_%s_awaddr', self.address_width, 'input', ), |
( 'i_%s_wvalid', 1, 'input', ), |
( 'o_%s_wready', 1, 'output', ), |
( 'i_%s_wdata', 32, 'input', ), |
169,7 → 174,7
( 'i_%s_bready', 1, 'input', ), |
( 'i_%s_arvalid', 1, 'input', ), |
( 'o_%s_arready', 1, 'output', ), |
( 'i_%s_araddr', math.log(self.size,2), 'input', ), |
( 'i_%s_araddr', self.address_width, 'input', ), |
( 'o_%s_rvalid', 1, 'output', ), |
( 'i_%s_rready', 1, 'input', ), |
( 'o_%s_rdata', 32, 'output', ), |
177,10 → 182,10
): |
thisName = signal[0] % self.basePortName; |
config.AddIO(thisName,signal[1],signal[2],loc); |
config.AddSignal('s__%s__mc_addr' % self.namestring, int(math.log(self.size,2)), loc); |
config.AddSignal('s__%s__mc_addr' % self.namestring, self.address_width, loc); |
config.AddSignal('s__%s__mc_rdata' % self.namestring, 8, loc); |
config.AddOutport((self.address,False, |
('s__%s__mc_addr' % self.namestring, int(math.log(self.size,2)), 'data', ), |
('s__%s__mc_addr' % self.namestring, self.address_width, 'data', ), |
),loc); |
config.AddInport((self.read, |
('s__%s__mc_rdata' % self.namestring, 8, 'data', ), |
212,3 → 217,8
body = re.sub(subpair[0],subpair[1],body); |
body = self.GenVerilogFinal(config,body); |
fp.write(body); |
|
# Write the TCL script to facilitate creating Vivado IP for the port. |
vivadoFile = os.path.join(os.path.dirname(self.peripheralFile),'vivado_AXI4_Lite_Bus.py'); |
execfile(vivadoFile,globals()); |
WriteTclScript('slave',self.basePortName,self.address_width); |