diff --git a/doc/Makefile b/doc/Makefile index b5a04537..5ed6b817 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -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 diff --git a/doc/informal.tex b/doc/informal.tex index 60b6eafe..70734867 100644 --- a/doc/informal.tex +++ b/doc/informal.tex @@ -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): diff --git a/doc/reference.tex b/doc/reference.tex index 86f86cb6..c58b4b1d 100644 --- a/doc/reference.tex +++ b/doc/reference.tex @@ -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} diff --git a/doc/tools/toc2bkm.py b/doc/tools/toc2bkm.py new file mode 100755 index 00000000..45c7ef88 --- /dev/null +++ b/doc/tools/toc2bkm.py @@ -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()