在此汇编代码中如何设置进位标志?
How is the carry flag being set in this assembly code?
给定以下 16 位 PRNG 函数的汇编代码,
/8111 E2 20 SEP # ; set 8-bit mode accumulator
/8113 AD E5 05 LDA E5 ; load low byte of last random number
/8116 8D 02 42 STA 02
/8119 A9 05 LDA # ; multiply it by 5
/811B 8D 03 42 STA 03
/811E EA NOP
/811F C2 20 REP # ; set 16-bit mode accumulator
/8121 AD 16 42 LDA 16 ; load the resultant product
/8124 48 PHA ; push it onto the stack
/8125 E2 20 SEP # ; 8-bit
/8127 AD E6 05 LDA E6 ; load high byte of last random number
/812A 8D 02 42 STA 02
/812D A9 05 LDA # ; multiply by 5
/812F 8D 03 42 STA 03
/8132 EB XBA ; exchange high and low bytes of accumulator
/8133 EA NOP
/8134 AD 16 42 LDA 16 ; load low byte of product
/8137 38 SEC
/8138 63 02 ADC ,s ; add to it the high byte of the original product
/813A 83 02 STA ,s ; save it to the high byte of the original product
/813C C2 20 REP # ; 16-bit
/813E 68 PLA ; pull it from the stack
/813F 69 11 00 ADC #[=10=]11 ; add 11
/8142 8D E5 05 STA E5 ; save as new random number
/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++ and Overflow and Carry flags on Z80 but it's not clear to me because the instruction set appears to be different I'm not familiar with 65C816 assembly。 (这是来自一款流行的 1994 SNES 游戏,其 NA 发布周年纪念日刚刚过去;免费投票给正确的猜测:-)
下一行...
uint8_t carry = HIGH(v1) ? 1 : 0;
为什么会这样?我把它读成 "Set the carry flag if and only if the high byte is non-zero." 但是只有当高字节 是 零时才不会指示溢出?(我可能误解了这条线在做什么。)
提前感谢您的任何见解。
- but how can we be sure that the carry flag is set to 1? What previous operation would guarantee this?
/8137 38 SEC ; SEt Carry flag
uint8_t carry = HIGH(v1) ? 1 : 0;
Why would it work this way? I read this as, "Set the carry flag if and only if the high byte is non-zero." But wouldn't the indication of an overflow be only if the high byte is zero?
加法 ADC #[=12=]11
使用了 ADC ,s
的进位。当执行 ADC ,s
时,累加器设置为 8 位(因为 SEP #
),因此如果 ADC ,s
的结果超过 8 位(也就是说,如果你在 16 位模式下得到了 >= $100 的东西。
在 C 版本中,您有一个 16 位变量 (v1
) 来保存结果,因此您的进位将位于 v1
的第 8 位,您可以使用 HIGH(v1) == 1
对其进行测试, 或者简单地 HIGH(v1)
因为它要么是 1 要么是 0.
1) 行
/8137 38 SEC
明确地在 ADC
add-with-carry 指令之前设置进位,这就是 C 代码中 +1
的原因。
2) 处理器有一个8位累加器,加法会溢出到进位,为下一条ADC
指令做准备。但是,C 代码使用的是 16 位变量 v1
,进位保留在高 8 位。因此测试那些高 8 位以提取所谓的 "carry".
给定以下 16 位 PRNG 函数的汇编代码,
/8111 E2 20 SEP # ; set 8-bit mode accumulator
/8113 AD E5 05 LDA E5 ; load low byte of last random number
/8116 8D 02 42 STA 02
/8119 A9 05 LDA # ; multiply it by 5
/811B 8D 03 42 STA 03
/811E EA NOP
/811F C2 20 REP # ; set 16-bit mode accumulator
/8121 AD 16 42 LDA 16 ; load the resultant product
/8124 48 PHA ; push it onto the stack
/8125 E2 20 SEP # ; 8-bit
/8127 AD E6 05 LDA E6 ; load high byte of last random number
/812A 8D 02 42 STA 02
/812D A9 05 LDA # ; multiply by 5
/812F 8D 03 42 STA 03
/8132 EB XBA ; exchange high and low bytes of accumulator
/8133 EA NOP
/8134 AD 16 42 LDA 16 ; load low byte of product
/8137 38 SEC
/8138 63 02 ADC ,s ; add to it the high byte of the original product
/813A 83 02 STA ,s ; save it to the high byte of the original product
/813C C2 20 REP # ; 16-bit
/813E 68 PLA ; pull it from the stack
/813F 69 11 00 ADC #[=10=]11 ; add 11
/8142 8D E5 05 STA E5 ; save as new random number
/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++ and Overflow and Carry flags on Z80 but it's not clear to me becausethe instruction set appears to be differentI'm not familiar with 65C816 assembly。 (这是来自一款流行的 1994 SNES 游戏,其 NA 发布周年纪念日刚刚过去;免费投票给正确的猜测:-)下一行...
uint8_t carry = HIGH(v1) ? 1 : 0;
为什么会这样?我把它读成 "Set the carry flag if and only if the high byte is non-zero." 但是只有当高字节 是 零时才不会指示溢出?(我可能误解了这条线在做什么。)
提前感谢您的任何见解。
- but how can we be sure that the carry flag is set to 1? What previous operation would guarantee this?
/8137 38 SEC ; SEt Carry flag
uint8_t carry = HIGH(v1) ? 1 : 0;
Why would it work this way? I read this as, "Set the carry flag if and only if the high byte is non-zero." But wouldn't the indication of an overflow be only if the high byte is zero?
加法 ADC #[=12=]11
使用了 ADC ,s
的进位。当执行 ADC ,s
时,累加器设置为 8 位(因为 SEP #
),因此如果 ADC ,s
的结果超过 8 位(也就是说,如果你在 16 位模式下得到了 >= $100 的东西。
在 C 版本中,您有一个 16 位变量 (v1
) 来保存结果,因此您的进位将位于 v1
的第 8 位,您可以使用 HIGH(v1) == 1
对其进行测试, 或者简单地 HIGH(v1)
因为它要么是 1 要么是 0.
1) 行
/8137 38 SEC
明确地在 ADC
add-with-carry 指令之前设置进位,这就是 C 代码中 +1
的原因。
2) 处理器有一个8位累加器,加法会溢出到进位,为下一条ADC
指令做准备。但是,C 代码使用的是 16 位变量 v1
,进位保留在高 8 位。因此测试那些高 8 位以提取所谓的 "carry".