1

有人可以帮我理解,为什么只有在 input<69 时才有效?我正在为 Little Man Computer 使用简单的汇编代码

    INP 
    STA INPUT
    LDA C
    OUT 
    ADD ONE
    OUT
LOOP LDA A  \\ first loop
    ADD ONE
    STA A
    SUB INPUT
    BRP END
    LDA A
    ADD LDINS
    STA READINS
READINS DAT
    BRZ PRIME
    BRA LOOP
PRIME LDA A
    OUT
    STA B
WRITELOOP LDA B  \\ second loop
    SUB INPUT
    BRP LOOP
    LDA B  \\ at this moment program breakdown when input is more than 69
    ADD STINS
    STA WRINS
    LDA A 
WRINS   DAT
    LDA B
    ADD A
    STA B
    BRA WRITELOOP
END     HLT
INPUT   DAT 0
LDINS   DAT 531  \\ this is working, but i think i might do a better code 
STINS   DAT 331
A       DAT 1
ONE     DAT 1
B       DAT
C       DAT 2

我正在使用http://peterhigginson.co.uk/lmc/来尝试使用这个程序

4

1 回答 1

0

由于 LMC 可用的内存有限,该程序在输入值 69 以上发生故障。可能的最高地址(邮箱)是 99。

此代码使用筛子的内存空间,筛子需要与您给它的输入一样大。筛子的内存从邮箱 31 开始,该邮箱在标签LDINSSTINS代码中定义: 531 表示LDA 31,其中 31 是邮箱地址。同样 331 表示STA 31。这定义了筛子的最大尺寸:31 到 99 给出了总共 69 个可用于筛子的邮箱。

该指令STA WRINS将动态更改标签处的代码,WRINS以便在筛子数组中写入一个值。写入的动态操作码是 300 + 31 + [一些动态偏移]。300 代表STA, 31 是筛子阵列的起点。现在当偏移量为69以上时,这条指令就变成了400以上,不再代表一条STA指令,而是一个未定义的操作码。

你可以在下面的代码片段中运行你的代码,当你给它 70 作为输入时,你会看到它停在那个指令上,说操作码是无效的:

#input: 70
    INP 
    STA INPUT
    LDA C
    OUT 
    ADD ONE
    OUT
LOOP LDA A  \\ first loop
    ADD ONE
    STA A
    SUB INPUT
    BRP END
    LDA A
    ADD LDINS
    STA READINS
READINS DAT
    BRZ PRIME
    BRA LOOP
PRIME LDA A
    OUT
    STA B
WRITELOOP LDA B  \\ second loop
    SUB INPUT
    BRP LOOP
    LDA B  \\ at this moment program breakdown when input is more than 69
    ADD STINS
    STA WRINS
    LDA A 
WRINS   DAT
    LDA B
    ADD A
    STA B
    BRA WRITELOOP
END     HLT
INPUT   DAT 0
LDINS   DAT 531  \\ this is working, but i think i might do a better code 
STINS   DAT 331
A       DAT 1
ONE     DAT 1
B       DAT
C       DAT 2
 
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.76/lmc.js"></script>

所以结论是,这种行为实际上并不是程序中的错误,而更多的是 LMC 的内存限制。埃拉托色尼筛子的 LMC 实现总是在该大小附近有一个限制,这取决于您可以使代码多么简洁——为数组留出空间。

关于代码的备注

以上回答了您的问题,但有一些关于您的代码的评论。

看来你修改了一个现有的程序,快速添加了一些初步指令输出2和3,但是你没有按照这个调整筛内存的起始地址。在您当前的程序中,地址 31 指向带有 的行(邮箱)BRA WRITELOOP,这不是您的目的。动态代码 at 第一次READINS执行时,该位置有指令LDA INPUTas INPUT,对应于地址 33。

这也是程序不输出 5 作为素数的原因。除了您已经使用的数据之外,该程序应该真正指向为它的筛子释放内存。为了节省空间,您可以让筛子地址从标签开始ONE,因为筛子的前两个条目永远不会被访问。

我认为使用标签和助记符而不是硬编码的操作码和地址也更好,因此避免使用 331 和 531 之类的东西,它们非常神秘,并且(如图所示)在修改程序时容易出错。

此外,您应该明确列出DAT您的程序将使用的条目。

这是一个更正的版本,显然对输入仍有限制:67 是您可以在不破坏代码的情况下输入的最大值。

#input: 67
          INP 
          STA INPUT
LOOP      LDA A    \\ first loop
          ADD ONE
          STA A
          SUB INPUT
          BRP END
          LDA A
          ADD LDINS
          STA READINS
READINS   DAT
          BRZ PRIME
          BRA LOOP
PRIME     LDA A
          OUT
          STA B
WRITELOOP LDA B     \\ second loop
          SUB INPUT
          BRP LOOP
          LDA B
          ADD STINS
          STA WRINS
          LDA A 
WRINS     DAT
          LDA B
          ADD A
          STA B
          BRA WRITELOOP
END       HLT
INPUT     DAT
LDINS     LDA ONE
STINS     STA ONE
A         DAT 1
ONE       DAT 1    // also the start of the sieve
B         DAT

<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.76/lmc.js"></script>

于 2020-09-26T09:31:04.663 回答