Z80 Assembly (1MHz) CP/M:如何使用按钮获得正确的物理输入
Z80 Assembly (1MHz) CP/M: How to get correct physical input using buttons
我是一名学习计算机科学的大一学生。在计算机工程中,我们正在研究 Zilog Z80 8 位微处理器 (1MHz) 和一组需要使用面包板和电缆手动连接的组件。
连接部分并不让我担心,但我确实有关于我需要编写的汇编程序的问题,以使我的程序正常工作(LED 运行宁光,手动输入行为和频率).
我已经阅读了手册并知道可以使用的指令集(仅是基本必需品)。首先,我并不是要尽可能获得最干净、最好看的代码;不过不用担心,我稍后会对其进行美化,因为我喜欢简洁高效的代码。
目前,该程序似乎 运行 在模拟器中运行良好,因此语法似乎没问题。不过,我不确定如何解决某些逻辑问题。
练习有以下规格:
- RAM起始地址:E000h
- 输入端口1:03h
- 输出端口1:05h
- I/O-mapping 端口
- 电路自动打开 (1) 所以 LED LOW-active (0)
- 输入 2、3、4 改变 LED 移动行为
- 输入 5,6 改变 LED 闪烁频率
我已经使用 ORG E000h
设置了起始地址并使用 MOV SP,FFFFh
初始化了堆栈指针。对于输入(三种不同类型的blinking/running,以及两种不同的频率,总共等于五个按钮)我创建了不同的标签。
我现在的问题是我不太确定如何让我的物理输入正确 - IIRC,我需要通过使用 XOR 来指定一个位模式,除了所需的输入之外的所有内容都是 1,这样我可以在我的程序中使用这些信息。
但即使我确实知道它的工作方式(至少我认为我知道),我还是无法完全理解软件实现。另外,我的条件有问题:按下一个开关将闪烁频率更改为 1/4 Hz,而按下另一个将其更改为 4Hz。在 higher-level 语言中,我在这里只使用 IF/ELSE,但我不知道在这种情况下该怎么做 - 遗憾的是,该手册仅包含基本操作,所以我不知所措。
因此,我想试试运气,向社区寻求帮助。
如果有兴趣,我会 post 我的代码。正如我已经提到的,这是非常基本的,但我只需要它来暂时完成工作。因为我不喜欢大块笨拙的格式化代码,所以我 post 编辑了文件 here。该文件是通过 GoogleDrive 托管的 *.txt。
感谢您的宝贵时间,祝您愉快!
[编辑] 根据用户 Ruud Helderman
的输入在 post 中添加了特定代码
[编辑] 更新了 *.txt-file 中的代码 - 现在更简单、更高效
[EDIT] 使用 HTML-formatting 突出显示 post
中的指令
具体代码片段:
blink: ;function: all LED blinking, activated via input[2]
MOV A,FFh
OUT 05h,A ;all LED out
CALL pause1 ;frequency 1/4Hz, activated via input[5]
MOV A,00h
OUT 05h,A ;all LED on
CALL pause1
JP blink ;jump back to begin of function
以上函数改变了 LED 行为(在本例中:闪烁),还改变了输入开关板上不同特定物理开关的频率,总共有 8 个开关(1 到 8,未激活状态 = 1;开关 2 到 6 是用过的)。我知道获取输入应该是小菜一碟——它应该只是使用位模式为 0 和一个 1 的 XOR 的问题。
在尝试为我的问题寻找解决方案时,我在网上发现了不同的方法,例如使用 TEST
检查特定位置上的位。不过,我的指导手册没有提到任何这样的指令,作业本身也没有提到它。
我很清楚这可能是一个微不足道的问题,也许我只是陷入了我自己因过度思考而造成的心理循环,但目前我不知道如何到达我需要的地方成为(尽管我可以在 horizon 上看到城堡 - 谢谢卡夫卡!)。
非常感谢任何帮助。
首先要注意的是:如果您使用的是 MOV
,那么您可能使用的是 8080 语法而不是 Z80 语法。由于历史法律原因,Z80 不仅扩展了 8080 的汇编语言,它还重命名了所有现有的助记符(例如,MOV
到 LD
)。如果您正在搜索 Z80 代码并找到您不认识的指令,那很可能是其中的一部分。
实现if/else-type条件的常用方法是:
- 以适当的方式执行任何设置状态标志的操作;和
- 使用条件跳转之一来跳过某些代码或不跳过,具体取决于状态标志。
在你的情况下,你想做某事或不做某事取决于是否设置了某个位,所以一种方法是 ANI
(z80: AND
)。它计算累加器和操作数的逻辑与,将其存储在累加器中,但除其他外,它还设置了零标志。因此,您可以使用 JNZ
(/JP NZ
) 和 JZ
(/JP Z
) 根据是否设置位来做某事或不做某事。例如
; upon entry, A has an unknown value, loaded from somewhere.
ANI 08h ; Set a = a & 8; so either bit 2 was originally set and a now
; has the value 8, or bit 2 wasn't set and a now has the value 0.
; Also: the zero flag is now set if a is zero, reset otherwise.
; So you've loaded NOT (a.bit2) into the zero flag.
; You've also lost the rest of the accumulator, but such is life.
; Keep a copy somewhere, or grab it again via IN as required.
JZ bitnotset
; code here will be performed only if bit 2 was originally unset.
bitnotset:
; this code will happen regardless of whether bit 2 was set.
我不知道 8080 或 Z80 风格的语法中有 TEST
。
您可能还会看到一种破坏性较小且效率稍高的解决方案,通过将它们移入进位位来按顺序测试字节中的多个位。这是另一种选择,但不一定值得担心,除非你的课程笔记强烈暗示这是你应该关注的方向。
经过几天的思考和绞尽脑汁,在大家的帮助下,我终于找到了解决问题的办法。最后,我最担心的是我不知道如何正确检查输入。
如我所料,问题出在我的错误观念上,幸运的是我的实验室伙伴纠正了我的错误观念。所以,毕竟,我们能够让我们的程序运行 - 最后一分钟而不是 100%,但它运行并满足要求。
那么我的误解是什么?有趣的是,我知道我们必须去哪里,而且这个想法是正确的。问题是我跳过了逻辑运算的主要部分——我已经在脑海中计算过了,然后将实际工作的解决方案与一个过时的 AND
结合起来,这破坏了功能。
总而言之,XOR
和 AND
的正确组合如下:
programloop:
MOV A,40h ;state of button 2, inverted (XOR FFh)
MOV B,A ;save state to register B
IN A,03h ;input at port-address 03h
AND B ;find out if button is pressed
JPNZ blink ;if yes, jump to blink
MOV A,20h ;state of button 3, inverted (XOR FFh)
MOV B,A ;save state to register B
IN A,03h ;input at port-address 03h
AND B ;find out if button is pressed
JPNZ goright ;if yes, jump to goright
MOV A,10h ;state of button 4, inverted (XOR FFh)
MOV B,A ;save state to register B
IN A,03h ;input at port-address 03h
AND B ;find out if button is pressed
JPNZ goleft ;if yes, jump to goleft
JP programloop ;go back to beginning (input has to be checked constantly)
这对改变 LED 行为的三个按钮起到了作用。
关于频率,由于时间紧迫,我们不得不将复杂性降低到只有两个状态(我们误读了作业并错误地从奖励问题开始,这花费了我们大约 50% 的开发时间 - 是的,我们. 经验教训:始终 从顶部开始阅读并仔细阅读。)
但是由于频率的改变起作用了,所以结果是 OK。
MOV A,03h ;state of button five being pressed (inverted)
MOV B,A ;saved state into register B for later use
IN A,03h ;physical input over button
AND B ;find out if button is pressed
JPNZ freq025Hz ;if yes, jump to freq025Hz
JPZ freq4Hz ;if no, jump to freq4Hz
就是这样!
再次感谢大家的帮助。
如有任何问题,欢迎随时提问!
我是一名学习计算机科学的大一学生。在计算机工程中,我们正在研究 Zilog Z80 8 位微处理器 (1MHz) 和一组需要使用面包板和电缆手动连接的组件。
连接部分并不让我担心,但我确实有关于我需要编写的汇编程序的问题,以使我的程序正常工作(LED 运行宁光,手动输入行为和频率).
我已经阅读了手册并知道可以使用的指令集(仅是基本必需品)。首先,我并不是要尽可能获得最干净、最好看的代码;不过不用担心,我稍后会对其进行美化,因为我喜欢简洁高效的代码。
目前,该程序似乎 运行 在模拟器中运行良好,因此语法似乎没问题。不过,我不确定如何解决某些逻辑问题。
练习有以下规格:
- RAM起始地址:E000h
- 输入端口1:03h
- 输出端口1:05h
- I/O-mapping 端口
- 电路自动打开 (1) 所以 LED LOW-active (0)
- 输入 2、3、4 改变 LED 移动行为
- 输入 5,6 改变 LED 闪烁频率
我已经使用 ORG E000h
设置了起始地址并使用 MOV SP,FFFFh
初始化了堆栈指针。对于输入(三种不同类型的blinking/running,以及两种不同的频率,总共等于五个按钮)我创建了不同的标签。
我现在的问题是我不太确定如何让我的物理输入正确 - IIRC,我需要通过使用 XOR 来指定一个位模式,除了所需的输入之外的所有内容都是 1,这样我可以在我的程序中使用这些信息。
但即使我确实知道它的工作方式(至少我认为我知道),我还是无法完全理解软件实现。另外,我的条件有问题:按下一个开关将闪烁频率更改为 1/4 Hz,而按下另一个将其更改为 4Hz。在 higher-level 语言中,我在这里只使用 IF/ELSE,但我不知道在这种情况下该怎么做 - 遗憾的是,该手册仅包含基本操作,所以我不知所措。
因此,我想试试运气,向社区寻求帮助。
如果有兴趣,我会 post 我的代码。正如我已经提到的,这是非常基本的,但我只需要它来暂时完成工作。因为我不喜欢大块笨拙的格式化代码,所以我 post 编辑了文件 here。该文件是通过 GoogleDrive 托管的 *.txt。
感谢您的宝贵时间,祝您愉快!
[编辑] 根据用户 Ruud Helderman
的输入在 post 中添加了特定代码[编辑] 更新了 *.txt-file 中的代码 - 现在更简单、更高效
[EDIT] 使用 HTML-formatting 突出显示 post
中的指令具体代码片段:
blink: ;function: all LED blinking, activated via input[2]
MOV A,FFh
OUT 05h,A ;all LED out
CALL pause1 ;frequency 1/4Hz, activated via input[5]
MOV A,00h
OUT 05h,A ;all LED on
CALL pause1
JP blink ;jump back to begin of function
以上函数改变了 LED 行为(在本例中:闪烁),还改变了输入开关板上不同特定物理开关的频率,总共有 8 个开关(1 到 8,未激活状态 = 1;开关 2 到 6 是用过的)。我知道获取输入应该是小菜一碟——它应该只是使用位模式为 0 和一个 1 的 XOR 的问题。
在尝试为我的问题寻找解决方案时,我在网上发现了不同的方法,例如使用 TEST
检查特定位置上的位。不过,我的指导手册没有提到任何这样的指令,作业本身也没有提到它。
我很清楚这可能是一个微不足道的问题,也许我只是陷入了我自己因过度思考而造成的心理循环,但目前我不知道如何到达我需要的地方成为(尽管我可以在 horizon 上看到城堡 - 谢谢卡夫卡!)。
非常感谢任何帮助。
首先要注意的是:如果您使用的是 MOV
,那么您可能使用的是 8080 语法而不是 Z80 语法。由于历史法律原因,Z80 不仅扩展了 8080 的汇编语言,它还重命名了所有现有的助记符(例如,MOV
到 LD
)。如果您正在搜索 Z80 代码并找到您不认识的指令,那很可能是其中的一部分。
实现if/else-type条件的常用方法是:
- 以适当的方式执行任何设置状态标志的操作;和
- 使用条件跳转之一来跳过某些代码或不跳过,具体取决于状态标志。
在你的情况下,你想做某事或不做某事取决于是否设置了某个位,所以一种方法是 ANI
(z80: AND
)。它计算累加器和操作数的逻辑与,将其存储在累加器中,但除其他外,它还设置了零标志。因此,您可以使用 JNZ
(/JP NZ
) 和 JZ
(/JP Z
) 根据是否设置位来做某事或不做某事。例如
; upon entry, A has an unknown value, loaded from somewhere.
ANI 08h ; Set a = a & 8; so either bit 2 was originally set and a now
; has the value 8, or bit 2 wasn't set and a now has the value 0.
; Also: the zero flag is now set if a is zero, reset otherwise.
; So you've loaded NOT (a.bit2) into the zero flag.
; You've also lost the rest of the accumulator, but such is life.
; Keep a copy somewhere, or grab it again via IN as required.
JZ bitnotset
; code here will be performed only if bit 2 was originally unset.
bitnotset:
; this code will happen regardless of whether bit 2 was set.
我不知道 8080 或 Z80 风格的语法中有 TEST
。
您可能还会看到一种破坏性较小且效率稍高的解决方案,通过将它们移入进位位来按顺序测试字节中的多个位。这是另一种选择,但不一定值得担心,除非你的课程笔记强烈暗示这是你应该关注的方向。
经过几天的思考和绞尽脑汁,在大家的帮助下,我终于找到了解决问题的办法。最后,我最担心的是我不知道如何正确检查输入。
如我所料,问题出在我的错误观念上,幸运的是我的实验室伙伴纠正了我的错误观念。所以,毕竟,我们能够让我们的程序运行 - 最后一分钟而不是 100%,但它运行并满足要求。
那么我的误解是什么?有趣的是,我知道我们必须去哪里,而且这个想法是正确的。问题是我跳过了逻辑运算的主要部分——我已经在脑海中计算过了,然后将实际工作的解决方案与一个过时的 AND
结合起来,这破坏了功能。
总而言之,XOR
和 AND
的正确组合如下:
programloop:
MOV A,40h ;state of button 2, inverted (XOR FFh)
MOV B,A ;save state to register B
IN A,03h ;input at port-address 03h
AND B ;find out if button is pressed
JPNZ blink ;if yes, jump to blink
MOV A,20h ;state of button 3, inverted (XOR FFh)
MOV B,A ;save state to register B
IN A,03h ;input at port-address 03h
AND B ;find out if button is pressed
JPNZ goright ;if yes, jump to goright
MOV A,10h ;state of button 4, inverted (XOR FFh)
MOV B,A ;save state to register B
IN A,03h ;input at port-address 03h
AND B ;find out if button is pressed
JPNZ goleft ;if yes, jump to goleft
JP programloop ;go back to beginning (input has to be checked constantly)
这对改变 LED 行为的三个按钮起到了作用。
关于频率,由于时间紧迫,我们不得不将复杂性降低到只有两个状态(我们误读了作业并错误地从奖励问题开始,这花费了我们大约 50% 的开发时间 - 是的,我们. 经验教训:始终 从顶部开始阅读并仔细阅读。)
但是由于频率的改变起作用了,所以结果是 OK。
MOV A,03h ;state of button five being pressed (inverted)
MOV B,A ;saved state into register B for later use
IN A,03h ;physical input over button
AND B ;find out if button is pressed
JPNZ freq025Hz ;if yes, jump to freq025Hz
JPZ freq4Hz ;if no, jump to freq4Hz
就是这样!
再次感谢大家的帮助。
如有任何问题,欢迎随时提问!