tiny2313.pdfより抜粋

ニモニック意味動作
BRSH 符号なしの≧で分岐 C = 0 なら, P C ← P C + K + 1
BRLO 符号なしの<で分岐 C = 1 なら, P C ← P C + K + 1
BRGE 符号付きの≧で分岐 ( N EOR V ) = 0 なら, P C ← P C + K + 1
BRLT 符号付きの<で分岐 ( N EOR V ) = 1 なら, P C ← P C + K + 1

たとえば、こんな感じ

ソース

 char comp(char x,char y)
 {
	if(x>y) return 1;
	return 0;
 }
アセンブリ
 00000344 <comp>:
 344:	68 17       	cp	r22, r24
 346:	1c f4       	brge	.+6      	; 0x34e <comp+0xa>
 348:	81 e0       	ldi	r24, 0x01	; 1
 34a:	90 e0       	ldi	r25, 0x00	; 0
 34c:	08 95       	ret
 34e:	80 e0       	ldi	r24, 0x00	; 0
 350:	90 e0       	ldi	r25, 0x00	; 0
 352:	08 95       	ret


AVR補足

  • AVRでは、(比較、減算)の多倍長演算を行った結果のZフラグは、
  • 全桁がゼロになったかどうかの結果が反映されるように工夫されています。
    • CPC,SBC命令では該当桁8bitの演算結果が非ゼロのときだけZフラグが変化し、ゼロのときはZフラグを変化させない(引き継ぐ)ようになっています。
  • 他のCPUでは、あまりこのような細かい配慮がされていなかったと思います。


追記

tntnさんから、もっと説明しろということなので追記。
  • 符号なし大小比較(減算)の結果はCフラグ(実は9ビット目の演算結果である)に残ります。
  • 符号つき大小比較(減算)の結果は、結果データのMSB(符号bit)をコピーしたNフラグを見て判定しても良いのですが、
  • 演算(減算)がオーバーフローした場合に正負の符号逆転が発生するので、
  • その場合を考慮するなら、NフラグとVフラグのXORを保存したSフラグを見ればよいのです。


参考:ARM(Thumb)の分岐命令

  • 分岐命令は16種類ありますが、ARM命令フォーマット内のCondフィールドの4ビット(分岐命令の種類を決めるフィールド)と、
  • フラグレジスタ各ビットの間に何かの関連があるわけではないですので勘違いしないでね。
  • ARM(Thumb)にはN.xor.VをあらわすSビットという実在フラグはないです。


68000の場合

 Bcc	Branch on condition cc
 Operation:	If cc = 1 THEN [PC]   &not;   [PC] + d
 
 Syntax:	Bcc <label>
 
 Sample syntax:	BEQ Loop_4
                                     BVC *+8
 
 Attributes:	BEQ takes an 8-bit or a 16-bit offset (i.e., displacement).
 
 Description:	
If the specified logical condition is met, program execution continues at location [PC] + displacement, d. The displacement is a two's complement value. The value in the PC corresponds to the current location plus two. The range of the branch is -126 to +128 bytes with an 8-bit offset, and -32K to +32K bytes with a 16-bit offset. A short branch to the next instruction is impossible since the branch code 0 indicates a long branch with a 16-bit offset. The assembly language form BCC *+8 means branch to the point eight bytes from the current PC if the carry bit is clear.

 	BCC	branch on carry clear	         C
 	BCS	branch on carry set	         C
 	BEQ	branch on equal	                  Z
         BGE	branch on greater than or equal	N.V + N.V
         BGT	branch on greater than	         N.V.Z + N.V.Z
 	BHI	branch on higher than	         C.Z
         BLE	branch on less than or equal	Z + N.V + N.V
 	BLS	branch on lower than or same	C + Z
 	BLT	branch on less than	         NV + NV
 	BMI	branch on minus (i.e., negative)	N
 	BNE	branch on not equal                  Z
 	BPL	branch on plus (i.e., positive)	N
 	BVC	branch on overflow clear	         V
 	BVS	branch on overflow set	         V
 
Note that there are two types of conditional branch instruction: those that branch on an unsigned condition and those that branch on a signed condition. For example, $FF is greater than $10 when the numbers are regarded as unsigned (i.e., 255 is greater than 16). However, if the numbers are signed, $FF is less than $10 (i.e., -1 is less than 16).
 The signed comparisons are:
 	BGE		branch on greater than or equal
 	BGT		branch on greater than
 	BLE		branch on lower than or equal
 	BLT		branch on less than
 The unsigned comparisons are:
 	BHS	BCC	branch on higher than or same
 	BHI		branch on higher than
 	BLS		branch on lower than or same
 	BLO	BCS	branch on less than
 
The official mnemonics BCC (branch on carry clear) and BCS (branch on carry set) can be renamed as BHS (branch on higher than or same) and BLO (branch on less than), respectively. Many 68000 assemblers support these alternative mnemonics.
 
 Condition codes:           X   N   Z   V   C


8086の場合

 フラグ 名称 機能 
 OF オーバーフローフラグ 符号付演算で桁あふれが生じたときにセットされる 
 DF ディレクションフラグ ストリング操作命令においてポインタの増減方法を示す 
 IF インタラプト・イネーブルフラグ クリアすると外部割込みを受け付けなくなる 
 TF トラップフラグ シングルステップモードで実行するときのフラグ 
 SF サインフラグ 演算結果の符合を表す。負ならばセットされる 
 ZF ゼロフラグ 演算結果がゼロであればセットされる 
 AF 補助キャリーフラグ BCD演算で使用されるキャリーフラグ 
 PF パリティフラグ 演算の結果、1となるビット数が偶数のときセットされ、
    奇数のとき リセットされる 
 CF キャリーフラグ 演算の結果、桁上がりが生じた場合にセットされる 

 ニーモニック 条件 CMPの結果に対する意味 
 JA JNBE CFとZFが両方0のとき Op1 > Op2 
 JAE JNB CFが0のとき Op1 >= Op2 
 JB JNAE CFが1のとき Op1 < Op2 
 JBE JNA CFまたはZFどちらかが1のとき Op1 <= Op2 
 JC      CFが1のとき 
 JCXZ    CXレジスタが0のとき CX=0 
 JE JZ   ZFが1のとき Op1 = Op2 
 JG JNLE SFとOFが一致し、かつZFが0のとき Op1 > Op2 
 JGE JNL SFとOFが一致するとき Op1 >= Op2 
 JL JNGE SFとOFが一致しないとき Op1 < Op2 
 JLE JNG SFとOFが一致せず、ZFが1のとき Op1 <= Op2 
 JMP     常に 
 JNC     CFが0のとき 
 JNE JNZ ZFが0のとき Op1 <> Op2 

  • Above
    • 大きい(符号なし)
  • Below
    • 小さい(符号なし)
  • Greater
    • 大きい(符号あり)
  • Less
    • 小さい(符号あり)
  • Equal
    • 等しい
  • Not
    • 論理の反転
  • ZとかCとか
    • フラグの名前


PIC18では?

  • かなり悲惨
 0000 00349 _comp:
                00350 ;       .line   121; main.c     char comp(char x,char y)
 0000 CFD9 FFE5 00351         MOVFF   FSR2L, POSTDEC1
 0004 CFE1 FFD9 00352         MOVFF   FSR1L, FSR2L
 0008 C000 FFE5 00353         MOVFF   r0x00, POSTDEC1
 000C C000 FFE5 00354         MOVFF   r0x01, POSTDEC1
 0010 0E02      00355         MOVLW   0x02
 0012 CFDB F000 00356         MOVFF   PLUSW2, r0x00
 0016 0E03      00357         MOVLW   0x03
 0018 CFDB F000 00358         MOVFF   PLUSW2, r0x01
                00359 ;       .line   123; main.c     if(x>y) return 1;
 001C 5000      00360         MOVF    r0x01, W
 001E 0F80      00361         ADDLW   0x80
 0020 6EF3      00362         MOVWF   PRODL
 0022 5000      00363         MOVF    r0x00, W
 0024 0F80      00364         ADDLW   0x80
 0026 5CF3      00365         SUBWF   PRODL, W
 0028 E200      00366         BC      _00174_DS_
 002A 0E01      00367         MOVLW   0x01
 002C D000      00368         BRA     _00175_DS_
 002E 00369 _00174_DS_:
                00370 ;       .line   124; main.c     return 0;
 002E 6AE8      00371         CLRF    WREG
 0030 00372 _00175_DS_:
 0030 CFE4 F000 00373         MOVFF   PREINC1, r0x01
 0034 CFE4 F000 00374         MOVFF   PREINC1, r0x00
 0038 CFE4 FFD9 00375         MOVFF   PREINC1, FSR2L
 003C 0012      00376         RETURN  

  • 見たところ、0x80のゲタを履かせたあとで、符号なし比較を行っている模様です。

  • 昔の8bitCPUには符号付整数という概念がそもそもありません。
    • (符号なし整数とビットパターンは同一なために、とくに区別して扱っていません)

  • なので、N.xor.Vという判定命令自体が存在しません。(Z80)
  • たぶん、判定しようとすると、Nフラグ判定とVフラグ判定の4通り分岐が必要です。
    • 符号付8ビット整数を扱うこと自体、メモリの無駄になるのでしないのが通例です。
    • C言語をコンパイルする場合は符号付整数を避けて通れません。


Z80

          7   6   5   4   3   2   1   0
 Flag = | S | Z | 0 | H | 0 |P/V| N | C |
  • H ... ハーフキャリー (BCD演算用 下位4bitからのBCD演算キャリー)
  • N ... 減算フラグ 直前の演算命令が減算命令だったかどうかを記憶。
  • 10進補正命令を実行するときに、直前の演算が加算なのか減算なのかの情報が必要なためです。

ビット8080/8085undocumented 8085Z80 CPU 備考
7 (MSB)SSS符号フラグ
6ZZZゼロフラグ
50/#X5#本来は未使用、X5は8085の隠し機能Flag
4ACACH補助キャリないしハーフキャリ、BCD演算補正用
30/#0#未使用
2PPP/Vパリティフラグ、Z80 CPUだけはオーバーフローフラグ兼用
11/#VNオーバーフローフラグか減算フラグ
0 (LSB)CCCキャリ

  • 条件分岐は8種類です。
 JP cc,nn	
         NZ; non zero
         Z;  zero
	NC; non carry
         C; carry
	PO; parity odd
	PE; parity even
	P;  positive
	M;  negative
  • 条件returnというのもありました。
 RET cc

  • Parityは
    • 論理演算後、Aregの'1'の立っている数が偶数か奇数かを示しますが、
    • 算術演算後はオーバーフローしたかどうかの意味に化けます。
    • (フラグまぎらわしい、ともいう。)

  • オリジナルのintel 8080は、parityはparityだけの意味で使われていたのを
  • Zilog社がむりやり2重の意味を持たせた(と記憶しています)。
  • そもそもparityなんて、使う場面はかなり限定されていたと思います。
    • RS232Cの送受信プログラムで7bitパリティあり(にすることもめったにないが)のパリティ算出に1箇所づつ使われる程度だと思います。
    • もしかしたら、紙テープパンチャの出力プログラムにも使う?
    • そういうやつで、算術演算後にP/Vビットを見たら互換性アウト!

  • 相対分岐は
 JR 無条件
 JR Z
 JR NZ
 JR C
 JR NC
の5種類しかありません。


おまけ:6502の分岐命令

 MNE. REL  条件
 BCC  90 2 C = 0
 BCS  B0 2 C = 1
 BEQ  F0 2 Z = 1
 BMI  30 2 N = 1
 BNE  D0 2 Z = 0
 BPL  10 2 N = 0
 BVC  50 2 V = 0
 BVS  70 2 V = 1
  • NとVを独立に判定する分岐命令しか存在しません。


おまけ:SC/MPIIの分岐命令

 分岐命令は少なくて4種類しかありません。 
 Mne.  Op  Cy  N  CO  動作 
 JMP   90  11  2      PC <- EA 
 JP    94 9/11 2      If (AC) >= 0, PC <- EA 
 JZ    98 9/11 2      If (AC) = 0, PC <- EA 
 JNZ   9C 9/11 2      If (AC) != 0, PC <- EA 

  • SC/MPの分岐は特殊で、フラグを見るのではなく、アキュームレーター(唯一の8ビットレジスタ)の内容で分岐する。
  • オーバーフローフラグは(SR:ステータスレジスタのbit6に)存在する。
  • SRとAC(アキュームレータ)は相互にコピーする命令がある(CSA,CAS)。


MC6800

 意味              ニーモニック   REL   条件 
 Branch Always            BRA   20 3*2  常に分岐 
 Branch Never            *BRN   21 3 2  常に分岐せず(2 Byte NOP命令) 
 Branch If Carry Clear    BCC   24 3*2  C = 0 
 Branch If Carry Set      BCS   25 3*2  C = 1 
 Branch If = Zero         BEQ   27 3*2  Z = 1 
 Branch If >= Zero        BGE   2C 3*2  N eor V = 0 
 Branch If > Zero         BGT   2E 3*2  Z + (N eor V) = 0 
 Branch If Higher         BHI   22 3*2  C + Z = 0 
 Branch If <= Zero        BLE   2F 3*2  Z + (N eor V) = 1 
 Branch If Lower or Same  BLS   23 3*2  C + Z = 1 
 Branch If < Zero         BLT   2D 3*2  N eor V = 1  
 Branch If Minus          BMI   2B 3*2  N = 1 
 Branch If Not Equal Zero BNE   26 3*2  Z = 0 
 Branch If Overflow Clear BVC   28 3*2  V = 0 
 Branch If Overflow Set   BVS   29 3*2  V = 1 
 Branch If Plus           BPL   2A 3*2  N = 0 
  • 6800は賢いことに8ビット古代CPUなのに符号付整数の条件判断が可能です。
  • コンディションコード(命令コードが0x2* となっていて、*の部分)のLSBが
  • 反転条件になっています。つまり、分岐命令の種類は基本的に8種類で、それの逆条件に修飾するビットがLSBになっています。
  • で、BRAの逆が、BRNとなり、2バイトのNOPと同等になります。
    • これを逆手に利用すると、1バイトの命令スキップに使えます。

    db  0x21   ; Branch never
    clra       ; A<-0
  • と書いて、clraの位置に飛び込むとかの技です。
  • 0x21が存在しなかったら、通常の無条件分岐命令を書くので2バイト命令になります。

  • 6800から68000になったときにBRNが廃止されて、BSR命令がそこに埋め込まれていた(と、記憶しています)。


推測

いにしえのCPUには、なぜ符号付き整数を扱うフラグや命令がないのか?

  • そもそもレジスタ幅は8ビットしかなくて、MSBを(特別に意味付けて)符号に使おうという発想が無かった。
  • 基本、制御用なので、ビット操作を行うか、8ビットカウンタで回数を数えるという使い方が多く、bit7を特別扱いする場面にはならない。
  • C言語が発明される前に設計されたため、(signed) char という型を知らない。
    • 16bit整数も、あえてbit15を符号ビットとして別扱いすることも少なかった。
    • アセンブラコーディングではレジスタ(ペア)をunsigned int(主にカウンタ?)として扱うほうが圧倒的に多かった。

  • 大小比較の場面以外では、符号付き整数と符号なし整数を区別する必要が無い。
    • ADD / SUB などの基本命令はsigned/unsignedのどちらが入っていても同じ動作をする。


まとめ

CPU符号付き整数の大小判断命令サポート
SC/MP×
8080×
6800
6809
Z80×
6502×
680x0
80x86
H8/SH-[1..4] *1
PIC16/PIC18×
AVR
ARM/Thumb

  • Cコンパイラ出力コードを普通にサポートしているCPUには全て備わっているというのが常識です。


あなたの名前: 合言葉


参考文献:半導体コレクション展示会場


*1 Bcc系も含めて命令体系は68000のぱくりになっているものが多い)), *2, ((NECの8080互換CPUにも同じような話がある。ただ、NECの場合はインテルのセカンドソースですらなくて、リバースエンジニアリングだった。
*2 というのも、H8の設計動機はmotorola縛りから逃れるためだった。)), ((motorola縛りと言うのは、MC680x互換CPUを製造していた当時、こっそり追加した機能や命令はmotorolaから物言いがついたという噂

Last-modified: 2009-09-18 23:43:49