1
0
mirror of https://github.com/myhdl/myhdl.git synced 2025-01-24 21:52:56 +08:00
This commit is contained in:
jand 2003-02-04 21:52:52 +00:00
parent 05983f3e65
commit 516fb7bf38
4 changed files with 206 additions and 44 deletions

View File

@ -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

View File

@ -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):

View File

@ -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
View 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()