mirror of
https://github.com/myhdl/myhdl.git
synced 2025-01-24 21:52:56 +08:00
Added
This commit is contained in:
parent
05983f3e65
commit
516fb7bf38
@ -2,15 +2,17 @@ NAME = manual
|
||||
|
||||
default: $(NAME).dvi $(NAME).ps $(NAME).pdf
|
||||
|
||||
%.pdf: %.ps
|
||||
ps2pdf $<
|
||||
#%.pdf: %.ps
|
||||
# ps2pdf $<; \
|
||||
|
||||
%.ps: %.dvi
|
||||
dvips -o $@ -t a4 -Ppdf -G0 $<
|
||||
|
||||
%.dvi: %.tex
|
||||
latex $<; \
|
||||
latex $<
|
||||
python tools/toc2bkm.py -c chapter $(NAME).toc
|
||||
latex $<; \
|
||||
pdflatex $<
|
||||
|
||||
clean:
|
||||
-rm *.dvi *.log *.toc *.ps *.pdf *.aux *.out
|
||||
|
@ -39,22 +39,22 @@ explain the \samp{import *} syntax}.
|
||||
|
||||
Next, we define a generator function called
|
||||
\code{sayHello}. This is a generator function (as opposed to
|
||||
a classic Python function) because it contains a \code{yield}
|
||||
statement (instead of \code{return} statement). In \myhdl\, a
|
||||
\code{yield} statement has a similar purpose as a \code{wait}
|
||||
a classic Python function) because it contains a \keyword{yield}
|
||||
statement (instead of \keyword{return} statement). In \myhdl\, a
|
||||
\keyword{yield} statement has a similar purpose as a \keyword{wait}
|
||||
statement in VHDL: the statement suspends execution of the function,
|
||||
and its clauses specify when the function should resume. In this case,
|
||||
there is a \code{delay} clause, that specifies the required delay.
|
||||
|
||||
To make sure that the generator runs ``forever'', we wrap its behavior
|
||||
in a \code{while 1} loop. This is as standard Python idiom, and it is
|
||||
the \myhdl\ equivalent to a Verilog \code{always} block or a
|
||||
VHDL \code{process}.
|
||||
the \myhdl\ equivalent to a Verilog \keyword{always} block or a
|
||||
VHDL \keyword{process}.
|
||||
|
||||
In \myhdl\, the basic simulation objects are generators. Generators
|
||||
are created by calling a generator function. For example, variable
|
||||
are created by calling generator functions. For example, variable
|
||||
\code{gen} refers to a generator. To simulate this generator, we pass
|
||||
it as an argument to a code{Simulation} object constructor. We then
|
||||
it as an argument to a \class{Simulation} object constructor. We then
|
||||
run the simulation for the desired amount of time.
|
||||
|
||||
|
||||
@ -64,14 +64,15 @@ In the previous section, we simulated a single generator. Of course,
|
||||
real hardware descriptions are not like that: in fact, they are
|
||||
typically massively concurrent. \myhdl\ supports this by allowing an
|
||||
arbitrary number of concurrent generators. More specifically, a
|
||||
\code{Simulation} constructor can take an arbitrary number of
|
||||
\class{Simulation} constructor can take an arbitrary number of
|
||||
arguments, each of which can be a generator or a nested list of
|
||||
generators.
|
||||
|
||||
With concurrency comes the problem of determinism. Therefore, hardware
|
||||
languages use special objects to support deterministic communication
|
||||
between concurrent regions. \myhdl\ has as \code{Signal} object which
|
||||
is roughly modelled after VHDL signals.
|
||||
With concurrency comes the problem of deterministic
|
||||
communication. Therefore, hardware languages use special objects to
|
||||
support deterministic communication between concurrent
|
||||
regions. \myhdl\ has as \class{Signal} object which is roughly modelled
|
||||
after VHDL signals.
|
||||
|
||||
We will demonstrate these concepts by extending our first example. We
|
||||
introduce a clock signal, driven by a second generator. The
|
||||
@ -120,21 +121,22 @@ attribute. This is the \myhdl\ equivalent of VHDL signal assignments
|
||||
and Verilog's non-blocking assignments.
|
||||
|
||||
The \code{sayHello} generator function shows a second form of a
|
||||
\code{yield} statement: \samp{yield posedge(\var{aSignal})}. Again,
|
||||
\keyword{yield} statement: \samp{yield posedge(\var{aSignal})}. Again,
|
||||
the generator will suspend execution at that point, but in this case
|
||||
it specifies that it should resume when there is a rising edge on the
|
||||
signal.
|
||||
|
||||
The \code{Simulation} constructor now takes two generator arguments
|
||||
The \class{Simulation} constructor now takes two generator arguments
|
||||
that run concurrently throughout the simulation.
|
||||
|
||||
\section{Parameters and instantiations}
|
||||
|
||||
So far, the generator function examples had no parameters. The signals
|
||||
they operated on were defined in their enclosing scope. However,
|
||||
to make the code reusable we will want to pass arguments through a
|
||||
parameter list. For example, we can change the clock generator
|
||||
function as follows to make it more general and reusable:
|
||||
So far, the generator function examples had no parameters. For
|
||||
example, the \code{clk} signal was defined in the enclosing scope of
|
||||
the generator functions. However, to make the code reusable we will
|
||||
want to pass arguments through a parameter list. For example, we can
|
||||
change the clock generator function to make it more general
|
||||
and reusable, as follows:
|
||||
|
||||
\begin{verbatim}
|
||||
def clkGen(clock, period=20):
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
\myhdl\ is implemented as a Python package called \code{myhdl}. This
|
||||
chapter describes all objects that are expored by this package.
|
||||
chapter describes the objects that are expored by this package.
|
||||
|
||||
\section{The \class{Simulation} class}
|
||||
\begin{classdesc}{Simulation}{arg \optional{, arg \moreargs}}
|
||||
@ -17,7 +17,7 @@ object.
|
||||
A \class{Simulation} instance has the following method:
|
||||
|
||||
\begin{methoddesc}[Simulation]{run}{\optional{duration}}
|
||||
Run the simulation forever or for a specified duration.
|
||||
Run the simulation forever (by default) or for a specified duration.
|
||||
\end{methoddesc}
|
||||
|
||||
\section{The \class{Signal} class}
|
||||
@ -44,16 +44,16 @@ statements are called \emph{sensitivity lists}. The general format is:
|
||||
|
||||
\keyword{yield} \var{clause \optional{, clause ...}}
|
||||
|
||||
After a simulator executes a \keyword{yield} statement, it suspends
|
||||
execution of the generator. At the same time, each \var{clause} is a
|
||||
\emph{trigger object} which defines the condition upon which the
|
||||
generator should be resumed. However, per invocation of a \keyword{yield}
|
||||
statement, the generator is resumed exactly once, regardless of the
|
||||
number of clauses. This happens when the \emph{first} trigger object
|
||||
triggers; subsequent triggers are neglected. (However, as a result of
|
||||
the resumption, it is possible that the same \keyword{yield} statement
|
||||
is invoked again, and that a subsequent trigger still triggers the
|
||||
generator.)
|
||||
After a simulation object executes a \keyword{yield} statement, it
|
||||
suspends execution of the generator. At the same time, each
|
||||
\var{clause} is a \emph{trigger object} which defines the condition
|
||||
upon which the generator should be resumed. However, per invocation of a
|
||||
\keyword{yield} statement, the generator is resumed exactly once,
|
||||
regardless of the number of clauses. This happens when the
|
||||
\emph{first} trigger object triggers; subsequent triggers are
|
||||
neglected. (However, as a result of the resumption, it is possible
|
||||
that the same \keyword{yield} statement is invoked again, and that a
|
||||
subsequent trigger still triggers the generator.)
|
||||
|
||||
In this section, the trigger objects and their functionality will be
|
||||
described. When referring to ``the generator'' we mean the generator
|
||||
@ -139,10 +139,10 @@ assignment to indexes and slices, as is common in hardware design. For
|
||||
the same reason, \class{intbv} is not a subclass from \class{int},
|
||||
even though \class{int} provides most of the desired
|
||||
functionality. (It is not possible to derive a mutable subtype from
|
||||
and immutable type.)
|
||||
an immutable base type.)
|
||||
|
||||
An \class{intbv} object supports all comparison, numberic, bitwise,
|
||||
and logical operations as \class{int} objects. See
|
||||
An \class{intbv} object supports the same comparison, numberic,
|
||||
bitwise, logical, and conversion operations as \class{int} objects. See
|
||||
\url{http://www.python.org/doc/current/lib/typesnumeric.html} for more
|
||||
information on such operations. In all binary operations,
|
||||
\class{intbv} objects can work together with \class{int} objects; in
|
||||
@ -153,7 +153,7 @@ operations:
|
||||
|
||||
\begin{tableiii}{clc}{code}{Operation}{Result}{Notes}
|
||||
\lineiii{\var{bv}[\var{i}]}
|
||||
{\var{i}'th item of \var{bv}}
|
||||
{item \var{i} of \var{bv}}
|
||||
{(1)}
|
||||
\lineiii{\var{bv}[\var{i}] = \var{x}}
|
||||
{item \var{i} of \var{bv} is replaced by \var{x}}
|
||||
@ -162,7 +162,7 @@ operations:
|
||||
{slice of \var{bv} from \var{i} downto \var{j}}
|
||||
{(2)(3)}
|
||||
\lineiii{\var{bv}[\var{i}:\var{j}] = \var{t}}
|
||||
{slice of \var{bv} from \var{i} downto to \var{j} is replaced
|
||||
{slice of \var{bv} from \var{i} downto \var{j} is replaced
|
||||
by \var{t}}
|
||||
{(2)(4)}
|
||||
\end{tableiii}
|
||||
@ -171,14 +171,29 @@ operations:
|
||||
\item[(1)] Indexing follows the most common hardware design
|
||||
conventions: the lsb bit is the rightmost bit, and it has
|
||||
index 0. This has the following desirable property: if the
|
||||
value is decomposed as a sum of powers of 2, the bit with
|
||||
index \var{i} corresponds to the term \code{2**i}.
|
||||
\class{intbv} value is decomposed as a sum of powers of 2,
|
||||
the bit with index \var{i} corresponds to the term
|
||||
\code{2**i}.
|
||||
|
||||
\item[(2)] slicing
|
||||
\item[(2)] It follows from the indexing convention that slicing ranges
|
||||
are downward, in contrast to standard Python. However, the
|
||||
Python convention of half-open ranges is followed. In
|
||||
accordance with standard Python, the high index is not
|
||||
included, however, it is the \emph{leftmost} index in this
|
||||
case. As in standard Python, this takes care of one-off
|
||||
issues in many practical cases: in particular,
|
||||
\code{bv[\var{i}:]} returns \var{i} bits;
|
||||
\code{bv[\var{i}:\var{j}]} has \code{\var{i}-\var{j}}
|
||||
bits. As \class{intbv} objects have an undefined bit width,
|
||||
the high index \var{j} has no default value and cannot be
|
||||
ommitted, while the low index \var{j} defaults to \code{0}.
|
||||
|
||||
\item[(3)] positive return
|
||||
\item[(3)] The value returned from a slicing operation is always
|
||||
positive; higher order bits are implicitly assumed to be
|
||||
zero.
|
||||
|
||||
\item[(4)] value check
|
||||
\item[(4)] In setting a slice, it is checked whether the slice is wide
|
||||
enough to accept all significant bits of the value.
|
||||
|
||||
\end{description}
|
||||
|
||||
|
143
doc/tools/toc2bkm.py
Executable file
143
doc/tools/toc2bkm.py
Executable file
@ -0,0 +1,143 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Convert a LaTeX .toc file to some PDFTeX magic to create that neat outline.
|
||||
|
||||
The output file has an extension of '.bkm' instead of '.out', since hyperref
|
||||
already uses that extension.
|
||||
"""
|
||||
|
||||
import getopt
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
|
||||
|
||||
# Ench item in an entry is a tuple of:
|
||||
#
|
||||
# Section #, Title String, Page #, List of Sub-entries
|
||||
#
|
||||
# The return value of parse_toc() is such a tuple.
|
||||
|
||||
cline_re = r"""^
|
||||
\\contentsline\ \{([a-z]*)} # type of section in $1
|
||||
\{(?:\\numberline\ \{([0-9.A-Z]+)})? # section number
|
||||
(.*)} # title string
|
||||
\{(\d+)}$""" # page number
|
||||
|
||||
cline_rx = re.compile(cline_re, re.VERBOSE)
|
||||
|
||||
OUTER_TO_INNER = -1
|
||||
|
||||
_transition_map = {
|
||||
('chapter', 'section'): OUTER_TO_INNER,
|
||||
('section', 'subsection'): OUTER_TO_INNER,
|
||||
('subsection', 'subsubsection'): OUTER_TO_INNER,
|
||||
('subsubsection', 'subsection'): 1,
|
||||
('subsection', 'section'): 1,
|
||||
('section', 'chapter'): 1,
|
||||
('subsection', 'chapter'): 2,
|
||||
('subsubsection', 'section'): 2,
|
||||
('subsubsection', 'chapter'): 3,
|
||||
}
|
||||
|
||||
INCLUDED_LEVELS = ("chapter", "section", "subsection", "subsubsection")
|
||||
|
||||
|
||||
def parse_toc(fp, bigpart=None):
|
||||
toc = top = []
|
||||
stack = [toc]
|
||||
level = bigpart or 'chapter'
|
||||
lineno = 0
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
lineno = lineno + 1
|
||||
m = cline_rx.match(line)
|
||||
if m:
|
||||
stype, snum, title, pageno = m.group(1, 2, 3, 4)
|
||||
title = clean_title(title)
|
||||
entry = (stype, snum, title, string.atoi(pageno), [])
|
||||
if stype == level:
|
||||
toc.append(entry)
|
||||
else:
|
||||
if stype not in INCLUDED_LEVELS:
|
||||
# we don't want paragraphs & subparagraphs
|
||||
continue
|
||||
direction = _transition_map[(level, stype)]
|
||||
if direction == OUTER_TO_INNER:
|
||||
toc = toc[-1][-1]
|
||||
stack.insert(0, toc)
|
||||
toc.append(entry)
|
||||
else:
|
||||
for i in range(direction):
|
||||
del stack[0]
|
||||
toc = stack[0]
|
||||
toc.append(entry)
|
||||
level = stype
|
||||
else:
|
||||
sys.stderr.write("l.%s: " + line)
|
||||
return top
|
||||
|
||||
|
||||
hackscore_rx = re.compile(r"\\hackscore\s*{[^}]*}")
|
||||
raisebox_rx = re.compile(r"\\raisebox\s*{[^}]*}")
|
||||
title_rx = re.compile(r"\\([a-zA-Z])+\s+")
|
||||
title_trans = string.maketrans("", "")
|
||||
|
||||
def clean_title(title):
|
||||
title = raisebox_rx.sub("", title)
|
||||
title = hackscore_rx.sub(r"\\_", title)
|
||||
pos = 0
|
||||
while 1:
|
||||
m = title_rx.search(title, pos)
|
||||
if m:
|
||||
start = m.start()
|
||||
if title[start:start+15] != "\\textunderscore":
|
||||
title = title[:start] + title[m.end():]
|
||||
pos = start + 1
|
||||
else:
|
||||
break
|
||||
title = string.translate(title, title_trans, "{}")
|
||||
return title
|
||||
|
||||
|
||||
def write_toc(toc, fp):
|
||||
for entry in toc:
|
||||
write_toc_entry(entry, fp, 0)
|
||||
|
||||
def write_toc_entry(entry, fp, layer):
|
||||
stype, snum, title, pageno, toc = entry
|
||||
s = "\\pdfoutline goto name{page%03d}" % pageno
|
||||
if toc:
|
||||
s = "%s count -%d" % (s, len(toc))
|
||||
if snum:
|
||||
title = "%s %s" % (snum, title)
|
||||
s = "%s {%s}\n" % (s, title)
|
||||
fp.write(s)
|
||||
for entry in toc:
|
||||
write_toc_entry(entry, fp, layer + 1)
|
||||
|
||||
|
||||
def process(ifn, ofn, bigpart=None):
|
||||
toc = parse_toc(open(ifn), bigpart)
|
||||
write_toc(toc, open(ofn, "w"))
|
||||
|
||||
|
||||
def main():
|
||||
bigpart = None
|
||||
opts, args = getopt.getopt(sys.argv[1:], "c:")
|
||||
if opts:
|
||||
bigpart = opts[0][1]
|
||||
if not args:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
for filename in args:
|
||||
base, ext = os.path.splitext(filename)
|
||||
ext = ext or ".toc"
|
||||
process(base + ext, base + ".bkm", bigpart)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user