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

Subversion Repositories ssbcc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /ssbcc/trunk/core/9x8/peripherals
    from Rev 6 to Rev 9
    Reverse comparison

Rev 6 → Rev 9

/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)
/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:
/tb/UART_Rx/tb.v File deleted
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: tb/UART_Rx/tb.v-normal =================================================================== --- tb/UART_Rx/tb.v-normal (nonexistent) +++ 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: tb/UART_Rx/run =================================================================== --- tb/UART_Rx/run (revision 6) +++ 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;
/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
/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
/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
/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)
/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; }
/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
/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
/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;
tb/stepper_motor/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tb/stepper_motor/.gitignore =================================================================== --- tb/stepper_motor/.gitignore (nonexistent) +++ tb/stepper_motor/.gitignore (revision 9) @@ -0,0 +1,3 @@ +tb +tb.out +tb_stepper_motor.v Index: tb/stepper_motor/tb_stepper_motor.s =================================================================== --- tb/stepper_motor/tb_stepper_motor.s (nonexistent) +++ 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: tb/stepper_motor/tb.v =================================================================== --- tb/stepper_motor/tb.v (nonexistent) +++ 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
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: tb/stepper_motor/tb.good =================================================================== --- tb/stepper_motor/tb.good (nonexistent) +++ 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: tb/stepper_motor/tb_stepper_motor.9x8 =================================================================== --- tb/stepper_motor/tb_stepper_motor.9x8 (nonexistent) +++ 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: tb/servo_motor/tb_servo_motor.s =================================================================== --- tb/servo_motor/tb_servo_motor.s (nonexistent) +++ 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: tb/servo_motor/run =================================================================== --- tb/servo_motor/run (nonexistent) +++ 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;
tb/servo_motor/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: tb/servo_motor/.gitignore =================================================================== --- tb/servo_motor/.gitignore (nonexistent) +++ tb/servo_motor/.gitignore (revision 9) @@ -0,0 +1,2 @@ +tb.out +tb_servo_motor.v Index: tb/servo_motor/tb.v =================================================================== --- tb/servo_motor/tb.v (nonexistent) +++ 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
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: tb/servo_motor/tb_servo_motor.9x8 =================================================================== --- tb/servo_motor/tb_servo_motor.9x8 (nonexistent) +++ 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: tb/servo_motor/tb.good =================================================================== --- tb/servo_motor/tb.good (nonexistent) +++ 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: open_drain.py =================================================================== --- open_drain.py (revision 6) +++ 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: timer.py =================================================================== --- timer.py (revision 6) +++ 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: AXI4_Lite_Slave_DualPortRAM.py =================================================================== --- AXI4_Lite_Slave_DualPortRAM.py (revision 6) +++ 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: PWM_8bit.py =================================================================== --- PWM_8bit.py (revision 6) +++ 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: servo_motor.v =================================================================== --- servo_motor.v (nonexistent) +++ 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
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: UART_Rx.v =================================================================== --- UART_Rx.v (revision 6) +++ 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: UART_Tx.v =================================================================== --- UART_Tx.v (revision 6) +++ 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: inFIFO_async.py =================================================================== --- inFIFO_async.py (revision 6) +++ 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: UART.py =================================================================== --- UART.py (revision 6) +++ 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);
/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);
/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@
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: UART_Rx.py =================================================================== --- UART_Rx.py (revision 6) +++ 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);
/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);

powered by: WebSVN 2.1.0

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