update some cmds
This commit is contained in:
parent
b21a2c8611
commit
b0d1282d08
|
@ -0,0 +1,382 @@
|
|||
### Chisel教程
|
||||
|
||||
#### Chisel安装
|
||||
|
||||
##### 安装开发工具
|
||||
|
||||
##### 设置本教程
|
||||
|
||||
本教程的目录结构:
|
||||
|
||||
```
|
||||
build.stb # 工程描述
|
||||
run-examples.sh # 用于执行一个或多个例子的shell脚本
|
||||
run-problem.sh # 用于执行一个或多个问题的shell脚本
|
||||
run-solution.sh # 用于执行一个或多答案的shell脚本
|
||||
doc
|
||||
src/main/scala
|
||||
examples # 更多的高级电路的例子
|
||||
problems # 需要用户来完成的一系列问题电路
|
||||
solutions # 问题电路的答案
|
||||
src/test
|
||||
resources # 一些测试需要的资源
|
||||
scala/examples # 例子电路的测试工具
|
||||
scala/problems # 问题电路的测试工具
|
||||
scala/solutions # 答案电路的测试工具
|
||||
scala/util # TutorialRunner.scala
|
||||
```
|
||||
|
||||
#### 基础
|
||||
|
||||
##### 运行第一个Chisel构建
|
||||
|
||||
- **以GCD.scala为例熟悉Chisel源代码**
|
||||
|
||||
进到`src/main/scala/examples/`目录,打开`GCD.scala`文件。它实现了众所周知的GCD算法。
|
||||
|
||||
第一个要注意的是`import chisel3._`,它导入了Chisel库文件,这让我们可以把Scala当作硬件构建语言来用。
|
||||
|
||||
接下来就是Scala类定义,它就是要实现的Chisel组件,基本上可以认为它对应的就是Verilog里的模块声明。
|
||||
|
||||
第二个要注意的是`val io = IO(new Bundle{...})`,它是本组件的I/O规范。
|
||||
|
||||
这个bundle有多个参数,这些参数都是它构造的一部分,每个参数都有类型(UInit, Bool等)、位宽,并包装进一个direction(Input 或Output)。
|
||||
|
||||
如果不指定位宽,Chisel将推断一个合适的位宽(在本例里默认为1)。
|
||||
|
||||
这个`io` Bundle其实是组件接口的构造器。
|
||||
|
||||
第三个要注意的是寄存器的声明,它告诉Chisel把`x`和`y`当作类型为UInt()的寄存器。
|
||||
|
||||
第四个要注意的是`when`语句,它告诉Chisel条件为真时执行操作。在硬件上,它基本上是一个多路复用器在`when`块里选择值(如果条件为真),否则就使用默认的赋值或保留寄存器的值。
|
||||
|
||||
如果条件为真,赋值将在正时钟边沿执行。
|
||||
|
||||
这相当于Verilog里使用`always @ (posedge clk)`来定义同步逻辑。
|
||||
|
||||
最后要注意的是输出语句,用于计算`io.out`和`io.valid`。
|
||||
|
||||
其实在本例里我们不必指定`x`和`y`的宽度,因为Chisel会基于它们要执行的计算,推断并设置合适的值。
|
||||
|
||||
- **使用tester和firrtl解释器进行模拟**
|
||||
|
||||
首先,看看Chisel代码`src/test/scala/examples/GCDTests.scala`。它包含了一个`PeekPokeTester`的Chisel实现,和一个tester驱动,这个驱动用来模拟电路、把自己连接到tester、在模拟电路上运行tester。
|
||||
|
||||
tester用`poke`来驱动电路输入,用`step`来单周期运行电路,用`expect`来验证它的输出。
|
||||
|
||||
然后,在顶层目录下使用要要模拟的电路的名称来执行脚本:
|
||||
|
||||
```
|
||||
./run-examples.sh GCD
|
||||
```
|
||||
|
||||
这将会生成GCD.scala电路的firrtl描述,并使用firrtl解释器使用GCDTests.scala的测试工具来模拟它。最后会输出一些调试信息。
|
||||
|
||||
如上脚本还会生成`test_run_dir/examples/GCD/GCD.fir`文件,包含了GCD电路和它的tester的firrtl定义。
|
||||
|
||||
- **生成Verilog**
|
||||
|
||||
要生成Verilog,要指定后端:
|
||||
|
||||
```
|
||||
./run-examples.sh GCD --backend-name verilator
|
||||
```
|
||||
|
||||
这将指示tester驱动生成Verilog,并使用Verilator生成C++模拟。
|
||||
|
||||
执行完毕后将看到一些[success]信息。
|
||||
|
||||
在`test_run_dir/examples/GCD/`目录下会看到多了不少文件,需要关注的是:
|
||||
|
||||
- GCD.v - Chisel电路的Verilog实现
|
||||
- GCD.vcd - 模拟期间电路信息的波形输出
|
||||
|
||||
Verilog源文件大致可分为三个部分:
|
||||
|
||||
- 带有input和output的模块声明
|
||||
- 用于保存中间值的临时wire和寄存器声明
|
||||
- 在`always @ (posedge clk)`里的寄存器assignments
|
||||
|
||||
可以使用`gtkwave`来看vcd输出。
|
||||
|
||||
##### 组合逻辑
|
||||
|
||||
- **Scala节点:声明Wires**
|
||||
|
||||
用Chisel构建组合逻辑的块是相当简单的;当在Scala里声明一个`val`,它就创建一个代表那个数据的结点。如果该值不是寄存器类型,Chisel编译器会把它当作wire。
|
||||
|
||||
因此可以把任意数量的这样的值连接起来,以生成我们想要的值。
|
||||
|
||||
假设我们想构造一个完整的加法器。
|
||||
|
||||
一个完整的加法器有两个输入`a`和`b`,一个进位输入`cin`,产生一个`sum`和进位输出`cout`。
|
||||
|
||||
完整加法器的Chisel代码如下所示:
|
||||
|
||||
```scala
|
||||
class FullAdder extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val a = Input(UInt(1.W))
|
||||
val b = Input(UInt(1.W))
|
||||
val cin = Input(UInt(1.W))
|
||||
val sum = Output(UInt(1.W))
|
||||
val cout = Output(UInt(1.W))
|
||||
})
|
||||
// Generate the sum
|
||||
val a_xor_b = io.a ^ io.b
|
||||
io.sum := a_xor_b ^ io.cin
|
||||
// Generate the carry
|
||||
val a_and_b = io.a & io.b
|
||||
val b_and_cin = io.b & io.cin
|
||||
val a_and_cin = io.a & io.cin
|
||||
io.cout := a_and_b | b_and_cin | a_and_cin
|
||||
}
|
||||
```
|
||||
|
||||
`cout`是输入`a`,`b`和`cin`的组合函数。
|
||||
|
||||
你会发现为了从`io` bundle访问输入值,你需要先引用`io`,因为输入和输出值都属于`io` bundle。`|`,`&`和`^`操作符分别对应于按位的OR,AND,和XOR操作。
|
||||
|
||||
- **位宽接口**
|
||||
|
||||
如果没有在Chisel里显式地定义值的宽度,Chisel编译器将基于输入的值推测位宽。
|
||||
|
||||
注意在`FullAdder`的定义里,`a_xor_b, a_and_b, b_and_cin, a_and_cin `是没有定义宽度的。
|
||||
|
||||
然而,基于输入的计算方式,Chisel将正确推断出那些值都是一个比特的宽度,因为它们的输入都是比特宽度操作的结果。
|
||||
|
||||
从生成的Verilog里可见那些值确实是一个比特宽的。
|
||||
|
||||
如果我们在`FullAdder`里把宽度改为2比特,那么Chisel编译器会推测中间值`a_xor_b, a_and_b, b_and_cin, a_and_cin`都是两比特宽。从生成的Verilog里可以发现确实如此。
|
||||
|
||||
##### 使用寄存器
|
||||
|
||||
和Verilog不同,在Chisel里定义一个寄存器实际上是告诉编译器生成一个正边沿触发的寄存器。
|
||||
|
||||
在本节中,我们将探索如何通过构造移位寄存器来实例化Chisel中的寄存器。
|
||||
|
||||
在Chisel中,当您实例化一个寄存器时,有几种方法可以指定到寄存器的输入的连接。
|
||||
|
||||
如GCD所示,您可以“声明”寄存器并在`when...`块里分配它的输入连接到的对象,或您可以简单地将寄存器作为参数的值传递给寄存器。
|
||||
|
||||
如果你在构造时使用`next`命名参数或专门的寄存器构造函数`RegNext`,选择将下一个值传递给寄存器,它将无条件地在每个周期中记录下这个新值:
|
||||
|
||||
```scala
|
||||
// 在每个周期里记录新寄存器
|
||||
val y = io.x
|
||||
val z = RegNext(y)
|
||||
```
|
||||
|
||||
如果满足某个条件时我们才更新,我们使用`when`块来表明这一点:
|
||||
|
||||
```scala
|
||||
// 当满足条件 a > b 时,才记录新寄存器的值
|
||||
val x = Reg(UInt())
|
||||
when (a > b) { x := y }
|
||||
.elsewhen ( b > a) {x := z}
|
||||
.otherwise { x := w}
|
||||
```
|
||||
|
||||
需要注意的是,在使用条件方法时,准备分配给寄存器输入的值需要与您声明的寄存器的类型和位宽相匹配。
|
||||
|
||||
而在无条件寄存器分配里不需要这么做,因为Chisel会推断类型和位宽。
|
||||
|
||||
下面几节将介绍如何使用它们来构造移位寄存器。
|
||||
|
||||
- **无条件的寄存器更新**
|
||||
|
||||
假定我们想构造4比特的移位寄存器,它有接收一个串口输入`in`并生成一个串口输出`out`。
|
||||
|
||||
对于第一个示例,我们将不考虑并行load信号,并假设移位寄存器总是启用的。
|
||||
|
||||
我们也不考虑寄存器复位信号。
|
||||
|
||||
如果我们实例化,并显式地连接所有的4个寄存器,我们的Chisel代码如下:
|
||||
|
||||
```scala
|
||||
class ShiftRegister extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val in = Input(UInt(1.W))
|
||||
val out = Output(UInt(1.W))
|
||||
})
|
||||
val r0 = RegNext(io.in)
|
||||
val r1 = RegNext(r0)
|
||||
val r2 = RegNext(r1)
|
||||
val r3 = RegNext(r2)
|
||||
io.out := r3
|
||||
}
|
||||
```
|
||||
|
||||
从生成的Verilog代码可见,Chisel确实是把我们的设计映射到了移位寄存器。
|
||||
|
||||
需要注意的一点是,时钟信号和复位信号都隐式地附加到我们的设计中。
|
||||
|
||||
```verilog
|
||||
module ShiftRegister(input clk, input reset,
|
||||
input io_in,
|
||||
output io_out);
|
||||
|
||||
reg[0:0] r3;
|
||||
reg[0:0] r2;
|
||||
reg[0:0] r1;
|
||||
reg[0:0] r0;
|
||||
|
||||
assign io_out = r3;
|
||||
always @(posedge clk) begin
|
||||
r3 <= r2;
|
||||
r2 <= r1;
|
||||
r1 <= r0;
|
||||
r0 <= io_in;
|
||||
end
|
||||
endmodule
|
||||
```
|
||||
|
||||
- **有条件的寄存器更新**
|
||||
|
||||
如前所述,通过使用`when`,`.elsewhen`,`.otherwise`块,Chisel允许你有条件地更新寄存器(使用使能信号)。
|
||||
|
||||
假定我们给移位寄存器添加一个使能信号,这将使我们可以依据一个`enable`输入信号,在给定周期里控制是否将数据移入或移出。
|
||||
|
||||
新的移位寄存器如下:
|
||||
|
||||
```scala
|
||||
class ShiftRegister extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val in = Input(UInt(1.W))
|
||||
val enable = Input(Bool())
|
||||
val out = Output(UInt(1.W))
|
||||
})
|
||||
|
||||
val r0 = Reg(UInt())
|
||||
val r1 = Reg(UInt())
|
||||
val r2 = Reg(UInt())
|
||||
val r3 = Reg(UInt())
|
||||
|
||||
when (io.enable) {
|
||||
r0 := io.in
|
||||
r1 := r0
|
||||
r2 := r1
|
||||
r3 := r2
|
||||
}
|
||||
io.out := r3
|
||||
}
|
||||
```
|
||||
|
||||
注意不需要定义`.otherwise`条件,因为Chisel将正确推断出应该保留旧寄存器的值。
|
||||
|
||||
- **寄存器复位**
|
||||
|
||||
在第一次声明时通过指定一个附加参数,Chisel允许您将同步重置指定给某个值。
|
||||
|
||||
在我们的移值寄存器里,让我们添加一个重置功能,它将同步地把所有寄存器的值重置为零。
|
||||
|
||||
为了实现这点,我们使用`init`参数为我们的寄存器提供更多的信息,或者带着我们想要同步重置的值使用指定的构造函数:
|
||||
|
||||
```scala
|
||||
class ShiftRegister extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val in = Input(UInt(1.W))
|
||||
val enable = Input(Bool())
|
||||
val out = Output(UInt(1.W))
|
||||
})
|
||||
// Register reset to zero
|
||||
val r0 = RegInit(0.U(1.W))
|
||||
val r1 = RegInit(0.U(1.W))
|
||||
val r2 = RegInit(0.U(1.W))
|
||||
val r3 = RegInit(0.U(1.W))
|
||||
when (io.enable) {
|
||||
r0 := io.in
|
||||
r1 := r0
|
||||
r2 := r1
|
||||
r3 := r2
|
||||
}
|
||||
io.out := r3
|
||||
}
|
||||
```
|
||||
|
||||
注意要重置的值可以是任何值,只要把零和宽度替换为相应的值即可。
|
||||
|
||||
Chisel还有一个隐式的全局`reset`信号,可以在`when`块里使用它。
|
||||
|
||||
这个重置信号为了方便就叫`reset`,且不需要声明,但如果要把它作为布尔值,需要加上`toBool` 类型转换(cast)。
|
||||
|
||||
加上隐式的全局重置后的移位寄存器:
|
||||
|
||||
```scala
|
||||
class ShiftRegister extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val in = Input(UInt(1.W))
|
||||
val enable = Input(Bool())
|
||||
val out = Output(UInt(1.W))
|
||||
})
|
||||
val r0 = Reg(UInt())
|
||||
val r1 = Reg(UInt())
|
||||
val r2 = Reg(UInt())
|
||||
val r3 = Reg(UInt())
|
||||
when(reset.toBool) { // 把reset解释为布尔类型
|
||||
r0 := 0.U
|
||||
r1 := 0.U
|
||||
r2 := 0.U
|
||||
r3 := 0.U
|
||||
} .elsewhen(io.enable) {
|
||||
r0 := io.in
|
||||
r1 := r0
|
||||
r2 := r1
|
||||
r3 := r2
|
||||
}
|
||||
io.out := r3
|
||||
}
|
||||
```
|
||||
|
||||
这将生成外观略有不同的Verilog源代码,但仍然与先前实现的移位寄存器有相同的重置功能。
|
||||
|
||||
- **时序电路**
|
||||
|
||||
可以在`src/main/scala/problems`找到如下的练习。你会发现文件的某一部分已经完成,你需要完成的部分在文件中会指出。练习的答案在`src/main/scala/solutions/`。
|
||||
|
||||
第一个问题是写一个时序电路计算`in`值之和。`src/main/scala/problems/Accumulator.scala`是这个电路的截短版本。
|
||||
|
||||
`src/test/scala/problems/Accumulator.scala`是一个完整的tester,用于验证你是否正确的设计了这个电路。
|
||||
|
||||
运行:
|
||||
|
||||
```
|
||||
./run-problem.sh Accumulator
|
||||
```
|
||||
|
||||
如果你没有完成accumulator它将会报错。
|
||||
|
||||
#### 基本类型与操作
|
||||
|
||||
#### 实例化模块
|
||||
|
||||
#### 编写Scala测试程序
|
||||
|
||||
#### 创建你自己的工程
|
||||
|
||||
#### 条件赋值与内存
|
||||
|
||||
#### Scripting Hardware Generation
|
||||
|
||||
### 如何阅读Chisel程序
|
||||
|
||||
#### 一个路由器电路的例子
|
||||
|
||||
#### 路由器测试器
|
||||
|
||||
### 常见问题
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
### 快速开始
|
||||
|
||||
通过web接口访问OpenWrt
|
||||
|
||||
开启一个Wi-Fi访问点
|
||||
|
||||
走向OpenWrt安装
|
||||
|
||||
Factory安装:设备上的第一次安装
|
||||
|
||||
安装OpenWrt开发快照
|
||||
|
||||
Internet连接与故障排除
|
||||
|
||||
登陆运行着OpenWrt的路由器
|
||||
|
||||
OpenWrt Alternate目录搜索
|
||||
|
||||
新用户FAQ
|
||||
|
||||
安全性与开启Wi-Fi
|
||||
|
||||
新用户的SSH访问
|
||||
|
||||
诊断网络连接
|
||||
|
||||
通过web接口更新OpenWrt
|
||||
|
||||
通过SSH连接到internet,并安装Luci Web接口
|
||||
|
||||
验证OpenWrt固件二进制
|
||||
|
||||
WebUI系统更新:“Keep settings”复选框
|
||||
|
||||
### 用户手册
|
||||
|
||||
安装
|
||||
|
||||
基本配置
|
||||
|
||||
LuCI web接口
|
||||
|
||||
网络配置
|
||||
|
||||
固件配置
|
||||
|
||||
高级配置
|
||||
|
||||
安装其它软件
|
||||
|
||||
特定于硬件的配置
|
||||
|
||||
存储设备
|
||||
|
||||
附加服务
|
||||
|
||||
故障诊断与维护
|
||||
|
||||
在虚拟机或容器里运行OpenWrt
|
||||
|
||||
安全
|
||||
|
||||
版本的签名
|
||||
|
||||
半成品文档页
|
|
@ -0,0 +1,14 @@
|
|||
```
|
||||
# 安装terminal,应用商店搜索安装
|
||||
# 安装git,从git-scm.com下载
|
||||
# 连接github的时候如需公钥,用ssh-keygen生成密钥对
|
||||
# 安装typora,从https://typora.io/下载
|
||||
```
|
||||
|
||||
### 多工作区
|
||||
|
||||
在win10里叫多个桌面
|
||||
|
||||
点击任务栏上的**任务视图**,在最上方点击**新建桌面**
|
||||
|
||||
多桌面切换的快捷键:win+Ctrl+方向键
|
|
@ -27,7 +27,10 @@ ffmpeg [全局选项] [输入文件选项] -i <输入文件> [输出文件选项
|
|||
-c [:steam] <codec> # 在输入文件之前时,指定解码器;在输出文件之前,指定编码器。如<codec>为copy,则仅输出不重新编码。
|
||||
-q[:stream] <q> (output,per-stream) # 指定输出的品质。<q>的意义依赖于视频所用的编码格式。
|
||||
-ss <position> (input/output) # 当作为输入选项,则定位到输入文件的<position>。当作为输出选项,会解码输入文件但放弃结果,直到<position>为止。关于<position>详见ffmpeg-utils手册的Time duration section。
|
||||
-t <duration> (input/output) # 当作为输入选项,表示从输入文件读取数据的长度为<duration>;当作为输出选项,表示从写入输出文件的数据长度为<duration>。
|
||||
-t <duration> (input/output) # 当作为输入选项,表示从输入文件读取数据的长度为<duration>;当作为输出选项,表示写入输出文件的数据长度为<duration>。
|
||||
# <duration>有两种语法:
|
||||
# [-][HH:]<MM>:<SS>[.<m>...]
|
||||
# [-]<S>[.<m>...]
|
||||
-to <position> (output) # 写入到输出文件,直到<posion>。
|
||||
-y # 不进行询问直接覆盖输出文件。
|
||||
```
|
||||
|
@ -35,6 +38,8 @@ ffmpeg [全局选项] [输入文件选项] -i <输入文件> [输出文件选项
|
|||
##### 视频选项
|
||||
|
||||
```
|
||||
-r [:stream_specifier] <fps> (input/output, per-stream)
|
||||
# 设置帧率
|
||||
-vn # 去除音频流
|
||||
-vframes <number> (output) # 指定输出的帧数。
|
||||
```
|
||||
|
@ -73,6 +78,7 @@ ffmpeg -i input.mp4 -vn -c:a copy output.aac # 去掉视频,直接复制音频
|
|||
ffmpeg -i input.aac -i input.mp4 output.mp4 # 把input.aac和input.mp4合并成output.mp4
|
||||
|
||||
# 截图
|
||||
ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
|
||||
ffmpeg -y -i input.mp4 -ss 00:01:24 -t 00:00:01 output_%3d.jpg # 从1分24秒开始,每隔1秒截1张图
|
||||
ffmpeg -ss 01:23:45 -i input -vframes 1 -q:v 2 output.jpg # 从1小时23分45秒截取1帧,-q:v 2表示输出的图片质量,一般是1到5之间(1为质量最高)
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
剪切
|
||||
|
||||
拉伸
|
||||
|
||||
- 镜像
|
||||
|
||||
Layer->Transform->Flip*
|
||||
|
||||
#### 参考资料
|
||||
|
||||
[GIMP用户指南](http://linux-wiki.cn/work/gimp/)
|
|
@ -4,17 +4,16 @@
|
|||
|
||||
#### 子命令
|
||||
|
||||
- list
|
||||
- search
|
||||
- show
|
||||
- update
|
||||
- install
|
||||
- remove:
|
||||
- autoremove:曾经因为依赖关系而自动安装的包,现在已不再需要,可用此命令卸载。
|
||||
- autoclean:如果一个软件包已被卸载,则删除它的安装文件。
|
||||
- clean:删除所有安装文件。
|
||||
- upgrade
|
||||
- edit-sources:编辑`sources.list`
|
||||
```
|
||||
autoremove # 曾经因为依赖关系而自动安装的包,现在已不再需要,可用此命令卸载。
|
||||
autoclean # 如果一个软件包已被卸载,则删除它的安装文件。
|
||||
clean # 删除所有安装文件。
|
||||
edit-sources # 编辑sources.list
|
||||
remove # 删除包。删除打包数据,但会保留少量的配置文件,这样再次安装就会保留它删除之前的样子。
|
||||
purge # 删除包。删除打包数据和配置文件。即使使用了remove命令也可以使用purge命令进行更彻底的删除。但它不会作用于用户目录下的数据和配置。
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 用法示例
|
||||
|
||||
|
|
Loading…
Reference in New Issue