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

Subversion Repositories ssbcc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 8 to Rev 9
    Reverse comparison

Rev 8 → Rev 9

/ssbcc/trunk/ssbccPeripheral.py
132,12 → 132,27
#
##############################################################################
 
def FixedPow2(self,config,lowLimit,highLimit,value):
def IntPow2Method(self,config,value,lowLimit=1,highLimit=None):
"""
Check the provided constant as a power of 2 between the provided limits.\n
Note: This differs from InpPow2 in that localparams and constants are
permitted.
Return the integer value of the argument if it is a power of 2 between the
optional limits (inclusive). Otherwise throw an error.\n
Note: Other than a lower limit of 1 for "lowLimit", IntMethod validates
"lowLimit" and "highLimit".
"""
value = self.IntMethod(config,value,lowLimit,highLimit)
if lowLimit < 1:
raise SSBCCException('Program bug: lowLimit = %d is less than 1' % lowLimit);
if not IsPowerOf2(value):
raise SSBCCException('Must be a power of 2');
return value;
 
def IntMethod(self,config,value,lowLimit=None,highLimit=None):
"""
Return the integer value of the argument. Throw an error if the argument is
unrecognized, not an integer, or is outside the optionally specified range.
"""
if (lowLimit != None) and (highLimit != None) and (highLimit < lowLimit):
raise SSBCCException('Program bug: lowLimit = %d and highLimit = %d conflict' % (lowLimit,highLimit,));
if re.match(r'L_\w+$',value):
if not config.IsParameter(value):
raise SSBCCException('Unrecognized parameter');
147,72 → 162,68
if not config.IsConstant(value):
raise SSBCCException('Unrecognized constant');
value = config.constants[value];
if not IsPosInt(value):
raise SSBCCException('Must be a constant positive integer');
value = ParseIntExpr(value);
if not IsPowerOf2(value):
raise SSBCCException('Must be a power of 2');
if not (lowLimit <= value <= highLimit):
raise SSBCCException('Must be between %d and %d inclusive' % (lowLimit,highLimit,));
if (lowLimit != None) and value < lowLimit:
if lowLimit == 1:
raise SSBCCException('Must be a positive integer');
else:
raise SSBCCException('Cannot be less than %d' % lowLimit);
if (highLimit != None) and value > highLimit:
raise SSBCCException('Cannot be more than %d' % highLimit);
return value;
 
def IntPow2(self,value,minValue=1):
"""
Return the integer value of the argument if it is a power of 2. Otherwise
throw an error.
"""
if not IsPosInt(value):
raise SSBCCException('Not a positive integer');
value = ParseIntExpr(value);
if not IsPowerOf2(value):
raise SSBCCException('Not a power of 2');
if value < minValue:
raise SSBCCException('Must be at least %d' % minValue);
return value;
 
def PosInt(self,value,maxValue=0):
"""
Return the integer value of the argument unless it is out of bounds.\n
Note: maxValue=0 means that there is no upper limit.
"""
if not IsPosInt(value):
raise SSBCCException('Not a positive integer');
value = ParseIntExpr(value);
if (maxValue != 0) and (value > maxValue):
raise SSBCCException('Out of bounds -- can be at most %d' % maxValue);
return value;
 
def RateMethod(self,config,value):
"""
Return the string to evaluate the provided value or ratio of two values.
The value can be an integer (including underscores) or a parameter. Ratios
are restated to do rounding instead of truncation.\n
The value can be an integer (including underscores), a constant, or a
parameter. Ratios are restated to do rounding instead of truncation.\n
Examples:
123456
123_456
L_DIVISION_RATIO
G_CLOCK_FREQUENCY_HZ/19200
C_CLOCK_FREQUENCY_HZ/19200
G_CLOCK_FREQUENCY_HZ/L_BAUD_RATE
100_000_000/G_BAUD_RATE
"""
def TestAndGetValue(self,config,value,position):
if IsIntExpr(value):
return str(ParseIntExpr(value));
elif config.IsConstant(value):
value = config.constants[value];
if not value > 0:
raise SSBCCException('Constant "%s" must be positive');
return str(value);
elif config.IsParameter(value):
return value;
else:
raise SSBCCException('%s must be a positive integer or a previously declared positive constant or a parameter', position);
def LocalIntMethod(self,config,value,position=None):
try:
if config.IsParameter(value):
return value;
else:
v = self.IntMethod(config,value,lowLimit=1);
return str(v);
except SSBCCException, msg:
if not position:
raise SSBCCException(msg);
else:
raise SSBCCException('%s in %s' % (msg,position,));
if value.find('/') < 0:
return TestAndGetValue(self,config,value,'Value');
return LocalIntMethod(self,config,value);
else:
ratearg = re.findall('([^/]+)',value);
if len(ratearg) != 2:
raise SSBCCException('Only one "/" allowed in expression');
ratearg[0] = TestAndGetValue(self,config,ratearg[0],'Numerator');
ratearg[1] = TestAndGetValue(self,config,ratearg[1],'Denominator');
ratearg[0] = LocalIntMethod(self,config,ratearg[0],'numerator');
ratearg[1] = LocalIntMethod(self,config,ratearg[1],'denominator');
return '(%s+%s/2)/%s' % (ratearg[0],ratearg[1],ratearg[1],);
 
def TimeMethod(self,config,value,lowLimit=None,highLimit=None):
"""
Convert the provided time from the specified units to seconds.
"""
if not re.match(r'(0|[1-9]\d*)(\.\d*)?(e[+-]?\d+)?[mun]?s$',value):
raise SSBCCException('Malformed time value');
if value[-2:] == 'ms':
v = float(value[:-2]) * 1.e-3;
elif value[-2:] == 'us':
v = float(value[:-2]) * 1.e-6;
elif value[-2:] == 'ns':
v = float(value[:-2]) * 1.e-9;
else:
v = float(value[:-1]);
if (lowLimit != None) and (v < lowLimit):
raise SSBCCException('%s must be %s or greater' % (v,lowLimit,));
if (highLimit != None) and (v > highLimit):
raise SSBCCException('%s must be %s or smaller' % (v,highLimit,));
return v;
/ssbcc/trunk/ssbccUtil.py
105,7 → 105,7
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);
raise SSBCCException('Parameter length and value don\'t match: "%s"' % save_v);
return ov;
 
def IsIntExpr(value):
114,9 → 114,9
two integers.
Allow underscores as per Verilog.
"""
if re.match(r'[1-9][0-9_]*',value):
if re.match(r'-?[1-9][0-9_]*',value):
return True;
elif re.match(r'\([1-9][0-9_]*(\*[1-9][0-9_]*)+\)',value):
elif re.match(r'\(-?[1-9][0-9_]*(\*[1-9][0-9_]*)+\)',value):
return True;
else:
return False;
172,6 → 172,8
Note: If this routine is called, then the value should have already been
verified to be a well-formatted integer string.
"""
if type(value) == int:
return value;
if not IsIntExpr(value):
raise Exception('Program Bug -- shouldn\'t call with a badly formatted integer expression');
return eval(re.sub('_','',value));
/ssbcc/trunk/doc/MemoryInitialization.html
48,6 → 48,7
&nbsp;&nbsp;&nbsp;&nbsp;top_inst/uc_inst_Mram_s_opcodeMemory_1&nbsp;[0:8];<br/>
&nbsp;&nbsp;END_BUS_BLOCK;<br/>
END_ADDRESS_SPACE;<br/></tt><br/>
Note: For a Spartan-3A the bit indices <tt>[0:8]</tt> may need to be reversed.<br/><br/>
<li>Add this file to the build process.<br/><br/>
For a command-line build this is done by adding "<tt>-bm&nbsp;uc.bmm</tt>"
to the argument list for ngdbuild.<br/><br/>
/ssbcc/trunk/core/9x8/asm
44,6 → 44,7
 
argListParser = argparse.ArgumentParser(description='SSBCC 9x8 assembler');
argListParser.add_argument('-C', metavar='CONSTANT=value', action='append', help='Constant definition');
argListParser.add_argument('-D', metavar='define', type=str, action='append', help='Define symbol (must start with "D_")');
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');
64,7 → 65,7
# Record the constants in the program symbol table.
if argList.C:
for constant in argList.C:
a=re.findall(r'^(C_\w+)=(\w+)$',constant);
a=re.findall(r'^(C_\w+)=(-?[1-9]\d*|\w+)$',constant);
if not a:
raise asmDef.AsmException('Malformed -C argument: "%s"' % constant);
a = list(a[0]);
76,6 → 77,13
raise asmDef.AsmException('Command line constant "%s" already defined' % a[0]);
ad.AddSymbol(a[0], 'constant', body=[a[1]]);
 
# Record the defines.
if argList.D:
for name in argList.D:
if not re.match('D_',name):
raise SSBCCException('Bad define name "%s" should start with "D_"' % name);
ad.AddSymbol(name, 'define');
 
# Record the input names and values in the appropriate record type
if argList.G:
for parameter in argList.G:
/ssbcc/trunk/core/9x8/asmDef.py
401,7 → 401,7
if len(b.group(0)) == len(raw):
pass;
elif (raw[len(b.group(0))] != '(') or (raw[-1] != ')'):
raise AsmException('Malformed macro invokaction "%" at %s:%d' % (raw,fl_loc,col+1,));
raise AsmException('Malformed macro invokaction "%s" at %s:%d' % (raw,fl_loc,col+1,));
else:
tcol = len(b.group(0))+1;
while tcol < len(raw):
/ssbcc/trunk/core/9x8/ssbccGenVerilog.py
799,14 → 799,12
fp.write('// no additional signals\n');
return;
maxLength = 0;
for ix in range(len(config.signals)):
thisSignal = config.signals[ix];
for thisSignal in config.signals:
signalName = thisSignal[0];
if len(signalName) > maxLength:
maxLength = len(signalName);
maxLength = maxLength + 12;
for ix in range(len(config.signals)):
thisSignal = config.signals[ix];
for thisSignal in config.signals:
signalName = thisSignal[0];
signalWidth = thisSignal[1];
signalInit = "%d'd0" % signalWidth if len(thisSignal) < 3 else thisSignal[2];
/ssbcc/trunk/core/9x8/asmDef_9x8.py
42,8 → 42,8
"""
Add the named global symbol to the list of symbols including its mandatory
type and an optional body.\n
Note: Symbols include memory names, variables, constants, functions,
parameters, inports, outports, ...
Note: Symbols include memory names, variables, constants, defines,
functions, parameters, inports, outports, ...
"""
if self.IsSymbol(name):
raise Exception('Program Bug -- name "%s" already exists is symbols' % name);
383,19 → 383,10
# 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):
if (firstToken['value'] in ('.define','.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".
lastToken = rawTokens[-1];
if firstToken['value'] == '.main':
if (lastToken['type'] != 'macro') or (lastToken['value'] != '.jump'):
raise asmDef.AsmException('.main body does not end in ".jump" at %s' % lastToken['loc']);
# Ensure functions and interrupts end in a ".jump" or ".return".
if firstToken['value'] in ('.function','.interrupt',):
if (lastToken['type'] != 'macro') or (lastToken['value'] not in ('.jump','.return',)):
raise asmDef.AsmException('Last entry in ".function" or ".interrupt" must be a ".jump" or ".return" at %s' % lastToken['loc']);
# Ensure no macros and no instructions in non-"functions".
# Byproduct: No labels allowed in non-"functions".
if firstToken['value'] not in ('.function','.interrupt','.main',):
438,6 → 429,15
for arg in token['argument'][ixFirst:]:
if arg['type'] == 'symbol':
self.CheckSymbolToken(arg['value'],allowableTypes,arg['loc']);
# Ensure the main body ends in a ".jump".
lastToken = rawTokens[-1];
if firstToken['value'] == '.main':
if (lastToken['type'] != 'macro') or (lastToken['value'] != '.jump'):
raise asmDef.AsmException('.main body does not end in ".jump" at %s' % lastToken['loc']);
# Ensure functions and interrupts end in a ".jump" or ".return".
if firstToken['value'] in ('.function','.interrupt',):
if (lastToken['type'] != 'macro') or (lastToken['value'] not in ('.jump','.return',)):
raise asmDef.AsmException('Last entry in ".function" or ".interrupt" must be a ".jump" or ".return" at %s' % lastToken['loc']);
 
################################################################################
#
450,28 → 450,31
Return either (1) a list comprised of a single token which may not be a
byte or (2) a list comprised of multiple tokens, each of which is a single
byte.\n
Note: This is called by FillRawTokens.
Note: This is called by FillRawTokens.\n
Note: Multi-value lists must be single-byte values (i.e., in the range -128 to 255)
"""
if len(rawTokens) > 1:
limit = True;
values = list();
try:
for token in rawTokens:
if token['type'] == 'value':
v = token['value'];
if type(v) == int:
if limit and not (-128 <= v < 256):
raise Exception('Program Bug -- unexpected out-of-range value');
values.append(v);
else:
for v in token['value']:
if not (-128 <= v < 256):
raise Exception('Program Bug -- unexpected out-of-range value');
values.append(v);
else:
raise asmDef.AsmException('Illegal token "%s" at %s:%d:%d', (token['type'],token['loc']));
except:
raise asmDef.AsmException('Out-of-range token "%s" at %s:%d:%d', (token['type'],token['loc']));
for token in rawTokens:
if token['type'] == 'symbol':
ix = self.symbols['list'].index(token['value']);
symbolType = self.symbols['type'][ix];
if symbolType != 'constant':
raise asmDef.AsmException('Illegal symbol "%s" at %s' % (token['value'],token['loc'],));
value = self.symbols['body'][ix];
elif token['type'] == 'value':
value = token['value'];
else:
raise asmDef.AsmException('Illegal token "%s" with value "%s" at %s' % (token['type'],token['value'],token['loc'],));
if type(value) == int:
value = [value];
else:
limit = True;
for v in value:
if limit and not (-128 <= v < 256):
raise asmDef.AsmException('Out-of-rarnge value "%d" at %s' % (v,token['loc'],))
values.append(v);
return values;
 
def ExpandSymbol(self,token,singleValue):
596,6 → 599,9
if firstToken['value'] == '.constant':
byteList = self.ByteList(rawTokens[2:]);
self.AddSymbol(secondToken['value'],'constant',body=byteList);
# Process ".define" directive
elif firstToken['value'] == '.define':
self.AddSymbol(secondToken['value'],'define');
# Process ".function" definition.
elif firstToken['value'] == '.function':
self.AddSymbol(secondToken['value'],'function',self.ExpandTokens(rawTokens[2:]));
753,7 → 759,7
raise asmDef.AsmException('Function "%s" not defined for function "%s"' % (callName,self.functionEvaluation['list'][ix],));
ixName = self.symbols['list'].index(callName);
if self.symbols['type'][ixName] != 'function':
raise asmDef.AsmException('Function "%s" called by "%s" is not a function', (callName, self.functionEvaluation['list'][ix],));
raise asmDef.AsmException('Function "%s" called by "%s" is not a function' % (callName, self.functionEvaluation['list'][ix],));
self.functionEvaluation['list'].append(callName);
self.functionEvaluation['length'].append(self.symbols['body'][ixName]['length']);
self.functionEvaluation['body'].append(self.symbols['body'][ixName]['tokens']);
1207,6 → 1213,7
 
self.directives['list']= list();
self.directives['list'].append('.constant');
self.directives['list'].append('.define');
self.directives['list'].append('.function');
self.directives['list'].append('.interrupt');
self.directives['list'].append('.macro');
/ssbcc/trunk/core/9x8/peripherals/stepper_motor.py
0,0 → 1,476
################################################################################
#
# Copyright 2015, Sinclair R.F., Inc.
#
################################################################################
 
import math
 
from ssbccPeripheral import SSBCCperipheral
from ssbccUtil import CeilLog2
from ssbccUtil import SSBCCException
 
class stepper_motor(SSBCCperipheral):
"""
Stepper motor driver\n
This peripheral creates pulses to driver a stepper motor driver such as TI's
DRV8825. It includes a buffer which can be used to store acceleration,
motion, and deceleration profiles and returns a "completed" status to the
micro controller.\n
The core runs accumulators for the angle and the rate. I.e. the rate is an
accumulated sum of the initial rate and the commanded acceleration and the
angle is an accumulation of this possibly changing rate. The direction signal
to the stepper motor is the sign bit from the accumulated rate. The "step"
signal to the stepper motor driver is strobed every time the accumulated angle
overflows or underflows and the direction bit to the driver is set according
to whether the accumulated angle overflowed or underflowed.\n
The motor control word consists of the following signals:
initial rate
acceleration
number of steps to be performed this control word
optional mode specification
These control words are individually packed into one or more 8-bit bytes. The
8-bit values from the micro controller are shifted into a buffer from which
the control word is constructed. This completed control word is then shifted
into a FIFO. The control words in the FIFO are then used to generate the
timing for the step strobes to the stepper motor driver. When the FIFO
empties, the rate and the acceleration are set to zero and the mode retains
its most recent value. The user must ensure they do not overfill the FIFO --
the only FIFO status is an "empty" or control words "done" status.\n
Usage:
PERIPHERAL stepper_motor basename=name \\
outcontrol=O_name \\
outrecord=O_name \\
outrun=O_name \\
indone=I_name \\
inerror=I_name \\
ratemethod={CLK_FREQ_HZ/RATE_HZ|count} \\
ratescale=N_rate_scale \\
rateres=N_rate \\
accelscale=N_accel_scale \\
accelres=N_accel \\
[accumres=N_accum] \\
countwidth=N_count \\
[modewidth=N_mode] \\
[FIFO=N_fifo]\n
Or:\n
PERIPHERAL stepper_motor basename=name \\
master=mastername \\
outcontrol=O_name \\
outrecord=O_name \\
outrun=O_name \\
indone=I_name \\
inerror=I_name \\
[FIFO=N_fifo]\n
Where:
basename=name
specifies the name used to contruct the I/O signals
Note: The name must start with an alphabetic character.
Example: "basename=stepper" results in the names "o_stepper_dir",
"o_stepper_step", and "o_stepper_mode" for the output
direction, step, and optional mode signals and
"i_stepper_error" for the input error signal.
master=mastername
specifies a preceding stepper_motor peripheral to use for the internal
clock and to use for the accleration, rate, angle accumulator, and mode
sizes
outcontrol=O_name
specifies the port used to assemble 8-bit control values into the stepper
motor control word
Note: The name must start with "O_".
outrecord=O_name
specifies the port used to generate the strobe that pushes the assembled
motor control word into the stepper motor FIFO
Note: The name must start with "O_".
outrun=O_name
specified the port used to begin the sequence of operations specified by
the motor control words in the buffer
Note: The name must start with "O_".
indone=I_name
specifies the port used to determine whether or not the operations in the
FIFO have finished
Note: The name must start with "I_".
inerror=I_name
specifies the port used to read the error status from the stepper motor
controller
Note: The name must start with "I_".
ratemethod
specified the method to generate the internal clock rate from the
processor clock
1st method: CLK_FREQ_HZ/RATE_HZ
CLK_FREQ_HZ is the frequency of "i_clk" in Hz
a number will be interpreted as the clock frequency in Hz
a symbol will be interpreted as a constant or a parameter
Note: the symbol must be declared with the CONSTANT, LOCALPARARM,
or PARAMETER configuration command.
RATE_HZ is the desired internal clock rate
this is specified as per "CLK_FREQ_HZ"
2nd method: count
specify the number of "i_clk" clock cycles per internal clock cycle
Note: CLK_FREQ_HZ, RATE_HZ, and count can be parameters or constants. For example,
the following uses the parameter C_CLK_FREQ_HZ for the clock
frequency and an internal rate to 500 kHz:
"ratemethod=C_CLK_FREQ_HZ/500_000".
Note: The minimum value of "ratemethod" is 2.
ratescale=N_rate_scale
specifies the scaling for the most significant bit of the rate
Note: See the 'a' parameter in the "Theory of Operation" section.
rateres=N_rate
specifies the resolution of the rate
Note: See the 'r' parameter in the "Theory of Operation" section.
accelscale=N_accel_scale
specifies the scaling for the most significant bit of the acceleration
Note: See the 'a' parameter in the "Theory of Operation" section.
accelres=N_accel
specifies the resolution for the acceleration
Note: See the 'b' parameter in the "Theory of Operation" section.
accumres=N_accum
optionally specify the resolution for the accumulator to the summed angle
(from which the step strobes are generated)
Note: This must be between rateres and accelres.
Note: The default value is accelres.
countwidth=N_count
specifies the width of the counter for the number of steps to be performed
by the control word
modewidth=N_mode
- if not specified, there is no mode signal to the stepper motor
controller
- if specified then this specifies the width of the signal to the stepper
motor controller
FIFO=N_fifo
optionally specify the depth of the control word FIFO
Note: This must be a power of 2 and must be at least 16.
Note: The default is 16.\n
Theory of Operation:
Define the following:
n is the number of internal clock cycles since the control word
started being performed (i.e., these are counted after the dlock
rate is reduced by ratemethod)
F is the internal clock cycle frequency (i.e., RATE_HZ in the
second form for specifying the ratemethod
R_0 is the initial rate command
R_n is the accumulated rate after n internal clock cycles
A is the commanded acceleration
S_n is the accumulated step after n internal clock cycles
Then
R_n = R_0 + A * n
S_n = R_0 * n + A * n * (n-1) / 2
The rate R_n can be thought of as a signed fraction with the format "s0.r"
where 's' represents the sign bit, there are no bits to the left of the
decimal, and there are 'r' bits to the right of the decimal. Then the rate
can be as high as F and as low as F/2^r. Practically, the maximum rate
cannot exceed half the internal clock frequency, otherwise the "step"
signals will merge together and the stepper driver will not see distinct
driver pulses.\n
Similarly, the acceleration command A can be thought of as a signed fraction
with the format "sa.b". Here 's' again represents the sign bit and 'b'
represents the number of bits to the right of the decimial, but 'a' is a
negative number representing the first bit in A. I.e., aside from the sign
bit, A is b+a+1 bits wide. For example, the specification s-4.8 means that
A has a sign bit with 8-4+1 = 5 bits for the value of A with the leasts
significant bit representing a rate of F^2/2^8.\n
The bit widths are determined as follows: Let mR be the minimum non-zero
magnitude of the rate, mA be the minimum non-zero mangitude of the
acceleration, and MA be the mamximum magnitude of the acceleration, all in
step/sec or step/sec^2. Then\n
r = ceil(-log_2(mR/F))\n
a = floor(log_2(MA/F^2))\n
b = ceil(-log_2(mA/f^2))\n
Note: r and b may be increased by a few bits if accurate representations of
the minimum rates are needed.\n
Example:
A micro controller with an 8 MHz clock is used to operate a DRV8825 driving
a stepper motor assembly. The stepper motor has 200 steps per revolution,
can be operated in full-step or a 16-step micro step mode, has a maximum
rotation rate of 10 Hz, and has a maximum acceleration of 4 Hz/sec (i.e.,
800 full-steps/sec^2). The motor is attached to a 400mm theaded rod with a
pitch of 4mm per revolution.\n
The 1.9usec minimum high and low widths of the DRV8825 and the 8 MHz
processor clock mean that the stepper motor controller can realistically be
run at 500kHz. The rate method to divide the micro controller clock to the
internal processing rate is specified by "ratemethod" in the PERIPHERAL
command.\n
The bit widths are determine by choosing:\n
MR = 10 rev/sec * 200 full-step/rev * 16 micro-step/full-step
= 32000 micro-step/sec
==> R = -ceil(log_2(MR/F))
= -ceil(log_2((32000 micro-step/sec)/500kHz))
= 3
mR = 10 step/sec
==> r = -floor(log_2(mR/F))
= -floor(log_2((10 step/sec)/500kHz)
= 16\n
MA = 10 rev/sec^2 = 10*16*200 step/sec^2
==> A = -ceil(log_2(MA/F^2))
= -ceil(log_2((32,000 step/sec^2)/500kHz^2))
= 22\n
mA = 20 step/sec^2 (in full step mode)
==> a = -floor(log_2(mA/F^2))
= 34\n
The values R=3 and r=16 along with the sign bit mean the rate would be
stored in a signed 14-bit value. The rate requires two 8-bit writes to the
control word.\n
The values A=22 and a=34 mean the acceleration would be stored in a signed
1+(34-22) = 13 bit value. The acceleration requires two 8-bit writes to the
control word.\n
The accumulator width is set to the same value as the acceleration
resolution. This avoid non-linear trunction errors and makes the motion
profile more predictable using simple integer arithmetic.\n
The number of full steps to move from one of the of rod to the other is
(400mm/(4mm/rev)*(200steps/rev)=20_000 steps. In the micro-stepmode there
are 16 micro steps per full step, so at most 320_000 micro steps can be
performed before the full length of the rod is traversed. I.e., a 19-bit
counter will suffice for the worst-case unidirection motion. This 19-bit
count requires 3 8-bit writes to the control word.\n
A "modewidth" of 1 is specifies so that the controller can be operated in
either full step or a single hard-wired micro-step mode. If all 3 of the
DRV8825 mode pins were connected, then "modewidth=3" would need to
specified.\n
The peripheral is then specified as follows:\n
CONSTANT C_RATE_SCALE 3
CONSTANT C_RATE_RES 16
CONSTANT C_ACCEL_SCALE 22
CONSTANT C_ACCEL_RES 34
CONSTANT C_ACCUM_RES 34
CONSTANT C_COUNT_WIDTH 19
PERIPHERAL stepper_motor basename=stepper \\
outcontrol=O_stepper_control \\
outrecord=O_stepper_wr \\
outrun=O_stepper_go \\
indone=I_stepper_done \\
inerror=I_stepper_error \\
ratemethod=8_000_000/500_000 \\
ratescale=C_RATE_SCALE \\
rateres=C_RATE_RES \\
accelscale=C_ACCEL_SCALE \\
accelres=C_ACCEL_RES \\
accumres=C_ACCUM_RES \\
countwidth=C_COUNT_WIDTH \\
modewidth=1\n
and the TBD byte control words are pushed into the peripheral as follows:
R_0 14-bit initial rate stored in a 16-bit field (MSB first)
A 13-bit acceleration stored in a 16-bit field (MSB first)
COUNT 19-bit count stored in a 24-bit field (MSB first)
MODE 1-bit mode stored as the lsb of an 8-bit field
The control word is a total of 8 bytes wide.\n
To command the peripheral to accelerate from stop to 200 steps/sec in one
second in the forward direction using the full-step mode, the following
seqeuence of bytes would be written to the control port:
0x00 0x00 ; initial rate is zero
0x00 0x0E ; 200 step/sec^2 * 2^34 / 500kHz^2 = 14
0x00 0x00 0x63 ; send 100 step commands (command 100-1=99)
0x00 ; full-step mode
Note: It will take t=sqrt(2*100*2^34/14)/F = 0.99 sec to move the commanded
100 steps. At this time the speed will be r=t*14/2^34*F^2 = 201 step/sec.
A more accurate match to the commanded speed could be accomplished by adding
additional bits to the acceleration resolution at the cost of using more
FPGA resources. Alternatively, the acceleration could be commanded for 99
steps and any subsequent 200 step/sec motion could be lengthened by 1 step.
Another alternative would be to use a micro-step acceleration. Practically,
the computed command is within 0.5% of the desired step rate.\n
To command the peripheral to decelerate from 200 step/sec to zero in one
second, the following sequence of bytes would be written to the control
port:
0x00 0x01 0xDB ; 200 step/sec * 2^23 / 500kHz
0xFF 0x9C ; negative of the above acceleration
0x00 0x00 0x63 ; send 100 step commands (command 100-1=99)
0x00 ; full-step mode\n
The first of these two control words could be assembled and transmitted to
the peripheral as follows:\n
0x00 ; mode
.push24(${100-1}) ; send 100 step commands
.push16(14) ; 200 step/sec^2
.push16(0) ; initial rate is zero
${8-1} :loop swap .outport(O_stepper_control) .jumpc(loop,1-) drop
.outstrobe(O_stepper_wr) ; push the assembed control word into the FIFO
...
.outstrobe(O_stepper_go) ; perform the queued control words\n
Example:
Slave a second stepper motor controller peripheral to the preceding
periperal.\n
PERIPHERAL stepper_motor basename=slave \\
master=stepper \\
outcontrol=O_slave_control \\
outrecord=O_slave_wr \\
outrun=O_slave_go \\
indone=I_slave_done \\
inerror=I_slave_error\n
This controller will use the internal clock generated by the first
controller and the scales, resolutions, and accumulator width will be the
same as that master peripheral. What will be different is the four I/O
ports used to operate and status the controller.
"""
 
def __init__(self,peripheralFile,config,param_list,loc):
# Use the externally provided file name for the peripheral
self.peripheralFile = peripheralFile
# Get the parameters.
allowables = (
( 'FIFO', r'\S+$', lambda v : self.IntPow2Method(config,v,lowLimit=16), ),
( 'accelres', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1), ),
( 'accelscale', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1), ),
( 'accumres', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1), ),
( 'basename', r'[A-Za-z]\w*$', None, ),
( 'countwidth', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1), ),
( 'indone', r'I_\w+$', None, ),
( 'inerror', r'I_\w+$', None, ),
( 'master', r'[A-Za-z]\w*$', None, ),
( 'modewidth', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1), ),
( 'outcontrol', r'O_\w+$', None, ),
( 'outrecord', r'O_\w+$', None, ),
( 'outrun', r'O_\w+$', None, ),
( 'ratemethod', r'\S+$', lambda v : self.RateMethod(config,v), ),
( 'rateres', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1), ),
( 'ratescale', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1), ),
)
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])
# Signals that can't be specified when a master is specified.
masterExclude = (
'accelres',
'accelscale',
'accumres',
'countwidth',
'modewidth',
'ratemethod',
'rateres',
'ratescale',
)
# Ensure the required parameters are provided.
reqdParms = (
'basename',
'indone',
'inerror',
'outcontrol',
'outrecord',
'outrun',
)
if not hasattr(self,'master'):
reqdParms += tuple([me for me in masterExclude if me not in ('accumres','modewidth',)])
for paramname in reqdParms:
if not hasattr(self,paramname):
raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,))
# Ensure mutually exclusive parameters are not listed.
if hasattr(self,'master'):
for paramname in masterExclude:
if hasattr(self,paramname):
raise SSBCCException('Parameter "%s" cannot be specified alongside "master" at %s' % (paramname,loc,))
# Ensure basename is unique for this class of peripheral
for p in config.peripheral:
if (str(p.__class__) == str(self.__class__)) and (p.basename == self.basename):
raise SSBCCException('Duplicated stepper_motor basename "%s" at %s' % (self.basename,loc,))
# For slaves, copy the bit widths from the master peripheral.
if hasattr(self,'master'):
for p in config.peripheral:
if (str(p.__class__) == str(self.__class__)) and (p.basename == self.master):
break
else:
raise SSBCCException('Can\'t find preceding stepper_motor peripheral with basename=%s at %s ' % (self.master,loc,))
self.master = p
for paramname in masterExclude:
setattr(self,paramname,getattr(self.master,paramname))
# Set unspecified optional parameters.
if not hasattr(self,'accumres'):
self.accumres = self.accelres
if not hasattr(self,'modewidth'):
self.modewidth = 0
if not hasattr(self,'FIFO'):
self.FIFO = 16
# Ensure the parameters satisfy any mutual constraints.
if not (self.rateres < self.accelres):
raise SSBCCException('rateres should be smaller than accelres at %s' % loc)
if not (self.rateres <= self.accumres <= self.accelres):
raise SSBCCException('accumres must be between rateres and accelres at %s' % loc)
# Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
config.AddIO('o_%s_dir' % self.basename, 1, 'output', loc)
config.AddIO('o_%s_step' % self.basename, 1, 'output', loc)
if self.modewidth > 0:
config.AddIO('o_%s_mode' % self.basename, 1, 'output', loc)
config.AddIO('i_%s_error' % self.basename, 1, 'input', loc)
config.AddSignal('s__%s__done' % self.basename, 1, loc)
self.ix_outcontrol = config.NOutports()
config.AddOutport((self.outcontrol,
False,
# empty list
),loc)
self.ix_outrecord = config.NOutports()
config.AddOutport((self.outrecord,
True,
# empty list
),loc)
self.ix_outrun = config.NOutports()
config.AddOutport((self.outrun,
True,
# empty list
),loc)
config.AddInport((self.inerror,
('i_%s_error' % self.basename, 1, 'data', ),
), loc)
config.AddInport((self.indone,
('s__%s__done' % self.basename, 1, 'data', ),
), loc)
# Compute bit widths.
dw = config.Get('data_width')
self.data_width = dw
self.ratecmdwidth = 1 + self.rateres - self.ratescale
self.ratewidth = 1 + self.accelres - self.ratescale
self.accelwidth = 1 + self.accelres - self.accelscale
self.accumwidth = self.accumres + 1
self.controlwidth = self.ratecmdwidth
self.controlwidth += dw*int((self.accelwidth+dw-1)/dw)
self.controlwidth += dw*int((self.countwidth+dw-1)/dw)
self.controlwidth += dw*int((self.modewidth+dw-1)/dw)
self.controlwidthpacked = self.ratecmdwidth + self.accelwidth + self.countwidth + self.modewidth
# Add the 'clog2' function to the processor (if required).
config.functions['clog2'] = True
 
def GenVerilog(self,fp,config):
body = self.LoadCore(self.peripheralFile,'.v')
if hasattr(self,'master'):
body = re.sub(r'@MASTER_BEGIN@.*?@MASTER_END@\n','',body,flags=re.DOTALL)
else:
body = re.sub(r'@MASTER_BEGIN@\n','',body)
body = re.sub(r'@MASTER_END@\n','',body)
if self.modewidth == 0:
body = re.sub(r'@OUTMODE_BEGIN@.*?@OUTMODE_END@\n','',body,flags=re.DOTALL)
else:
body = re.sub(r'@OUTMODE_BEGIN@\n','',body)
body = re.sub(r'@OUTMODE_END@\n','',body)
for subpair in (
( r'@ACCEL_WIDTH@', str(self.accelwidth), ),
( r'@ACCEL_RES@', str(self.accelres), ),
( r'@ACCEL_SCALE@', str(self.accelscale), ),
( r'@ACCUM_RES@', str(self.accumres), ),
( r'@ACCUM_WIDTH@', str(self.accumwidth), ),
( r'@CONTROL_WIDTH@', str(self.controlwidth), ),
( r'@CONTROL_WIDTH_PACKED@', str(self.controlwidthpacked), ),
( r'@COUNT_WIDTH@', str(self.countwidth), ),
( r'@DW@', str(self.data_width), ),
( r'@DWM1@', str(self.data_width-1), ),
( r'@FIFO_DEPTH@', str(self.FIFO), ),
( r'@IX_OUTCONTROL@', str(self.ix_outcontrol), ),
( r'@IX_OUTRECORD@', str(self.ix_outrecord), ),
( r'@IX_OUTRUN@', str(self.ix_outrun), ),
( r'@MODE_WIDTH@', str(self.modewidth), ),
( r'@NAME@', self.basename, ),
( r'@NBITS_FIFO_DEPTH@', str(CeilLog2(self.FIFO)), ),
( r'@OUTMODEWIDTH@', str(self.modewidth), ),
( r'@RATECMD_WIDTH@', str(self.ratecmdwidth), ),
( r'@RATEMETHOD@', str(self.ratemethod), ),
( r'@RATE_RES@', str(self.rateres), ),
( r'@RATE_SCALE@', str(self.ratescale), ),
( r'@RATE_WIDTH@', str(self.ratewidth), ),
( r'\bL__', 'L__%s__' % self.basename, ),
( r'\bi__', 'i_%s_' % self.basename, ),
( r'\bo__', 'o_%s_' % self.basename, ),
( r'\bs__', 's__%s__' % self.basename, ),
( r'@S__CLK_EN@', 's__%s__clk_en' % (self.basename if not hasattr(self,'master') else self.master.basename), ),
):
body = re.sub(subpair[0],subpair[1],body)
body = self.GenVerilogFinal(config,body)
fp.write(body)
/ssbcc/trunk/core/9x8/peripherals/outFIFO_async.py
68,7 → 68,7
('data_empty', r'o_\w+$', None, ),
('outport', r'O_\w+$', None, ),
('infull', r'I_\w+$', None, ),
('depth', r'[1-9]\d*$', lambda v : self.IntPow2(v,minValue=16), ),
('depth', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v,lowLimit=16), ),
);
names = [a[0] for a in allowables];
for param_tuple in param_list:
ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/tb.v Property changes : Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -Author Date Id Revision \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/tb.v-normal =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/tb.v-normal (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/tb.v-normal (revision 9) @@ -0,0 +1,75 @@ +/******************************************************************************* + * + * Copyright 2013, Sinclair R.F., Inc. + * + * Test bench for the UART_Rx 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 + +// 115200 baud, 1 stop bit +reg [15*10:0] s_buf1 = { + // list last byte first + 1'b1, 8'h00, 1'b0, // null character (also terminates program) + 1'b1, 8'h0A, 1'b0, // LF + 1'b1, 8'h0D, 1'b0, // CR + 1'b1, 8'h12, 1'b0, // '!' + 1'b1, 8'h63, 1'b0, // 'd' + 1'b1, 8'h6C, 1'b0, // 'l' + 1'b1, 8'h72, 1'b0, // 'r' + 1'b1, 8'h6F, 1'b0, // 'o' + 1'b1, 8'h57, 1'b0, // 'W' + 1'b1, 8'h20, 1'b0, // ' ' + 1'b1, 8'h6F, 1'b0, // 'o' + 1'b1, 8'h6C, 1'b0, // 'l' + 1'b1, 8'h6C, 1'b0, // 'l' + 1'b1, 8'h65, 1'b0, // 'e' + 1'b1, 8'h48, 1'b0, // 'H' + 1'b1 + }; +wire s_uart = s_buf1[0]; +initial begin + @ (negedge s_rst); + #100; + forever begin + #8680.555; + s_buf1 <= { 1'b1, s_buf1[1+:15*10] }; + end +end + +wire [7:0] s_data; +wire s_data_wr; +wire s_done; +tb_UART_Rx uut( + // synchronous reset and processor clock + .i_rst (s_rst), + .i_clk (s_clk), + .i_uart_rx (s_uart), + .o_data (s_data), + .o_data_wr (s_data_wr), + .o_done (s_done) +); + +always @ (posedge s_clk) + if (s_data_wr) + $display("%h", s_data); + +always @ (posedge s_clk) + if (s_done) + $finish; + +endmodule Index: ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/run =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/run (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/run (revision 9) @@ -1,9 +1,9 @@ #!/bin/bash -# Copyright 2013, Sinclair R.F., Inc. +# Copyright 2013, 2015, Sinclair R.F., Inc. NAME=UART_Rx -cat < good +cat < tb.good 48 65 6c @@ -22,13 +22,14 @@ EOF # Test +/-2.7% and 0% baud rates. -cp tb_UART_Rx.s-normal tb_UART_Rx.s; +cp tb_${NAME}.s-normal tb_${NAME}.s; +cp tb.v-normal tb.v for baud in 112089 115200 118310; do sed -e "s/115200/${baud}/" tb_${NAME}.9x8-good > tb_${NAME}.9x8; ../../../../../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; - if ! cmp -s tb.out good; then + if ! cmp -s tb.out tb.good; then echo "${NAME} failed testing baud rate: ${baud}" > /dev/stderr; exit 1; fi @@ -35,15 +36,34 @@ done # Partial test for input FIFO. -cp tb_UART_Rx.s-fifo tb_UART_Rx.s; +cp tb_${NAME}.s-fifo tb_${NAME}.s; +cp tb.v-normal tb.v sed -e "s/G_BAUD$/G_BAUD inFIFO=16/" tb_${NAME}.9x8-good > tb_${NAME}.9x8; ../../../../../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 -if ! cmp tb.out good; then +if ! cmp tb.out tb.good; then echo "${NAME} FIFO test failed" > /dev/stderr; exit 1; fi +# Validate RTRn signal generation +cp tb_${NAME}.s-rtrn tb_${NAME}.s +cp tb.v-rtrn tb.v +for RTR_BUFFER in 1 2 4; do + for RTR_OVERFLOW in 0 1 2 3; do + if [ ${RTR_OVERFLOW} -ge ${RTR_BUFFER} ]; then continue; fi + sed -e "s/G_BAUD$/G_BAUD inFIFO=8 RTRn=o_uart_rtrn rtr_buffer=${RTR_BUFFER}/" tb_${NAME}.9x8-good > tb_${NAME}.9x8; + sed -e "s/@RTR_OVERFLOW@/${RTR_OVERFLOW}/" tb.v-rtrn > tb.v; + ../../../../../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 + if ! cmp tb.out tb.good; then + echo "${NAME} FIFO test failed" > /dev/stderr; + exit 1; + fi + done +done + echo "Passed: ${NAME}"; exit 0;
/ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/.gitignore
1,7 → 1,8
bad-*
good
tb
tb.good
tb.out
tb.v
tb_UART_Rx.9x8
tb_UART_Rx.s
tb_UART_Rx.v
/ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/tb_UART_Rx.9x8-good
1,4 → 1,4
# Copyright 2013, Sinclair R.F., Inc.
# Copyright 2013, 2015, Sinclair R.F., Inc.
# Test bench for UART_Rx peripheral.
 
ARCHITECTURE core/9x8 Verilog
9,9 → 9,9
PARAMETER G_CLK_FREQ_HZ 100_000_000
PARAMETER G_BAUD 115200
 
PERIPHERAL UART_Rx inport=I_UART_RX \
inempty=I_UART_RX_EMPTY \
insignal=i_uart \
PERIPHERAL UART_Rx inport=I_UART_RX \
inempty=I_UART_RX_EMPTY \
insignal=i_uart_rx \
baudmethod=G_CLK_FREQ_HZ/G_BAUD
 
OUTPORT 8-bit,strobe o_data,o_data_wr O_DATA
/ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/tb.v-rtrn
0,0 → 1,95
/*******************************************************************************
*
* Copyright 2015, Sinclair R.F., Inc.
*
* Test bench for the UART_Rx 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
 
// 115200 baud, 1 stop bit
reg [15*10:0] s_buf1 = {
// list last byte first
1'b1, 8'h00, 1'b0, // null character (also terminates program)
1'b1, 8'h0A, 1'b0, // LF
1'b1, 8'h0D, 1'b0, // CR
1'b1, 8'h12, 1'b0, // '!'
1'b1, 8'h63, 1'b0, // 'd'
1'b1, 8'h6C, 1'b0, // 'l'
1'b1, 8'h72, 1'b0, // 'r'
1'b1, 8'h6F, 1'b0, // 'o'
1'b1, 8'h57, 1'b0, // 'W'
1'b1, 8'h20, 1'b0, // ' '
1'b1, 8'h6F, 1'b0, // 'o'
1'b1, 8'h6C, 1'b0, // 'l'
1'b1, 8'h6C, 1'b0, // 'l'
1'b1, 8'h65, 1'b0, // 'e'
1'b1, 8'h48, 1'b0, // 'H'
1'b1
};
`define BIT_DELAY 8680.555
wire s_uart = s_buf1[0];
wire s_rtrn;
integer ix_bit = 0;
task xmit_char;
for (ix_bit=0; ix_bit<10; ix_bit=ix_bit+1) begin
#`BIT_DELAY;
s_buf1 <= { 1'b1, s_buf1[1+:15*10] };
end
endtask
integer ix_char = 0;
initial begin
@ (negedge s_rst);
#100;
for (ix_char=0; ix_char<15; ix_char=ix_char+1) begin
if (s_rtrn) begin
repeat (@RTR_OVERFLOW@) xmit_char;
while (s_rtrn)
#`BIT_DELAY;
end
xmit_char;
end
end
 
wire [7:0] s_data;
wire s_data_wr;
wire s_done;
tb_UART_Rx uut(
// synchronous reset and processor clock
.i_rst (s_rst),
.i_clk (s_clk),
.i_uart_rx (s_uart),
.o_uart_rtrn (s_rtrn),
.o_data (s_data),
.o_data_wr (s_data_wr),
.o_done (s_done)
);
 
always @ (posedge s_clk)
if (s_data_wr)
$display("%h", s_data);
 
always @ (posedge s_clk)
if (s_done)
$finish;
 
//initial begin
// $dumpfile("tb.vcd");
// $dumpvars();
//end
 
endmodule
/ssbcc/trunk/core/9x8/peripherals/tb/UART_Rx/tb_UART_Rx.s-rtrn
0,0 → 1,24
; Copyright 2015, Sinclair R.F., Inc.
;
; Test bench for UART_Rx peripheral with RTRn signal output.
 
.main
 
; Wait for the FIFO to fill.
0x00 0x41 >r :wait
.jumpc(no_major_dec,1-) r> 1- >r :no_major_dec r@ -1<> .jumpc(wait)
 
; Read from the UART Rx port until the terminating null character is encountered.
:loop
;If no character is available, then continue waiting.
.inport(I_UART_RX_EMPTY) .jumpc(loop)
; Read the next character and output it, preserving it on the data stack.
.inport(I_UART_RX) O_DATA outport
; If the character was not a null character, then continue running the loop.
.jumpc(loop)
 
; Signal program termination.
1 .outport(O_DONE)
 
; Wait forever.
:infinite .jump(infinite)
/ssbcc/trunk/core/9x8/peripherals/tb/runall
4,7 → 4,7
#
# Run all of the test benches for the peripherals.
 
for runname in `find -name run`; do
for runname in `find -maxdepth 2 -name run | sort`; do
cd ${runname:0:${#runname}-4};
echo -en "${runname:2:${#runname}-6}\r";
./run || { echo "Tests aborted"; exit 1; }
/ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_only.gtkw
0,0 → 1,25
[*]
[*] GTKWave Analyzer v3.3.59 (w)1999-2014 BSI
[*] Mon Feb 2 23:42:54 2015
[*]
[dumpfile] "/home/rsinclair/Projects/SSBCC/core/9x8/peripherals/tb/stepper_motor/tb.vcd"
[dumpfile_mtime] "Mon Feb 2 22:26:13 2015"
[dumpfile_size] 6332908
[savefile] "/home/rsinclair/Projects/SSBCC/core/9x8/peripherals/tb/stepper_motor/tb_only.gtkw"
[timestart] 0
[size] 1920 1161
[pos] 2559 0
*-33.735813 52850000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[sst_width] 225
[signals_width] 255
[sst_expanded] 1
[sst_vpaned_height] 427
@28
tb.s_rst
tb.s_clk
tb.s_done
tb.s_stepper_dir
@29
tb.s_stepper_step
[pattern_trace] 1
[pattern_trace] 0
/ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.gtkw
0,0 → 1,72
[*]
[*] GTKWave Analyzer v3.3.59 (w)1999-2014 BSI
[*] Thu Jan 29 19:29:10 2015
[*]
[dumpfile] "/home/rsinclair/Projects/SSBCC/core/9x8/peripherals/tb/stepper_motor/tb.vcd"
[dumpfile_mtime] "Thu Jan 29 19:29:10 2015"
[dumpfile_size] 5570292036
[savefile] "/home/rsinclair/Projects/SSBCC/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.gtkw"
[timestart] 107951000
[size] 1920 1161
[pos] 1279 0
*-19.698416 110500000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] tb.
[sst_width] 225
[signals_width] 395
[sst_expanded] 1
[sst_vpaned_height] 427
@28
tb.s_clk
tb.s_dir
tb.s_rst
tb.s_step
tb.s_done
@800200
-uut
@28
tb.uut.s_inport
tb.uut.s_outport
tb.uut.s__o_step__go
tb.uut.s__o_step__running
tb.uut.s__o_step__done
@200
-stepper_motor
@22
tb.uut.s__o_step__input_control_word[63:0]
tb.uut.s__o_step__input_control_word_packed[58:0]
@28
tb.uut.s__o_step__FIFO_wr
@22
tb.uut.s__o_step__FIFO_in_addr[4:0]
@28
tb.uut.s__o_step__FIFO_rd
@22
tb.uut.s__o_step__FIFO_out_addr[4:0]
tb.uut.s__o_step__output_control_word[58:0]
tb.uut.s__o_step__next_rate[23:0]
tb.uut.s__o_step__next_accel[15:0]
tb.uut.s__o_step__next_count[18:0]
@28
tb.uut.s__o_step__FIFO_empty
tb.uut.s__o_step__clk_en
@22
tb.uut.s__o_step__clk_en_count[3:0]
@28
tb.uut.s__o_step__go
tb.uut.s__o_step__running
tb.uut.s__o_step__load_next
tb.uut.s__o_step__done
tb.uut.s__o_step__step_pre
@22
tb.uut.s__o_step__count[18:0]
@28
tb.uut.s__o_step__count_zero
@22
tb.uut.s__o_step__angle[37:0]
tb.uut.s__o_step__rate[37:0]
tb.uut.s__o_step__accel[15:0]
tb.uut.s__o_step__angle_presum[37:0]
@1000200
-uut
[pattern_trace] 1
[pattern_trace] 0
/ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/run
0,0 → 1,17
#!/bin/bash
#
# Copyright 2015, Sinclair R.F., Inc.
 
NAME=stepper_motor
 
../../../../../ssbcc -q --define-clog2 -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;
 
if ! cmp -s tb.out tb.good; then
echo "${NAME} failed" > /dev/stderr;
exit 1;
fi
 
echo "Passed: ${NAME}";
exit 0;
ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/.gitignore =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/.gitignore (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/.gitignore (revision 9) @@ -0,0 +1,3 @@ +tb +tb.out +tb_stepper_motor.v Index: ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.s =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.s (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.s (revision 9) @@ -0,0 +1,77 @@ +; Copyright 2015, Sinclair R.F., Inc. +; +; Test bench for stepper_motor peripheral. + +.macro push16 +.macro push24 + +.main + + ; Forward acceleration. + .push24(${10-1}) ; 10 steps + .push16(3436) ; 50_000 step/sec^2 (50e3*2**34/F**2 where F=5.e5) + .push16(0) ; initial rate = 0 + .call(push_command) + + ; Continue uniform motion. + .push24(${10-1}) ; 10 steps + .push16(0) ; no acceleration + .push16(131) ; 1000 step/sec (1.e3*2**16/F) + .call(push_command) + + ; Decelerate to stop motion. + .push24(${10-1}) ; 10 steps + .push16(-3432) ; -50_000 step/sec^2 (actual -v**2/(2*10) ==> 3432.2) + .push16(131) ; 1000 step/sec + .call(push_command) + + ; Accelerate in negative direction. + .push24(${10-1}) ; 10 steps + .push16(-3436) ; -50_000 step/sec^2 + .push16(-1) ; ~0 step/sec + .call(push_command) + + ; Continue uniform motion. + .push24(${10-1}) ; 10 steps + .push16(0) ; no acceleration + .push16(-131) ; 1000 step/sec (1.e3*2**23/F) + .call(push_command) + + ; Decelerate to stop motion. + .push24(${10-1}) ; 10 steps + .push16(3432) ; -50_000 step/sec^2 + .push16(-131) ; 1000 step/sec (1.e3*2**23/F) + .call(push_command) + + ; Command the motion profile to run. + .outstrobe(O_GO) + + ; Wait for the profile to finish. + :loop_wait .inport(I_DONE) 0= .jumpc(loop_wait) + + ; Wait about 10 usec + ${(10*8)/3} :wait_done .jumpc(wait_done,1-) drop + + ; Indicate termination to the test bench. + 1 .outport(O_DONE) + + ; Wait forever + :infinite .jump(infinite) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; Stepper motor utilities. +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.constant C_RATE_WIDTH ${C_RATE_RES-C_RATE_SCALE+1} +.constant C_ACCEL_WIDTH ${1+C_ACCEL_RES-C_ACCEL_SCALE} +.constant C_NBYTES ${int((C_RATE_WIDTH+7)/8)+int((C_ACCEL_WIDTH+7)/8)+int((C_COUNT_WIDTH+7)/8)} + +; Send the control word on the stack to the stepper motor peripheral and record it in the FIFO. +; ( u_count_LSB ... u_accel_LSB ... u_rate_MSB - ) +.function push_command + ${C_NBYTES-1} :loop swap .outport(O_CONTROLWORD) .jumpc(loop,1-) drop + .outstrobe(O_CONTROLWORD_WR) + .return Index: ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb.v =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb.v (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb.v (revision 9) @@ -0,0 +1,51 @@ +/******************************************************************************* + * + * Copyright 2015, Sinclair R.F., Inc. + * + * Test bench for the stepper_motor peripheral. + * + ******************************************************************************/ + +`timescale 1ns/1ps + +module tb; + +// 2 MHz clock +reg s_clk = 1'b1; +always @ (s_clk) + s_clk <= #250 ~s_clk; + +reg s_rst = 1'b1; +initial begin + repeat (5) @ (posedge s_clk); + s_rst = 1'b0; +end + +wire s_stepper_dir; +wire s_stepper_step; +wire s_done; +tb_stepper_motor uut( + // synchronous reset and processor clock + .i_rst (s_rst), + .i_clk (s_clk), + // stepper motor controls + .o_stepper_dir (s_stepper_dir), + .o_stepper_step (s_stepper_step), + .i_stepper_error (1'b0), + // program termination + .o_done (s_done) +); + +always @ (posedge s_stepper_step) + $display("%12d : dir = %h", $time, s_stepper_dir); + +always @ (negedge s_clk) + if (s_done) + $finish; + +//initial begin +// $dumpfile("tb.vcd"); +// $dumpvars(1,tb); +//end + +endmodule
ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb.v Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb.good =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb.good (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb.good (revision 9) @@ -0,0 +1,60 @@ + 6526500 : dir = 0 + 9146500 : dir = 0 + 11156500 : dir = 0 + 12852500 : dir = 0 + 14344500 : dir = 0 + 15694500 : dir = 0 + 16936500 : dir = 0 + 18090500 : dir = 0 + 19176500 : dir = 0 + 20202500 : dir = 0 + 21204500 : dir = 0 + 22204500 : dir = 0 + 23204500 : dir = 0 + 24206500 : dir = 0 + 25206500 : dir = 0 + 26206500 : dir = 0 + 27206500 : dir = 0 + 28208500 : dir = 0 + 29208500 : dir = 0 + 30208500 : dir = 0 + 31236500 : dir = 0 + 32322500 : dir = 0 + 33478500 : dir = 0 + 34720500 : dir = 0 + 36070500 : dir = 0 + 37564500 : dir = 0 + 39258500 : dir = 0 + 41270500 : dir = 0 + 43888500 : dir = 0 + 49970500 : dir = 0 + 56146500 : dir = 1 + 58764500 : dir = 1 + 60774500 : dir = 1 + 62470500 : dir = 1 + 63962500 : dir = 1 + 65312500 : dir = 1 + 66554500 : dir = 1 + 67708500 : dir = 1 + 68794500 : dir = 1 + 69820500 : dir = 1 + 70822500 : dir = 1 + 71822500 : dir = 1 + 72822500 : dir = 1 + 73824500 : dir = 1 + 74824500 : dir = 1 + 75824500 : dir = 1 + 76824500 : dir = 1 + 77826500 : dir = 1 + 78826500 : dir = 1 + 79826500 : dir = 1 + 80854500 : dir = 1 + 81940500 : dir = 1 + 83096500 : dir = 1 + 84338500 : dir = 1 + 85688500 : dir = 1 + 87182500 : dir = 1 + 88876500 : dir = 1 + 90888500 : dir = 1 + 93506500 : dir = 1 + 99588500 : dir = 1 Index: ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.9x8 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.9x8 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/stepper_motor/tb_stepper_motor.9x8 (revision 9) @@ -0,0 +1,38 @@ +# +# Copyright 2015, Sinclair R.F., Inc. +# +# Test bench for stepper_motor peripheral. +# + +ARCHITECTURE core/9x8 Verilog +ASSEMBLY tb_stepper_motor.s + +INSTRUCTION 256 +DATA_STACK 16 +RETURN_STACK 16 + +CONSTANT C_CLK_FREQ_HZ 2_000_000 + +PORTCOMMENT stepper motor controls +CONSTANT C_RATE_SCALE 3 +CONSTANT C_RATE_RES 16 +CONSTANT C_ACCEL_SCALE 22 +CONSTANT C_ACCEL_RES 34 +CONSTANT C_ACCUM_RES 34 +CONSTANT C_COUNT_WIDTH 19 +PERIPHERAL stepper_motor basename=stepper \ + outcontrol=O_CONTROLWORD \ + outrecord=O_CONTROLWORD_WR \ + outrun=O_GO \ + indone=I_DONE \ + inerror=I_ERROR \ + ratemethod=C_CLK_FREQ_HZ/500_000 \ + ratescale=C_RATE_SCALE \ + rateres=C_RATE_RES \ + accelscale=C_ACCEL_SCALE \ + accelres=C_ACCEL_RES \ + accumres=C_ACCUM_RES \ + countwidth=C_COUNT_WIDTH + +PORTCOMMENT program termination +OUTPORT 1-bit o_done O_DONE Index: ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb_servo_motor.s =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb_servo_motor.s (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb_servo_motor.s (revision 9) @@ -0,0 +1,20 @@ +; Copyright 2015, Sinclair R.F., Inc. +; +; Test bench for servo_motor peripheral. + +.main + +; Wait for two cycles of the default servo settings pass. +${2-1} :loop_startup .inport(I_triple) 0= .jumpc(loop_startup) .jumpc(loop_startup,1-) drop + +; Modify the servo settings and wait for two cycles. + 0 .outport(O_triple_0) +125 .outport(O_triple_1) +250 .outport(O_triple_2) +${2-1} :loop_first .inport(I_triple) 0= .jumpc(loop_first) .jumpc(loop_first,1-) drop + +; Signal program termination. +0x01 .outport(O_DONE) + +; Wait forever. +:infinite .jump(infinite) Index: ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/run =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/run (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/run (revision 9) @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2015, Sinclair R.F., Inc. + +NAME=servo_motor + +../../../../../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; + +if ! cmp -s tb.out tb.good; then + echo "${NAME} failed" > /dev/stderr; + exit 1; +fi + +echo "Passed: ${NAME}"; +exit 0;
ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/.gitignore =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/.gitignore (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/.gitignore (revision 9) @@ -0,0 +1,2 @@ +tb.out +tb_servo_motor.v Index: ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb.v =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb.v (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb.v (revision 9) @@ -0,0 +1,56 @@ +/******************************************************************************* + * + * Copyright 2015, Sinclair R.F., Inc. + * + * Test bench for the servo_motor peripheral. + * + ******************************************************************************/ + +`timescale 1ns/1ps + +module tb; + +// 8 MHz clock +reg s_clk = 1'b1; +always @ (s_clk) + s_clk <= #62.5 ~s_clk; + +reg s_rst = 1'b1; +initial begin + repeat (5) @ (posedge s_clk); + s_rst = 1'b0; +end + +wire s_triple_0; +wire s_triple_1; +wire s_triple_2; +wire s_done; +tb_servo_motor uut( + // synchronous reset and processor clock + .i_rst (s_rst), + .i_clk (s_clk), + // 3 linked servo motor + .o_triple_0 (s_triple_0), + .o_triple_1 (s_triple_1), + .o_triple_2 (s_triple_2), + // program termination + .o_done (s_done) +); + +always @ (s_triple_0) + $display("%12d : s_triple_0 %h", $time, s_triple_0); +always @ (s_triple_1) + $display("%12d : s_triple_1 %h", $time, s_triple_1); +always @ (s_triple_2) + $display("%12d : s_triple_2 %h", $time, s_triple_2); + +always @ (posedge s_clk) + if (s_done) + $finish; + +//initial begin +// $dumpfile("tb.vcd"); +// $dumpvars(); +//end + +endmodule
ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb.v Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb_servo_motor.9x8 =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb_servo_motor.9x8 (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb_servo_motor.9x8 (revision 9) @@ -0,0 +1,39 @@ +# +# Copyright 2015, Sinclair R.F., Inc. +# +# Test bench for servo_motor peripheral. +# + +ARCHITECTURE core/9x8 Verilog +ASSEMBLY tb_servo_motor.s + +INSTRUCTION 256 +DATA_STACK 16 +RETURN_STACK 16 + +CONSTANT C_CLK_FREQ_HZ 8_000_000 + +PORTCOMMENT 3 linked servo motor +PERIPHERAL servo_motor outport=O_triple_0 \ + outsignal=o_triple_0 \ + freq_hz=C_CLK_FREQ_HZ \ + min_width=1000us \ + max_width=1500us \ + default_width=1250us \ + period=5ms \ + inperiod=I_triple +PERIPHERAL servo_motor outport=O_triple_1 \ + outsignal=o_triple_1 \ + freq_hz=C_CLK_FREQ_HZ \ + min_width=1000us \ + max_width=1500us \ + sync=o_triple_0 +PERIPHERAL servo_motor outport=O_triple_2 \ + outsignal=o_triple_2 \ + freq_hz=C_CLK_FREQ_HZ \ + min_width=1000us \ + max_width=1500us \ + sync=o_triple_0 + +PORTCOMMENT program termination +OUTPORT 1-bit o_done O_DONE Index: ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb.good =================================================================== --- ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb.good (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/tb/servo_motor/tb.good (revision 9) @@ -0,0 +1,24 @@ + 0 : s_triple_0 0 + 0 : s_triple_1 0 + 0 : s_triple_2 0 + 5000625 : s_triple_0 1 + 5000625 : s_triple_1 1 + 5000625 : s_triple_2 1 + 6000625 : s_triple_1 0 + 6000625 : s_triple_2 0 + 6250625 : s_triple_0 0 + 10000625 : s_triple_0 1 + 10000625 : s_triple_1 1 + 10000625 : s_triple_2 1 + 11000625 : s_triple_1 0 + 11000625 : s_triple_2 0 + 11250625 : s_triple_0 0 + 15000625 : s_triple_0 1 + 15000625 : s_triple_1 1 + 15000625 : s_triple_2 1 + 16000625 : s_triple_0 0 + 16250625 : s_triple_1 0 + 16500625 : s_triple_2 0 + 20000625 : s_triple_0 1 + 20000625 : s_triple_1 1 + 20000625 : s_triple_2 1 Index: ssbcc/trunk/core/9x8/peripherals/open_drain.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/open_drain.py (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/open_drain.py (revision 9) @@ -60,7 +60,7 @@ ( 'inport', r'I_\w+$', None, ), ( 'iosignal', r'io_\w+$', None, ), ( 'outport', r'O_\w+$', None, ), - ( 'width', r'[1-9]\d*$', lambda v : self.PosInt(v,maxValue=config.Get('data_width')), ), + ( 'width', r'\S+$', lambda v : self.IntMethod(config,v,lowLimit=1,highLimit=config.Get('data_width')), ), ); names = [a[0] for a in allowables]; for param_tuple in param_list: Index: ssbcc/trunk/core/9x8/peripherals/timer.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/timer.py (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/timer.py (revision 9) @@ -27,9 +27,9 @@ 1st method: clk/rate clk is the frequency of "i_clk" in Hz a number will be interpreted as the clock frequency in Hz - a symbol will be interpreted as a parameter - Note: this parameter must have been declared with a "PARAMETER" - command + a symbol will be interpreted as a constant or a parameter + Note: the symbol must be declared with the CONSTANT, LOCALPARARM, + or PARAMETER configuration command. rate is the desired baud rate this is specified as per "clk" 2nd method: Index: ssbcc/trunk/core/9x8/peripherals/AXI4_Lite_Slave_DualPortRAM.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/AXI4_Lite_Slave_DualPortRAM.py (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/AXI4_Lite_Slave_DualPortRAM.py (revision 9) @@ -104,7 +104,7 @@ ( 'ram8', None, None, ), ( 'ram32', None, None, ), ( 'read', r'I_\w+$', None, ), - ( 'size', r'\S+$', lambda v : self.FixedPow2(config,16,256,v), ), + ( 'size', r'\S+$', lambda v : self.IntPow2Method(config,v,lowLimit=16,highLimit=256), ), ( 'write', r'O_\w+$', None, ), ); names = [a[0] for a in allowables]; Index: ssbcc/trunk/core/9x8/peripherals/PWM_8bit.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/PWM_8bit.py (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/PWM_8bit.py (revision 9) @@ -30,8 +30,13 @@ Note: The name must start with "o_". ratemethod={clk/rate|count} specifies the frequency at which the PWM counter is incremented + Note: "clk," "rate," and "count" can be integers or can be declared by + CONSTANT, LOCALPARARM, or PARAMETER configuration commands. Example: ratemethod=count means to increment the PWM counter once every "count" clock cycles. + Example: ratemethod=G_CLK_HZ/1_000 means to use the parameter G_CLK_HZ + (set elsewhere) and a 1,000 Hz update rate to determine the + number of clock cycles between updates. invert|noinvert optional configuration command to invert or to not invert the PWM output Default: don't invert the output (i.e., a command of 0 means the output is Index: ssbcc/trunk/core/9x8/peripherals/servo_motor.v =================================================================== --- ssbcc/trunk/core/9x8/peripherals/servo_motor.v (nonexistent) +++ ssbcc/trunk/core/9x8/peripherals/servo_motor.v (revision 9) @@ -0,0 +1,96 @@ +// +// PERIPHERAL servo_motor: @NAME@ +// +generate +reg [@NBITS_PWM@-1:0] s__pwm_count_init = @DEFAULT_PWM@; +always @ (posedge i_clk) + if (i_rst) + s__pwm_count_init <= @DEFAULT_PWM@; + else if (s_outport && (s_T == @IX_OUTPORT@)) + s__pwm_count_init <= @PWM_FORMULA@; + else + s__pwm_count_init <= s__pwm_count_init; +reg [@NBITS_PWM@-1:0] s__pwm_count = @DEFAULT_PWM@; +@SCALE_0_BEGIN@ +@SCALE_0_ELSE@ +reg s__tick = 1'b0; +reg [@NBITS_SCALE@-1:0] s__tick_cnt = @SCALE_MINUS_ONE@; +wire s__tick_last = (s__tick_cnt == @ONE_SCALE@); +always @ (posedge i_clk) + if (i_rst) begin + s__tick <= 1'b0; + s__tick_cnt <= @SCALE_MINUS_ONE@; + end else begin + s__tick <= s__tick_last; + if (s__tick) + s__tick_cnt <= @SCALE_MINUS_ONE@; + else + s__tick_cnt <= s__tick_cnt - @ONE_SCALE@; + end +@SCALE_0_END@ +@PERIOD_BEGIN@ +reg [@NBITS_PERIOD@-1:0] s__period = @PERIOD_MINUS_ONE@; +@SCALE_0_BEGIN@ +always @ (posedge i_clk) + if (i_rst) begin + s__period <= @PERIOD_MINUS_ONE@; + s__period_done <= 1'b0; + end else begin + if (s__period_done) + s__period <= @PERIOD_MINUS_ONE@; + else + s__period <= s__period - @ONE_PERIOD@; + s__period_done <= (s__period == @ONE_PERIOD@); + end +@SCALE_0_ELSE@ +always @ (posedge i_clk) + if (i_rst) begin + s__period <= @PERIOD_MINUS_ONE@; + s__period_done <= 1'b0; + end else begin + if (s__period_done) + s__period <= @PERIOD_MINUS_ONE@; + else if (s__tick) + s__period <= s__period - @ONE_PERIOD@; + else + s__period <= s__period; + s__period_done <= s__tick_last && (s__period == @NBITS_PERIOD@'d0); + end +@SCALE_0_END@ +@PERIOD_END@ +@SCALE_0_BEGIN@ +always @ (posedge i_clk) + if (i_rst) + s__pwm_count <= @DEFAULT_PWM@; + else if (@PERIOD_SIGNAL@) + s__pwm_count <= s__pwm_count_init; + else + s__pwm_count <= s__pwm_count - @ONE_PWM@; +@SCALE_0_ELSE@ +always @ (posedge i_clk) + if (i_rst) + s__pwm_count <= @DEFAULT_PWM@; + else if (@PERIOD_SIGNAL@) + s__pwm_count <= s__pwm_count_init; + else if (s__tick) + s__pwm_count <= s__pwm_count - @ONE_PWM@; + else + s__pwm_count <= s__pwm_count; +@SCALE_0_END@ +reg s__outsignal = 1'b0; +always @ (posedge i_clk) + if (i_rst) + s__outsignal <= 1'b0; + else if (@PERIOD_SIGNAL@) + s__outsignal <= 1'b1; +@SCALE_0_BEGIN@ + else if (s__pwm_count == {(@NBITS_PWM@){1'b0}}) +@SCALE_0_ELSE@ + else if (s__tick && (s__pwm_count == {(@NBITS_PWM@){1'b0}})) +@SCALE_0_END@ + s__outsignal <= 1'b0; + else + s__outsignal <= s__outsignal; +always @ (*) + @OUTSIGNAL@ = @INVERT@s__outsignal; +endgenerate
ssbcc/trunk/core/9x8/peripherals/servo_motor.v Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/UART_Rx.v =================================================================== --- ssbcc/trunk/core/9x8/peripherals/UART_Rx.v (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/UART_Rx.v (revision 9) @@ -1,5 +1,6 @@ // // PERIPHERAL UART_Rx: @NAME@ +// Copyright 2013-2015 Sinclair R.F., Inc. // // Technique: // - optionally synchronize the incoming signal @@ -13,7 +14,7 @@ // localparam L__BAUDMETHOD = ((@BAUDMETHOD@)+1)/2; localparam L__BAUDMETHOD_MINUS = L__BAUDMETHOD - 2; -localparam L__BAUDMETHOD_NBITS = $clog2(L__BAUDMETHOD+1); +localparam L__BAUDMETHOD_NBITS = $clog2(L__BAUDMETHOD_MINUS+1); localparam L__SYNC_LENGTH = @SYNC@; localparam L__DEGLITCH_LENGTH = @DEGLITCH@; localparam L__NSTOP = @NSTOP@; @@ -159,7 +160,7 @@ end // Optional FIFO @RTR_BEGIN@ -reg s__rtr = 1'b1; +reg s__rtrn = 1'b1; // Disable reception until the core is out of reset. @RTR_END@ if (L__INFIFO == 0) begin : gen__nofifo always @ (posedge i_clk) @@ -186,9 +187,9 @@ @RTR_BEGIN@ always @ (posedge i_clk) if (i_rst) - s__rtr <= 1'b1; + s__rtrn <= 1'b1; else - s__rtr <= ~s__Rx_idle; + s__rtrn <= ~s__Rx_idle; @RTR_END@ end else begin : gen__fifo reg [L__INFIFO_NBITS:0] s__Rx_fifo_addr_in; @@ -222,7 +223,7 @@ s__Rx_full <= 1'b0; else s__Rx_full <= (s__Rx_fifo_addr_in == (s__Rx_fifo_addr_out ^ { 1'b1, {(L__INFIFO_NBITS){1'b0}} })); - reg [7:0] s__Rx_fifo_mem[@INFIFO@-1:0]; + reg [7:0] s__Rx_fifo_mem[L__INFIFO-1:0]; initial s__Rx_fifo_addr_in = {(L__INFIFO_NBITS+1){1'b0}}; always @ (posedge i_clk) if (i_rst) @@ -245,46 +246,22 @@ s__Rx <= s__Rx; end @RTR_BEGIN@ - // Isn't ready to receive if the FIFO is full or if the FIFO is almost full - // and there is incoming data (i.e., receiver is not idle). - reg s__Rx_idle_s = 1'b0; + // Isn't ready to receive if the FIFO is full or if the FIFO is almost full. + reg [L__INFIFO_NBITS:0] s__Rx_used = {(L__INFIFO_NBITS+1){1'b0}}; always @ (posedge i_clk) if (i_rst) - s__Rx_idle_s <= 1'b0; + s__Rx_used <= {(L__INFIFO_NBITS+1){1'b0}}; else - s__Rx_idle_s <= s__Rx_idle; - reg s__Rx_wr_s = 1'b0; + s__Rx_used <= s__Rx_fifo_addr_in - s__Rx_fifo_addr_out; always @ (posedge i_clk) if (i_rst) - s__Rx_wr_s <= 1'b0; + s__rtrn <= 1'b1; else - s__Rx_wr_s <= s__Rx_wr; - reg s__Rx_busy = 1'b0; - always @ (posedge i_clk) - if (i_rst) - s__Rx_busy <= 1'b0; - else if ({s__Rx_idle_s, s__Rx_idle} == 2'b10) - s__Rx_busy <= 1'b1; - else if (s__Rx_wr_s) - s__Rx_busy <= 1'b0; - else - s__Rx_busy <= s__Rx_busy; - reg s__Rx_almost_full = 1'b0; - always @ (posedge i_clk) - if (i_rst) - s__Rx_almost_full <= 1'b0; - else - s__Rx_almost_full <= (s__Rx_fifo_addr_in == (s__Rx_fifo_addr_out + { 1'b0, {(L__INFIFO_NBITS){1'b1}} })); - always @ (posedge i_clk) - if (i_rst) - s__rtr <= 1'b1; - else -// s__rtr <= ~(s__Rx_full || (s__Rx_almost_full && ~s__Rx_idle)); - s__rtr <= ~(s__Rx_full || (s__Rx_almost_full && s__Rx_busy)); + s__rtrn <= s__Rx_used[L__INFIFO_NBITS] || &(s__Rx_used[L__INFIFO_NBITS-1:@RTR_FIFO_COMPARE@]); @RTR_END@ end @RTR_BEGIN@ always @ (*) - @RTR_SIGNAL@ <= @RTR_INVERT@s__rtr; + @RTR_SIGNAL@ = @RTRN_INVERT@s__rtrn; @RTR_END@ endgenerate Index: ssbcc/trunk/core/9x8/peripherals/UART_Tx.v =================================================================== --- ssbcc/trunk/core/9x8/peripherals/UART_Tx.v (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/UART_Tx.v (revision 9) @@ -1,5 +1,6 @@ // // PERIPHERAL UART_Tx: @NAME@ +// Copyright 2013-2015 Sinclair R.F., Inc. // localparam L__OUTFIFO_NBITS = $clog2(@OUTFIFO@); localparam L__COUNT = @BAUDMETHOD@-1; @@ -12,7 +13,7 @@ reg s__Tx_go; reg s__Tx_uart_busy; if (@OUTFIFO@ == 0) begin : gen__nooutfifo - always @ (s__Tx_uart_busy) + always @ (s__Tx_uart_busy, s__Tx_enabled) s__Tx_busy = s__Tx_uart_busy || !s__Tx_enabled; always @ (s__Tx) s__Tx_data = s__Tx; Index: ssbcc/trunk/core/9x8/peripherals/inFIFO_async.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/inFIFO_async.py (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/inFIFO_async.py (revision 9) @@ -71,7 +71,7 @@ ( 'data_full', r'o_\w+$', None, ), ( 'inport', r'I_\w+$', None, ), ( 'inempty', r'I_\w+$', None, ), - ( 'depth', r'[1-9]\d*$', lambda v : self.IntPow2(v,minValue=16), ), + ( 'depth', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v,lowLimit=16), ), ); names = [a[0] for a in allowables]; for param_tuple in param_list: Index: ssbcc/trunk/core/9x8/peripherals/UART.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/UART.py (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/UART.py (revision 9) @@ -1,6 +1,6 @@ ################################################################################ # -# Copyright 2013-2014, Sinclair R.F., Inc. +# Copyright 2013-2015, Sinclair R.F., Inc. # ################################################################################ @@ -8,8 +8,8 @@ import re; from ssbccPeripheral import SSBCCperipheral -from ssbccUtil import IsPowerOf2; -from ssbccUtil import SSBCCException; +from ssbccUtil import CeilLog2 +from ssbccUtil import SSBCCException class UART(SSBCCperipheral): """ @@ -30,7 +30,8 @@ [noInFIFO|inFIFO=n] \\ [noOutFIFO|outFIFO=n] \\ [{CTS|CTSn}=i_cts_name] \\ - [{RTR|RTRn}=i_rtr_name] \\ + [{RTR|RTRn}=o_rtr_name] \\ + rtr_buffer=n \\ [nStop={1|2}]\n Where: inport=I_inport_name @@ -54,9 +55,9 @@ 1st method: clk/rate clk is the frequency of "i_clk" in Hz a number will be interpreted as the clock frequency in Hz - a symbol will be interpreted as a parameter - Note: this parameter must have been declared with a "PARAMETER" - command + a symbol will be interpreted as a constant or a parameter + Note: the symbol must be declared with the CONSTANT, LOCALPARARM, + or PARAMETER configuration command. rate is the desired baud rate this is specified as per "clk" 2nd method: @@ -110,17 +111,24 @@ Note: If there is no FIFO and the CTS/CTSn handshake indicates that the data flow is disabled, then the busy signal will be high and the processor code must not transmit the next byte. - RTR=i_rtr_name or RTRn=i_rtr_name + RTR=o_rtr_name or RTRn=o_rtr_name optionally specify an output handshake signal to indicate that the peripheral is ready to receive data Note: If RTR is specified then the receiver indicates it is ready when - i_rtr_name is high. If RTRn is specified then the transmitter - indicates it is ready when i_rtr_name is low. + o_rtr_name is high. If RTRn is specified then the transmitter + indicates it is ready when o_rtr_name is low. Note: The default, i.e., neither CTS nor CTSn is specified, is to always enable the receiver. Note: If there is no FIFO and the RTR/RTRn handshake indicates that the receiver is not ready as soon as it starts receiving data and until that data is read from the peripheral. + rtr_buffer=n + optionally specify the number of entries in inFIFO to reserve for data + received after the RTR/RTRn signal indicates to stop data flow. + Note: n must be a power of 2. + Note: This requires that inFIFO be specified. + Note: Some USB UARTs will transmit several characters after the RTR/RTRn + signal indicates to stop the data flow. nStop=n optionally configure the peripheral for n stop bits default: 1 stop bit @@ -185,7 +193,7 @@ ( 'RTRn', r'o_\w+$', None, ), ( 'baudmethod', r'\S+$', lambda v : self.RateMethod(config,v), ), ( 'deglitch', r'[1-9]\d*$', int, ), - ( 'inFIFO', r'[1-9]\d*$', lambda v : self.IntPow2(v), ), + ( 'inFIFO', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v), ), ( 'inempty', r'I_\w+$', None, ), ( 'inport', r'I_\w+$', None, ), ( 'insignal', r'i_\w+$', None, ), @@ -194,10 +202,11 @@ ( 'noOutFIFO', None, None, ), ( 'noSync', None, None, ), ( 'nStop', r'[12]$', int, ), - ( 'outFIFO', r'[1-9]\d*$', lambda v : self.IntPow2(v), ), + ( 'outFIFO', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v), ), ( 'outport', r'O_\w+$', None, ), ( 'outsignal', r'o_\w+$', None, ), ( 'outstatus', r'I_\w+$', None, ), + ( 'rtr_buffer', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v), ), ( 'sync', r'[1-9]\d*$', int, ), ); names = [a[0] for a in allowables]; @@ -225,7 +234,16 @@ ): if not hasattr(self,optionalpair[0]): setattr(self,optionalpair[0],optionalpair[1]); - # Ensure exclusive pair configurations are set and consistent. + # Ensure the rtr_buffer, if specified, is consistent with the inFIFO + # specification. + if hasattr(self,'rtr_buffer'): + if not hasattr(self,'inFIFO'): + raise SSBCCException('rtr_buffer specification requires simultaneous inFIFO specification at %s' % loc); + if self.rtr_buffer > self.inFIFO: + raise SSBCCException('rtr_buffer=%d specification cannot exceed inFIFO=%d specification at %s' % (self.rtr_buffer,self.inFIFO,loc,)); + else: + self.rtr_buffer = 1; + # Ensure optional exclusive pair configurations are set and consistent. for exclusivepair in ( ( 'CTS', 'CTSn', None, None, ), ( 'RTR', 'RTRn', None, None, ), @@ -261,25 +279,25 @@ ): if hasattr(self,ioEntry[0]): config.AddIO(getattr(self,ioEntry[0]),ioEntry[1],ioEntry[2],loc); - config.AddSignal('s__%s__Rx' % self.namestring,8,loc); - config.AddSignal('s__%s__Rx_empty' % self.namestring,1,loc); - config.AddSignal('s__%s__Rx_rd' % self.namestring,1,loc); - config.AddSignal('s__%s__Tx' % self.namestring,8,loc); - config.AddSignal('s__%s__Tx_busy' % self.namestring,1,loc); - config.AddSignal('s__%s__Tx_wr' % self.namestring,1,loc); + config.AddSignal('s__%s__Rx' % self.namestring,8,loc); + config.AddSignal('s__%s__Rx_empty' % self.namestring,1,loc); + config.AddSignal('s__%s__Rx_rd' % self.namestring,1,loc); + config.AddSignalWithInit('s__%s__Tx' % self.namestring,8,None,loc); + config.AddSignal('s__%s__Tx_busy' % self.namestring,1,loc); + config.AddSignalWithInit('s__%s__Tx_wr' % self.namestring,1,None,loc); config.AddInport((self.inport, - ('s__%s__Rx' % self.namestring,8,'data',), - ('s__%s__Rx_rd' % self.namestring,1,'strobe',), + ('s__%s__Rx' % self.namestring,8,'data',), + ('s__%s__Rx_rd' % self.namestring,1,'strobe',), ),loc); config.AddInport((self.inempty, - ('s__%s__Rx_empty' % self.namestring,1,'data',), + ('s__%s__Rx_empty' % self.namestring,1,'data',), ),loc); config.AddOutport((self.outport,False, - ('s__%s__Tx' % self.namestring,8,'data',), - ('s__%s__Tx_wr' % self.namestring,1,'strobe',), + ('s__%s__Tx' % self.namestring,8,'data',), + ('s__%s__Tx_wr' % self.namestring,1,'strobe',), ),loc); config.AddInport((self.outstatus, - ('s__%s__Tx_busy' % self.namestring,1,'data',), + ('s__%s__Tx_busy' % self.namestring,1,'data',), ),loc); # Add the 'clog2' function to the processor (if required). config.functions['clog2'] = True; @@ -294,20 +312,21 @@ if re.search(r'@RTR_BEGIN@',body): body = re.sub(r'@RTR_BEGIN@.*?@RTR_END@\n','',body,flags=re.DOTALL); for subpair in ( - ( r'@RTR_SIGNAL@', self.RTR if hasattr(self,'RTR') else self.RTRn if hasattr(self,'RTRn') else '', ), - ( r'@RTR_INVERT@', '' if hasattr(self,'RTR') else '!', ), - ( r'\bL__', 'L__@NAME@__', ), - ( r'\bgen__', 'gen__@NAME@__', ), - ( r'\bs__', 's__@NAME@__', ), - ( r'@INPORT@', self.insignal, ), - ( r'@BAUDMETHOD@', str(self.baudmethod), ), - ( r'@SYNC@', str(self.sync), ), - ( r'@DEGLITCH@', str(self.deglitch), ), - ( r'@INFIFO@', str(self.inFIFO), ), - ( r'@ENABLED@', self.CTS if hasattr(self,'CTS') else ('!%s' % self.CTSn) if hasattr(self,'CTSn') else '1\'b1', ), - ( r'@NSTOP@', str(self.nStop), ), - ( r'@OUTFIFO@', str(self.outFIFO), ), - ( r'@NAME@', self.namestring, ), + ( r'@RTR_SIGNAL@', self.RTR if hasattr(self,'RTR') else self.RTRn if hasattr(self,'RTRn') else '', ), + ( r'@RTRN_INVERT@', '!' if hasattr(self,'RTR') else '', ), + ( r'\bL__', 'L__@NAME@__', ), + ( r'\bgen__', 'gen__@NAME@__', ), + ( r'\bs__', 's__@NAME@__', ), + ( r'@INPORT@', self.insignal, ), + ( r'@BAUDMETHOD@', str(self.baudmethod), ), + ( r'@SYNC@', str(self.sync), ), + ( r'@DEGLITCH@', str(self.deglitch), ), + ( r'@INFIFO@', str(self.inFIFO), ), + ( r'@ENABLED@', self.CTS if hasattr(self,'CTS') else ('!%s' % self.CTSn) if hasattr(self,'CTSn') else '1\'b1', ), + ( r'@NSTOP@', str(self.nStop), ), + ( r'@OUTFIFO@', str(self.outFIFO), ), + ( r'@NAME@', self.namestring, ), + ( r'@RTR_FIFO_COMPARE@', str(CeilLog2(self.rtr_buffer)), ), ): if re.search(subpair[0],body): body = re.sub(subpair[0],subpair[1],body);
/ssbcc/trunk/core/9x8/peripherals/servo_motor.py
0,0 → 1,250
################################################################################
#
# Copyright 2015, Sinclair R.F., Inc.
#
################################################################################
 
import math
 
from ssbccPeripheral import SSBCCperipheral
from ssbccUtil import CeilLog2
from ssbccUtil import SSBCCException
 
class servo_motor(SSBCCperipheral):
"""
Servo Motor driver:\n
Creates PWM modulated signals to operate micro servos for UAVs and similar.\n
Usage:
PERIPHERAL servo_motor outport=O_name \\
{outsignal|outsignaln}=o_name \\
freq_hz=FREQ_HZ \\
min_width=XXX{s|ms|us|ns} \\
max_width=XXX{s|ms|us|ns} \\
[default_width=XXX{s|ms|us|ns}] \\
{period=XXX{s|ms|us|ns}|sync=o_name} \\
[inperiod=I_name] \\
[scale=C_name] \\
[scale_max=C_name]\n
Where:
outport=O_name
specifies the symbol used to write the 8-bit PWM control to this
peripheral
Note: The name must start with "O_".
{outsignal|outsignaln}=o_name
specifies the name of the output PWM signal
Note: outsignal creates a positive pulse for the PWM control and
outsignaln creates an inverted pulse for the PWM control.
Note: The name must start with "o_".
freq_hz=FREQ_HZ
specifies the processor clock speed to the peripheral
min_width=XXX{s|ms|us|ns}
specifies the minimum pulse width
Note: XXX may be an integer or a real number
Note: The minimum width must be a realizable positive value (since a
pulse width of zero means no control is being given to the servo).
max_width=XXX{s|ms|us|ns}
specifies the maximum pulse width
Note: XXX may be an integer or a real number
default_width=XXX{s|ms|us|ns}
optionally specifies the default width of the PWM before it is set by the
processor
Note: If the default width is not specified then the minimum width is
used as the default width.
{period=XXX{s|ms|us|ns}|sync=o_name}
either specifies the rate at which the PWM is generated or synchronize the
PWM generation to a preceding servo_motor peripheral with the output
signal o_name
Note: XXX may be an integer or a real number
Note: When sync is specified the leading edges of the PWMs will coincide.
inperiod=I_name
optionally specifies an input port to receive the strobe generated by the
associated period
Note: This optional parameter requires that period be specified. It is
not compatible with the sync parameter.
scale=C_name
optionally creates a constant named "C_name" which states how many clock
cycles are used for each count in the 8-bit PWM control
Note: The name must start with "C_".
Example: A PWM range of 1000 to 1500 usec and a clock frequency of 8 MHz
produces a value of ceil((1500-1000)*8/(256-1)) = 16 clock
cycles per 8-bit control value count.
scale_max=C_name
optionally creates a constant named "C_name" wich states the upper limit
of the continuous control range
Note: The name must start with "C_".
Example: For the example in "scale=C_name" the upper limit would be
ceil((1500-1000)*8/16) = 250. I.e., control values of 251
through 255 inclusive will produce the same PWM width as the
control value 250.
Example:
A micro servo that responds to positive PWM pulses between 1000 usec and
1500 usec once every 20 msec and the processor clock is 8 MHz. The
architecture file would include the following:\n
CONSTANT C_FREQ_HZ 8_000_000
PORTCOMMENT servo motor control
PERIPHERAL servo_motor outport=O_SERVO \\
outsignal=o_servo \\
freq_hz=C_FREQ_HZ \\
min_width=1000us \\
max_width=1500us \\
period=20ms \\
scale=C_servo_scale \\
scale_max=C_servo_scale_max\n
will create a peripheral generating the desired PWM signal.\n
The constants C_servo_scale and C_servo_scale_max could be reported by the
micro controller to a controlling application to specify the sensitivity and
upper limit for the servo motor controller.\n
Example:
Synchronize a second servo motor with PWM pulses between 1000 usec and 2500
usec to the preceding servo motor controller:\n
PERIPHERAL servo_motor outport=O_SERVO_2 \\
outsignal=o_servo2 \\
freq_hz=C_FREQ_HZ \\
min_width=1.0ms \\
max_width=2.5ms \\
sync=o_servo\n
"""
 
def __init__(self,peripheralFile,config,param_list,loc):
# Use the externally provided file name for the peripheral
self.peripheralFile = peripheralFile;
# Get the parameters.
allowables = (
( 'default_width', r'\S+', lambda v : self.TimeMethod(config,v), ),
( 'freq_hz', r'\S+$', lambda v : self.IntMethod(config,v), ),
( 'inperiod', r'I_\w+$', None, ),
( 'max_width', r'\S+$', lambda v : self.TimeMethod(config,v), ),
( 'min_width', r'\S+$', lambda v : self.TimeMethod(config,v), ),
( 'outport', r'O_\w+$', None, ),
( 'outsignal', r'o_\w+$', None, ),
( 'outsignaln', r'o_\w+$', None, ),
( 'period', r'\S+$', lambda v : self.TimeMethod(config,v), ),
( 'scale', r'C_\w+$', None, ),
( 'scale_max', r'C_\w+$', None, ),
( 'sync', r'o_\w+$', None, ),
)
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.
for paramname in (
'outport',
'freq_hz',
'min_width',
'max_width',
):
if not hasattr(self,paramname):
raise SSBCCException('Required parameter "%s" is missing at %s' % (paramname,loc,));
# Ensure exactly one of mandatory exclusive pairs are specified.
for exclusivepair in (
( 'outsignal', 'outsignaln', ),
( 'period', 'sync', ),
):
if not hasattr(self,exclusivepair[0]) and not hasattr(self,exclusivepair[1]):
raise SSBCCException('One of %s or %s must be specified at %s', (exclusivepair[0], exclusivepair[1], loc, ));
if hasattr(self,exclusivepair[0]) and hasattr(self,exclusivepair[1]):
raise SSBCCException('Only one of %s or %s may be specified at %s', (exclusivepair[0], exclusivepair[1], loc, ));
# Set optional signals
if not hasattr(self,'default_width'):
self.default_width = self.min_width;
# Ensure signal values are reasonable.
if self.min_width >= self.max_width:
raise SSBCCException('min_width must be smaller than max_width at %s' % loc);
if not self.min_width <= self.default_width <= self.max_width:
raise SSBCCException('default_width is not between min_width and max_width at %s' % loc);
# Ensure the optionally provided "sync" servo_motor peripheral has been specified.
if hasattr(self,'sync'):
for p in config.peripheral:
if (str(p.__class__) == str(self.__class__)) and (p.outsignal == self.sync):
break;
else:
raise SSBCCException('Can\'t find preceding servo_motor peripheral with outsignal=%s at %s ' % (self.sync,loc,));
if not hasattr(p,'period'):
raise SSBCCException('servo_motor peripherial with outsignal=%s must have period specified to be used at %s' % (self.sync,loc,));
# Translate the outsignal specification into a single member for the signal
# name and a specification as to whether or not the signal is inverted.
if hasattr(self,'outsignaln'):
self.outsignal = self.outsignaln;
self.invertOutsignal = True;
else:
self.invertOutsignal = False;
# Set the string used to identify signals associated with this peripheral.
self.namestring = self.outsignal;
# Calculate the name of the signal to start the PWM.
self.periodSignal = 's__%s__period_done' % (self.namestring if hasattr(self,'period') else self.sync)
# Calculate the scaling and set the optionally specified constants.
# TODO -- ensure the realizable min_width is positive
self.scaleValue = int(math.ceil((self.max_width-self.min_width)*self.freq_hz/2**config.Get('data_width')));
self.scale_maxValue = int(math.ceil((self.max_width-self.min_width)*self.freq_hz/self.scaleValue));
for scalingPair in (
( 'scaling', 'scaleValue', ),
( 'scale_max', 'scale_maxValue', ),
):
if hasattr(self,scalingPair[0]):
config.AddConstant(scalingPair[1], getAttr(self,scalingPair[1]));
# Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral.
config.AddIO(self.outsignal,1,'output',loc);
if hasattr(self,'period'):
config.AddSignal(self.periodSignal, 1, loc);
self.ix_outport = config.NOutports();
config.AddOutport((self.outport,
False,
# empty list
),loc);
if hasattr(self,'inperiod'):
config.AddSignal('s_SETRESET_%s' % self.periodSignal,1,loc);
config.AddInport((self.inperiod,
(self.periodSignal, 1, 'set-reset',),
),loc);
 
def GenVerilog(self,fp,config):
body = self.LoadCore(self.peripheralFile,'.v');
if hasattr(self,'period'):
body = re.sub(r'@PERIOD_BEGIN@\n','',body);
body = re.sub(r'@PERIOD_END@\n','',body);
else:
body = re.sub(r'@PERIOD_BEGIN@.*?@PERIOD_END@\n','',body,flags=re.DOTALL);
nbits_scale = CeilLog2(self.scaleValue);
if nbits_scale == 0:
body = re.sub(r'@SCALE_0_BEGIN@\n','',body);
body = re.sub(r'@SCALE_0_ELSE@.*?@SCALE_0_END@\n','',body,flags=re.DOTALL);
else:
body = re.sub(r'@SCALE_0_BEGIN@.*?@SCALE_0_ELSE@\n','',body,flags=re.DOTALL);
body = re.sub(r'@SCALE_0_END@\n','',body);
scaled_min_width = int(math.floor(self.min_width*self.freq_hz/self.scaleValue));
scaled_default_width = int(math.floor(self.default_width*self.freq_hz/self.scaleValue));
scaled_max_width = int(math.floor(self.max_width*self.freq_hz/self.scaleValue));
nbits_pwm = max(config.Get('data_width')+1,CeilLog2(scaled_max_width));
pwm_formula = "%d'd%d + { %d'd0, s_N }" % (nbits_pwm,scaled_min_width-1,nbits_pwm-8,);
if hasattr(self,'period'):
period = self.period * self.freq_hz / self.scaleValue;
nbits_period = CeilLog2(period);
else:
period = 1;
nbits_period = 0;
for subpair in (
( r'@DEFAULT_PWM@', "%d'd%d" % (nbits_pwm,scaled_default_width-1,), ),
( r'@INVERT@', '!' if self.invertOutsignal else '', ),
( r'@IX_OUTPORT@', "8'd%d" % self.ix_outport, ),
( r'@NAME@', self.namestring, ),
( r'@NBITS_PERIOD@', str(nbits_period), ),
( r'@NBITS_PWM@', str(nbits_pwm), ),
( r'@NBITS_SCALE@', str(nbits_scale), ),
( r'@ONE_PERIOD@', "%d'd1" % nbits_period, ),
( r'@ONE_PWM@', "%d'd1" % nbits_pwm, ),
( r'@ONE_SCALE@', "%d'd1" % nbits_scale, ),
( r'@OUTSIGNAL@', self.outsignal, ),
( r'@PERIOD_MINUS_ONE@', "%d'd%d" % (nbits_period,period-1,), ),
( r'@PWM_FORMULA@', pwm_formula, ),
( r'@SCALE_MINUS_ONE@', "%d'd%d" % (nbits_scale,self.scaleValue-1,), ),
( r'\bgen__', 'gen__%s__' % self.namestring, ),
( r'\bs__', 's__%s__' % self.namestring, ),
( r'@PERIOD_SIGNAL@', self.periodSignal, ), # must be after ( r'\bs__', ...
):
body = re.sub(subpair[0],subpair[1],body);
body = self.GenVerilogFinal(config,body);
fp.write(body);
/ssbcc/trunk/core/9x8/peripherals/stepper_motor.v
0,0 → 1,207
//
// PERIPHERAL stepper_motor: @NAME@
// Copyright 2015, Sinclair R.F., Inc.
//
// Assemble the byes of the control word from the input bytes.
@MASTER_BEGIN@
localparam L__RATEMETHOD_MINUS_1 = @RATEMETHOD@ - 1;
localparam L__NBITS_RATEMETHOD = clog2(L__RATEMETHOD_MINUS_1);
@MASTER_END@
reg [@CONTROL_WIDTH@-1:0] s__input_control_word = {(@CONTROL_WIDTH@){1'b0}};
always @ (posedge i_clk)
if (i_rst)
s__input_control_word <= {(@CONTROL_WIDTH@){1'b0}};
else if (s_outport && (s_T == 8'd@IX_OUTCONTROL@))
s__input_control_word <= { s__input_control_word[0+:@CONTROL_WIDTH@-@DW@], s_N };
else
s__input_control_word <= s__input_control_word;
wire [@CONTROL_WIDTH_PACKED@-1:0] s__input_control_word_packed = {
s__input_control_word[@DW@*((@MODE_WIDTH@+@DWM1@)/@DW@)+@DW@*((@COUNT_WIDTH@+@DWM1@)/@DW@)+@DW@*((@ACCEL_WIDTH@+@DWM1@)/@DW@)+:@RATECMD_WIDTH@],
s__input_control_word[@DW@*((@MODE_WIDTH@+@DWM1@)/@DW@)+@DW@*((@COUNT_WIDTH@+@DWM1@)/@DW@)+:@ACCEL_WIDTH@],
s__input_control_word[@DW@*((@MODE_WIDTH@+@DWM1@)/@DW@)+:@COUNT_WIDTH@]
@OUTMODE_BEGIN@
, s__input_control_word[0+:@MODE_WIDTH@]
@OUTMODE_END@
};
// Instantiate the control word FIFO and operate its input side.
reg s__FIFO_wr = 1'b0;
always @ (posedge i_clk)
if (i_rst)
s__FIFO_wr <= 1'b0;
else
s__FIFO_wr <= (s_outport && (s_T == 8'd@IX_OUTRECORD@));
reg [@NBITS_FIFO_DEPTH@:0] s__FIFO_in_addr = {(@NBITS_FIFO_DEPTH@+1){1'b0}};
always @ (posedge i_clk)
if (i_rst)
s__FIFO_in_addr <= {(@NBITS_FIFO_DEPTH@+1){1'b0}};
else
s__FIFO_in_addr <= s__FIFO_in_addr + { @NBITS_FIFO_DEPTH@'d0, s__FIFO_wr };
reg [@CONTROL_WIDTH_PACKED@-1:0] s__FIFO[@FIFO_DEPTH@-1:0];
always @ (posedge i_clk)
if (s__FIFO_wr)
s__FIFO[s__FIFO_in_addr[0+:@NBITS_FIFO_DEPTH@]] <= s__input_control_word_packed;
// Operate the output side of the FIFO and translate the packed controls into
// individual signals.
reg s__FIFO_rd = 1'b0;
reg [@NBITS_FIFO_DEPTH@:0] s__FIFO_out_addr = {(@NBITS_FIFO_DEPTH@+1){1'b0}};
always @ (posedge i_clk)
if (i_rst)
s__FIFO_out_addr <= {(@NBITS_FIFO_DEPTH@+1){1'b0}};
else
s__FIFO_out_addr <= s__FIFO_out_addr + { @NBITS_FIFO_DEPTH@'d0, s__FIFO_rd };
reg [@CONTROL_WIDTH_PACKED@-1:0] s__output_control_word = @CONTROL_WIDTH_PACKED@'d0;
always @ (posedge i_clk)
s__output_control_word <= s__FIFO[s__FIFO_out_addr[0+:@NBITS_FIFO_DEPTH@]];
wire [@RATECMD_WIDTH@-1:0] s__next_rate = s__output_control_word[@MODE_WIDTH@+@COUNT_WIDTH@+@ACCEL_WIDTH@+:@RATECMD_WIDTH@];
wire [@ACCEL_WIDTH@-1:0] s__next_accel = s__output_control_word[@MODE_WIDTH@+@COUNT_WIDTH@+:@ACCEL_WIDTH@];
wire [@COUNT_WIDTH@-1:0] s__next_count = s__output_control_word[@MODE_WIDTH@+:@COUNT_WIDTH@];
@OUTMODE_BEGIN@
wire [@MODE_WIDTH@-1:0] s__next_mode = s__output_control_word[0+:@MODE_WIDTH@];
@OUTMODE_END@
// Indicate whether or not the FIFO is empty.
reg s__FIFO_empty = 1'b1;
always @ (posedge i_clk)
if (i_rst)
s__FIFO_empty <=1'b1;
else
s__FIFO_empty <= (s__FIFO_out_addr == s__FIFO_in_addr);
@MASTER_BEGIN@
// Generate the clock enable for the effective internal clock rate.
reg s__clk_en = 1'b0;
reg [L__NBITS_RATEMETHOD-1:0] s__clk_en_count = L__RATEMETHOD_MINUS_1[0+:L__NBITS_RATEMETHOD];
always @ (posedge i_clk)
if (i_rst) begin
s__clk_en <= 1'b0;
s__clk_en_count <= L__RATEMETHOD_MINUS_1[0+:L__NBITS_RATEMETHOD];
end else begin
s__clk_en <= (s__clk_en_count == { {(L__NBITS_RATEMETHOD-1){1'b0}}, 1'b1 });
if (s__clk_en)
s__clk_en_count <= L__RATEMETHOD_MINUS_1[0+:L__NBITS_RATEMETHOD];
else
s__clk_en_count <= s__clk_en_count - { {(L__NBITS_RATEMETHOD-1){1'b0}}, 1'b1 };
end
@MASTER_END@
// Capture the start strobe from the micro controller.
reg s__go = 1'b0;
always @ (posedge i_clk)
if (i_rst)
s__go <= 1'b0;
else if (s_outport && (s_T == 8'd@IX_OUTRUN@))
s__go <= 1'b1;
else if (@S__CLK_EN@)
s__go <= 1'b0;
else
s__go <= s__go;
// Indicate when the controller is running.
reg s__running = 1'b0;
wire s__load_next;
always @ (posedge i_clk)
if (i_rst)
s__running <= 1'b0;
else if (s__go && @S__CLK_EN@)
s__running <= 1'b1;
else if (s__load_next && s__FIFO_empty)
s__running <= 1'b0;
else
s__running <= s__running;
always @ (posedge i_clk)
if (i_rst)
s__done <= 1'b1;
else if (s_outport && (s_T == 8'd@IX_OUTRUN@))
s__done <= 1'b0;
else
s__done <= !s__go && !s__running;
// Operate the step count
wire s__step_pre;
reg [@COUNT_WIDTH@-1:0] s__count = @COUNT_WIDTH@'d0;
reg s__count_zero = 1'b1;
always @ (posedge i_clk)
if (i_rst)
s__count <= @COUNT_WIDTH@'d0;
else if (s__load_next && !s__FIFO_empty)
s__count <= s__next_count;
else if (@S__CLK_EN@ && s__step_pre)
s__count <= s__count - { {(@COUNT_WIDTH@-1){1'b0}}, !s__count_zero };
else
s__count <= s__count;
always @ (posedge i_clk)
if (i_rst)
s__count_zero <= 1'b1;
else
s__count_zero <= (s__count == @COUNT_WIDTH@'d0);
assign s__load_next = @S__CLK_EN@ && (s__go || s__running && s__step_pre && s__count_zero);
always @ (posedge i_clk)
if (i_rst)
s__FIFO_rd <= 1'b0;
else
s__FIFO_rd <= s__load_next && !s__FIFO_empty;
// Operate the accumulators.
reg [@ACCUM_WIDTH@-1:0] s__angle = @ACCUM_WIDTH@'d0;
reg [@RATE_WIDTH@-1:0] s__rate = @RATE_WIDTH@'d0;
reg [@ACCEL_WIDTH@-1:0] s__accel = @ACCEL_WIDTH@'d0;
@OUTMODE_BEGIN@
reg [@MODE_WIDTH@-1:0] s__mode = @MODE_WIDTH@'d0;
@OUTMODE_END@
reg [@ACCUM_WIDTH@-1:0] s__angle_presum = @ACCUM_WIDTH@'d0;
always @ (posedge i_clk)
if (i_rst)
s__angle_presum <= @ACCUM_WIDTH@'d0;
else
s__angle_presum <= s__angle + { {(@RATE_SCALE@){s__rate[@RATE_WIDTH@-1]}}, s__rate[@RATE_WIDTH@-1:@ACCEL_RES@-@ACCUM_RES@] };
always @ (posedge i_clk)
if (i_rst) begin
s__angle <= @ACCUM_WIDTH@'d0;
s__rate <= @RATE_WIDTH@'d0;
s__accel <= @ACCEL_WIDTH@'d0;
@OUTMODE_BEGIN@
s__mode <= @MODE_WIDTH@'d0;
@OUTMODE_END@
end else if (s__load_next && !s__FIFO_empty) begin
s__angle <= {(@ACCUM_WIDTH@){s__next_rate[@RATECMD_WIDTH@-1]}};
s__rate <= { s__next_rate, {(@ACCEL_RES@-@RATE_RES@){1'b0}} };
s__accel <= s__next_accel;
@OUTMODE_BEGIN@
s__mode <= s__next_mode;
@OUTMODE_END@
end else if (!s__running || (s__load_next && s__FIFO_empty)) begin
s__angle <= @ACCUM_WIDTH@'d0;
s__rate <= @RATE_WIDTH@'d0;
s__accel <= @ACCEL_WIDTH@'d0;
@OUTMODE_BEGIN@
s__mode <= s__mode;
@OUTMODE_END@
end else begin
if (@S__CLK_EN@) begin
s__angle <= s__angle_presum;
s__rate <= s__rate + { {(@ACCEL_SCALE@-@RATE_SCALE@){s__accel[@ACCEL_WIDTH@-1]}}, s__accel };
end else begin
s__angle <= s__angle;
s__rate <= s__rate;
end
s__accel <= s__accel;
@OUTMODE_BEGIN@
s__mode <= s__mode;
@OUTMODE_END@
end
// Generate the direction and step signals.
assign s__step_pre = (s__angle[@ACCUM_WIDTH@-1] != s__angle_presum[@ACCUM_WIDTH@-1]);
always @ (posedge i_clk)
if (i_rst) begin
o__dir <= 1'b0;
o__step <= 1'b0;
end else if (@S__CLK_EN@) begin
o__dir <= s__rate[@RATE_WIDTH@-1];
o__step <= s__step_pre;
end else begin
o__dir <= o__dir;
o__step <= o__step;
end
@OUTMODE_BEGIN@
always @ (posedge i_clk)
if (i_rst)
o__mode <= @OUTMODEWIDTH@'d0;
else if (@S__CLK_EN@)
o__mode <= s__mode;
else
o__mode <= o__mode;
@OUTMODE_END@
ssbcc/trunk/core/9x8/peripherals/stepper_motor.v Property changes : Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: ssbcc/trunk/core/9x8/peripherals/UART_Rx.py =================================================================== --- ssbcc/trunk/core/9x8/peripherals/UART_Rx.py (revision 8) +++ ssbcc/trunk/core/9x8/peripherals/UART_Rx.py (revision 9) @@ -1,6 +1,6 @@ ################################################################################ # -# Copyright 2013-2014, Sinclair R.F., Inc. +# Copyright 2013-2015, Sinclair R.F., Inc. # ################################################################################ @@ -8,7 +8,8 @@ import re; from ssbccPeripheral import SSBCCperipheral -from ssbccUtil import SSBCCException; +from ssbccUtil import CeilLog2 +from ssbccUtil import SSBCCException class UART_Rx(SSBCCperipheral): """ @@ -24,7 +25,8 @@ [noSync|sync=n] \\ [noDeglitch|deglitch=n] \\ [noInFIFO|inFIFO=n] \\ - [{RTR|RTRn}=i_rtr_name] \\ + [{RTR|RTRn}=o_rtr_name] \\ + rtr_buffer=n \\ [nStop={1|2}] \n Where: inport=I_inport_name @@ -40,9 +42,9 @@ 1st method: clk/rate clk is the frequency of "i_clk" in Hz a number will be interpreted as the clock frequency in Hz - a symbol will be interpreted as a parameter - Note: this parameter must have been declared with a "PARAMETER" - command + a symbol will be interpreted as a constant or a parameter + Note: the symbol must be declared with the CONSTANT, LOCALPARARM, + or PARAMETER configuration command. rate is the desired baud rate this is specified as per "clk" 2nd method: @@ -52,7 +54,7 @@ frequency and a hard-wired baud rate of 9600: "baudmethod=G_CLK_FREQ_HZ/9600". Note: The numeric values can have Verilog-style '_' separators between - the digits. For example, 100_000_000 represents 100 million. + the digits. For example, 100_000_000 represents 100 million. insignal=i_name optionally specifies the name of the single-bit transmit signal Default: i_UART_Rx @@ -76,17 +78,25 @@ inFIFO=n optionally add a FIFO of depth n to the input side of the UART Note: n must be a power of 2. - RTR=i_rtr_name or RTRn=i_rtr_name + RTR=o_rtr_name or RTRn=o_rtr_name optionally specify an output handshake signal to indicate that the peripheral is ready to receive data Note: If RTR is specified then the receiver indicates it is ready when - i_rtr_name is high. If RTRn is specified then the transmitter - indicates it is ready when i_rtr_name is low. + o_rtr_name is high. If RTRn is specified then the transmitter + indicates it is ready when o_rtr_name is low. Note: The default, i.e., neither CTS nor CTSn is specified, is to always enable the receiver. Note: If there is no FIFO and the RTR/RTRn handshake indicates that the receiver is not ready as soon as it starts receiving data and until that data is read from the peripheral. + Default: 1 + rtr_buffer=n + optionally specify the number of entries in inFIFO to reserve for data + received after the RTR/RTRn signal indicates to stop data flow. + Note: n must be a power of 2. + Note: This requires that inFIFO be specified. + Note: Some USB UARTs will transmit several characters after the RTR/RTRn + signal indicates to stop the data flow. nStop=n optionally configure the peripheral for n stop bits default: 1 stop bit @@ -121,7 +131,7 @@ ( 'RTRn', r'o_\w+$', None, ), ( 'baudmethod', r'\S+$', lambda v : self.RateMethod(config,v), ), ( 'deglitch', r'[1-9]\d*$', int, ), - ( 'inFIFO', r'[1-9]\d*$', lambda v : self.IntPow2(v), ), + ( 'inFIFO', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v), ), ( 'inempty', r'I_\w+$', None, ), ( 'inport', r'I_\w+$', None, ), ( 'insignal', r'i_\w+$', None, ), @@ -129,6 +139,7 @@ ( 'noInFIFO', None, None, ), ( 'noSync', None, None, ), ( 'nStop', r'[12]$', int, ), + ( 'rtr_buffer', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v), ), ( 'sync', r'[1-9]\d*$', int, ), ); names = [a[0] for a in allowables]; @@ -153,6 +164,15 @@ ): if not hasattr(self,optionalpair[0]): setattr(self,optionalpair[0],optionalpair[1]); + # Ensure the rtr_buffer, if specified, is consistent with the inFIFO + # specification. + if hasattr(self,'rtr_buffer'): + if not hasattr(self,'inFIFO'): + raise SSBCCException('rtr_buffer specification requires simultaneous inFIFO specification at %s' % loc); + if not self.rtr_buffer < self.inFIFO: + raise SSBCCException('rtr_buffer=%d specification must be less than the inFIFO=%d specification at %s' % (self.rtr_buffer,self.inFIFO,loc,)); + else: + self.rtr_buffer = 1; # Ensure exclusive pair configurations are set and consistent. for exclusivepair in ( ( 'RTR', 'RTRn', None, None, ), @@ -206,17 +226,18 @@ body = re.sub(r'@RTR_BEGIN@.*?@RTR_END@\n','',body,flags=re.DOTALL); for subpair in ( ( r'@RTR_SIGNAL@', self.RTR if hasattr(self,'RTR') else self.RTRn if hasattr(self,'RTRn') else '', ), - ( r'@RTR_INVERT@', '' if hasattr(self,'RTR') else '!', ), - ( r'\bL__', 'L__@NAME@__', ), - ( r'\bgen__', 'gen__@NAME@__', ), - ( r'\bs__', 's__@NAME@__', ), - ( r'@INPORT@', self.insignal, ), - ( r'@BAUDMETHOD@', str(self.baudmethod), ), - ( r'@SYNC@', str(self.sync), ), - ( r'@DEGLITCH@', str(self.deglitch), ), - ( r'@INFIFO@', str(self.inFIFO), ), - ( r'@NSTOP@', str(self.nStop), ), - ( r'@NAME@', self.namestring, ), + ( r'@RTRN_INVERT@', '!' if hasattr(self,'RTR') else '', ), + ( r'\bL__', 'L__@NAME@__', ), + ( r'\bgen__', 'gen__@NAME@__', ), + ( r'\bs__', 's__@NAME@__', ), + ( r'@INPORT@', self.insignal, ), + ( r'@BAUDMETHOD@', str(self.baudmethod), ), + ( r'@SYNC@', str(self.sync), ), + ( r'@DEGLITCH@', str(self.deglitch), ), + ( r'@INFIFO@', str(self.inFIFO), ), + ( r'@NSTOP@', str(self.nStop), ), + ( r'@NAME@', self.namestring, ), + ( r'@RTR_FIFO_COMPARE@', str(CeilLog2(self.rtr_buffer)), ), ): if re.search(subpair[0],body): body = re.sub(subpair[0],subpair[1],body);
/ssbcc/trunk/core/9x8/peripherals/UART_Tx.py
1,6 → 1,6
################################################################################
#
# Copyright 2012-2014, Sinclair R.F., Inc.
# Copyright 2012-2015, Sinclair R.F., Inc.
#
################################################################################
 
39,9 → 39,9
1st method: clk/rate
clk is the frequency of "i_clk" in Hz
a number will be interpreted as the clock frequency in Hz
a symbol will be interpreted as a parameter
Note: this parameter must have been declared with a "PARAMETER"
command
a symbol will be interpreted as a constant or a parameter
Note: the symbol must be declared with the CONSTANT, LOCALPARARM,
or PARAMETER configuration command.
rate is the desired baud rate
this is specified as per "clk"
2nd method:
118,7 → 118,7
( 'baudmethod', r'\S+$', lambda v : self.RateMethod(config,v), ),
( 'noOutFIFO', None, None, ),
( 'nStop', r'[12]$', int, ),
( 'outFIFO', r'[1-9]\d*$', lambda v : self.IntPow2(v), ),
( 'outFIFO', r'[1-9]\d*$', lambda v : self.IntPow2Method(config,v), ),
( 'outport', r'O_\w+$', None, ),
( 'outsignal', r'o_\w+$', None, ),
( 'outstatus', r'I_\w+$', None, ),
171,9 → 171,9
):
if hasattr(self,ioEntry[0]):
config.AddIO(getattr(self,ioEntry[0]),ioEntry[1],ioEntry[2],loc);
config.AddSignal('s__%s__Tx' % self.namestring,8,loc);
config.AddSignal('s__%s__Tx_busy' % self.namestring,1,loc);
config.AddSignal('s__%s__Tx_wr' % self.namestring,1,loc);
config.AddSignalWithInit('s__%s__Tx' % self.namestring,8,None,loc);
config.AddSignal('s__%s__Tx_busy' % self.namestring,1,loc);
config.AddSignalWithInit('s__%s__Tx_wr' % self.namestring,1,None,loc);
config.AddOutport((self.outport,False,
('s__%s__Tx' % self.namestring,8,'data',),
('s__%s__Tx_wr' % self.namestring,1,'strobe',),
188,14 → 188,14
for bodyextension in ('.v',):
body = self.LoadCore(self.peripheralFile,bodyextension);
for subpair in (
( r'\bL__', 'L__@NAME@__', ),
( r'\bgen__', 'gen__@NAME@__', ),
( r'\bs__', 's__@NAME@__', ),
( r'@BAUDMETHOD@', str(self.baudmethod), ),
( r'@ENABLED@', self.CTS if hasattr(self,'CTS') else ('!%s' % self.CTSn) if hasattr(self,'CTSn') else '1\'b1', ),
( r'@NSTOP@', str(self.nStop), ),
( r'@OUTFIFO@', str(self.outFIFO), ),
( r'@NAME@', self.namestring, ),
( r'\bL__', 'L__@NAME@__', ),
( r'\bgen__', 'gen__@NAME@__', ),
( r'\bs__', 's__@NAME@__', ),
( r'@BAUDMETHOD@', str(self.baudmethod), ),
( r'@ENABLED@', self.CTS if hasattr(self,'CTS') else ('!%s' % self.CTSn) if hasattr(self,'CTSn') else '1\'b1', ),
( r'@NSTOP@', str(self.nStop), ),
( r'@OUTFIFO@', str(self.outFIFO), ),
( r'@NAME@', self.namestring, ),
):
body = re.sub(subpair[0],subpair[1],body);
body = self.GenVerilogFinal(config,body);
/ssbcc/trunk/ssbccConfig.py
26,6 → 26,7
"""
self.config = dict(); # various settings, etc.
self.constants = dict(); # CONSTANTs
self.defines = dict(); # defines
self.functions = dict(); # list of functions to define
self.inports = list(); # INPORT definitions
self.ios = list(); # List of I/Os
66,6 → 67,19
raise SSBCCException('Could not evaluate expression "%s" for constant at %s' % (value,loc,));
self.constants[name] = ParseIntExpr(value);
 
def AddDefine(self,name):
"""
Add the defined symbol.\n
name name for the symbol (must start with "D_")\n
Note: This is only invoked for the command line arguments so there is no
"loc" available.\n
Note: Defines can be declared more than once on the command line with no
ill effects.
"""
if not self.IsDefine(name):
self.AddSymbol(name);
self.defines[name] = 1;
 
def AddIO(self,name,nBits,iotype,loc):
"""
Add an I/O signal to the processor interface to the system.\n
342,6 → 356,15
else:
return False;
 
def IsDefine(self,name):
"""
Indicate whether or not the specified symbol is a recognized define.
"""
if re.match(r'D_\w+$',name) and name in self.defines:
return True;
else:
return False;
 
def IsMemory(self,name):
"""
Indicate whether or not the specified symbol is the name of a memory.
/ssbcc/trunk/README
48,15 → 48,15
the sizes of the instruction memory, data stack, and return stack; the input and
output ports; RAM and ROM types and sizes; and peripherals.
 
The instructions are all single-cycle. The instructions include
The instructions are all single-cycle. The instructions are:
- 4 arithmetic instructions: addition, subtraction, increment, and decrement
- 2 carry bit instructions: +c and -c for addition and subtraction respectively
- 3 bit-wise logical instructions: and, or, and exclusive or
- 7 shift and rotation instructions: <<0, <<1, 0>>, 1>>, <<msb, >>msb, and >>lsb
- 7 shift and rotation instructions: <<0, <<1, 0>>, 1>>, <<msb, msb>>, and lsb>>
- 4 logical instructions: 0=, 0<>, -1=, -1<>
- 6 Forth-like data stack instructions: drop, dup, nip, over, push, swap
- 3 Forth-like return stack instructions: >r, r>, r@
- 2 input and output
- 2 I/O: inport, outport
- 6 memory read and write with optional address post increment and post decrement
- 2 jump and conditional jump
- 2 call and conditional call
90,6 → 90,7
 
SPEED AND RESOURCE UTILIZATION
================================================================================
 
These device speed and resource utilization results are copied from the build
tests. The full results are listed in the core/9x8/build directories. The
tests use a minimal processor implementation (clock, reset, and one output).
599,7 → 600,16
dropped from the data stack so that it can be used by the subsequent conditional
function call.
 
The input from a set-reset INPORT is a pure flag. I.e., either all of the bits
are zero or all of the bits are one. This can be used as part of executing a
loop a fixed number of times. For example, the inperiod argument of the
servo_motor peripheral can be used to receive a strobe every time the PWM goes
high. The following loop will wait for 10 occurrences of the rising edge of the
servo_motor PWM before proceeding to the next block of code:
 
10 :loop .inport(I_INPERIOD) + .jumpc(loop,nop) drop
 
 
PERIPHERAL
================================================================================
 
652,6 → 662,8
open_drain for software-implemented I2C buses or similar
outFIFO_async output FIFO with an asynchronous read clock
PWM_8bit PWM generator with an 8-bit control
servo_motor PWM modulation suitable for servo motor or similar control
stepper_motor stepper motor controller with acceleration
timer timing for polled loops or similar
trace simulation diagnostic (see below)
UART bidirectional UART
1071,6 → 1083,7
 
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
1153,54 → 1166,88
 
CONDITIONAL COMPILATION
================================================================================
The computer compiler and assembler recognize conditional compilation as
follows: .IFDEF, .IFNDEF, .ELSE, and .ENDIF can be used in the architecture
file and they can be used to conditionally include functions, files, etc within
the assembly code; .ifdef, .ifndef, .else, and .endif can be used in function
bodies, variable bodies, etc. to conditionally include assembly code, symbols,
or data. Conditionals cannot cross file boundaries.
 
The computer compiler examines the list of defined symbols such as I/O ports,
I/O signals, etc. to evaluate the true/false condition associated with the
.IFDEF and .IFNDEF commands. The "-D" option to the computer compiler is
provided to define symbols for enabling conditionally compiled configuration
commands. Similarly, the assembler examines the list of I/O ports, I/O signals,
parameters, constants, etc. to evaluate the .IFDEF, .IFNDEF, .ifdef, and .ifndef
conditionals.
Conditional compilation is accepted in the architecture file and in the assembly
source files and is based on whether or not the referenced symbol is defined.
 
For example, a diagnostic UART can be conditionally included using the
configuration commands:
In the architecture file, symbols are defined by CONSTANT, INPORT, OUTPORT, and
PERIPHERAL statements, or by the "-D D_name" argument to ssbcc. The line
 
.IFDEF ENABLE_UART
.IFDEF name
<statements>
.ENDIF
 
will then include the lines "<statements>" if the symbol "name" is defined.
The ".IFNDEF" command is similar except that the statements included if the
symbol is not defined. A ".ELSE" is also provided.
 
In an assembly file directives are conditionally included using the .IFDEF and
.IFNDEF directives, an optional .ELSE directive, and the terminating .ENDIF
directive. Note that this is done at the directive level, i.e. function
declarations, memory declarations, and so forth. Within a function code is
conditionally included starting with a ".ifdef(name)" or a ".ifndef(name)", an
optional ".else" and a terminating ".endif".
 
For example, a diagnostic UART can be conditionally included in a program by
including the following lines in the architecture file:
 
.IFDEF D_ENABLE_UART
PORTCOMMENT Diagnostic UART
PERIPHERAL UART_Tx outport=O_UART_TX ...
.ENDIF
 
And the assembly code can include conditional code fragments such the following,
where the existence of the output port is used to determine whether or not to
send a character to that output port:
A "uart_tx" function can be optionally created using code similar to the
following. Note that the symbol for the .outport macro is used to determine
whether or not the function is defined since that is more closely related to
whether or not the function can be defined. The function definition must
preceed any ".ifdef(uart_tx)" conditionals used to output diagnostics.
 
.ifdef(O_UART_TX) 'A' .outport(O_UART_TX) .endif
.IFDEF O_UART_TX
.function uart_tx
:loop .outport(O_UART_TX) .jumpc(loop,nop) .return(drop)
.ENDIF
 
Invoking the computer compiler with "-D ENABLE_UART" will generate a module with
the UART peripheral and will enable the conditional code sending the 'A'
character to the UART port.
Diagnostics in the assembly code can be included using either
 
The following code can be used to preclude multiple attempted inclusions of an
assembly library file.
.ifdef(D_ENABLE_UART) N"Msg\r\n" .call(uart_tx) .endif
 
or
 
.ifdef(uart_tx) N"Msg\r\n" .call(uart_tx) .endif
 
Conditional compilation cannot cross file boundaries.
 
The assembler also recognizes the ".define" directive. For example, specific
diagnostics could be enabled if the UART is instantiated as follows:
 
.IFDEF O_UART_TX
.define D_DEBUG_FUNCTION_A
.ENDIF
 
...
 
.ifdef(D_DEBUG_FUNCTION_A) N"Debug Msg\r\n" .call(uart_tx) .endif
 
The following code illustrates how to preclude multiple attempted inclusions of
an assembly library file.
 
; put these two lines near the top of the file
.IFNDEF C_FILENAME_INCLUDED
.constant C_FILENAME_INCLUDED 1
.IFNDEF D_FILENAME_INCLUDED
.define D_FILENAME_INCLUDED
; put the library body here
...
; put this line at the bottom of the file
.ENDIF ; .IFNDEF C_FILENAME_INCLUDED
.ENDIF ; .IFNDEF D_FILENAME_INCLUDED
 
The ".INCLUDE" configuration command can be used to read configuration commands
from additional sources.
from additional sources. For example, the following code will conditionally
include a general UART library if the outport O_UART_TX is defined:
 
.IFDEF O_UART_TX
.INCLUDE uart.s
.ENDIF
 
 
SIMULATIONS
================================================================================
 
1276,5 → 1323,3
 
The "INVERT_RESET" configuration command is used to indicate an active-low reset
is input to the micro controller rather than an active-high reset.
 
A VHDL package file is automatically generated by the computer compiler.
/ssbcc/trunk/ssbcc
45,7 → 45,7
 
import argparse
argListParser = argparse.ArgumentParser(description='SSBCC system builder');
argListParser.add_argument('-D', metavar='symbol', type=str, action='append', help='Define symbol');
argListParser.add_argument('-D', metavar='D_name', type=str, action='append', help='Define symbol (must start with "D_")');
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');
74,13 → 74,15
config.functions['display_opcode'] = True;
 
if argList.D:
for symbol in argList.D:
config.AddSymbol(symbol);
for name in argList.D:
if not re.match('D_',name):
raise SSBCCException('Bad define name "%s" should start with "D_"' % name);
config.AddDefine(name);
 
if argList.I:
for pathString in argList.I:
if not os.path.isdir(pathString):
raise SSBCCException('Bad path string: "%s"' % pathString);
raise SSBCCException('Bad path string: "%s/%s"' % (os.getcwd(),pathString,));
config.AppendIncludePath(pathString);
config.InsertPeripheralPath(pathString);
 
199,7 → 201,7
elif re.match(r'\s*CONSTANT\b',line):
if not config.Exists('architecture'):
raise SSBCCException('"CONSTANT"s cannot be defined before the "ARCHITECTURE" is defined at %s' % loc);
cmd = re.findall(r'\s*CONSTANT\s+(C_\w+)\s+(\w+)\s*$',line);
cmd = re.findall(r'\s*CONSTANT\s+(C_\w+)\s+(-?[1-9]\d*|\w+)\s*$',line);
if not cmd:
raise SSBCCException('Malformed "CONSTANT" configuration command on %s: "%s"' % (loc,line,));
cmd = cmd[0];
367,8 → 369,8
################################################################################
 
# Generate peripheral libraries (if any).
for ix in range(len(config.peripheral)):
config.peripheral[ix].GenAssembly(config);
for p in config.peripheral:
p.GenAssembly(config);
 
# Compute the file name to store the assembler output
assemblerOutput = os.path.splitext(argList.filename.name)[0]+'.9x8-meta'
379,6 → 381,8
cmd = os.path.join(config.Get('corepath'), compiler[0]);
for name in config.constants:
cmd += (' -C %s=%s' % (name,config.constants[name],));
for name in config.defines:
cmd += (' -D %s' % name);
for ix in range(len(config.parameters)):
cmd += (' -G %s' % config.parameters[ix][0]);
for ix in range(config.NInports()):
548,10 → 552,10
elif fillCommand == 'peripherals':
if not config.peripheral:
fpOutCore.write('//\n// No peripherals\n//\n');
for ix in range(len(config.peripheral)):
if ix != 0:
for p in config.peripheral:
if p != config.peripheral[0]:
fpOutCore.write('\n');
config.peripheral[ix].GenHDL(fpOutCore,config);
p.GenHDL(fpOutCore,config);
# "s_memory" declaration
elif fillCommand == 's_memory':
if config.NMemories() == 0:

powered by: WebSVN 2.1.0

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