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/AXI4_Lite_Slave_DualPortRAM/.gitignore
1,3 → 1,4
*.9x8 |
*.tcl |
tb.out |
tb_*.v |
/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/AXI4_Lite_Master/.gitignore
1,2 → 1,3
*.tcl |
tb.out |
tb_*.v |
/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; |