Skip to content

Latest commit

 

History

History
229 lines (160 loc) · 7.09 KB

README.md

File metadata and controls

229 lines (160 loc) · 7.09 KB

ONICPU

English Readme <- Click Me

简介

ONICPU 是游戏缺氧的一个 CPU 模组,支持你建造可编程的代码执行控制单元,用它来实现复杂的自动化功能。

目前原版游戏只有简单的逻辑门自动化,这在实现一些很大型的电路时,会非常复杂,因此设计了这个模组,使用代码来控制自动化。

主要功能:

  • CPU 运算单元,支持 4 输入 4 输出 IO,8 输入 8 输出 IO
  • CPU 支持使用汇编代码或者 JavaScript 代码进行控制
  • 拓展线组读取器、线组写入器使其支持传输 32 位数值
  • 拓展一系列传感器,使其可以直接读取数值,传给 CPU 处理
  • 数码管显示

使用方法

CPU

你可以在自动化菜单中找到 CPU(需要先解锁相应科技树),目前有三种大小的 CPU:

  • 2 输入 2 输出 IO
  • 4 输入 4 输出 IO
  • 8 输入 8 输出 IO

CPU 左侧是输入端口,程序可以读取它的值,右侧是输出端口,可以输出值,控制下游连接的设备。 CPU 使用一个控制端口(中下位置)来进行控制,只有在控制端口接收到绿色信号时,单元才会启动。

启动状态下,你的程序默认会以 5Hz 的频率执行,在每个执行周期中,你可以读取输入参数,进行自定义计算,然后修改输出端口的值。

因为游戏代码限制,所有 CPU 端口最大支持 Int32(-2,147,483,648 ~ 2,147,483,647)

每种 CPU 都有两个版本,有(JavaScript)后缀的表示这个 CPU 使用 JavaScript 代码进行控制。JavaScript 简单易上手,汇编比较复杂但有趣,你可以选择自己喜欢的。

注意: 在代码中请不要使用 while 循环来做延迟,这会导致游戏卡住,应该使用变量计数器来实现延时。

快速排障指南

有些时候总是会遇到一些奇奇怪怪的问题,这时候你可以按照以下顺序尝试

  1. 检查是否有接线错误,尤其是Reset位置是否存在误接线
  2. 保存并重新加载(SL)游戏,这通常来说会解决大多数的问题
  3. 尝试开一个新存档并禁用其它mod(根据个人经验,这一步几乎没有作用)
  4. 提交一个Issue

代码编辑器

你可以在选中 CPU 单元后,在右侧菜单中点击“编写程序”,来打开编辑器,在编辑器中:

  • 顶部显示的是程序当前的状态信息
  • 在左侧输入框中编写代码
  • 右上角按钮控制程序运行、暂停。
  • 右侧显示的是实时的程序 IO 数值
    • 在汇编模式中,右侧还会显示寄存器、内存数据
    • 在 JavaScript 模式中,右侧还会显示程序输出日志信息

建议你可以在 Visual Studio Code 或者其他代码编辑器软件中编写好代码再复制到游戏中。

点击 立即编译 可以立即编译程序,编译会临时暂停运行程序,可以再点击上方运行按钮开始运行,点击 保存并关闭 可以编译程序然后关闭。

提示:CPU 是否运行是受控制端口是否有绿色信号控制的,但你在代码编辑器中手动点击运行时运行不受信号限制。

数字化传感器

本模组拓展了一系列传感器,使其可以直接读取数值,你可以将其连接至 CPU,然后就可以读取数值来进行相关处理。

数码管显示器

本模组添加了数值显示器,你可以用它来显示网络中的数值。分为 3 档,分别可以显示 8 位、16 位、32 位整数。

JavaScript

当你选择有(JavaScript)后缀的 CPU 后,你就可以开始用 JavaScript 写代码了。你的程序会以下方 3 个主要函数来组织:

  • start:程序启动时执行
  • stop:程序停止时执行
  • tick:程序在运行中每逻辑帧执行

tick 函数必须存在,否则 CPU 单元会停止执行,start 和 stop 可选。

function start() {
  //代码,启动时执行
}
function stop() {
  //代码,停止时执行
}
function tick() {
  //代码,每逻辑帧执行
}

你的主要程序通常应该写在 tick 函数中,tick 函数的推荐逻辑应该是,读取数据->处理数据->输出数据。

你可以在 Demo 目录 来查看几个示例

你还可以根据更多条件来实现更多复杂功能,下方是 CPU 单元一些支持的功能说明:

输入和输出: 你可以使用 io.PX 读取或设置引脚值。例如:

  • 读 P0 输入
let pin0value = io.P0;
  • 设置 P4 输出
io.P3 = 1;

注意:游戏会在名称 start、stop、tick 执行完毕后将修改后的输出值同步到信号网络。

存储数据: 你的代码中其他的位置声明变量,在每次编译/上电/游戏重新加载会丢失,需要手动加载。 模组内置了 storage 对象,在这个对象下的数据会被游戏保存,可以在下次存档加载后读取

  • 储存数据
storage.example = 31;
  • 读取数据
io.P3 = storage.example;

辅助函数

  • **getbit: 你可以调用 **getbit(io.P0, 1) 得到输入引脚的 1 位值。
  • **changebit: 你可以调用 io.P3 = **changebit(io.P3, 1, 0) 设置输出引脚的 1 位值=0。
  • **log: 你可以调用' **log('message') '来记录编辑器中的一些消息。
  • **reset: 调用 **reset() 来重置所有输出 IO
  • **shutdown: 你可以调用 **shutdown('error message') 来关闭这个 CPU 单元。

汇编

CPU 支持使用汇编代码。但汇编比较难,推荐还是使用 JavaScript,也可以用汇编,因为挺好玩的,但在写代码之前,你需要学习汇编相关知识。

本 CPU 支持的是类 C51 汇编(部分子集,和标准不一样),所有计算指令、寄存器大小均为 32 位。本文只说明 CPU 指令相关支持情况和特殊说明,汇编相关知识你需要到互联网上搜索相关资料。

指令格式

[操作码] [操作数] 例如: MOV A, P0 :label 标签

支持的寻址方式

  • 立即数寻址 #20H 例如:MOV A,#20H
  • 寄存器寻址 PSW / A / R1 例如:MOV A,R1
  • 寄存器间接寻址 @R1 / @REG1 例如:MOV A,@R1
  • 跳转寻址 :label 例如:jne :loop

支持的寄存器

  • R0-R7 内置通用寄存器
  • PSW 程序状态字寄存器 (与 8086 定义一致)
  • A
  • B
  • C
  • ACC 累加寄存器
  • SP 堆栈指针寄存器
  • PC 程序计数器

支持的指令表

无操作数指令

  • NOP
  • RST
  • HLT
  • POP

1 操作数指令

  • SWAP
  • PUSH
  • NEG
  • JMP
  • JE
  • JNE
  • JZ
  • JO
  • JNO
  • JS
  • JNS
  • JP
  • JNP
  • JC
  • JNC
  • JB
  • JNB
  • JA
  • JNA
  • JAE
  • JNAE
  • JBE
  • JNBE

2 操作数指令

  • MOV
  • XCHG
  • XCHD
  • ADD
  • SUB
  • INC
  • DEC
  • MUL
  • MOD
  • AND
  • OR
  • XOR
  • NOR
  • MOD
  • SHL
  • SHR
  • CMP

读取写入 IO

  • 读取写入 IO 简化了,无特殊指令,需要内置寄存器一样,直接读取/写入:MOV A, P0 或者 MOV P0, #11

示例程序

mov r0,#10 mov r1,#0 mov r2,#0 :loop inc r2 dec r0 cmp r0,r1 jne :loop mov p3,r2 hlt

Steam 模组页面