User:Arnie97/HP Saturn Intro
此用户页面尚未完工。原作者将会继续进行编写,而您也可以对该条目进行编辑。
本条目介绍的是 HP Apple 39gs 等 Saturn 系列计算器的基础知识。
Saturn
Saturn 是 HP 于上世纪 80 年代为其计算器开发的一种 4 位微处理器,该处理器有 Bert、Sacajawea、Lewis、Clarke、Yorke、New-Yorke 等子系列。[1]
Apple(Saturn+)系列
在 Saturn 处理器停产后,为了保持与 Saturn 平台原有程序的兼容性,HP 推出了一系列在 ARM 处理器上运行 Saturn 模拟器的计算器,与上面的那些子系列相对,软件模拟的 Saturn 处理器被称为 Apple 系列。这些模拟处理器相比之前真实的 Saturn 处理器拥有更多的功能,因此也被称作 Saturn+。 Apple 系列推出后,39、49 系列的图形计算器均发布了多款对应的新型号:
| 系列 | 原型号(Yorke 系列处理器) | 新型号(Apple 系列模拟处理器) |
|---|---|---|
| 39 | 39g 40g | 39g+ 39gs 40gs |
| 49 | 49g | 48gII 49g+ 50g |
这些新型号的系统软件与相对应的原有型号非常相近,只不过系统是运行在模拟器内,而不是运行在真实的 Saturn 处理器上。因此,很多相关的术语保留了下来。
值得注意的是,名为“HP ??gII”的计算器(“?”代指数字)往往与同编号的其他产品大相径庭,切勿混淆。例如,HP 48gII 不属于 HP 48 系列,而属于 HP 49 系列;而 HP 39gII 则不属于 Saturn 系列产品,而与后期推出的 HP Prime 有几分相近。
系统架构概述
Saturn 汇编语言
无论是原有 Saturn 系列还是 Apple 系列,由于使用了或真或假的 Saturn 处理器,显然都可以直接使用 Saturn 汇编语言编写程序。
Saturn 汇编常与编译型语言 System RPL 共同使用,相关内容详见下文,在此不再赘述。
RPN
RPN(Reverse Polish Notation,逆波兰表示法)将运算符置于操作数的后面,因此又称后缀表示法。与之相对的是绝大多数语言采用的代数表示法(Algebraic Notation,运算符位于操作数之间,又称中缀表示法)和 Lisp 等语言采用的波兰表示法(运算符位于操作数之前,又称前缀表示法)。
| 表达式记法 | 运算符位置 | 示例 | 采用该记法的语言 |
|---|---|---|---|
| 波兰表示法 | 前缀 | * - 3 4 5 | Scheme,Common Lisp 等 |
| 代数表示法 | 中缀 | (3 - 4) * 5 | C++,Python,TI-Lua,HP Basic 等 |
| 逆波兰表示法 | 后缀 | 3 4 - 5 * | Forth,System RPL 等 |
逆波兰表达式的解释器一般是基于栈(Stack)这一数据结构的。要理解 RPN,最好先理解栈的概念。 RPN 解释求值的过程一般是:遇到操作数时入栈;遇到运算符时,取对应数量的操作数出栈,求值,将结果入栈;最终栈顶就是表达式的值。
例如,常规中缀记法的 12 * (3 + 4) - 6 + 8 / 2 用 RPN 写作 12 3 4 + * 6 - 8 2 / +,其运算过程如下:
- 首先,12、3、4 依次入栈。
- 输入加号时,由于它是二元运算符,会弹出栈顶的两个数进行运算,并将结果 7 压入栈中。
- 乘法同样是二元运算,弹出栈顶的 12 和 7 两个数,并将结果 84 返回栈顶。
- 随后,数字 6 入栈。
- 之后是减法,取出栈顶的 84 和 6,并返回结果 78。
- 随后,8 和 2 入栈。
- 之后是除法,取出栈顶的 8 和 2,并将结果 4 压入栈中。
- 最后取出 4 和 78 做加法,得到最终结果 82。
RPN 的运算符之间不存在优先级的高低,不需要使用括号来表明运算的优先级,因此能减少输入部分复杂表达式时按键的次数。
例如,常规中缀记法中 3 - 4 * 5 与 (3 - 4) * 5 的意义不相同,需要用括号加以区分;但后缀记法中前者写做 3 4 5 * - ,后者则写做 3 4 - 5 * 。
System RPL
System RPL(其中 RPL 指 Reverse Polish Lisp)是 HP 计算器上广泛使用的一种编译型语言。顾名思义,该语言中的语句采用逆波兰表示法。
HP 38、39(40)、48、49(50)等系列的图形计算器均支持该语言[2],且大部分系统软件和很多第三方软件由该语言写就。HP 38、39(40)、49(50)等新系列计算器的很多第三方应用来源于对 HP 48 等早期系列中 System RPL 应用的移植和重新编译。
作为一种贴近底层的编译型系统编程语言,System RPL 常与 Saturn 汇编共同使用,这与 PC 平台上的 C 语言和 x86 汇编语言有着相通之处。这两种语言可以用 PC 上的 HP Tools 开发。此外,HP 49、50 等系列的计算器内置了 MASD,可以直接在计算器上进行编译、汇编、调试操作。注意 HP Tools 和 MASD 均是编译器本身,并不包含头文件(Entry Points,或简称 Entries),如果不希望手动声明系统提供的函数,需要自行下载头文件,其中的原理与 C 语言是相通的。HP 28、38、39(40)、48、49(50)系列的头文件互不相同,下载时需根据所针对的机型正确选择。
Library
Aplet
User RPL
User RPL 是 HP RPN 计算器上的一种解释型语言。顾名思义,该语言同样采用逆波兰表示法。
HP 28、48、49(50)等系列的计算器支持该语言代码的运行。如果在设置中选择 RPN 输入模式,那么用户在计算界面中输入的有效指令实际上均可以视为合法的 User RPL 代码。
与 System RPL 的关系
User RPL 的语法和 System RPL 相近,但代码可以直接在计算器上运行而不需要编译。运行时发生的大部分错误会被正确捕获,且部分较为危险的底层命令无法直接使用。这些特性使得 User RPL 的编写和调试更方便和安全,但也使它的运行速度较 System RPL 缓慢,在需要对系统底层进行操控及性能因素至关重要的场合(如某些游戏)应当选择 System RPL。
User RPL 能通过多种方式调用 System RPL 特有的函数,相关内容并入下文 HP Basic 的相关章节,在此不再赘述。
在 HP 49(50)系列计算器内置的文件管理器(Filer)中,User RPL 代码的文件类型为 PROG,System RPL 源码的类型为普通字符串 STRNG,而 System RPL 编译出的二进制对象类型为 CODE。
HP Basic
HP Basic 是 HP 38、39(40)系列计算器的解释型语言,其定位与 HP 48、49(50)系列中的 User RPL 相似——用户在 HOME 界面中输入的有效指令均为合法的 HP Basic 代码。由于该语言的代码通过解释器执行,且解释器本身又运行在 Saturn 处理器或模拟器上,因此速度是本文提及的所有语言中最慢的。
调用 System RPL
HPGCC
ARM Toolbox
Aplet 框架
内存布局与固件
数据类型与联机传输
数据对象的内部表示(变量)
数据在内存中以不同的方式(数据结构)储存着。这些数据结构当中有顺序的(例如线性表的数组形式),也有非顺序的(例如线性表的链表形式)。
数据对象的外部表示(文件)
为了将数据,尤其是非顺序的数据:
- 保存于外存(硬盘、光盘、闪存等)的某个文件中以备后用
- 通过网络等方式共享给另一台计算机
- 通过串口等方式传送至图形计算器等设备
我们需要将数据编码为字符串(字节流)方能储存或传输,这一编码过程称为序列化(Serialization)。
变量的类型系统:静态类型与动态类型
变量是代指数据的名称、符号。
- 在 C++、Java 等语言中,每个变量均对应一个特定的数据类型,使用前必须声明每个变量的数据类型,这样的类型系统称为静态类型。
- 在 Haskell 等语言中,虽然很多情况下不需手动声明变量的数据类型,而是通过计算机的自动推导来确定数据类型,但每个变量均有特定的类型——类似 C++ 11 中使用
auto的情形——因此同样属于静态类型。 - 在 Python、JavaScript 等语言中,类型依附于变量中储存的数据本身,数据有类型而变量无类型,这样的类型系统称为动态类型。
文件的类型系统:扩展名与特征签名
类比变量,文件名(和路径)是代指文件的符号。对于文件来说,同样有数种不同的方式来记录它的类型,其中就包括:
- 文件名称的某个特定部分指示一个文件的类型——通常是最后一个小数点后的部分,也就是扩展名(Extension)。
- 文件内容的某个特定部分,即特征签名(File Signature)指示一个文件的类型——通常是最前面的部分,也就是头部(Header)。
扩展名最早在 CP/M 操作系统中被采用,而后又随一脉相承的 DOS 和 Windows 得到了推广;特征签名则在 Unix 中被广泛应用,而后又被 Linux 等操作系统所继承下来。由于两类操作系统均得到了广泛的应用,现实中两种方式常常共存:
| 文件类型 | 扩展名 | 特征签名[3] |
|---|---|---|
| MZ 可执行文件
PE 可执行文件 |
com exe
exe dll sys ocx cpl scr 等 |
MZ(设计者 Mark Zbikowski)
(为向下兼容 DOS,PE 文件头部与之相同) |
| ELF 可执行文件 | 无 | \x7F E L F
|
| PDF 文档 | %PDF
| |
| ZIP 压缩文件 | zip docx pptx xlsx 等 | PK(设计者 Phil Katz)
|
| RAR 压缩文件 | rar | Rar!
|
| CAB 压缩文件 | cab | MSCF(Microsoft Cabinet File)
|
| PNG 图片 | png | \x89 P N G
|
| GIF 图片 | gif | GIF89a 或 GIF87a
|
| JPEG 图片 | jpg jpeg | 以 \xFF \xD8开始,\xFF \xD9 结束
|
| Midi 音轨 | midi | MThd(MIDI Track header)
|
| Java 字节码 | class | \xCA \xFE \xBA \xBE,即十六进制 CAFEBABE
|
从上面的例子中可以看出,既有一个扩展名对应多种特征签名的情况(如 GIF 文件),也有多种扩展名对应单一特征签名的情况(如 PE 文件)。当扩展名和特征签名共存时,有时会结合两种因素来决定文件如何解析,更多时候则只选择其中的主要因素来判断文件的类型。例如,将 JPEG 图片的扩展名更改为 png 仍能用多数图片查看器正常打开,说明这些软件仅通过文件内容中的特征签名来判断文件的格式,扩展名无关紧要。同样,HP Saturn 系列计算器也仅判定文件的特征签名,而扩展名的作用只是辅助人类的辨识:
| 文件类型 | 常见扩展名 | 特征签名 |
|---|---|---|
| HP 39(40)系列 | 000 apt lib 等 | HP39Asc?(文本,ASCII)
|
| HP 48 系列 | 不固定 | HPHP48-?
|
| HP 49(50)系列 | hp lib 等 | HPHP49-?
|
上表中,? 代指表示文件类型的一个大写拉丁字母;同一字母在不同系列中有着不同的意义,详见下文各章节。另外,由于扩展名并无实质性作用,用户可根据自己的喜好和实际情况选择不同的扩展名——例如,为了方便用记事本打开,可以用 txt 作为扩展名;[4]为了方便用户区分不同机种的文件,跨平台应用的开发者有时直接用 48、49 等作为扩展名。[5]
内部表示(变量)与外部表示(文件)间的关系
表面上看,HP 39(40)、48、49(50)的文件格式互不相同,PC 上的官方联机工具(Connectivity Kit)也形式各异。但是,多项证据已经表明,不同系列的 Saturn 机种使用相同的方式来储存 RAM 中的对象。
我们可以通过下面的实验来验证这一结论:用含有 HP 48gII 固件的 ROM 替换 HP 39gs 原有的闪存,期间保持电源供给,以免 RAM 中的数据丢失。那么,当进入 49 系列的系统后,我们将看到之前在 39 系列系统中储存的所有文件(和文件夹)。鉴于 39 系列系统中并未提供完整的文件管理器,如果想探查 39 系列计算器的目录结构,除了选择自己编写文件管理器外,亦可利用这一特性,借助 49 系列内置的文件管理器来达到目的。
综上所述,不同系列间文件格式的差异,本质上是相同对象类型的不同序列化形式,传入计算器后的生成的对象是相同的,可谓“换汤不换药”。