Linux

Linux 系统的可配置性太高了,但同时对于刚入门的我来说不禁显得有点陌生和不适应。刚才试着重新配置一下vim(加装md插件md_preview插件),但是过程过于繁琐,打算一步步来,现在暂时放一放,先尝试加装md插件。

并没有加装md插件,继续看ppt,并体会Linux的神奇。这幅图片很有意思,曲线确实有点陡峭:

img

以下命令基本上覆盖了大多数需求,要勤加掌握:

1
2
3
4
5
6
文件管理 - cd, pwd, mkdir, rmdir, ls, cp, rm, mv, tar
文件检索 - cat, more, less, head, tail, file, find
输入输出控制 - 重定向, 管道, tee, xargs
文本处理 - vim, grep, awk, sed, sort, wc, uniq, cut, tr
正则表达式
任务管理 - jobs, ps, top, kill, free, lsof

第二遍看完工具是第一生产力——Linux入门教程,比第一次更加熟悉其中的一些命令,也更加明白yzh兄的用心所在。还是找一本书看起,系统地学习是最好的,然后在使用的途中在通过RTFM和STFW解决实际问题。

欢迎 - Linux 101ustc的这个教程不错,其中基本上以实操为基础讲解,但是介于内容有点多,调了感兴趣的网络操作wgetcurl看了一下,其他内容慢慢再看。

C

union

C语言部分简略过了一下,把两个习题做了就行。

将指针转换为整数如何进行:使用特殊的数据类型uint_ptr或者int_ptr,使用普通的unsigned int会存在数据位宽不一致的情况。c、c++指针和整型的互相转换–强制转换,类型转换_淡淡的宁静的博客-CSDN博客_c++ 指针转换为整型

这里面的用到了Union数据类型,以前不是很熟,学习了一下。其对同一块地址空间定义多种数据类型的访问接口,实现复用。例如,使用int和float定义一个变量:

1
2
3
4
typedef union inst {
int n,
float m
} inst_t;

位域

结构体中可以使用位域来 按位(bit) 进行数据定义,准守的规则是低位在前、高位在后(c语言中使用冒号结构体拆分16位的数的低字节和高字节_modi000的博客-CSDN博客):

1
2
3
struct {
u8 rs : 2, rt : 2, addr : 4;
} rtpye; // rs -> rtpye[1 : 0], rt -> rtpye[3 : 2], addr -> rtpye[7 : 4]

YEMU的实现

实现要求

存储器系统:

1
2
寄存器: PC, R0 (RA), R1, R2, R3 (8-bit) 
内存: 16字节 (按字节访问)

指令集:

1
2
3
4
5
       7 6 5 4   3 2   1 0 
mov [0 0 0 0] [ rt] [ rs]
add [0 0 0 1] [ rt] [ rs]
load [1 1 1 0] [ addr ]
store [1 1 1 1] [ addr ]

具体实现

手搓了一遍源码,经常犯一些莫名其妙的小错误,不过gcc是真的智能,还能够提示我怎么改。

参考了源码改的一个bug是:定义结构体的时候成员变量忘记加分号,struct {u8 rs : 2, rt : 2, addr = 4;} rtpye;(第一个分号)

官方给的源码的网址在:

yemu code

C 语言到而进制

预处理

预处理包含头文件的查找过程理解:

未加-I参数,<>包括的头文件将从系统的路径中查找。

1
2
3
4
5
6
7
8
9
pxy@pxy-Inspiron-3480:FromCToBits$ gcc -E a.c --verbose > /dev/null
...
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/11/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
...

增减-I参数,将从用户指定的目录下开始找起。

1
2
3
4
5
6
7
8
9
pxy@pxy-Inspiron-3480:FromCToBits$ gcc -E a.c -Iaaa -Ibbb --verbose 
#include "..." search starts here:
#include <...> search starts here:
aaa
bbb
/usr/lib/gcc/x86_64-linux-gnu/11/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include

在指定目标为riscv的时候代码,运行会发生报错:error: 'stdio.h' file not found with <angled> include; use "quotes" instead

解决方法:

  • 尝试装riscv-gnu-toolchain:
    • make过程中出现报错:fatal: unable to access 'https://gcc.gnu.org/git/gcc.git/': gnutls_handsha ke() failed: The TLS connection was non-properly terminated.
    • 可能是网络环境问题。
    • 从图书馆回到宿舍网依旧有一些问题,参考issue:Git clone is stuck when not used with –recursive · Issue #909 · riscv-collab/riscv-gnu-toolchain
    • 重新git clone:git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
    • 出现新的报错;error: RPC failed; curl 56 GnuTLS recv error (-9): Error decoding the received TLS packet.

C语言的implementation-defined behavior

在不同的操作系统中,intcharlong等数据类型的定义都是不同的,编程的时候,应当定义确定的数据类型,例如:int8_tint16_tint32_tsigned charunsigned char等。

参考资料:

程序的执行和模拟器

在学习C语言部分,写了一下YEMU(参照源代码),这里给出了Chisel实现的代码,后面可以也实现一下。

Verilator仿真环境搭建

make 文件中YSYX路径问题,解决方法是:使用了绝对路径(由于在另一个文件夹下clone了PA,现在找到的NEMU_HOME不是这里的NEMU,因此改成了绝对路径)。

1
YSYX_HOME = ~/Documents/ysyx/ysyx-workbench

然后按照手册完成了第一个cpp仿真程序,并成功运行。

GTKWave

使用GTKWave查看生成的波形。

出现报错:

1
2
3
4
5
Gtk-Message: 12:14:21.701: Failed to load module "canberra-gtk-module"     

GTKWave Analyzer v3.3.104 (w)1999-2020 BSI

GTKWAVE | Use the -h, --help command line flags to display help.

debug结果是发现代码写错了,忘记了写:

1
tfp->close();

导致文件没有被正常关闭,因此出现了vcd文件无法读取的现象。

参考资料:

NVBoard实现流水灯

实现思路

使用nvboard的模板,改写vsrc和csrc文件,make生成可执行文件即可。

遇到的问题

  1. 不能够直接写脚本自动获取当前的路径,并生成环境变量:

    • 使用的方法是:
    1
    2
    3
    4
    NVBOARD_PATH=$(cd `dirname $0`; pwd)
    # and
    NVBOARD_PATH=$(cd `dirname $0`; pwd)
    # both not work

    暂时没有解决思路。

  2. TOP_NAME找不到是在哪里定义的:

    只看见了在main.cpp里面的调用,但是找不到定义。可能是在makefile中进行了处理,但是现在还暂时没有弄明白。

    答案就在makefile中:

    1
    CFLAGS += $(INCFLAGS) -DTOP_NAME="\"V$(TOPNAME)\""

    问题找到了,出在make里面,暂时的解决办法是将使用Vlight替换TOP_NAME

    最终的问题原因找到了,粘贴原来的makefile,改变TOPNAME值,运行正确。使用diff比较两个文件,发现makefile第一行light后面多打了一个空格;

    1
    2
    3
    TOPNAME = light_
    ^
    多打了一个空格

实验结果

main.cpp代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <nvboard.h>
#include <Vlight.h>

static TOP_NAME dut;

void nvboard_bind_all_pins(Vlight* top);

static void single_cycle() {
dut.clk = 0; dut.eval();
dut.clk = 1; dut.eval();
}

static void reset(int n) {
dut.rst = 1;
while (n -- > 0) single_cycle();
dut.rst = 0;
}

int main() {
nvboard_bind_all_pins(&dut);
nvboard_init();

reset(10);

while(1) {
nvboard_update();
single_cycle();
}
nvboard_quit();
}