SystemVerilog已经支持参数化数据类型?

和BlueSpec和Chisel等等高级硬件语言相比,SystemVerilog缺乏对硬件模块(module)的泛型定义。或者说,SystemVerilog还不能将module对待成class从而实现对module的继承。SystemVerilog的泛型支持依赖于参数(parameter),但是长久以来parameter本身必须是以一个编译时可求值的常数(SystemVerilog已经支持浮点数的参数)。但是现在,SystemVerilog看来已经开始支持类型parameter,这绝对是个好事。如果参数可以是一个类型而不是一个数,那么我们就可以传一个结构类型作为参数到模块,实现模块的接口的泛型支持。不过一个很重要的问题是:

好像现在的类型参数只能被使用于class而不能用于module!?

如果参考IEEE Std 1800-2012 Section 6.25 Parameterized data types

virtual class C#(parameter type T = logic, parameter SIZE = 1);
  typedef logic [SIZE-1:0] t_vector;
  typedef T t_array [SIZE-1:0];
  typedef struct {
    t_vector m0 [2*SIZE-1:0];
    t_array m1;
  } t_struct;
endclass

module top ();
  typedef logic [7:0] t_t0;
  C#(t_t0,3)::t_vector v0; C#(t_t0,3)::t_array a0;
  C#(bit,4)::t_struct s0;
endmodule

其中,class C的参数T就是一个类型参数,用来定义t_array的类型。在module top中,a0的数据类型实际上是logic [7:0]。但是这种类型的参数式定义却使用了对象这么扭曲的方式。我估计下面的代码估计还不支持吧。(要是可以该省多少代码哦。。。)

module top#(parameter type T = logic) ();
  T a0;
endmodule
Advertisements

在Ubunutu 14.04中安装JabRef 3.5 (安装openjdk 8)

我一直都使用JabRef作为我的文档管理软件,因为它是开源的,支持bibtex并和Latex无缝连接,支持各数据库的自动文章搜索和bibtex生成。配戴使用Git作为后台的版本控制,现在我用它管理我的所有电子书和期刊文献,并在多电脑多操作系统保持同步。

可是最近发现了一个很尴尬的问题。Jabef的最新版本需要openjdk 8才能运行,而我所使用的Linux电脑由于工作原因都运行的是Ubuntu 14.04 LTS,支持的openjdk最高版本是7。为了能安装并使用上JabRef 3.5,我最终把openjdk 8给安上了。

安装Jabref 3.5其实比较简单。首先是安装系统自有版本,如果从来没有安装过JabRef的话。

$ sudo apt-get install jabref

这样就会安装一个JabRef 2.10b,非常老的版本。不过我们需要的这个安装会建立所有的系统链接,这样就不用手动建立图标和运行脚本了。安装之后:

$ which jabref
/usr/bin/jabref
$ ls -l /usr/share/java/jabref.jar
lrwxrwxrwx 1 root root 24 Aug 4 22:36 /usr/share/java/jabref.jar -> ../jabref/JabRef-2.10b2.jar

可见JabRef被安装到了/uar/bin,但这其实是一个脚本,会自动检查Java和其他扩展包的路径然后运行jabref.jar,而jabref.jar是一个软连接,指向了JabRef-2.10b2.jar。其实这方便了我们安装JabRef 3.5。

$ cd /usr/share/jabref
$ sudo wget https://github.com/JabRef/jabref/releases/download/v3.5/JabRef-3.5.jar
$ sudo mv /usr/share/java/jabref.jar /usr/share/java/jabref.jar.old
$ sudo ln -s ../jabref/JabRef-3.5.jar /usr/share/java/jabref.jar

现在我们就把jabref.jar指向了新的JarbRef-3.5.jar。不过这时候JabRef并不能正常运行:

$ jabref
Exception in thread "main" java.lang.UnsupportedClassVersionError: net/sf/jabref/JabRefMain : Unsupported major.minor version 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:803)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)

这里的Unsupported major.minor.version 52.0实际上就是说需要jdk 8。所以,我们需要给Ubuntu 14.04安装openjdk 8:

$ sudo add-apt-repository ppa:openjdk-r/ppa
$ sudo apt-get update
$ sudo apt-get install openjdk-8-jre openjdk-8-jre-headless

不过这个时候系统默认的java版本仍然是openjdk 7,我们需要改变系统的默认java版本才能默认使用openjdk8:

$ sudo update-alternatives --config java

出现提示符后,请选择openjdk8的选项,这样默认java版本就被改变。

$ java -versionopenjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-0ubuntu4~14.04-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

但是很糟糕的是,JabRef仍然不能自动运行,因为JabRef使用/usr/lib/java-wrappers/jvm-list.sh这个脚本来寻找java的默认版本,为了能正确的找到默认版本,我们需要作如下的修改:

  __jvm_openjdk7="/usr/lib/jvm/java-7-openjdk-$__arch /usr/lib/jvm/java-7-openjdk"
+ __jvm_openjdk8="/usr/lib/jvm/java-8-openjdk-$__arch /usr/lib/jvm/java-8-openjdk"

  # And a few aliases
  __jvm_gcj="$__jvm_gcj2"
- __jvm_openjdk="$__jvm_openjdk7 $__jvm_openjdk6"
+ __jvm_openjdk="$__jvm_openjdk8 $__jvm_openjdk7 $__jvm_openjdk6"

现在,JabRef应该可以正常运行了。终于。

cppRange 多维范围计算库

范围计算是电路综合中的一个常见问题。在计算一个多比特信号是否被完全赋值,或者是否存在多驱动的时候,都需要计算该信号的范围。比如说一个信号(sig)有8比特(Verilog HDL):

wire [7:0] sig;
assign sig[3:0] = 4'd5;
assign sig[6:3] = 4'd3;

对于sig的两次赋值就造成了对sig[3]的多驱(两个assign同时对其赋值)。同时,sig[7]没有驱动。

为了检查没有驱动的情况,可以判断[7:0] 是否等于 [3:0] 和 [6:3]的并集([3:0] | [6:3])。检查多驱,则可查看[3:0]和[6:3]的交集是否为空([3:0] & [6:3])。这似乎很简单。但是一旦信号的范围支持多维,就复杂很多。比如下面的例子:

wire [7:0][3:0] multi_sig;
assign multi_sig[0] = 4'd9;
assign multi_sig[7:2] = 24'd96;
assign multi_sig[1][2:0] = 3'd7;
assign multi_sig[4][0]=1'b1;

multi_sig[4][0]被驱动了两次,而multi_sig[1][3]没有驱动。为了判断驱动,需要计算 [0] | [7:2] | [1][2:0] | [4][0]。这种一维和两维的混合是非常难计算的。将信号的声明考虑在内,则可以规范化范围计算,从而计算 [0][3:0] | [7:2][3:0] | [1:1][2:0] | [4:4][0:0]。可是,这仍然是一个难题,比如说如何表示 [1:1][2:0] | [4:4][0:0]?

这种问题在硬件综合之外的其他环境中也可能出现,但是到现在好像还没有一个很好的解决方按,更别说开源库。

所以我自己写了一个简单的多维范围计算库(C++)[https://github.com/wsong83/cppRange]

这个库可以用来计算一维或多维范围表达式。现在支持功能如下:

========
一个范围可以表示为:

1比特:            [3:3] or [3]
一维:             [3:0]
多维:             [5:0][2:-1]

* 范围默认为[上边界:下边界]。如果上边界<下边界,该范围非法。
* 该库使用STL支持任何可以比较和加减的数据类型。支持负数范围。

========
支持的计算:

包含 (>)
    [7:0] > [3:2]                               真
    [7:0][4:0][3:-2] > [1:0][3][1:0]            真
    [5:3][2:0] > [5:1][2:0]                     假
    [5:3][2:0] > [5:1]                          假 (非法计算)
* 相判断的两个多维范围必须有相同的维数,否则非法。

其他支持的比较 >=, <, <=, ==, !=

并集运算 (|)
    [7:3] | [4:0]                            -> [7:0]
    [5:4] | [1:0]                            -> []              // 空 (无法求值)
    [4:0][3:1] | [4:0][5:2]                  -> [4:0][5:1]
    [1:0][5:1] | [4:2][5:1]                  -> [4:0][5:1]
    [1:0][3:1] | [4:0][5:2]                  -> []              // 空 (非法运算)
    [1:0][3:1] | [4:0]                       -> []              // 空 (非法运算)
* 合并两个多维范围时,只能有一个纬度上的范围不等,同时该不等范围相邻才可计算。
交集运算 (&)
    [7:3] & [4:0]                            -> [4:3]
    [5:4] & [1:0]                            -> []
    [4:0][3:1] & [4:0][5:2]                  -> [4:0][3:2]
    [2:0][5:1] & [4:2][5:1]                  -> [2:2][5:1]
    [1:0][3:1] & [4:0][5:2]                  -> [1:0][3:2]
    [1:0][3:1] & [4:0]                       -> []
* 求取两个多维范围的交集时,两个范围必须有相同的维度。

去除 (-)
    [7:3] - [4:0]                            -> [7:5]
    [5:4] - [1:0]                            -> [5:4]
    [4:0][3:1] - [4:0][5:2]                  -> [4:0][1]
    [2:0][5:1] - [4:2][5:1]                  -> [1:0][5:1]
    [1:0][3:1] - [4:0][5:2]                  -> []
    [1:0][3:1] - [4:0]                       -> []
* 多维范围运算时,只能有一个维度上的范围不等。 

标准分割 (^)
    [7:3] ^ [4:0]                            -> [7:5],[4:3],[2:0]
    [5:4] ^ [1:0]                            -> []
    [4:0][3:1] ^ [4:0][5:2]                  -> [4:0][5:4],[4:0][3:2],[4:0][1:1]
    [2:0][5:1] ^ [4:2][5:1]                  -> [4:2][5:1],[2:2][5:1],[1:0][5:1]
    [1:0][3:1] ^ [4:0][5:2]                  -> []
    [1:0][3:1] ^ [4:0]                       -> []
* A ^ B = {High, A&B, Low}
* 多维范围运算时,只能有一个维度上的范围不等。同时范围相邻才可计算。

详细的使用则只能查看具体的代码了。

我计划在不久的将来扩展该库的运算,让其支持多维运算时多个维度上的不等范围。不过该计算的计算复杂度和时间则会大幅增长。

关于语法分析器

最近的工作导致我学习了好些编译器相关的知识,也接触了些语法分析相关的编程工具。基本上相关的编程已告一段落,于是是时写点小结了(生活平淡无趣,也好久没写东西了,最近也许会再写点)。

编译器说白了,其实就是个计算机语言转换器:将用一种语言编写的代码变成另一种语言的代码。比如GCC,其实就是将C代码变成机器汇编代码。一个完整的编译器一定会包含几个基本模块:语言解释器(Parser)、优化器(Optimizer)、目标代码生成器(Object Code Generator/Mapper)。其中语言解释器负责读入并理解输入语言;优化器可能对代码所描述的行为针对目标语言做一些优化;最后目标代码生成器将优化后的行为用目标语言描述一遍并输出。

我的工作是读入硬件设计语言Verilog HDL,做一些优化然后重新输出Verilog HDL。所以主要的工作在于前面两项,解释器和优化。目标代码生成基本就是简单打印输出。

语言解释器本身也有内部结构:预编译(Preprocessor)、语法分析(Lexical Analyser)和语意分析(Syntactic Analyser)。以C语言为例,预编译会处理所有的宏语句,比如条件编译#ifdef,头文件#include和宏定义#define等等。预编译的输出基本就是不包含宏的C语言文件(但仍有一个宏会出现:#line,用于标注预编译后文件与源文件的行号对应,否则GCC的报错信息就没有错误位置了)。语法分析则会检查输入语言的语法是否正确:比如括号是否对应、标识符是否合法、操作符是否都有操作数、类型定义是否合法、标识符是否有类型定义等等。如果语法正确,语法分析还负责将输入语言划分为语义分析所能理解的单词(token)。语意分析是最复杂的部分了,它负责理解所有的单词,并将它们转换为抽象语法树(即将所有单词存放入一个由语义关系构造的树形结构)。比如,语意分析会检查一个类型是否没有定义,操作符和操作数的类型是否不一至,一个表达式的左值是否不可修改或者一个函数是否返回了错误类型。

总的来说,语言有着不同的分析难度。语言的语法和语义特性决定了它们相应语言解释器的复杂度。比如,我们可以将计算器的输入理解成一种语言,该语言就非常简单。它不需要预编译(没有宏),甚至不需要语意分析(只有数字和运算符两种类型)。一个语法分析即可得出答案。如果计算器支持表达式输入就会复杂一些,语意分析就需要了。比如2+3*5,语意分析需要知道*的优先级比+高才能得到结果。同时()的出现也导致复杂度的提升。再往上,某些计算器还支持变量、函数,这便引入了存储和变量,一个表达式的求值不再简单取决于表达式本身。编程语言就更复杂了,简单的Basic语言支持引入库,则可能需要预编译。同时数据出现了类型,比如数和字符,语意分析则需要判别每一个变量的类型是否正确。C语言就更复杂了,结构体的出现导致用户能够自定义类型、语意分析需要学习所有用户定义的类型才能工作。C++则又把问题上升一个级别:typedef的出现导致一个类型可能有多种不同名称;namespace导致类型出现了作用域;子父类继承关系导致一个目标类型可以使用所有的父类类型,出现了类型的一对多关系。我现在所能想到最复杂的语言系统可能要数Haskell为代表的函数式语言了。它们支持类型自动推导,即表达式本身不许要一一标注类型,类型可根据调用关系动态指定和推断。

说到这里,你应该意识到类型是一个多么重要的概念。讲编译器的书往往会花大量章节讲不同的语法,比如语法是否有递归,是否需要大于1的预读取(lookahead)。但一旦涉及到类型,语法的那些复杂度就一下子变得小儿科了,因为大多数递归型语法可换成非递归的,大多数预读取问题可用更多的语法解决。但用户可自定义的语法则代表语言解释器需要自学习!在这个方面,我现在还是相当无知。好在Verilog HDL并不存在用户自定义类型,我现在还不需要处理这块大石头,但很可能将来需要(很可能我将读入VHDL,VHDL支持自有类型定义!)。不过我要说,这一块的水很深,慎入!!:-)

在工具方面,我现在用Flex+Bison处理Verilog,Boost.Spirit处理命令行解释和pugixml处理用标记语言(marking language)存储的数据文件。

针对复杂语言,基本需要解释器自动生成工具,比如Bison和ANTLR。它们都需要用户用语法描述语言定义目标语言的语法和语义。工具则通过这些语法描述自动生成一个语言解释器。这样做的好处是将代码编写的问题转嫁给了工具,但单独编译导致了语言解释器本身非常静态。在这方面,Boost.Spirit就允许用户动态定义语法,因为它本省就是一个C++库。不过它的编译速度可不敢恭维(大量使用范型STL的结果)。

对于标记语言,现在的工具基本已经傻瓜化了。我用的pugixml就是一个轻量级的XML解释器,能自动生成语法分析树,完全不用动脑。

不知我这半桶水的理解是否正确,不过用近一年的时间就从没学过编译器到独自写了个Verilog语言解释器我还是挺满意的。

C++/Tcl :更容易地在C++中嵌入Tcl

才发现原来在C++程序中嵌入一个完整的script语言环境不是那么的困难。鉴于项目需要,我决定将Tcl语言解释器嵌到我的代码里,加上一个非常简单的输入流处理,就实现了一个动态Tcl命令行用户接口。

稍微说一下语言解释器。一般来说script语言,也就是脚本语言是解释执行的。但并不是所有的脚本语言都能用于嵌入。有些太大了不好嵌入,比如python,有些则基本不适合用于嵌入,比如Javascript。现在用的最多的一个是Tcl,另一个是较新的Lau。据说Lau在游戏里面用的很多,一般用作后台命令行解释。我自己受限于以往的类似软件多使用Tcl,因此还是继续使用Tcl的向后兼容新会好一些。

Tcl的C/C++接口使用C标准,提供了约50来个API函数。C/C++程序可以使用这些API运行Tcl解释器,任意扩展Tcl命令集,查看和修改Tcl变量,以及设定事件触发回调函数(这仅仅是我关心的功能,还有其他的一堆)。

但这些函数并不怎么好用,基本都是指针操作,而且文档看起来也不是那么好懂。一番搜索之后我发现了个好库,C++/Tcl,这个库将一部分的Tcl API用C++封装,并使用Tcl和Boost库实现了资源自动管理和释放,以及自动函数类型匹配,支持最多达9个参数的函数和对象扩展。

不过它还缺了两个我必须使用的功能,即在Tcl环境中修改我程序的环境变量和设定Tcl变量事件的回调。如果没有这些,Tcl就像是一个与世隔绝的封闭嵌入式解释器,没什么实际功能。

于是,我在Github上开了个新分支并在原有基础上增加了这两个功能。这是我第一次如此大规模的使用STL来构建自己的库,居然还动用了boost/preprocessor预处理来减少代码量。我已经更新了文档,并给出了最新功能的使用范例。具体链接如下:

文档:wsong83.github.com/cpptcl
代码:github.com/wsong83/cpptcl

如有bug或功能请求,欢迎发信,提供patch就更好了。

一些Latex的小问题

昨天终于把博士论文的最终版送去装订了。

在博士论文的写作中又遇到了许多Latex的小问题,想想现在应该总结一下。比较乱,凑活看。

1. hyperref
曾经认为只有使用pdflatex才能使用hyperref包来生成超级连接和pdf的目录搜索页。现在发现这是个误解。
hyperref包的默认pdf生成工具是pdflatex,但它也支持latex+dvipdf/dvipdfm的方式。只不过需要配置一下。
在我的博士论文当中,hyperref包的使用如下:

\usepackage[
dvipdfm,
pdftitle={\thesistitle},
pdfauthor={\thesisauthor},
colorlinks=true,
linkcolor=black,
breaklinks=true,
urlcolor=blue,
citecolor=black
]{hyperref}

其中第一行dvipdfm则告诉hyperref最终的pdf生成工具是dvipdfm。hyperref会在生成的dvi文件中插入dvipdfm能够正确识别的注释符。
pdftitle和pdfauthor将会改变生成的pdf文件的标签页中的文件标题和作者。
colorlinks=true表明使用颜色来表示所有的链接(默认为不使用)
linkcolor=black设定内部链接使用黑色文本(默认为难看的红色)
breakline=true允许将长的url拆成多行(默认为禁止,长url将在一行显示,无论多长)
urlcolor=blue使用蓝色显示url(默认为粉色,??不符合一般网页定义)
citecolor=black引用用黑色显示(默认为绿色)
其他参数参看http://mirror.ctan.org/macros/latex/contrib/hyperref/doc/manual.pdf

2. booktabs
Latex传统的表格已经过时了。为了让表格更加美观,现在有了一个新的表格包— booktabs
这个包将覆盖原有的table关键字,基本上原有的tabular命令都可以使用,不过booktabs提供了一些新的命令,比如\toprule,\middlerule和\bottomrule。两种表格的风格比较参见http://en.wikibooks.org/wiki/LaTeX/Tables中的Proffessional tables小节

3. 显示源代码
有时候我们希望在文本中加入源代码。源代码和普通文本不同,代码往往用等宽字符显示才美观,而文本字体往往会使用非等宽字体来隐藏难看的字符间的不等空隙。
Latex本身就自带了一种等宽显示模式(verbatim),所有在\begin{verbatim}和\end{verbatim}之间显示的问题都将使用等宽字符显示。不过,所用的字体看起来就像原来的DOS的控制行显示字体,好像叫terminal字体。更令人抓狂的是,所有的加粗,斜体,颜色等等命令在verbatim环境中都会失效。也就是说,尽管代码能用等宽字体显示了,不过你也别想加粗关键字和用颜色显示注释。
其实,listings包提供了代码显示的支持。我所使用的配置如下:

\usepackage{listings}
\lstset{
  language=Verilog,
  basicstyle=\ttfamily\scriptsize
}

其中Verilog就表明了将显示的代码是Verilog HDL,这样listing能自动识别关键字并使用不同的格式显示。不过我的\ttfamily好像还是覆盖了关键字显示。仍然只能有一种字体格式。不过注释现在能自动斜体显示了。稍微有一点点遗憾。具体配置请参看http://mirror.ctan.org/macros/latex/contrib/listings/listings.pdf

4. 单位符号
为了统一各种单位的显示,比如byte/s,uJ, ^oC等等,我使用了SIunits包。该包定义了大部分的单位并用统一的格式显示单位和其数值。使用该包后,24 mm^2将写作\unit{24}{\milli\squaren\metre},然后latex就能正确显示。不过该包重定义了\square,和数学包中的\square冲突。配置SIunits使用squaren将迫使SIunits定义平方符号为\squaren
我的使用配置如下:

\usepackage[binary,squaren]{SIunits}

其中binary告诉SIunit支持和byte,bit相关的单位。如果有没有定义的单位,比如MByte/Node/s中的node就没有定义。可以直接在unit代码中写文字(\mega\byte\perNode\per\second)。

5. 对某些文字使用不同字体。
我们经常希望某些文字用不同的字体显示,比如说标题和页眉。Latex往往使用全局配置控制字体,换字体往往意味着换环境,比如进入数学模式。换字体在latex还真不是很容易。
我在我的论文中定义了一个新命令:

\newcommand{\arial}[1]{{\fontencoding{T1}\usefont{T1}{phv}{m}{n}{#1}}}

这样we \arial{are} human.中are就会使用arial显示。linux下面没有arial,而叫做Helvetica,一个瑞士人发明的。其实Arial反而是后来的,只不过我们windows用多了,不知道其实微软copy了Helvetica而已。我的命令中phv就是Helvetica。T1说明使用T1字体。字体是一个很复杂的问题,我自己还没太搞清楚。。。。在使用新字体的时候,准备好latex会爆出一大堆缺少文件,缺少map或字体不识别的问题。。。

6. 图片的多行标题显示
从没有想到原来多行显示图片标题居然会是个问题。在默认环境下,使用caption包,短于一行的标题会居中显示,长于一行的标题将会沾满整行然后在行尾断行。这都没有问题。不过,要是想在某个地方人为断行,这个就难了。比如说下面:

Assuming
this
is a Figure

Fig. The figure
caption

人为在figure后加上\\断行后,单行标题变成多行标题,所有行都会顶在行左,就出现了这种难看的样子。到现在我也没有发现有什么办法告诉Latex去居中显示整个标题块,好象是因为latex并不知道标题块有多宽。
这种的办法是配置caption包。我最终的配置:

\usepackage{caption}
\captionsetup{margin=20pt,format=hang,justification=justified}

其中margin告诉latex在标题块的两边都留20pt的空白,如果标题超长,至少多行不会直接顶在最左边。现在是有了20pt的整体缩进。后面的hang是告诉caption允许多行标题,如果出现多行,按照正常的多段文本处理(默认标题只有一段文字,禁止多段文字)。然后justified确定使用默认的问题对齐方式(两端对齐加短行靠左)。不过,这些特性仅仅在新的caption包中才支持。Fedora自带的texlive-2007不支持,需要单独安装最新的caption。后面再说这个问题。

7. 超长行的自动换行
以前没有注意到,原来latex的自动拆单词换行是依靠字典的。如果遇到latex不认识的单词,他就不会换行了。我就遇到如下的问题:

This is a dummy sentence.
I am going to show a longsentence
that latex does not recogn-
ise correctly and does not
how to hyphen it. It is left th-
ere as a super long line.

其中longsentence是一个latex不认识的单词,他就不会拆了(很愚蠢!)解决这种问题,需要两步:
1. 使用\usepackage[british]{babel}告诉latex用正确的字典去查单词,比如我就使用英式英语而非美式(默认)。然后对于长的自造单词,使用hyphenation告诉latex如何拆:

\hyphenation{long-sen-ten-ce net-works semi-conduc-tor meta-sta-bi-lity MU-TEX pi-pe-line}

8. 不想显示章节号的章节
我们往往会希望有些章节没有章节号,比如备注或者致谢。在我的论文中,我有备注。我希望备注和正文直接有一页纸显示备注,但是不希望该页成为论文的第四个部分(论文正文有三个部分了)。简单的将章节号去除,latex将认为该章节不存在,所以目录中就不会显示了,但这又是我不希望看到的。我希望有一个没有编号的第4部分,同时在目录中显示。以下的代码就能做到这点:

\appendix
\part*{Appendix}\label{part_appendix}
\addcontentsline{toc}{part}{Appendix}

\appendix显示备注开始,\part*{Appendix}定义了一个没有编号的部分,会以单独的一页纸显示Appendix的开始。不过该部分并不被latex认为是一个部分。所以后面的addcontentsline重新一部分的方式将Appendix加入目录。(不过,hyperref在pdf中的标签导航还是显示整个Appedix属于第3部分而不是单独的一个部分,不知道怎么搞。。。)

9. 孤行控制
在Word中我们只要选中孤行控制,Word就不会将一段的第一行或者最后一行放在不同的页面。Latex中好像没有相应的命令。Latex只是尽量防止孤行,当避免孤行会导致大量的页面空白的时候,Latex会放弃避免孤行。我们可以改变孤行的惩罚权重来告诉Latex我们更在乎孤行。有两个参数控制这些:

\widowpenalty=4000
\clubpenalty=4000

其中\widowpentalty是出现尾行分页所产生的惩罚值,\clubpenalty是出现首行分页的惩罚值。默认是150。我把他们都设成4000,就是告诉latex要更努力的减少孤行。如果设定惩罚为10000,就会完全的避免孤行,但是排版会很难看,因为latex会放弃一切的去排除孤行。

10. Tex-live 2011
Fedora的默认latex是tex-live 2007包,也就是说所有的包都是2007年之前的,已经很落后了。从Fedora 13开始,Fedora提供了tex-live 2011和tex-live 2010的开发包支持。参看http://fedoraproject.org/wiki/Features/TeXLive,那里提供了更新到tex-live新版本的rpm yum升级包。安装之后就可以使用yum来自动更新所有的tex-live包。我个人一直在fedora 14上使用tex-live 2011,除了有时候yum 升级会出现版本冲突问题(他们一直在更新,所以难免会有版本冲突,往往过几天就没了,继续升级就好),没有发现有什么问题,一切OK。非常推荐升级tex-live。

Open Core in preparation (开源准备中)

要毕业了,如何保存PhD期间的工作成了个问题。前途仍然渺茫。改变研究方向或者失去原有的工具链是很可能发生的事情。然而,还有那么多可以做而没有做的事情。思考再三,我决定把大部分的工作开源。一来也许我的那点东西也许对别人有用,另外也是种不断研究的激励,毕竟自己闷头搞是很容易灰心的。

现在正在整理我的异步片上网络路由器设计(时空复用的异步片上网络路由器)。已经在OpenCores网站上注册了一个新项目:http://opencores.org/project,async_sdm_noc

大部分的代码还在整理中,估计会在下个月答辩之前完成初步的代码上传。