LMC 中的输出和复位列表

Output and Reset Lists in LMC

提问人:julio11 提问时间:7/18/2021 最后编辑:trincotjulio11 更新时间:7/19/2021 访问量:749

问:

我正在应对这个编码挑战:

为小人计算机编写一个程序,允许用户管理值列表。它应该从一个空列表开始,然后按如下方式处理输入:

如果输入为:

  • 小于 100:将此值添加到列表中,除非列表已具有 10 个值,在这种情况下,将忽略该值
  • 995:将列表设为空
  • 996:输出列表当前具有的值数
  • 997:输出列表当前具有的每个值,按它们添加到列表中的顺序
  • 998:以相反的顺序输出列表当前具有的每个值
  • 999:结束程序
  • 任何其他值都将被忽略

只要输入值不是 999,输入值的处理就会继续。

当输入 997 时,我在获取代码以向前顺序打印存储列表时遇到问题。我想我可能会混淆和说明。输入 995 时,我也无法正确重置存储的列表。ADDSUB

我能够正确编程的其他一切。

以下是我的代码:

START   INP
        STA TEMP
        SUB NINES
        BRZ end

        LDA TEMP
        SUB EIGHT
        BRZ PRIT

        lda temp
        sub seven
        brz printf

        LDA TEMP
        SUB SIX
        BRZ DOOUT

        LDA TEMP
        SUB FIVE
        BRZ RESET

        LDA COUNT
        SUB TEN
        BRZ START

        LDA TEMP
        SUB HUND
        BRP START

SIT     LDA SINST
        ADD COUNT
        STA SLOC
        LDA TEMP
SLOC    DAT 0
        LDA COUNT
        ADD ONE
        STA COUNT
        BRA START
PRIT    LDA COUNT
        BRZ END
PRINTR  LDA LINST
        ADD COUNT
        SUB ONE
        STA LDIT
LDIT    DAT 0
        OUT
        LDA COUNT
        SUB ONE
        STA COUNT
        BRZ END
        BRA PRINTR

---PRINTF  LDA LINST
        ADD COUNT
        add ONE
        STA LDIT
LDIT    DAT 0
        OUT
        LDA COUNT
        SUB ONE
        STA COUNT
        BRZ END
        BRA PRINTF 

doout   lda count
        out
        bra start

reset   lda zero
        sta count
        bra start

END     HLT

TEMP    DAT 0
COUNT   DAT 0
ONE     DAT 1
TWO     DAT 2
TEN     DAT 10
HUND    DAT 100
SINST   DAT 380
LINST   DAT 580
five    dat 995
six     dat 996
seven   dat 997
eight   dat 998
NINES   DAT 999
组装 小人电脑

评论

0赞 trincot 7/18/2021
您应该描述该程序要做什么。当然,在标签前面加上前缀会使程序无效......---

答:

1赞 trincot 7/18/2021 #1

程序中的问题可以分为以下几类:

  1. 与运行程序之前应检测到的标签相关的问题
  2. 与程序逻辑相关的问题,使程序产生错误的输出
  3. 与代码样式相关的问题

1. 标签

一个好的模拟器不应该接受以下错误:

  • PRINTF未定义标签。

    有一个指令,但该标签未定义,因为它使其成为注释。显然,需要将其删除才能使标签引用有效。brz printf------

  • LDIT标签重复:

    标签 LDIT 被定义两次。这将产生不可靠的行为。一个好的模拟器应该给出一个关于这一点的错误消息,但其他模拟器只会接受一个定义并忽略重复项。无论哪种方式,程序的意图都是使用第一个 LDIT 位置,第二个使用第二个 LDIT 位置。如果有的话,这不会发生。因此,重命名两个标签之一,并相应地调整其中一个说明。STA LDITSTA LDITSTA LDIT

  • zero标签未定义:

    重置计数器的代码是指未定义的标签。同样,好的模拟器在加载程序时会产生错误,但其他人可能会以静默方式使用邮箱 0,这会导致不良行为。因此,将标签定义为zerozero

    zero DAT 0
    

2. 逻辑

  • 打印列表的代码,无论是向前还是向后,都会改变 的值,但这样代码就会丢失列表的大小!例如,如果在这样的遍历之后,你选择操作 996 - 即查询列表的大小 - 它不会给出正确的结果。解决方案是使用不同的变量遍历列表,并且保持不变。 只有在向列表添加值或重置列表时才应更改。COUNTCOUNTCOUNT

  • 打印代码以跳转到 结束,但似乎应该允许用户继续使用另一个“菜单”选项,因此应该跳转到 ,而不是跳到它。跳转到的唯一原因应该是因为用户输入了 999 选项。ENDENDSTARTEND

  • 对于正向打印,不应从添加到动态加载指令开始,因为您需要从列表的第一个元素开始,而不是最后一个元素。因此,在第一次打印之前不要这样做。相反,增加动态加载指令,直到它与原始加载指令的差异(即计算列表中的相对偏移量)至少为 。COUNTADD COUNTADD ONECOUNT

  • LMC 规范有一个特别的奇怪之处:它没有定义当减法会导致负结果时累加器的值是多少。累加器不能存储负值,只能标记负结果。因此,当您刚刚执行了可能导致负值的指令时,这样做是不安全的(因为奇怪的是,当减法为负值时,模拟器可能会对累加器中的零值做出反应)。简而言之,如果可以的话,最好使用而不是 ,或者在使用 之前至少使用 。注意:即使是这门学科的老师也并不总是意识到这一点。BRZSUBBRPBRZBRPBRZ

  • LMC 有一个复位“句柄”,它将程序计数器设置回程序的开头。发生这种情况时,您将希望从头开始,并重置为 0。因此,在程序的最顶部添加重置代码。COUNT

这将解决程序中的语义问题。

3. 代码风格

  • 我建议你使用更有意义的名称。 不是很有启发性,因为你的程序被设计成输出不同的东西(按前向顺序列出,按后向顺序列出,列表的大小)。例如,使用 而不是 .像 、 、 ...都是相当神秘的。当程序使用描述性名称时,它将更容易阅读和理解,而没有只有您才能理解的缩写。dooutoutput_sizedooutLDITPRIT

  • 动态指令基于 (store 指令) 和 (load 指令),它们被硬编码为:SINSTLINST

    SINST  DAT 380
    LINST  DAT 580
    

    但遗憾的是,你这样对它们进行了硬编码。首先,他们假设邮箱 80 可以自由存储列表,其次,它需要了解这些指令(3 和 5)的操作码。然而,有了一个好的汇编程序,你不应该这样做。所以我建议这样做:

    store_instruction STA list
    load_instruction  LDA list
    

    ...并使用代码最底部的指令进行定义(因为这是有邮箱可用的地方)。我什至会在它后面添加虚拟行,以便非常清楚地了解该列表中的邮箱 - 它只是使某人更容易理解代码:listDATDAT

    list DAT
         DAT
         DAT
         DAT
         DAT
         DAT
         DAT
         DAT
         DAT
         DAT
    

    这样,列表可能不会存储在邮箱 80 中,但我们不在乎。我们把它留给汇编程序为我们的列表分配下一个免费邮箱。在“数据部分”的中间有 和 指令可能看起来很奇怪,它们永远不会被执行,但 LMC 架构(冯诺依曼架构)的原理是代码和数据使用相同的内存,所以这很好。和指令将从那里复制到实际程序中。STALDALDASTA

更正的程序

考虑到上述所有因素,该程序可能如下所示:

#input:1 2 3 997 998 999
clear_list        LDA zero # Start by resetting the list
                  STA list_size

start             INP
                  STA input
                  SUB menu_nine
                  BRP end

                  LDA input
                  SUB menu_eight
                  BRP output_reversed

                  LDA input
                  SUB menu_seven
                  BRP output_forward

                  LDA input
                  SUB menu_six
                  BRP output_size

                  LDA input
                  SUB menu_five
                  BRP clear_list

                  LDA list_size
                  SUB max_list_size
                  BRP start

                  LDA input
                  SUB input_limit
                  BRP start

                  LDA store_instruction
                  ADD list_size
                  STA store
                  LDA input
store             DAT 0
                  LDA list_size
                  ADD one
                  STA list_size
                  BRA start

output_reversed   LDA load_instruction
                  ADD list_size
loop_reversed     SUB one
                  STA load_reversed
                  SUB load_instruction # are we still within the list?
                  BRP load_reversed # yes, continue printing
                  BRA start
load_reversed     DAT 0
                  OUT
                  LDA load_reversed # decrement the dynamic LDA instruction
                  BRA loop_reversed

output_forward    LDA load_instruction
loop_forward      STA load_forward
                  SUB load_instruction # get relative offset in the list
                  SUB list_size # are we still within the list?
                  BRP start # no, stop printing
load_forward      DAT 0
                  OUT
                  LDA load_forward # increment the dynamic LDA instruction
                  ADD one
                  BRA loop_forward

output_size       LDA list_size
                  OUT
                  BRA start

end               HLT

# constants
zero              DAT 0
one               DAT 1
two               DAT 2
max_list_size     DAT 10
input_limit       DAT 100
load_instruction  LDA list
store_instruction STA list
menu_five         DAT 995
menu_six          DAT 996
menu_seven        DAT 997
menu_eight        DAT 998
menu_nine         DAT 999
# variables
input             DAT 0
list_size         DAT 0
list              DAT
                  DAT
                  DAT
                  DAT
                  DAT
                  DAT
                  DAT
                  DAT
                  DAT
                  DAT



<script src="https://cdn.jsdelivr.net/gh/trincot/[email protected]/lmc.js"></script>

您可以使用此代码片段在此处运行代码。单击以激活 LMC 模拟器,然后使用右侧的面板与其交互。Run Code Snippet

评论

0赞 julio11 7/19/2021
很有帮助!每当我将其加载到 LMC 模拟器的 RAM 中时,第 45 行都会出现错误。是因为列表变量的编程方式吗?
0赞 trincot 7/19/2021
哪个模拟器?
1赞 trincot 7/19/2021
某些模拟器无法处理只有注释(如 或 或)或第一行的行。如果是这种情况,请删除这些行。或者使用可以处理这个问题的模拟器,就像我的一样# variables# constants
1赞 trincot 7/20/2021
您能告诉我您正在使用哪个模拟器,以及删除注释行是否解决了您的问题吗?
1赞 julio11 7/20/2021
我使用101computing LMC模拟器进行了测试。这是评论行,修复它解决了问题。