给出以下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);
}
我对两件事感到困惑。
在这一行......
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发布周年纪念日最近通过;免费提供正确的猜测: - )
在下一行......
uint8_t carry = HIGH(v1) ? 1 : 0;
为什么会以这种方式运作?我读这个,“当且仅当高字节非零时才设置进位标志。”但是只有当高字节为<时,才会出现溢出指示。 / em>零?(我可能误解了这条线正在做什么。)
提前感谢任何见解。
答案 0 :(得分:4)
- 但我们怎样才能确定进位标志设置为1?之前的操作可以保证这一点吗?
醇>
$80/8137 38 SEC ; SEt Carry flag
- 醇>
uint8_t carry = HIGH(v1) ? 1 : 0;
它为什么会这样工作?我读这个,&#34;当且仅当高字节非零时才设置进位标志。&#34;但是,只有当高字节为零时才会指示溢出?
添加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位以提取所谓的“进位”。