【问题标题】:Little Man Computer Program to output 1 with delay of 5 seconds小人计算机程序以 5 秒的延迟输出 1
【发布时间】:2020-11-23 15:45:45
【问题描述】:

假设一个小人计算机程序需要 1 微秒来执行一条指令。我需要编写一个 LMC 程序,它接受 0 到 10(含)之间的输入,并在延迟这么多秒后产生一个 1 的输出。

例如,输入 5 将在 5 秒后产生输出 1。延迟不必是完美的,但必须在 0.01% 或 100 µsec 内准确。我怎样才能做到这一点?

【问题讨论】:

    标签: delay little-man-computer


    【解决方案1】:

    您需要创建循环来花费时间。您将需要一个大约需要 1 秒才能执行的代码块,然后根据输入的数字重复执行该代码块。因此,挑战在于设计需要 1 秒才能执行的代码。

    让我们用循环试试:

           LDA start
    loop   STA count
           LDA count
           SUB one
           BRP loop
    
           ; ...other code...
    
    one    DAT 1
    start  DAT 999
    count  DAT
    

    这个循环将有 1000 次迭代。每次迭代有 4 条指令,因此 1000 次迭代需要 4000µs。我们可以稍微加强一下代码以使循环有更多指令,但我们离 1 秒还差得很远,所以我们最好使用第二个循环来重复执行上述操作。该外部循环需要迭代大约 250 次,因为 250*4000 = 一百万,即 1 秒。

    所以我们会:

           LDA start2
    loop2  STA count2
    
    ; here starts the code we used earlier
           LDA start3
    loop3  STA count3
           LDA count3
           SUB one
           BRP loop3
    ; end of the code we used earlier
    
           LDA count2
           SUB one
           BRP loop2
           
           ; ... other code
    
    one    DAT 1
    start2 DAT 249
    start3 DAT 999
    count2 DAT
    count3 DAT
    

    如果我们对执行的指令数量进行精确计算,那么我们会得出:

    • 内循环执行4*1000条指令
    • 外循环在内循环之前有 2 条指令,在内循环之后有 3 条指令,因此它总共有 5 条指令的“开销”。
    • 所以这相当于 250*(5+4000) 条指令,即 1001250。

    这有点过分(因为开销):偏差大约为 0.1%,所以我们需要稍微调整一下数字。

    但是让我们首先通过实现执行上述代码的外循环来完成程序:

           INP
           BRZ output ; output immediately!
           SUB one
    
    ; a new outer loop: 
    loop1  STA count1
    
    ; start of what we already had:
           LDA start2
           
    loop2  STA count2
           LDA start3
    
    loop3  STA count3
           LDA count3
           SUB one
           BRP loop3
    
           LDA count2
           SUB one
           BRP loop2
    ; end of what we already had
    
           LDA count1
           SUB one
           BRP loop1
    
    output LDA one
           OUT
           HLT
    
    one    DAT 1
    start2 DAT 249
    start3 DAT 999
    count1 DAT
    count2 DAT
    count3 DAT
    

    请注意,我们添加的外部循环也有它的开销……如果我们将 LDA start2 包含在该计数中,那么还有 5 条指令开销。

    loop1 的一次迭代因此需要 5 + 1001250 = 1001255。

    最后,现在让我们调整 start2 和 start3 的值,以使我们更接近 1000000。在电子表格中玩数字对,您会发现在 542 次迭代中与 start2 = 541 接近,并且start3 = 459 进行 460 次迭代(您可以使用其他有趣的对,结果相似)。

    • 在loop3 的一次迭代中执行的指令:4
    • 在loop2 的一次迭代中执行的指令:5 + (460*4) = 1845
    • 在loop1 的一次迭代中执行的指令:5 + (542*1845) = 999995

    所以我们还需要 5 条指令才能达到完美的秒数。这很简单……只需在loop1 的开销中重复几次指令即可。所以我们最终得到了这个:

           INP
           BRZ output ; output immediately!
           SUB one
    
    ; a new outer loop: 
    loop1  STA count1
    
           LDA start2
           LDA start2 ; dummy instructions to spend 5µs more...
           LDA start2 ; ...
           LDA start2 ; ...
           LDA start2 ; ...
           LDA start2 ; ...
           
    loop2  STA count2
           LDA start3
    
    loop3  STA count3
           LDA count3
           SUB one
           BRP loop3
    
           LDA count2
           SUB one
           BRP loop2
    
           LDA count1
           SUB one
           BRP loop1
    
    output LDA one
           OUT
           HLT
    
    one    DAT 1
    start2 DAT 541 ; the two magic numbers
    start3 DAT 459 ; ...
    count1 DAT
    count2 DAT
    count3 DAT
    

    我们还没有谈到在loop1 之外执行的开销。这包括BRZ、SUB(在非零输入的情况下)和output 部分中的两条指令(LDA 和OUT),因此需要3-4µs。

    这意味着我们会为以下每个输入获得以下延迟:

    input | µs from INP to OUT
    ------+-------------------
        0 |        3
        1 |  1000004
        2 |  2000004
      ... | ...
        9 |  9000004
       10 | 10000004
    

    您甚至可以通过在外循环的最后一次迭代中跳过 4 条虚拟指令来消除这些额外的 4 毫秒。所以改变这个:

    loop1  STA count1
    
           LDA start2
           LDA start2 ; dummy instructions to spend 5µs more...
           LDA start2 ; ...
           LDA start2 ; ...
           LDA start2 ; ...
           LDA start2 ; ...
    

    到这里:

    loop1  STA count1
    
           BRZ skip   ; this branches only in the last iteration
           LDA start2 ; dummy instructions to spend 4µs more...
           LDA start2 ; ...
           LDA start2 ; ...
           LDA start2 ; ...
    skip   LDA start2
    

    所以现在时间是准确的,除了输入为 0 的情况。没有办法花费少于 3 条指令来处理这种情况(零检测、加载 1 并输出它)。

    【讨论】:

    • 我试图浏览您发布的代码,它看起来很简洁。感谢您对此的帮助。我正在继续解决这个问题,但这是一个好的开始。非常感谢!
    • 一个问题。当我使用幻数运行程序时,它需要很长时间,所以我如何确保代码在 1 秒。每个输入数字?
    • 在您的问题中,您说一条指令需要 1 微秒。在您运行代码的 LMC 上是否如此?
    • 不,它会像在 459 和 541 上运行一样循环。所以,我永远看不到它是否有效。我把它改成了 4 和 5,它可以在 LMC 模拟器上像魅力一样工作,但这不是现实生活中的处理吗?
    • 不,我知道的模拟器没有这样的性能:它们在执行一条指令上花费的时间比一微秒多得多。所以我把你的问题当作一个理论练习,用一些想象的 LMC在一微秒内执行一条指令。这是您在问题中提出的限制。如果您不知道执行一条指令需要多长时间,那么这个问题就无法回答:LMC 无法访问实时时钟。并非所有模拟器都具有相同的速度。
    猜你喜欢
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多