@wxy
https://linux.cn/article-15461-1.html
This commit is contained in:
Xingyu Wang 2023-01-20 19:02:56 +08:00
parent 27de8fe5be
commit ed81c0e26e
2 changed files with 215 additions and 210 deletions

View File

@ -0,0 +1,215 @@
[#]: subject: "Learn to code with my retro computer program"
[#]: via: "https://opensource.com/article/23/1/learn-machine-language-retro-computer"
[#]: author: "Jim Hall https://opensource.com/users/jim-hall"
[#]: collector: "lkxed"
[#]: translator: "wxy"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-15461-1.html"
用复古电脑程序 Toy CPU 学习低级编程
======
![][0]
> 我写了一个名为 “Toy CPU” 的教育性复古计算机程序,以便我的学生能够学习机器语言。
我兼职教授大学课程,包括一个对所有专业开放的一般计算机主题的课程。这是一门入门课程,向学生讲授技术是如何运作的,以消除围绕计算的神秘感。
虽然不是计算机科学课程,但这门课的一个部分涉及计算机编程。我通常用非常抽象的术语谈论编程,所以不会让听众听不懂。但是今年,我想让我的学生以 “老派” 的方式做一些需要 “动手” 的编程。同时,我又想保持简单,以便让每个人都能跟上。
我喜欢将我的课程结构化,以显示你是如何从 “那里” 到 “这里” 的。理想情况下,我会让我的学生学习如何编写一个简单的程序。然后,我将从这里开始,展示现代编程是如何让开发人员创建更复杂的程序的。我决定尝试一种非常规的方法 —— 教学生学习终极的低级别编程语言:机器语言。
### 机器语言编程
早期的个人电脑如 Apple II1977 年、TRS-801977 年)和 IBM PC1981 年)让用户用键盘输入程序,并在屏幕上显示结果。但计算机并不总是带有屏幕和键盘。
Altair 8800 和 IMSAI 8080均为 1975 年制造)要求用户使用面板上的 “开关和灯” 输入程序。你可以用机器语言输入指令,使用一组开关,机器会点亮 LED 灯以代表每个二进制指令的 1 和 0。
![Altair 8800 计算机的图片][1]
对这些早期机器进行编程,需要了解被称为 “<ruby>操作码<rt>opcode</rt></ruby>” (操作代码的简称)的机器语言指令,以执行基本操作,如将两个数字相加或将一个值存储到计算机的存储器中。我想向我的学生展示程序员是如何通过开关和灯,手工输入一系列指令和内存地址的。
然而,在这门课上,使用实际的 Altair 8800 就有点太复杂了。我需要一些简单的、任何初级水平的学生都能掌握的东西。理想情况下,我希望能找到一个简单的 “业余” 复古计算机,其工作原理与 Altair 8800 相似,但我无法找到一个价格低于 100 美元的合适的 “类似 Altair” 的设备。我找到了几个 “Altair” 软件模拟器,但它们忠实地再现了 Altair 8800 的操作码,这对我的需求来说太过沉重。
我决定编写我自己的 “教育” 复古计算机。我称它为 “Toy CPU”。你可以在我的 [GitHub 代码库][2] 上找到它,包括几个可以运行的版本。第一版是一个实验性的原型,运行在 [FreeDOS][3] 上。第二版是一个更新的原型,在 Linux 上用 [ncurses][4] 运行。版本 3 是一个 FreeDOS 程序,在图形模式下运行。
### Toy CPU 的编程
Toy CPU 是一个非常简单的复古计算机。它只有 256 字节的内存和一个最小化的指令集,其目的是在复制 “开关和灯” 编程模式的同时保持简单化。它的界面模仿 Altair 8800有一系列 8 个 LED 灯,分别代表计数器(程序的 “行号”)、指令、累积器(用于临时数据的内部存储器)和状态。
当你启动 Toy CPU 时,它通过清除内存来模拟 “启动”。当它启动时,它也会在屏幕右下方的状态灯中显示 “INI”初始化。“PWR”电源灯亮表示 Toy CPU 已被打开。
![Toy CPU 的启动屏幕][5]
当 Toy CPU 准备好让你进入一个程序时,它通过状态灯指示 “INP”“输入”模式并让你从程序的计数器 0 开始。Toy CPU 的程序总是从计数器 0 开始。
在 “输入” 模式下,用上下方向键显示不同的程序计数器,按回车键编辑当前计数器上的指令。当你进入 “编辑” 模式时Toy CPU 的状态灯上会显示 “EDT”“编辑” 模式)。
![Toy CPU 编辑屏幕][6]
Toy CPU 有一张速查表,被 “贴” 在显示屏的前面。它列出了 Toy CPU 可以处理的不同操作码。
- `00000000``STOP`):停止程序执行。
- `00000001``RIGHT`):将累加器中的位向右移动一个位置。值 `00000010` 变成 `00000001``00000001` 变成 `00000000`
- `00000010``LEFT`):将累加器中的位向左移动一个位置。值 `01000000` 变成 `10000000``10000000` 变成 `00000000`
- `00001111``NOT`):对累加器进行二进制非操作。例如,值 `10001000` 变成 `01110111`
- `00010001``AND`):对累加器用存储在某一地址的值进行二进制与操作。该地址被存储在下一个计数器中。
- `00010010``OR`):对累积器用存储在某一地址的值进行二进制或运算。
- `00010011``XOR`):对累加器用存储在某一地址的值进行二进制异或运算。
- `00010100``LOAD`):将一个地址的值加载(复制)到累加器中。
- `00010101``STORE` 存储(复制)累加器中的值到一个地址。
- `00010110``ADD`):将存储在某一地址的数值加入到累加器中。
- `00010111``SUB`):从累积器中减去储存在某一地址的数值。
- `00011000``GOTO`):转到(跳到)一个计数器地址。
- `00011001``IFZERO`):如果累加器为零,转到(跳到)一个计数器地址。
- `10000000``NOP`):空操作,可以安全地忽略。
当处于 “编辑” 模式时使用左右方向键选择操作码中的一个位然后按空格键在关闭0和开启1之间翻转数值。当你完成编辑后按回车键回到 “输入” 模式。
![Toy CPU 输入模式屏幕][7]
### 一个示例程序
我想通过输入一个简短的程序来探索 Toy CPU将两个数值相加并将结果存储在 Toy CPU 的内存中。实际上,这执行的是算术运算 `A+B=C`。要创建这个程序,你只需要几个操作码:
- `00010100``LOAD`
- `00010110``ADD`
- `00010101``STORE`
- `00000000``STOP`
`LOAD`、`ADD` 和 `STORE` 指令需要一个内存地址,这个地址总是在下一个计数器的位置。例如,程序的前两条指令是:
```
计数器 000010100
计数器 1某个内存地址第一个值 A 存放在那里
```
计数器 0 中的指令是 `LOAD` 操作,计数器 1 中的值是你存储某个值的内存地址。这两条指令一起将内存中的数值复制到 Toy CPU 的累加器中,在那里你可以对该数值进行操作。
将一个数字 `A` 装入累加器后,你需要将数值 `B` 加到它上面。你可以用这两条指令来做:
```
计数器 200010110
计数器 3存储第二个值 B 的内存地址
```
假设你把值 `1``A`)装入累加器,然后把值 `3``B`)加到它上面。现在累加器的值是 `4`。现在你需要用这两条指令把数值 `4` 复制到另一个内存地址(`C`
```
计数器 400010101
计数器 5一个内存地址C我们可以在那里保存新的值
```
把这两个值加在一起后,现在可以用这条指令结束程序:
```
计数器 6: 00000000
```
计数器 6 之后的任何指令都可以供程序作为存储内存使用。这意味着你可以用计数器 7 的内存来储存值 `A`,计数器 8 的内存来储存值 `B` ,计数器 9 的内存来储存值 `C`。你需要将这些分别输入到 Toy CPU 中:
```
计数器 7000000011
计数器 8000000113
计数器 9000000000以后会被覆盖
```
在弄清了所有指令和 `A`、`B` 和 `C` 的内存位置后,现在可以将完整的程序输入到 Toy CPU 中。这个程序将数值 1 和 3 相加,得到 4
```
计数器 000010100
计数器 1000001117
计数器 200010110
计数器 3000010008
计数器 400010101
计数器 5000010019
计数器 600000000
计数器 7000000011
计数器 8000000113
计数器 9000000000以后会被覆盖
```
要运行程序,在 “输入” 模式下按下 `R` 键。Toy CPU 将在状态灯中显示 “RUN”“运行” 模式),并从计数器 0 开始执行你的程序。
Toy CPU 有一个明显的延迟,所以你可以看到它执行程序中的每一步。随着程序的进行,你应该看到计数器从 `00000000`0移动到 `00000110`6。在计数器 1 之后,程序从内存位置 7 加载数值 `1`,累积器更新为 `00000001`1。在计数器 3 之后,程序将加数值 `3`,并更新累加器显示 `00000100`4。累加器将保持这种状态直到程序在计数器 5 之后将数值存入内存位置 9然后在计数器 6 结束。
![在运行模式下的 Toy CPU][8]
### 探索机器语言编程
你可以使用 Toy CPU 来创建其他程序,并进一步探索机器语言编程。通过用机器语言编写这些程序来测试你的创造力。
### 一个在累积器上闪灯的程序
你能点亮累加器上的右四位,然后是左四位,然后是所有的位吗?你可以用两种方法之一来写这个程序。
一种直接的方法是,从不同的内存地址加载三个数值,像这样:
```
计数器 0LOAD
计数器 1“右边”
计数器 2LOAD
计数器 3“左边”
计数器 4LOAD
计数器 5“所有”
计数器 6STOP
计数器 700001111“右边”
计数器 811110000“左边”
计数器 911111111“全部”
```
写这个程序的另一种方法是尝试使用 `NOT``OR` 二进制操作。这样可以得到一个更小的程序:
```
计数器 0LOAD
计数器 1“右边”
计数器 2NOT
计数器 3OR
计数器 4“右边”
计数器 5STOP
计数器 600001111“右边”
```
### 从一个数字开始倒数
你可以把 Toy CPU 作为一个倒数计时器。这个程序行使 `IFZERO` 测试,只有当累加器为零时,程序才会跳转到一个新的计数器:
```
计数器 0LOAD
计数器 1“初始值”
计数器 2IFZERO这也是倒计时的“开始”
计数器 3“结束”
计数器 4SUB
计数器 5“1”
计数器 6GOTO
计数器 7“开始”
计数器 8STOP
计数器 900000111“初始值”
计数器 1000000001“1”
```
Toy CPU 是学习机器语言的一个好方法。我在入门课程中使用了 Toy CPU学生们说他们发现写第一个程序很困难但写下一个程序就容易多了。学生们还表示用这种方式编写程序其实很有趣他们学到了很多关于计算机实际工作的知识。Toy CPU 既具有教育性,也很有趣味性!
--------------------------------------------------------------------------------
via: https://opensource.com/article/23/1/learn-machine-language-retro-computer
作者:[Jim Hall][a]
选题:[lkxed][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jim-hall
[b]: https://github.com/lkxed
[1]: https://opensource.com/sites/default/files/2022-12/MITS_Altair_8800_Computer_%281975%29.png
[2]: https://github.com/freedosproject/toycpu
[3]: https://opensource.com/downloads/guide-using-freedos
[4]: https://opensource.com/article/21/8/ncurses-linux
[5]: https://opensource.com/sites/default/files/2022-12/toycpu.png
[6]: https://opensource.com/sites/default/files/2022-12/edit0-load.png
[7]: https://opensource.com/sites/default/files/2022-12/input0-load.png
[8]: https://opensource.com/sites/default/files/2022-12/run-3.png
[0]: https://opensource.com/sites/default/files/lead-images/retro_old_unix_computer.png

View File

@ -1,210 +0,0 @@
[#]: subject: "Learn to code with my retro computer program"
[#]: via: "https://opensource.com/article/23/1/learn-machine-language-retro-computer"
[#]: author: "Jim Hall https://opensource.com/users/jim-hall"
[#]: collector: "lkxed"
[#]: translator: " "
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
Learn to code with my retro computer program
======
I teach university courses part-time, including a class about general computing topics, open to all majors. This is an introductory course that teaches students about how technology works, to remove the mystery around computing.
While not a computer science course, one section of this course covers computer programming. I usually talk about programming in very abstract terms, so I don't lose my audience. But this year, I wanted my students to do some "hands-on" programming in an "old school" way. At the same time, I wanted to keep it simple, so everyone could follow along.
I like to structure my lessons to show how you got from "there" to "here." Ideally, I would let my students learn how to write a simple program. Then I would pick it up from there to show how modern programming allows developers to create more complex programs. I decided to try an unconventional approach — teach the students about the ultimate in low-level programming: machine language.
### Machine language programming
Early personal computers like the Apple II (1977), TRS-80 (1977), and IBM PC (1981) let users enter programs with a keyboard, and displayed results on a screen. But computers didn't always come with a screen and keyboard.
The Altair 8800 and IMSAI 8080 (both made in 1975) required users to enter a program using "switches and lights" on a panel. You would enter an instruction in machine language, using a bank of switches, and the machine would light up the ones and zeros of each binary instruction using LEDs.
![Image of an Altair 8800 Computer.][1]
Programming these early machines required knowing the machine language instructions, called opcodes, short for operation codes, to perform basic operations like adding two numbers or storing a value into the computer's memory. I wanted to show my students how programmers would enter a series of instructions and memory addresses by hand, using the switches and lights.
However, using an actual Altair 8800 would be too much overhead in this class. I needed something simple that any beginner-level student could grasp. Ideally, I hoped to find a simple "hobby" retro computer that worked similarly to the Altair 8800, but I couldn't find a suitable "Altair-like" device for less than $100. I found several "Altair" software emulators, but they faithfully reproduce the Altair 8800 opcodes, and that was too much for my needs.
I decided to write my own "educational" retro computer. I call it the Toy CPU. You can find it on my [GitHub repository][2], including several releases to play with. Version 1 was an experimental prototype that ran on [FreeDOS][3]. Version 2 was an updated prototype that ran on Linux with [ncurses][4]. Version 3 is a FreeDOS program that runs in graphics mode.
### Programming the Toy CPU
The Toy CPU is a very simple retro computer. Sporting only 256 bytes of memory and a minimal instruction set, the Toy CPU aims for simplicity while replicating the "switches and lights" programming model. The interface mimics the Altair 8800, with a series of eight LEDs for the counter (the "line number" for the program), instruction, accumulator (internal memory used for temporary data), and status.
When you start the Toy CPU, it simulates "booting" by clearing the memory. While the Toy CPU is starting up, it also displays `INI` ("initialize") in the status lights at the bottom-right of the screen. The `PWR` ("power") light indicates the Toy CPU has been turned on.
![Image of start screen for the toy cpu.][5]
When the Toy CPU is ready for you to enter a program, it indicates `INP` ("input" mode) via the status lights, and starts you at counter 0 in the program. Programs for the Toy CPU always start at counter 0.
In "input" mode, use the up and down arrow keys to show the different program counters, and press Enter to edit the instruction at the current counter. When you enter "edit" mode, the Toy CPU shows `EDT` ("edit" mode) on the status lights.
![Image of the toy CPU editing screen.][6]
The Toy CPU has a cheat sheet that's "taped" to the front of the display. This lists the different opcodes the Toy CPU can process:
- `00000000` (`STOP`): Stop program execution.
- `00000001` (`RIGHT`): Shift the bits in the accumulator to the right by one position. The value 00000010 becomes 00000001, and 00000001 becomes 00000000.
- `00000010` (`LEFT`): Shift the bits in the accumulator to the left by one position. The value 01000000 becomes 10000000, and 10000000 becomes 00000000.
- `00001111` (`NOT`): Binary NOT the accumulator. For example, the value 10001000 becomes 01110111.
- `00010001` (`AND`): Binary AND the accumulator with the value stored at an address. The address is stored in the next counter.
- `00010010` (`OR`): Binary OR the accumulator with the value stored at an address.
- `00010011` (`XOR`): Binary XOR (“exclusive or”) the accumulator with the value stored at an address.
- `00010100` (`LOAD`): Load (copy) the value from an address into the accumulator.
- `00010101` (`STORE`): Store (copy) the value in the accumulator into an address.
- `00010110` (`ADD`): Add the value stored at an address to the accumulator.
- `00010111` (`SUB`): Subtract the value stored at an address from the accumulator.
- `00011000` (`GOTO`): Go to (jump to) a counter address.
- `00011001` (`IFZERO`): If the accumulator is zero, go to (jump to) a counter address.
- `10000000` (`NOP`): No operation; safely ignored.
When in "edit" mode, use the left and right arrow keys to select a bit in the opcode, and press `Space`to flip the value between off (0) and on (1). When you are done editing, press `Enter`to go back to "input" mode.
![Image of the toy CPU input mode screen.][7]
### A sample program
I want to explore the Toy CPU by entering a short program that adds two values, and stores the result in the Toy's memory. Effectively, this performs the arithmetic operation **A+B=C**. To create this program, you only need a few opcodes:
- `00010100` (`LOAD`): Load (copy) the value from an address into the accumulator.
- `00010110` (`ADD`): Add the value stored at an address to the accumulator.
- `00010101` (`STORE`): Store (copy) the value in the accumulator into an address.
- `00000000` (`STOP`): Stop program execution.
The `LOAD`, `ADD`, and `STORE` instructions require a memory address, which will always be in the next counter location. For example, the first two instructions of the program are:
```
counter 0: 00010100
counter 1: some memory address where the first value A is stored
```
The instruction in counter 0 is the `LOAD`operation, and the value in counter 1 is the memory address where you have stored some value. The two instructions together copy a value from memory into the Toy's accumulator, where you can work on the value.
Having loaded a number **A** into the accumulator, you need to add the value **B** to it. You can do that with these two instructions:
```
counter 2: 00010110
counter 3: a memory address where the second value B is stored
```
Say that you loaded the value 1 (**A**) into the accumulator, then added the value 3 (**B**) to it. The accumulator will now have the value 4. Now you need to copy the value 4 into another memory address (**C**) with these two instructions:
```
counter 4: 00010101
counter 5: a memory address (C) where we can save the new value
```
Having added the two values together, you can now end the program with this instruction:
```
counter 6: 00000000
```
Any instructions after counter 6 are available for the program to use as stored memory. That means you can use the memory at counter 7 for the value **A**, the memory in counter 8 for the value **B**, and the memory at counter 9 for the stored value **C**. You need to enter these separately into the Toy:
```
counter 7: 00000001 (1)
counter 8: 00000011 (3)
counter 9: 00000000 (0, will be overwritten later)
```
Having figured out all the instructions and the memory locations for **A**, **B**, and **C**, you can now enter the full program into the Toy. This program adds the values 1 and 3 to get 4:
```
counter 0: 00010100
counter 1: 00000111 (7)
counter 2: 00010110
counter 3: 00001000 (8)
counter 4: 00010101
counter 5: 00001001 (9)
counter 6: 00000000
counter 7: 00000001 (1)
counter 8: 00000011 (3)
counter 9: 00000000 (0, will be overwritten later)
```
To run the program, press the `R` key when in "input" mode. The Toy CPU will show `RUN` ("run" mode) in the status lights, and execute your program starting at counter 0.
The Toy has a significant delay built into it, so you can watch the Toy execute each step in the program. You should see the counter move from 00000000 (0) to 00000110 (6) as the program progresses. After counter 1, the program loads the value 1 from memory location 7, and the accumulator updates to 00000001 (1). After counter 3, the program will add the value 3 and update the accumulator to show 00000100 (4). The accumulator will remain that way until the program stores the value into memory location 9 after counter 5 then ends at counter 6.
![Image of the Toy in RUN mode.][8]
### Exploring machine language programming
You can use the Toy to create other programs and further explore machine language programming. Test your creativity by writing these programs in machine language.
### A program to flash the lights on the accumulator
Can you light up the right four bits on the accumulator, then the left four bits, then all of the bits? You can write this program in one of two ways:
A straightforward approach would be to load three values from different memory addresses, like this:
```
counter 0: LOAD
counter 1: "right"
counter 2: LOAD
counter 3: "left"
counter 4: LOAD
counter 5: "all"
counter 6: STOP
counter 7: 00001111 ("right")
counter 8: 11110000 ("left")
counter 9: 11111111 ("all")
```
Another way to write this program is to experiment with the NOT and OR binary operations. This results in a smaller program:
```
counter 0: LOAD
counter 1: "right"
counter 2: NOT
counter 3: OR
counter 4: "right"
counter 5: STOP
counter 6: 00001111 ("right")
```
### Count down from a number
You can use the Toy as a countdown timer. This program exercises the IFZERO test, which will jump the program to a new counter only if the accumulator is zero:
```
counter 0: LOAD
counter 1: "initial value"
counter 2: IFZERO (this is also the "start" of the countdown)
counter 3: "end"
counter 4: SUB
counter 5: "one"
counter 6: GOTO
counter 7: "start"
counter 8: STOP
counter 9: 00000111 ("initial value")
counter 10: 00000001 ("one")
```
The Toy CPU is a great way to learn about machine language. I used the Toy CPU in my introductory course, and the students said they found it difficult to write the first program, but writing the next one was much easier. The students also commented that writing programs in this way was actually fun, and they learned a lot about how computers actually work. The Toy CPU is educational and fun!
--------------------------------------------------------------------------------
via: https://opensource.com/article/23/1/learn-machine-language-retro-computer
作者:[Jim Hall][a]
选题:[lkxed][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jim-hall
[b]: https://github.com/lkxed
[1]: https://opensource.com/sites/default/files/2022-12/MITS_Altair_8800_Computer_%281975%29.png
[2]: https://github.com/freedosproject/toycpu
[3]: https://opensource.com/downloads/guide-using-freedos
[4]: https://opensource.com/article/21/8/ncurses-linux
[5]: https://opensource.com/sites/default/files/2022-12/toycpu.png
[6]: https://opensource.com/sites/default/files/2022-12/edit0-load.png
[7]: https://opensource.com/sites/default/files/2022-12/input0-load.png
[8]: https://opensource.com/sites/default/files/2022-12/run-3.png