OpenCores
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 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/trunk/ssbccUtil.py
7,6 → 7,7
################################################################################
 
import math
import os
import re
 
################################################################################
73,10 → 74,38
"""
Convert a Verilog format integer into an integer value.
"""
save_v = v;
if re.match(r'([1-9]\d*)?\'[bodh]',v):
length = 0;
while v[0] != '\'':
length *= 10;
length += ord(v[0]) - ord('0');
v = v[1:];
v=v[1:];
if v[0] == 'b':
base = 2;
elif v[0] == 'o':
base = 8;
elif v[0] == 'd':
base = 10;
elif v[0] == 'h':
base = 16;
else:
raise Exception('Program bug -- unrecognized base: "%c"' % v[0]);
v = v[1:];
else:
length = 0;
base = 10;
ov = 0;
for vv in [v[i] for i in range(len(v)) if '0' <= v[i] <= '9']:
ov *= 10;
ov += ord(vv)-ord('0');
for vv in [v[i] for i in range(len(v)) if v[i] != '_']:
ov *= base;
try:
dv = int(vv,base);
except:
raise SSBCCException('Malformed parameter value: "%s"' % save_v);
ov += dv;
if length > 0 and ov >= 2**length:
raise SSBCCException('Paramter length and value don\'t match: "%s"' % save_v);
return ov;
 
def IsPowerOf2(v):
85,7 → 114,7
"""
return v == 2**int(math.log(v,2)+0.5);
 
def LoadFile(filename):
def LoadFile(filename,config):
"""
Load the file into a list with the line contents and line numbers.\n
filename is either the name of the file or a file object.\n
92,22 → 121,28
Note: The file object is closed in either case.
"""
if type(filename) == str:
try:
filename = file(filename);
except:
raise SSBCCException('Error opening "%s"' % filename);
for path in config.includepaths:
fullfilename = os.path.join(path,filename);
if os.path.isfile(fullfilename):
try:
fp = file(fullfilename);
except:
raise SSBCCException('Error opening "%s"' % filename);
break;
else:
raise SSBCCException('.INCLUDE file "%s" not found' % filename);
elif type(filename) == file:
pass;
fp = filename;
else:
raise Exception('Unexpected argument type: %s' % type(filename))
v = list();
ixLine = 0;
for tmpLine in filename:
for tmpLine in fp:
ixLine += 1;
while tmpLine and tmpLine[-1] in ('\n','\r',):
tmpLine = tmpLine[0:-1];
v.append((tmpLine,ixLine,));
filename.close();
fp.close();
return v;
 
################################################################################
/trunk/macros/9x8/pushByte.py
0,0 → 1,32
# Copyright 2014, Sinclair R.F., Inc.
 
def pushByte(ad):
"""
User-defined macro to push a 32 bit value onto the data stack so that the LSB
is deepest in the data stack and the MSB is at the top of the data stack.
Usage:
.pushByte(v,ix)
where
v is a multi-byte value, a constant, or an evaluated expression
ix is the index to the byte to push (ix=0 ==> push the LSB, ...)\n
The effect is to push "(v/2**ix) % 0x10" onto the data stack.\n
( - u_byte )
"""
 
# Add the macro to the list of recognized macros.
ad.AddMacro('.pushByte', 1, [
['','singlevalue','symbol'],
['','singlevalue','symbol'],
]);
 
# Define the macro functionality.
def emitFunction(ad,fp,argument):
v = ad.Emit_IntegerValue(argument[0]);
ix = ad.Emit_IntegerValue(argument[1]);
if ix < 0:
raise asmDef.AsmException('ix must be non-negative in .pushByte at %s' % argument[1]['loc']);
v = int(v/2**ix) % 0x100;
printValue = argument[0]['value'] if type(argument[0]['value']) == str else '0x%X' % argument[0]['value'];
printIx = argument[1]['value'] if type(argument[1]['value']) == str else '0x%X' % argument[1]['value'];
ad.EmitPush(fp,v,'.pushByte(%s,%s)' % (printValue,printIx,));
ad.EmitFunction['.pushByte'] = emitFunction;
/trunk/macros/9x8/push32.py
0,0 → 1,42
# Copyright 2014, Sinclair R.F., Inc.
 
def push32(ad):
"""
User-defined macro to push a 32 bit value onto the data stack so that the LSB
is deepest in the data stack and the MSB is at the top of the data stack.
Usage:
.push32(v)
where
v is a 32-bit value, a constant, or an evaluated expression\n
The effect is to push v%0x100, int(v/2**8)%0x100, int(v/2**16)%0x100, and
int(v/2**24)%0x100 onto the data stack.\n
( - u_LSB u u u_MSB )
"""
 
# Add the macro to the list of recognized macros.
ad.AddMacro('.push32', 4, [ ['','singlevalue','symbol'] ]);
 
# Define the macro functionality.
def emitFunction(ad,fp,argument):
argument = argument[0];
if argument['type'] == 'value':
v = argument['value'];
elif argument['type'] == 'symbol':
name = argument['value'];
if not ad.IsSymbol(name):
raise asmDef.AsmException('Symbol "%s" not recognized at %s' % (argument['value'],argument['loc'],));
ix = ad.symbols['list'].index(name);
v = ad.symbols['body'][ix];
if len(v) != 1:
raise asmDef.AsmException('Argument can only be one value at %s' % argument['loc']);
v = v[0];
else:
raise asmDef.AsmException('Argument "%s" of type "%s" not recognized at %s' % (argument['value'],argument['type'],argument['loc'],));
if type(v) != int:
raise Exception('Program Bug -- value should be an "int"');
ad.EmitPush(fp,v%0x100,''); v >>= 8;
ad.EmitPush(fp,v%0x100,''); v >>= 8;
ad.EmitPush(fp,v%0x100,''); v >>= 8;
printValue = argument['value'] if type(argument['value']) == str else '0x%08X' % argument['value'];
ad.EmitPush(fp,v%0x100,'.push32(%s)' % printValue);
ad.EmitFunction['.push32'] = emitFunction;
/trunk/macros/9x8/push16.py
0,0 → 1,39
# Copyright 2014, Sinclair R.F., Inc.
 
def push16(ad):
"""
User-defined macro to push a 16 bit value onto the data stack so that the LSB
is deepest in the data stack and the MSB is at the top of the data stack.\n
Usage:
.push16(v)
where
v is a 16-bit value, a constant, or an evaluated expression\n
The effect is to push v%0x100 and int(v/2**8)%0x100 onto the data stack.\n
( - u_LSB u u u_MSB )
"""
 
# Add the macro to the list of recognized macros.
ad.AddMacro('.push16', 2, [ ['','singlevalue','symbol'] ]);
 
# Define the macro functionality.
def emitFunction(ad,fp,argument):
argument = argument[0];
if argument['type'] == 'value':
v = argument['value'];
elif argument['type'] == 'symbol':
name = argument['value'];
if not ad.IsSymbol(name):
raise asmDef.AsmException('Symbol "%s" not recognized at %s' % (argument['value'],argument['loc'],));
ix = ad.symbols['list'].index(name);
v = ad.symbols['body'][ix];
if len(v) != 1:
raise asmDef.AsmException('Argument can only be one value at %s' % argument['loc']);
v = v[0];
else:
raise asmDef.AsmException('Argument "%s" of type "%s" not recognized at %s' % (argument['value'],argument['type'],argument['loc'],));
if type(v) != int:
raise Exception('Program Bug -- value should be an "int"');
ad.EmitPush(fp,v%0x100,''); v >>= 8;
printValue = argument['value'] if type(argument['value']) == str else '0x%08X' % argument['value'];
ad.EmitPush(fp,v%0x100,'.push16(%s)' % printValue);
ad.EmitFunction['.push16'] = emitFunction;
/trunk/lib/9x8/char.s
7,20 → 7,51
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Conversion to and from hex.
; Convert to and from binary.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; Convert a single binary digit to its byte value. Return 0x00 on success and
; 0xFF on failure.
; ( u_binary_n - u f )
.function char__binary_to_byte
'0' -
dup 0xFE & .jumpc(error)
.return(0)
:error .return(0xFF)
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Convert to and from hex.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; Convert a byte to its 2-digit hex representation with the digit for the most
; significant nible at the top of the data stack.
; significant nibble at the top of the data stack.
; ( u - u_hex_lsn u_hex_msn )
.function char__byte_to_2hex
; ( u - u u_hex_low )
; ( u - u u_hex_lsn )
dup 0x0F .call(char__nibble_to_hex,&)
; ( u u_hex_low - u_hex_low u_hex_high )
; ( u u_hex_lsn - u_hex_lsn u_hex_msn )
swap 0>> 0>> 0>> .call(char__nibble_to_hex,0>>)
.return
 
; Convert a byte to the minimal 1 or 2 digit hex representation with the digit
; for the most significant nibble at the top of the data stack.
; ( u - u_hex_lsn u_hex_msn ) or ( u - u_hex_lsn )
.function char__byte_to_hex
dup 0xF0 & .jumpc(include_msn)
.call(char__nibble_to_hex) .return
:include_msn
.call(char__byte_to_2hex) .return
 
; Convert a 4 byte value to its 8-digit hexadecimal representation.
; ( u_LSB u u u_MSB - )
.function char__4byte_to_8hex
>r >r >r >r
${4-1} :loop r> swap >r .call(char__byte_to_2hex) r> .jumpc(loop,1-)
.return(drop)
 
; Convert a nibble between 0x00 and 0x0F inclusive to it hex digit.
; ( u - u_hex_n )
.function char__nibble_to_hex
/trunk/core/9x8/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.
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/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;
/trunk/core/9x8/tb/.gitignore
0,0 → 1,2
*.mem
*_pkg.vhd
/trunk/core/9x8/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);
/trunk/core/9x8/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];
/trunk/core/9x8/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;
/trunk/core/9x8/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, ),
/trunk/core/9x8/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);
/trunk/core/9x8/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, ),
/trunk/core/9x8/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();
/trunk/core/9x8/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);
/trunk/core/9x8/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
/trunk/core/9x8/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
/trunk/core/9x8/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
/trunk/core/9x8/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;
trunk/core/9x8/peripherals/tb/wide_strobe/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/core/9x8/peripherals/tb/wide_strobe/.gitignore =================================================================== --- trunk/core/9x8/peripherals/tb/wide_strobe/.gitignore (nonexistent) +++ trunk/core/9x8/peripherals/tb/wide_strobe/.gitignore (revision 3) @@ -0,0 +1,2 @@ +tb.out +tb_wide_strobe.v Index: trunk/core/9x8/peripherals/tb/wide_strobe/tb.v =================================================================== --- trunk/core/9x8/peripherals/tb/wide_strobe/tb.v (nonexistent) +++ trunk/core/9x8/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
trunk/core/9x8/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: trunk/core/9x8/peripherals/tb/wide_strobe/tb_wide_strobe.s =================================================================== --- trunk/core/9x8/peripherals/tb/wide_strobe/tb_wide_strobe.s (nonexistent) +++ trunk/core/9x8/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: trunk/core/9x8/peripherals/tb/wide_strobe/md5sums =================================================================== --- trunk/core/9x8/peripherals/tb/wide_strobe/md5sums (nonexistent) +++ trunk/core/9x8/peripherals/tb/wide_strobe/md5sums (revision 3) @@ -0,0 +1 @@ +77b52028b0a44699738498289d9045c9 tb.out Index: trunk/core/9x8/peripherals/tb/inFIFO_async/tb_inFIFO_async.9x8 =================================================================== --- trunk/core/9x8/peripherals/tb/inFIFO_async/tb_inFIFO_async.9x8 (revision 2) +++ trunk/core/9x8/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
/trunk/core/9x8/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
/trunk/core/9x8/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);
/trunk/ssbccConfig.py
41,8 → 41,12
# list of how the memories will be instantiated
self.config['combine'] = list();
 
# initial search path for .INCLUDE configuration commands
self.includepaths = list();
self.includepaths.append('.');
 
# initial search paths for peripherals
self.peripheralpaths= list();
self.peripheralpaths = list();
self.peripheralpaths.append('.');
self.peripheralpaths.append('peripherals');
self.peripheralpaths.append(os.path.join(sys.path[0],'core/peripherals'));
163,6 → 167,14
raise SSBCCException('Symbol "%s" already defined before %s' % (name,loc,));
self.symbols.append(name);
 
def AppendIncludePath(self,path):
"""
Add the specified path to the end of the paths to search for .INCLUDE
configuration commands.\n
path path to add to the list
"""
self.includepaths.insert(-1,path);
 
def CompleteCombines(self):
"""
Ensure all memories are assigned addresses.\n
294,7 → 306,7
thisSlice = '[0+:8]';
for ix in range(len(self.parameters)):
if self.parameters[ix][0] == name:
return ExtractBits(int(self.parameters[ix][1]),thisSlice);
return ExtractBits(IntValue(self.parameters[ix][1]),thisSlice);
else:
raise Exception('Program Bug: Parameter "%s" not found' % name);
 
804,7 → 816,7
nBlocks = int(value[findStar+1:]);
nbits_blockSize = int(round(math.log(blockSize,2)));
if blockSize != 2**nbits_blockSize:
raise SSBCCException('block size must be a power of 2 on line %d: "%s"' % errorInfo);
raise SSBCCException('block size must be a power of 2 at %s: "%s"' % errorInfo);
nbits_nBlocks = CeilLog2(nBlocks);
self.Set(name, dict(
length=blockSize*nBlocks,
/trunk/README
621,6 → 621,7
UART bidirectional UART
UART_Rx receive UART
UART_Tx transmit UART
wide_strobe 1 to 8 bit strobe generator
 
The following command illustrates how to display the help message for
peripherals:
1001,6 → 1002,83
 
${(size['o_big']+7)/8-1} :loop 0 .outport(O_BIG) .jumpc(loop,1-) drop
 
 
MACROS
================================================================================
There are 3 types of macros used by the assembler.
 
The first kind of macros are built in to the assembler and are required to
encode instructions that have embedded values or have mandatory subsequent
instructions. These include function calls, jump instructions, function return,
and memory accesses as follows:
.call(function,[op])
.callc(function,[op])
.fetch(ramName)
.fetch+(ramName)
.fetch-(ramName)
.jump(label,[op])
.jumpc(label,[op])
.return([op])
.store(ramName)
.store+(ramName)
.store-(ramName)
 
The second kind of macros are designed to ease access to input and output
operations and for memory accesses and to help ensure these operations are
correctly constructed. These are defined as python scripts in the
core/9x8/macros directory and are automatically loaded into the assembler.
These macros are:
.fetchindexed(variable)
.fetchoffset(variable,ix)
.fetchvalue(variableName)
.fetchvector(variableName,N)
.inport(I_name)
.outport(O_name[,op])
.outstrobe(O_name)
.storeindexed(variableName[,op])
.storeoffset(variableName,ix[,op])
.storevalue(variableName[,op])
.storevector(variableName,N)
 
The third kind of macro is user-defined macros. These macros must be registered
with the assembler using the ".macro" directive.
 
For example, the ".push32" macro is defined by macros/9x8/push32.py and can be
used to push 32-bit (4-byte) values onto the data stack as follows:
 
.macro push32
.constant C_X 0x87654321
.main
...
.push32(0x12345678)
.push32(C_X)
.push32(${0x12345678^C_X})
...
 
The following macros are provided in macros/9x8:
.push16(v) push the 16-bit (2-byte) value "v" onto the data stack with the
MSB at the top of the data stack
.push32(v) push the 32-bit (4-byte) value "v" onto the data stack with the
MSB at the top of the data stack
 
Directories are searched in the following order for macros:
.
./macros
include paths specified by the '-M' command line option.
macros/9x8
 
The python scripts in core/9x8/macros and macros/9x8 can be used as design
examples for user-defined macros. The assembler does some type checking based
on the list provided when the macro is registered by the "AddMacro" method, but
additional type checking is often warranted by the macro "emitFunction" which
emits the actual assembly code. The ".fetchvector" and ".storevector" macros
demonstrates how to design variable-length macros.
 
It is not an error to repeat the ".macro MACRO_NAME" directive for user-defined
macros. The assembler will issue a fatal error if a user-defined macro
conflicts with a built-in macro.
 
 
CONDITIONAL COMPILATION
================================================================================
The computer compiler and assembler recognize conditional compilation as
/trunk/ssbcc
48,11 → 48,14
argListParser.add_argument('-D', metavar='symbol', type=str, action='append', help='Define symbol');
argListParser.add_argument('-G', metavar='parameter_name=value', type=str, action='append', help='Override parameter value');
argListParser.add_argument('-I', metavar='include_dir', type=str, action='append', help='Add search directory for included files and peripherals');
argListParser.add_argument('-M', metavar='macropath', action='append', help='Macro search path');
argListParser.add_argument('-P', metavar='peripheral_name[="parameters"]', type=str, action='append', help='Add peripheral');
argListParser.add_argument('-o', metavar='outCoreName', type=str, help='output core name');
argListParser.add_argument('-q', action='store_true', help='quiet');
argListParser.add_argument('--define-clog2', action='store_true', help='define clog2 instead of using built-in $clog2');
argListParser.add_argument('--display-opcode', action='store_true', help='add 3-letter decode of opcode (for trace viewer)');
argListParser.add_argument('--rand-instr-mem', action='store_true', help='fill unused instruction memory with random values');
argListParser.add_argument('--synth-instr-mem', type=str, help='synthesis constraint for instruction memory');
argListParser.add_argument('--verilator-tracing-on', action='store_true', help='show all signals in verilator waveform files');
argListParser.add_argument('filename', metavar='filename', type=validateFile, help='SSBCC configuration file');
argList = argListParser.parse_args();
64,6 → 67,7
config = SSBCCconfig();
 
config.Set('define_clog2',argList.define_clog2);
config.Set('rand_instr_mem',argList.rand_instr_mem);
config.Set('verilator_tracing_on',argList.verilator_tracing_on);
 
if argList.display_opcode:
73,17 → 77,31
for symbol in argList.D:
config.AddSymbol(symbol);
 
if argList.I:
for pathString in argList.I:
if not os.path.isdir(pathString):
raise SSBCCException('Bad path string: "%s"' % pathString);
config.AppendIncludePath(pathString);
config.InsertPeripheralPath(pathString);
 
if argList.o:
config.Set('outCoreName',argList.o);
else:
config.Set('outCoreName',os.path.splitext(os.path.basename(argList.filename.name))[0]);
 
if argList.synth_instr_mem:
config.Set('synth_instr_mem',argList.synth_instr_mem);
else:
config.Set('synth_instr_mem',None);
 
#
# Read the configuration file into a line-by-line buffer.
# Note: argList.filename is a file handle, so no paths will be searched by
# LoadFile. This is ensured by setting config to None.
#
 
filename = argList.filename.name;
configList = LoadFile(argList.filename);
configList = LoadFile(argList.filename,None);
ifstack = list();
 
configListStack = list();
149,7 → 167,7
raise SSBCCException('Malformed ".INCLUDE" configuration command on %s' % loc);
configListStack.append((filename,configList,ifstack,));
filename = cmd[0];
configList = LoadFile(filename);
configList = LoadFile(filename,config);
ifstack = list();
# Consume configuration commands disabled by conditionals
elif ifstack and not ifstack[-1]:
275,8 → 293,9
# USER_HEADER
elif re.match(r'\s*USER_HEADER\b',line):
user_header_done = False;
while (line,ixLine) in configList:
if re.match(r'\s*END_USER_HEADER\s',line):
while configList:
(line,ixLine) = configList.pop(0);
if re.match(r'\s*END_USER_HEADER\b',line):
user_header_done = True;
break;
user_header.append(line);
303,12 → 322,6
cmd = cmd[0];
config.OverrideParameter(cmd[0],cmd[1]);
 
if argList.I:
for pathString in argList.I:
if not os.path.isdir(pathString):
raise SSBCCException('Bad path string: "%s"' % pathString);
config.InsertPeripheralPath(pathString);
 
#
# Append peripherals from command-line.
#
382,7 → 395,11
cmd += ' -o ' + assemblerOutput;
for stack_name in ('data_stack','return_stack',):
cmd += ' -s %s=%d' % (stack_name,config.config[stack_name],);
cmd += ' -L %s/%s' % (sys.path[0], 'lib/9x8');
cmd += ' -L %s' % os.path.join(sys.path[0],'lib','9x8');
if argList.M:
for path in argList.M:
cmd += ' -M %s' % path;
cmd += ' -M %s' % os.path.join(sys.path[0],'macros','9x8');
if argList.I:
for pathString in argList.I:
cmd += ' -L %s' % pathString;

powered by: WebSVN 2.1.0

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