- 运行 PAL (仙剑奇侠传)
- 多用户程序无缝切换
理解 "程序如何在计算机上运行" 的根本途径是从 "零" 开始实现一个完整的计算机系统,南京大学计算机科学与技术系计算机系统基础课程的实验项目 (Programming Assignment, PA) 将提出 x86/mips32/riscv32(64) 架构相应的教学版子集,指导学生实现一个经过简化但功能完备的 x86/mips32/riscv32(64) 模拟器 NEMU (NJU EMUlator),最终在 NEMU 上运行游戏 "仙剑奇侠传" 来探究 "程序在计算机上运行" 的基本原理。NEMU 受到了 QEMU 的启发, 并去除了大量与课程内容差异较大的部分。PA 包括一个准备实验 (配置实验环境) 以及 5 部分连贯的实验内容:
- 图灵机与简易调试器
- 冯诺依曼计算机系统
- 批处理系统
- 分时多任务
- 程序性能优化 (可选)
-
单个 CPU、128 MB 内存
-
简易调试器
sdb(simple debugger)命令 格式 使用举例 说明 帮助(1) helphelp打印命令的帮助信息 继续运行(1) cc继续运行被暂停的程序 退出(1) qq退出NEMU 单步执行 si [N]si 10让程序单步执行 N条指令后暂停执行,
当N没有给出时, 缺省为1打印程序状态 info SUBCMDinfo rinfo w打印寄存器状态
打印监视点信息扫描内存(2) x N EXPRx 10 $esp求出表达式 EXPR的值, 将结果作为起始内存
地址, 以十六进制形式输出连续的N个 4 字节表达式求值 p EXPRp $eax + 1求出表达式 EXPR的值,EXPR支持的运算请见下方设置监视点 w EXPRw *0x2000当表达式 EXPR的值发生变化时, 暂停程序执行删除监视点 d Nd 2删除序号为 N的监视点备注:
-
(1) 命令已实现
-
(2) 命令与 GDB 相比进行了简化,更改了命令的格式
-
以上表格来自 PA1.4
-
EXPR支持的运算(采用 BNF 范式定义)<expr> ::= <decimal-number> | <hexadecimal-number> # 以"0x"开头 | <reg_name> # 以"$"开头 | "(" <expr> ")" | <expr> "+" <expr> | <expr> "-" <expr> | <expr> "*" <expr> | <expr> "/" <expr> | <expr> "==" <expr> | <expr> "!=" <expr> | <expr> "&&" <expr> | "*" <expr> # 指针解引用
-
-
50 条 RISC-V ISA 指令,涵盖
- 全部 RV32I Base Instruction Set
- 全部 RV32M Standard Extension
- 部分 RV32/RV64 Zicsr Standard Extension
-
异常 / 中断响应处理机制
-
设备及其内存映射 (mmap)
- 串口 serial
- 时钟 timer
- 键盘 keyboard
- VGA (GPU)
- 声卡 audio
-
Sv32 分页及其 page table walk
设计 AM 的目的:程序与架构(ISA 以及 platform)解耦
-
TRM(Turing Machine) - 图灵机, 最简单的运行时环境, 为程序提供基本的计算能力,包含如下 API
// ----------------------- TRM: Turing Machine ----------------------- extern Area heap; // 堆,程序运行时动态分配的内存区域 void putch (char ch); // 输出字符 void halt (int code) __attribute__((__noreturn__)); // 停机 void _trm_init (void) // TRM初始化
-
IOE(I/O Extension) - 输入输出扩展, 为程序提供输出输入的能力,包含如下 API
// -------------------- IOE: Input/Output Devices -------------------- bool ioe_init (void); // IOE初始化 void ioe_read (int reg, void *buf); // 从IO读入内容 void ioe_write (int reg, void *buf); // 将内容写入IO
-
CTE(Context Extension) - 上下文扩展, 为程序提供上下文管理的能力,包含如下 API
// ---------- CTE: Interrupt Handling and Context Switching ---------- bool cte_init (Context *(*handler)(Event ev, Context *ctx)); // CTE初始化 void yield (void); // 程序自陷 bool ienabled (void); // PA不使用 void iset (bool enable); // PA不使用 Context *kcontext (Area kstack, void (*entry)(void *), void *arg); // 内核进程上下文创建
-
VME(Virtual Memory Extension) - 虚存扩展, 为程序提供虚存管理的能力,包含如下 API
// ----------------------- VME: Virtual Memory ----------------------- bool vme_init (void *(*pgalloc)(int), void (*pgfree)(void *)); // VME初始化 void protect (AddrSpace *as); // 为用户进程创建地址空间 void unprotect (AddrSpace *as); // 销毁用户进程创建地址空间 void map (AddrSpace *as, void *vaddr, void *paddr, int prot); // 进行虚拟-物理内存映射 Context *ucontext (AddrSpace *as, Area kstack, void *entry); // 用户进程上下文创建
-
Klib (kernel library,兼容 libc 的常用库函数)
-
stdio.c// stdio.h int printf (const char *format, ...); int sprintf (char *str, const char *format, ...); int snprintf (char *str, size_t size, const char *format, ...); int vsprintf (char *str, const char *format, va_list ap); int vsnprintf (char *str, size_t size, const char *format, va_list ap);
-
stdlib.c// stdlib.h void srand (unsigned int seed); int rand (void); void *malloc (size_t size); void free (void *ptr); int abs (int x); int atoi (const char *nptr);
-
string.c// string.h void *memset (void *s, int c, size_t n); void *memcpy (void *dst, const void *src, size_t n); void *memmove (void *dst, const void *src, size_t n); int memcmp (const void *s1, const void *s2, size_t n); size_t strlen (const char *s); char *strcat (char *dst, const char *src); char *strcpy (char *dst, const char *src); char *strncpy (char *dst, const char *src, size_t n); int strcmp (const char *s1, const char *s2); int strncmp (const char *s1, const char *s2, size_t n); char *strtok (char *str, const char *delim);
-
-
内存磁盘 ramdisk 及其简易驱动程序
-
Sv32 分页及虚拟内存管理
-
基于时间片的抢占分时多任务,支持最多4个用户进程和内核进程分时运行,使用时钟中断驱动
-
简易文件系统 sfs (simple file system)
-
文件数量和大小固定
-
无目录结构
-
采用虚拟文件系统 (VFS) 和一切皆文件思想进行文件抽象
-
标准输入输出错误流
-
设备(串口、键盘、VGA、声卡)
-
含如下 API
typedef struct { char *name; // 文件名 size_t size; // 文件大小 size_t disk_offset; // 文件在ramdisk中的偏移 ReadFn read; // 读函数指针 WriteFn write; // 写函数指针 } Finfo; int fs_open (const char *pathname, int flags, int mode); size_t fs_read (int fd, void *buf, size_t len); size_t fs_write(int fd, const void *buf, size_t len); size_t fs_lseek(int fd, size_t offset, int whence); int fs_close(int fd);
-
-
-
9 个系统调用 (open, read, write, lseek, close, gettimeofday, brk, exit, execve)
-
进程 Scheduler
-
ELF Program Loader
-
fsimg文件系统镜像bin/ -- 二进制文件(该目录默认未创建) share/ -- 平台无关文件 files/ -- 用于文件测试 fonts/ -- 字体文件 music/ -- 示例音乐 pictures/ -- 示例图像 games/ -- 游戏数据(该目录默认未创建) nes/ -- NES Roms pal/ -- 仙剑奇侠传相关数据文件 -
各种用户程序运行时库
libc: C运行库, 移植自 newlib 3.3.0, 同时包含最小的手写 C++ 运行库(但不支持 libstdc++)libos: 系统调用接口compiler-rt: 移植自 llvm, 主要用于在 32 位 ISA 上提供 64 位除法的支持libfixedptc: 提供定点数计算的支持, 包含sin,pow,log等初等函数功能, 可以替代范围不大的浮点数libndl: NDL(NJU DirectMedia Layer), 提供时钟, 按键, 绘图, 声音的底层抽象libbmp: 支持 32 位 BMP 格式文件的读取libbdf: 支持 BDF 字体格式的读取libminiSDL: 基于 NDL 的多媒体库, 提供部分兼容 SDL 库的 APIlibvorbis: OGG 音频解码器, 仅支持解码成s16le格式的PCM编码, 移植自 stb 项目libam: 通过 Navy 的运行时环境实现的 AM API, 可以运行 AM 程序, 目前仅支持 TRM 和 IOElibSDL_ttf: 基于 libminiSDL 和 stb 项目中的 truetype 字体解析器, 支持 truetype 字体的光栅化libSDL_image: 基于 libminiSDL 和 stb 项目中的图像解码器, 支持 JPG, PNG, BMP, GIF 的解码libSDL_mixer: 基于 libminiSDL 和 libvorbis, 支持多通道混声, 目前仅支持 OGG 格式
-
多种应用程序
nslider: NJU 幻灯片播放器, 可以播放 4:3 的幻灯片menu: 启动菜单, 可以选择需要运行的应用程序nterm: NJU 终端, 包含一个简易內建 Shell, 也支持外部 Shellbird: flappy bird, 移植自 sdlbirdpal: 仙剑奇侠传, 支持音效, 移植自 SDLPALam-kernels: 可在 libam 的支持下运行部分AM应用, 目前支持 coremark, dhrystone 和打字小游戏fceux: 可在 libam 的支持下运行的红白机模拟器oslab0: 学生编写的游戏集合, 可在 libam 的支持下运行nplayer: NJU 音频播放器, 支持音量调节和可视化效果, 目前仅支持 OGG 格式lua: LUA 脚本解释器busybox: BusyBox 套件(版本 1.32.0), 系统调用较少时只能运行少量工具onscripter: NScripter 脚本解释器, 在Navy环境中可支持 Planetarian, Clannad 等游戏的运行nwm: NJU 窗口管理器(需要 mmap, newlib 中不支持, 故目前只能运行在 native)
- sdb (simple debugger)
- tracer
- itrace (instruction trace):跟踪 NEMU 中程序的指令执行路径
- iringbuf (instruction ring buffer):itrace 的指令近场追踪
- mtrace (memory trace):跟踪 NEMU 中程序的访存行为
- ftrace (function trace):跟踪 NEMU 中程序的函数调用路径
- dtrace (device trace):跟踪 NEMU 中程序的 IO 访问行为
- etrace (exception trace):跟踪 NEMU 中程序的异常触发行为
- strace (syscall trace):跟踪 NEMU 中程序的系统调用行为
- AM native (Abstract Machine with host hardware, not NEMU)
- Nanos-lite native (Nanos-lite with AM native)
- Navy native (Navy with Linux native)
- difftest (Differential Testing)
- snapshot


