pb实现简单计算器的思想_在TI-84计算器上造台计算机

bc602d1bf3e661f0dc8825d27bcb97b6.png

我有一台TI 84 Plus CE计算器。320x240 16色彩屏,265x165大小的区域可以直接绘图,字符界面有26x10大小可以用。

这台计算器最棒的一点是它能运行一个叫TI-Basic的动态语言。这个语言是图灵完备的,而且可以在计算器上直接写。所以我现在就有了一台能让我不用电脑也能实现编程想法的萌萌哒设备了。Pt-on(1,1,BLUE)就可以在1,1处生成一个蓝色小点。简单。最纯粹的编程体验。(想想在一台普通笔记本上控制屏幕上的某像素是怎样一个过程,你就明白我什么意思了。)

下面展示了一些我用它完成的事情:

1.Flappy Bird

945490ecc878b1830a364720a8a0faf2.gif
请把头顺时针转90度再看。我说过字符显示有26列和10行,如果让鸟横着飞的话高度就只有10种不同取值了,玩起来一点意思都没有。

2.翻转棋

4c8867c296e9b3f3afb0680401b776ec.gif

3.'Unity' 3D

0a58feccf98e162656e4b634ceec68fc.gif

有一天我在想3D游戏是怎么写的。。。然后发现其实挺简单的。场景在一个虚拟视网膜上的投影就构成了玩家该看见的东西,然后一点点矩阵运算(毕竟这是台计算器!)就能让玩家在场景里移动和四处张望了。(搞了一大堆优化后FPS达到了惊人的1.67 xswl)

4.还有很多、很多。。。

从扫雷到俄罗斯方块,啥都能写!A̶n̶o̶t̶h̶e̶r̶ ̶g̶o̶o̶d̶ ̶t̶h̶i̶n̶g̶ ̶i̶s̶ ̶t̶h̶a̶t̶ ̶w̶i̶t̶h̶ ̶a̶ ̶L̶O̶T̶ ̶o̶f̶ ̶g̶a̶m̶e̶s̶ ̶o̶n̶b̶o̶a̶r̶d̶ ̶i̶t̶ ̶i̶s̶ ̶s̶t̶i̶l̶l̶ ̶a̶ ̶c̶a̶l̶c̶u̶l̶a̶t̶o̶r̶ ̶i̶n̶ ̶t̶h̶e̶ ̶t̶e̶a̶c̶h̶e̶r̶s̶'̶ ̶e̶y̶e̶s̶.̶

于是有一天我觉得我该去完成用TI-Basic的终极挑战了。编译也是一种计算任务,TI-Basic作为一门图灵完备的语言肯定是能完成的。所以理论上我能用这个语言写一台能编译和运行我自己的语言的虚拟机,也就是在计算器上写一台计算机出来。

刚开始我觉得这很容易。TI-Basic提供了完整的字符串操作,比如截取和拼接。同时,也有个自带函数expr()可以接字符串并把它当TI-Basic运行。看上去,我只要写个字符处理程序,输入我自己的语言,输出TI-Basic代码,然后丢进expr()里执行就完事了。

然而事情没有这么简单。第一,所有可用字符都可以被存储在一个字符串里,除了'',唯一的赋值符。要是不能count=count+1的话这还算什么计算机啊。第二,不仅这个赋值符的缺失使得上面的思路不可实现,使用expr()本就是一种‘作弊’行为。只要我还在用TI原生的指令,那么就一层虚拟都没有了。

我想到了‘机器码‘这个词。虚拟机是台机器。一般的电脑有计算单元、寄存器、内存。。。如果我能写出虚拟的这些零部件,并让它们像硬件对待电信号那样去对我自定义的虚拟机器码那样作出反应,那么一台真正的虚拟机就写出来了。

计算单元。计算器本身就认识+-*/,其实就没必要再做什么事了,一个符号本身就对应了一个虚拟的小零件。为了简单(和纯粹),我只用+和-。

寄存器。每个TI上的字符都是一个可存一个实数的变量。我用了XYAB。至于指令计数器,我用了Ś(TI上第三快的变量)。我还设计了一个变量Ans,存储每一步操作的结果,用θ(TI上第二快的变量)实现(后面你会看到这个寄存器干啥用的)。

内存。在Commdore64上‘POKE 1 1 A‘会让屏幕左上角显示个A(我虽然是00后,但还是很向往那样的“美好旧时光”)。我想要这样纯粹的内存读写体验。虚拟屏幕大小是16*9,所以我把内存地址1-144分给屏幕。向这些位置写数据就会显示它们,比如向[18]写个'A'就会让第二列第二行出现一个'A'。内存0位用来留给一些特殊用途,比如如果里面存了21,虚拟机就会停止,存了45就会清空屏幕。当任何按键被按下时对应的keycode也会被存在0位里,当0位被读取它就会被重置。145-160位是自由的,程序员可以随便用。整个内存是用TI里的一个数组实现的。

接下来设计我的虚拟机将用到的指令集

0 MOV

MOV 1 A 将1存入寄存器A

MOV [146] ?A 将内存地址146里的内容存入内存地址A

1 ADD

ADD 1 1 完成1+1并把答案赋给Ans,所以c=c+1就会是

ADD C 1

MOV θ C

2 SUB

SUB A B 完成A-B并把答案赋给Ans。其实这主要是用来完成比较而非减法。

3 JNE Jump If Not Equal

JNE 5 跳过后面5行指令如果Ans不为0

这便是关键之处。计算器和计算机的本质区别是什么?分支结构。现在你看到了,Ans起到了flag的作用。

说给没接触过汇编的读者:如何让计算机明白if (A=1) { print("B") }?:

SUB A 1

JNE 1

MOV "B" [1]

那么除非A是1,否则print语句就被跳过了。

4 JLE Jump If Less Than or Equal to

JLE 5 跳过后5行代码如果Ans不是正数。

事实上JLE可以完全替代JNE,因为(a≤b and b≤a) === (a=b)。但这样写判断相等也太蛋疼了,所以我就留了JNE。

最后,想出一个方法来让TI里可以存储我的代码。以下是我的最终设计:

1条指令由9个字符组成,结构:

[操作符][类型符][数据][数据][数据][类型符][数据][数据][数据]

0 操作符。0是MOV,1是ADD,以此类推

1 第一个类型符。[空格]标记了接下来是个寄存器,+标记是个数字,"字符串,[一个用作内存地址的数字,?一个用作内存地址的寄存器。

234 第一个数据。如果不够,用空格保证它占满3格

5 第二个类型符。

678 第二个数据。

来点例子。继续用上面那个if (A=1) { print("B") },写出来是:

2 A +001

3+001

0"B [011

看着很炫是吧?用这些符号拼成的字符串就组成了一份程序。我的名字是 @Richardn ,所以就叫它Rssembly或者RSM好了。

我的一个朋友, @Kunologist ,是个UI设计师,也很喜欢玩TI计算器,帮我写了个IDE。它能让我们用舒服的方式写代码并转成RSM代码。示范:

3aa555f99ba73540fa3c997fc189c238.gif

看到了吧?一个A确实被显示在第一行第十一列了!我虽然不会证明,但我相信我的语言也是图灵完备的,能做比单独显示一个字母更高妙的事情。

以下是我在RSM里的毕业项目,一个一位乘一位计算器,代码:

2a3232f6e4e69187ca8e9bec4dd6c352.png
从左往右,从上往下读。额外信息:在TI上数字按键和对应的Keycode是7-9对72-74,4-6对82-84,1-3对92-94

最终结果:让它算3*4:

46a7621ddb49c285de5e84db3c203325.gif

等待第一个输入。我打3。

寻找我按了哪个按键。找到了3。显示3。

等待第二个输入。我打4。

寻找我按了哪个按键。找到了4。显示4。

把4加3遍,显示最终答案。

就这样了。我在我的TI-84 Plus CE上写了台电脑出来。理论上我还能用RSM写个gcc或者一个操作系统(如果计算器有无穷的时间去运行的话。。。)。

用图灵完备的编程语言TI-Basic,我能实现一切,包括计算机本身。用仅仅5个不同的RSM指令我仍然能实现一切。我觉得计算机编程的灵魂大概就在这附近了。它有点类似于我在学习物理中感受到的那种美,无穷无尽的复杂过程都能被抽象为少数几条简洁的规律。但计算机编程比物理还多点东西。在物理里,我只是这个世界的一个谦卑的观测者。而当我拿起一台计算机,我就是规律的创造者,也即每一个由我代码创造的宇宙的造物主。

这让我不禁更崇拜起冯诺伊曼和图灵了。一位证明了一切可能的计算任务都可以由仅有7条规则的图灵机完成,另一位教会了人类如何去设计这样的一台机器。所以从根本上来说,一切我在我的计算器上玩出来的花样,一切正在我笔记本上跑的程序,一切在网络世界发生的变革,一切已被设计或将被设计的软件,一切已经被想象的或者将要被想象的,早已存在于他们的思想中。


原文发布于Cent,一个基于以太坊,目标是让用户在社交网络上创造的价值变现的区块链应用。当时我写的这个东西短暂地登顶全站最火,赚了几美元。。。链接:

Cent - Building a Computer on a Calculator​beta.cent.co

以下为英文原文(对的,这玩意最初的版本就是英文的,我刚刚得自己把自己说过的话翻译回来。感觉我语文实在是不太行,有些想法转成中文就没内味了。。语 文 高 考 完 蛋 了):

I have a Texas Instruments 84 Plus CE calculator. 320x240 16-color screen with 265x165 pixels directly controllable in graphing mode and 26x10 character output in home screen.

The best thing about it is that it can run a dynamic language called TI-Basic which is Turing-complete and can be written directly on the calculator. So now I have a handy little machine with which I can realize any of my thoughts related to programming without a computer. Pt-on(1,1,BLUE) spawns a blue dot at 1,1. Simple. Programming in its purest form. (Just think of how difficult it is to control a screen pixel on a modern laptop.)

So here's something I've done on it:

1.Flappy Bird. (Please rotate your head 90 degrees clockwise. I've mentioned that the home screen have 26 columns and 10 rows. A bird with only 10 different values of height is no fun to play with...)

2.Reversi.

3.'Unity' 3D engine.

I one day was thinking of how 3D games are made...then I discovered it is not that difficult as it sounds. Projections to a virtual retina generates what the player see and simple matrix calculations(after all this is a calculator!) enable the player to walk around and look around. Here is a demo of looking at a floating tetrahedral. (With a lot optimizations it reaches an amazing FPS of 1.67 lol).

4.And a lot others! From Minesweepers to Tetris...Anything can be coded! A̶n̶o̶t̶h̶e̶r̶ ̶g̶o̶o̶d̶ ̶t̶h̶i̶n̶g̶ ̶i̶s̶ ̶t̶h̶a̶t̶ ̶w̶i̶t̶h̶ ̶a̶ ̶L̶O̶T̶ ̶o̶f̶ ̶g̶a̶m̶e̶s̶ ̶o̶n̶b̶o̶a̶r̶d̶ ̶i̶t̶ ̶i̶s̶ ̶s̶t̶i̶l̶l̶ ̶a̶ ̶c̶a̶l̶c̶u̶l̶a̶t̶o̶r̶ ̶i̶n̶ ̶t̶h̶e̶ ̶t̶e̶a̶c̶h̶e̶r̶s̶'̶ ̶e̶y̶e̶s̶.̶

And one day I came up with the final challenge of the TI-Basic language. Compiling is also a computational task, something a Turing-Complete machine can surely do. So in theory I can write a virtual machine out of the language that can compile and run my own language, which means building a computer on top of the calculator.

At first thought this is easy. Because firstly, TI-Basic provides full operations of strings like sub and append. Secondly, there is a function called expr() which can take a string and treat it as TI code. So it seemed like I could just do some string operations based on a script written in my own language, then churn out the corresponding TI_Basic codes for expr() to execute. Bingo! Virtual machine complete!

Then I discovered something. Every character available in the TI-Basic can be put into a string, except '→'. It is the only assignment operator. What can a computer do if it can't count=count+1? And not only the approach is unfeasible, it is not the way of building a virtual machine in the first place. Using expr() is fundamentally a cheat. As long as I am using the original characters for executing commands, there would be no layer of virtualization at all!

I began thinking again. The word 'Machine Code' jumped into my mind. A 'Virtual Machine' is a machine. A computer has ALU, registers, RAM...If I can code the virtual ones which understand the virtual machine code of my own, just like how circuits react to electrical signals, then I can really say I've built a virtual machine.

ALU. As TI understands +-*/ natively, this does not require additional work. For simplicity(and purity), I will only use + and -.

Registers. Every Alphabet is a variable that can store a real number on TI. I will take X Y A B as eax, ebx..(I've really learnt something about the x86 architecture lol). Program counter? I use Ś, the third-quickest variable on TI. And I designed an Ans register for taking the answer of every previous operation, using θ, the second-quickest variable.(You will see its purpose later)

RAM. On Commdore64 'POKE 1 A' will put an 'A' in the top left corner of the screen (I'm born after 2000, but still attracted to those 'good old days'). Let's achieve this pure RAM access experience. I chose the virtual screen to be 16*9, thus I map RAM address 1~144 to the screen. Writing to those addresses will display something, like writing an 'A' to [18] will make an 'A' appear at row 2, column 2. RAM address 0 is for special purposes like a 21 in it will terminate the machine and a 45 in it will clear the screen. And a keycode will be stored in 0 when the corresponding key is pressed and address 0 will be reseted after using. 145~160 is free for using.

Now we've come to designing the command set my virtual machine will use.

0.MOV

MOV 1 A stores the value 1 to register A

MOV [146] ?A stores the value in RAM address 146 to RAM address A

1.ADD

ADD 1 1 does 1+1 and feeds the answer to the Ans register. So c=c+1 will be like

ADD C 1

MOV θ C

2.SUB

SUB A B does A-B and feeds the answer to the Ans register.

actually this is usually used for comparison (cmp if you know something about assembly) instead of subtraction

3.JNE Jump If Not Equal

JNE 5 jumps forward the following 5 lines if Ans register is not 0.

Here the fun starts. What makes a computer computer, rather than just a calculator? Branch structures. Now you see. The Ans register also acts as a flag.

For those who don't know assembly: How to write if (A=1) { print("B") } in a computer-friendly way?

SUB A 1

JNE 1

MOV "B" [1]

so unless A equals 1, then the print gets jumped over.

4.JLE Jump If Less Than or Equal to

JLE 5 jumps forward the following 5 lines if Ans register is not positive.

Actually JLE can do all the work of JNE, because (a≤b and b≤a) equals to (a=b). But it is painful to write conditional statements using this approach, so I reserved JNE.

Then I must pack this language in a TI-readable syntax. This is my final design:

1 command consists of exactly 9 characters. Structure:

[operator][mark][data][data][data][mark][data][data][data]

0 Operator. 0 is MOV, 1 is ADD,etc.

1 Datatype Marker. [spacebar] indicates the following is a variable, + a number, " a string, [ a number taken as a RAM address and ? a variable taken as a RAM address

234 Data1. If a variable is put here than add two spaces to fill the 3 characters.

5 Datatype Marker.

678 Data2

Some examples. Again, let's try that if (A=1) { print("B") } above

2 A +001

3+001

0"B [011

Really cool isn't it? A string packed with these lines composes a 'program'. You see my name is @Richardn...So let's just call it Rssembly or RSM!

A friend of mine, @Kunologist, who is a UI designer and is also into playing around in TI, wrote an IDE. It enables us to write RSM codes in a human-friendly way and converts them to something the CORE I've written can interpret and run. Here's a demonstration:

See? An 'A' does get displayed at row 1 column 11! Actually, I believe my language is also Turing-Complete, which can do things way beyond just displaying a single character.

This is my final project in RSM, a multiplication calculator. I will show you the code:

(Additional information: Numbers and their corresponding keycodes in TI 84 Plus CE: 7-9:72-74, 4-6:82-84, 1-3:92-94)

Here's the final result, the calculator on the calculator doing 3*4:

Wait for the first input. I type a 3.

Find which key I've pressed. 3 detected, print a 3.

Wait for the second input. I type a 4.

Find which key I've pressed. 4 detected, print a 4.

Add 4 for 3 times, output the answer.

That's it. I've created a computer on my TI 84 Plus CE. I can write a gcc or even an operating system out of RSM (if the calculator has an infinite amount of time to run them lol).

With the Turing-complete language TI-Basic, I can realize anything, including the computer itself. And only with 5 different operations of RSM I still can build anything. I think the essence of computer programming just lies around here. It is somehow like the elegance I feel in physics, where all those complex movements of matter can be abstracted into a few simple rules. But programming is something more. In physics, I'm a humble observer of the universe. In programming, I'm the creator of the rules, thus the creator of every universe that comes from my lines of code.

And this made me admire Turing and Von Neumann more. One proved that every possible computational problem can be completed with 7 basic operations in a Turing machine, and the other taught us how to build such a machine in reality. So basically, everything I've played with on my calculator, every program that is running on my laptop, every advance that is happening on the Internet like the blockchain technology, every application built or to be built, everything imagined or to be imagined, lies in their minds.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简介一年多以前,Android平曾经出现过三个流行的TI计算器模拟器软件,分别包括TI-83、TI-85、TI-86,让许多用户大为欣喜,不过因为这些软件采用了一键安装模式导致侵犯了德州仪器的版权问题,最终这些软件被迫下架。 现在TI-89计算器又出现在Android平,这次为了避免重蹈覆辙,开发者采用了模拟机的方式,仅提供一个模拟器,用户需要自行下载德州仪器给出的计算器ROM用来给软件加载。 虽然现在这款模拟器还处于测试阶段,但是已经可以正常使用,而且是Android平上出现的第一个可用的TI-89计算器工具更新内容: - 优化变焦模式 - 增加振动器开/关 - 性能改进 - 改善应用程序的链接 安装说明:下载主程序和rom文件,解压zip格式的rom文件,再把解压后的文件放到SD卡任意目录,安装主程序,打开主程序并按菜单键,选择Load ROM,点击刚放到SD卡的rom文件,重新运行程序即可! 。可以成功模拟五种计算器: TI89,TI89Titanium,TI92,TI92plus,Voyage200。 安装使用方法步骤: 1:把rom包解压到sd卡根目录(TI89Titanium_OS.89u为解压后的rom包)。 2:安装TI89主程序,点击菜单点击ROM Manager(看截图1)。 3:点击Add Rom(看截图2)。 4:点击Browse(看截图3)。 5:向下滑动找到刚才解压后的rom包TI89Titanium_OS.89u,点击它(看截图4)。 6:点击Select Type,再滑动选择TI89或TI92或其它三个(TI83和84系列不可用,可能比较落后,模拟器不支持,建议用TI89和TI92或Voyage200系列)(看截图5)。 注意:关闭软件方法,按住2nd键不放,再按ON键,然后放开手指即可退出软件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值