如何在此汇编代码中设置进位标志?

时间:2016-04-20 13:36:45

标签: c assembly random carryflag 65816

给出以下16位PRNG函数的汇编代码,

$80/8111 E2 20       SEP #$20   ; set 8-bit mode accumulator
$80/8113 AD E5 05    LDA $05E5  ; load low byte of last random number
$80/8116 8D 02 42    STA $4202
$80/8119 A9 05       LDA #$05   ; multiply it by 5
$80/811B 8D 03 42    STA $4203
$80/811E EA          NOP
$80/811F C2 20       REP #$20   ; set 16-bit mode accumulator
$80/8121 AD 16 42    LDA $4216  ; load the resultant product
$80/8124 48          PHA        ; push it onto the stack
$80/8125 E2 20       SEP #$20   ; 8-bit
$80/8127 AD E6 05    LDA $05E6  ; load high byte of last random number
$80/812A 8D 02 42    STA $4202
$80/812D A9 05       LDA #$05   ; multiply by 5
$80/812F 8D 03 42    STA $4203
$80/8132 EB          XBA        ; exchange high and low bytes of accumulator
$80/8133 EA          NOP
$80/8134 AD 16 42    LDA $4216  ; load low byte of product
$80/8137 38          SEC
$80/8138 63 02       ADC $02,s  ; add to it the high byte of the original product
$80/813A 83 02       STA $02,s  ; save it to the high byte of the original product
$80/813C C2 20       REP #$20   ; 16-bit
$80/813E 68          PLA        ; pull it from the stack
$80/813F 69 11 00    ADC #$0011 ; add 11
$80/8142 8D E5 05    STA $05E5  ; save as new random number
$80/8145 6B          RTL

@sagara名称的用户将代码翻译为C:

#define LOW(exp)  ((exp) & 0x00FF)
#define HIGH(exp) (((exp) & 0xFF00) >> 8)

uint16_t prng(uint16_t v) {

    uint16_t low  = LOW(v);
    uint16_t high = HIGH(v);

    uint16_t mul_low  = low  * 5;
    uint16_t mul_high = high * 5;

    // need to check for overflow, since final addition is adc as well
    uint16_t v1    = LOW(mul_high) + HIGH(mul_low) + 1;
    uint8_t  carry = HIGH(v1) ? 1 : 0;

    uint16_t v2 = (LOW(v1) << 8) + LOW(mul_low);

    return (v2 + 0x11 + carry);
}

我对两件事感到困惑。

  1. 在这一行......

    uint16_t v1    = LOW(mul_high) + HIGH(mul_low) + 1;
    

    为什么会有+ 1?我认为这是因为ADC操作,但我们如何确定进位标志设置为1?之前的操作可以保证这一点? XBC?我读过一些帖子,例如Assembly ADC (Add with carry) to C++Overflow and Carry flags on Z80,但我不清楚,因为指令集看起来不同我不熟悉65C816 assembly 。 (这是一个流行的1994年SNES游戏,其NA发布周年纪念日最近通过;免费提供正确的猜测: - )

  2. 在下一行......

    uint8_t  carry = HIGH(v1) ? 1 : 0;
    

    为什么会以这种方式运作?我读这个,“当且仅当高字节非零时才设置进位标志。”但是只有当高字节为<时,才会出现溢出指示。 / em>零?(我可能误解了这条线正在做什么。)

  3. 提前感谢任何见解。

2 个答案:

答案 0 :(得分:4)

  
      
  1. 但我们怎样才能确定进位标志设置为1?之前的操作可以保证这一点吗?
  2.   
$80/8137 38          SEC   ; SEt Carry flag
  
      
  1. uint8_t carry = HIGH(v1) ? 1 : 0;
      它为什么会这样工作?我读这个,&#34;当且仅当高字节非零时才设置进位标志。&#34;但是,只有当高字节为零时才会指示溢出?
  2.   

添加ADC #$0011正在使用来自ADC $02,s的进位。执行ADC $02,s时,累加器设置为8位(因为SEP #$20),因此如果ADC $02,s的结果超过8,则将设置进位标志位(即如果你在16位模式下得到的东西&gt; = $ 100) 在C版本中,您有一个16位变量(v1)来保存结果,因此您的进位将位于v1的第8位,您可以使用{{1}进行测试或者只是HIGH(v1) == 1,因为它将是1或0。

答案 1 :(得分:3)

1)行

$80/8137 38     SEC

是在ADC add-with-carry指令之前设置进位,这就是C代码中+1的原因。

2)处理器有一个8位累加器,加法将溢出到进位,为下一个ADC指令做好准备。但是,C代码使用的是16位变量v1,并且进位保持在高8位。因此,测试那些高8位以提取所谓的“进位”。