我有一个大学作业。我需要为 z80 处理器编写一个汇编程序。该程序应执行以下操作。
从 0201H 开始的 20 个连续内存地址中存储了 20 个数字。程序应首先检查存储在 0200H 中的数字。如果值为 0,则程序应按升序对数字进行排序,否则按降序排序。最后在排序结束后,程序应该计算这 20 个数字的平均值。
我知道这个问题不是根据网站的规则形成的,但我真的需要帮助。
我有一个大学作业。我需要为 z80 处理器编写一个汇编程序。该程序应执行以下操作。
从 0201H 开始的 20 个连续内存地址中存储了 20 个数字。程序应首先检查存储在 0200H 中的数字。如果值为 0,则程序应按升序对数字进行排序,否则按降序排序。最后在排序结束后,程序应该计算这 20 个数字的平均值。
我知道这个问题不是根据网站的规则形成的,但我真的需要帮助。
这是 Z-80 汇编语言的快速指南。把它想象成 C,但删除了大部分功能。从根本上说,您只有几个变量可以使用:
unsigned char A;
unsigned short BC, DE, HL, IX, IY;
unsigned char memory[65536];
没有结构,没有块,没有 for 或 while 循环和一种 mangled if
。有goto
哪个会跳转到一个标签。或者您可以call
使用一个类似于子例程但不带参数并返回 void 的标签。我们总是可以从这些部分构建更多功能,但对于简单的程序,我们拥有的变量和一些部分memory[]
就足够了。
您可以=
用于分配,但有很多规则。例如,所有这些都是合法的:
A = memory[26];
memory[738] = A;
A = memory[BC];
memory[DE] = A;
但是您不能使用任何旧表达式,例如:
A = memory[BC + DE];
short
变量可以分配给和分配,但memory[]
因为它们比char
它们自动拆分的要大。当您说它memory[15] = BC;
认识到它不适合并代表您执行此操作时:
memory[15] = BC % 256;
memory[16] = BC / 256;
为了有用,当您说时会发生相反的情况BC = memory[15]
:
BC = memory[15] + memory[16] * 256;
更奇怪的是,您可以将这些高低部分BC
独立地讨论为B
和C
。但你不能这样做B = memory[25]
。如果你想这样,你需要A
在中间使用:
A = memory[25];
B = A;
DE
可以处理为D
andE
和HL
as H
and L
。但不是IX
和IY
(好吧,不是合法的,但我们不要进入那个)。
所有变量都可以递增和递减。 A = A + 1
或者A++
如果你喜欢。 A = A - 1
. 与BC
, DE
, HL
, IX
,B
等相同C
。
你能做到D = D + 2
吗?不!你必须做D++; D++;
。说到数学,A
很特别。您可以向其添加任何无符号字符或常量。或减去。有一些逻辑运算,例如,&
但我们不必担心这些。您还可以添加或减去我们的任何变量,例如或。但是你不能加或减。这也必须分段完成。假设你想要:|
^
unsigned char
D
L
memory[]
A = A + memory[84]
B = A; // save A
A = memory[84];
A = A + B;
是的,它会变得乏味。人们开始欣赏编译器。您还可以对 HL、IX 和 IY 进行加减运算,但在更有限的情况下:
HL = HL + BC;
HL = HL + DE;
HL = HL + HL; // Same as HL = 2 * HL.
IX = IX + BC;
IX = IX + DE;
IX = IX + IX;
// And follow the same pattern for IY
乘法和除法呢?不,不支持。不过,使用循环和位移运算符,您可以设法模拟它们。或者效率较低,您可以通过重复加法和重复减法进行乘法运算。
但是,无论如何,循环呢?好吧,你可以用这样的东西填充内存:
HL = 9; // You can assign constants to all your variables, thankfully.
A = 0;
loop:
memory[HL] = A;
HL = HL + 1;
goto loop;
我有没有提到你的程序住在memory[]
? 不?嗯,它确实是个问题。如果你只想清除 10 个memory[]
,你会怎么做?这就是精神错乱的地方if
。你想写这样的东西:
HL = 9;
A = 0;
B = 10;
loop:
memory[HL] = A;
HL++;
B = B - 1;
if (B == 0) goto loop
[哎呀,这是一个错误。应该是!= 0,但假装它是正确的;我懒得重新输入这一切。] 但if (B == 0)
不是支持的东西。太复杂。但是有一个是goto loop if zero;
什么意思?好吧,每次你做数学运算时,处理器都会记住一些关于结果的事情。一种是结果是否为零。事实证明,我们可以简单地将其替换if
为:
goto loop if zero;
我们将循环 10 次。我们甚至可以将代码概括为,例如,清除memory[]
由 给出的多个条目C
。如何?B
只要它不等于,就向上计数并循环回来C
。我们不能这样做if (B == C)
,但我们可以减去B
并C
检查零结果,这是同样的事情。好吧,我们做不到C = C - B
,只有A可以做到。循环看起来像这样:
loop:
memory[HL] = 0; // turns out we can do this
HL = HL + 1;
B = B + 1;
A = C;
A = A - B;
goto done if zero;
goto loop;
done:
尴尬,但它会工作。设计师有些仁慈。goto
如果结果不为零,您可以:
A = A - B;
goto loop if not zero;
如果结果小于或大于零,则允许进行一些其他测试。但是针对零的简单测试可以让我们走得更远。
特殊情况比比皆是。如果我们不小心写了这个怎么办:
loop:
memory[HL] = 0;
B = B - 1;
HL = HL + 1;
goto loop if not-zero;
看起来像一个错误,不是吗。我们不会进行B
迭代,而是继续进行直到HL
环绕到 0。但事实并非如此。当我们添加或减去一个短值时,HL
它不会影响zero/not-zero
条件。该代码将起作用。事实上,这被 Z-80 的设计者认为是一项功能。
如果你愿意的话,我将提到的唯一另一件事是函数调用或子例程。鉴于每件小事都必须拼写出来,您可以看到即使是一个将数字乘以 4 的简单函数也会很好。但是没有参数,也没有返回值。不能这么说B = mult4(B);
相反,我们只是设置了约定,我们决定专门使用哪些变量或内存位置来传递参数以及结果的去向。来电者然后想办法解决。我们可以定义一个乘以B
4 并返回结果的子例程A
:
mult4:
A = B;
A = A + A; // that is, B * 2
A = A + A; // B * 4, we're don!
return;
如果我们不想乘以D
4,我们会这样做:
B = D;
mult4();
D = A;
很公平。我们还必须记住 mult4() 清除了 in 的值,A
因此如果需要,我们最好保存它。就此而言,我们自己必须用尽B
全力才能打电话。如果我们需要这些变量,那么我们只需要找到某个地方将它们存放在memory[]
.
memory[20] = A; // can't forget A
B = D;
mult4();
D = A;
A = memory[20]; // back to what it was.
这就是 Z-80 汇编语言编程。哦,还有一堆其他的东西。而且您确实说所有话都带有口音,但是如果您查找有关 Z-80 汇编语言的信息,我相信您会明白的。这里有一些例子:
A = memory[4]; LD A,(4)
A = 3; LD A,3
memory[2] = A; LD (2),A
A = A + B; ADD A,B
B = B + 1; INC B
祝你的任务好运。
Rodnay Zaks 的 Z80 编程对于任何使用 Z80 汇编代码的人来说都是必读的。经作者许可可下载。
顺便说一句,该书中包含的代码示例之一是冒泡排序,从上到下进行了解释。
Z80 CPU 主页上提供了更多 Z80 相关信息。