В компьютерных процессорах флаг переноса (обычно обозначаемый как флаг C ) — это один бит в регистре состояния системы / регистре флага, используемый для указания того, когда арифметический перенос или заем были сгенерированы из старшей битовой позиции арифметико-логического устройства (АЛУ). Флаг переноса позволяет складывать/вычитать числа, превышающие ширину одного АЛУ, путем переноса (добавления) двоичной цифры из частичного сложения/вычитания в младшей битовой позиции старшего слова. Это обычно программируется пользователем процессора на уровне ассемблера или машинного кода, но может также происходить внутренне в некоторых процессорах, через цифровую логику или микрокод , где некоторые процессоры имеют более широкие регистры и арифметические инструкции, чем (комбинаторное или «физическое») АЛУ. [1] Он также используется для расширения битовых сдвигов и поворотов аналогичным образом на многих процессорах (иногда делается через выделенный флаг). Для вычитающих операций используются два (противоположных) соглашения, поскольку большинство машин устанавливают флаг переноса при заимствовании, в то время как некоторые машины (например, 6502 и PIC ) вместо этого сбрасывают флаг переноса при заимствовании (и наоборот).
Флаг переноса зависит от результата большинства арифметических (и обычно нескольких битовых) инструкций и также используется в качестве входных данных для многих из них. Некоторые из этих инструкций имеют две формы, которые либо считывают, либо игнорируют перенос. В языках ассемблера эти инструкции представлены мнемоникой, такой как ADD/SUB
, ADC/SBC
( ADD/SUB
включая перенос), SHL/SHR
( сдвиги битов ), ROL/ROR
(повороты битов), RCR/RCL
(поворот через перенос) и т. д. [2] Использование флага переноса таким образом позволяет выполнять многословные операции сложения, вычитания, сдвига и поворота.
Примером может служить то, что произойдет, если сложить 255 и 255 с использованием 8-битных регистров. Результат должен быть 510, что является 9-битным значением 111111110
в двоичном формате. 8 младших бит, всегда хранящихся в регистре, будут 11111110
двоичными (254 в десятичном формате), но поскольку есть перенос бита 7 (восьмой бит), перенос устанавливается, указывая, что результату нужно 9 бит. Допустимый 9-битный результат является конкатенацией флага переноса с результатом.
Для x86 ALU размером 8 бит, интерпретации 8-битного дополнения до двух, операция сложения 11111111
+ 11111111
приводит к 111111110
, Carry_Flag
установке, Sign_Flag
установке и Overflow_Flag
очистке.
Если 11111111
представляет собой знаковое целое число в формате дополнения до двух −1 ( ADD al,-1
), то интерпретация результата равна -2, поскольку Overflow_Flag
ясна, и Carry_Flag
игнорируется. Знак результата отрицательный, поскольку Sign_Flag
задано. 11111110
— знаковое целое число в формате дополнения до двух −2.
Если 11111111
представляет собой беззнаковое целое двоичное число 255 ( ADD al,255
), то интерпретация результата будет 254, что неверно, поскольку самый старший бит результата попал в Carry_Flag
, который, следовательно, нельзя игнорировать. Overflow_Flag
И Sign_Flag
игнорируются.
Другим примером может служить 8-битный регистр с битовой комбинацией 01010101
и установленным флагом переноса; если мы выполним инструкцию поворота влево через перенос , результатом будет 10101011
очищенный флаг переноса, поскольку старший бит (бит 7) был повернут в перенос, а перенос — в младший бит (бит 0).
Ранние микропроцессоры Intel 4004 и Intel 8008 имели специальные инструкции для явной установки и сброса флага переноса. Однако более поздние Intel 8080 (и Z80 ) не включали явный код операции сброса переноса, поскольку это можно было сделать одинаково быстро с помощью одной из побитовых инструкций AND, OR или XOR (которые не используют флаг переноса).
Флаг переноса также часто используется после инструкций сравнения, которые обычно реализуются с помощью вычитательных операций, чтобы можно было принять решение о том, какое из двух сравниваемых значений меньше (или больше или равно) другого. Инструкции перехода, которые проверяют флаг переноса, часто представлены мнемоникой , такой как BCC
и BCS
для перехода, если перенос очищен, или перехода, если перенос установлен соответственно. При использовании таким образом флаг переноса предоставляет механизм для сравнения значений как целых чисел без знака. Это контрастирует с флагом переполнения , который предоставляет механизм для сравнения значений как целых чисел со знаком.
Хотя флаг переноса хорошо определен для сложения, существуют два распространенных способа использования флага переноса для операций вычитания.
Первый использует бит как флаг заимствования, устанавливая его, если a < b при вычислении a − b , и заимствование должно быть выполнено. Если a ≥ b , бит очищается. Вычитание с инструкцией заимствования ( SBB
) вычислит a − b − C = a −( b + C ), в то время как вычитание без заимствования ( SUB
) действует так, как если бы бит заимствования был очищен. Семейства 8080 , 6800 , Z80 , 8051 , x86 [2] и 68k (среди прочих) используют бит заимствования.
Второй использует тождество, что − x = ( not x )+1 напрямую (т. е. без сохранения инвертированного бита переноса) и вычисляет a − b как a +( not b )+1. Флаг переноса устанавливается в соответствии с этим сложением, а вычитание с переносом вычисляет a + not( b )+ C , в то время как вычитание без переноса действует так, как если бы бит переноса был установлен. Результатом является то, что бит переноса устанавливается, если a ≥ b , и очищается, если a < b . Процессоры System/360 , [3] 6502 , MSP430 , COP8 , ARM и PowerPC используют это соглашение. 6502 является особенно известным примером, поскольку у него нет операции вычитания без переноса, поэтому программисты должны гарантировать, что флаг переноса установлен перед каждой операцией вычитания, где заем не требуется. [4]
Чаще всего первую альтернативу называют «вычитанием с заемом», а вторую — «вычитанием с переносом». Однако есть исключения в обоих направлениях; архитектуры VAX , NS320xx и Atmel AVR используют соглашение о заемном бите, но называют свою операцию a − b − C «вычитанием с переносом» ( SBWC
, SUBC
и SBC
). Архитектуры PA-RISC и PICmicro используют соглашение о переносном бите, но называют свою операцию a +not( b )+ C «вычитанием с заемом» ( SUBB
и SUBWFB
).
Микроконтроллеры ST6 8-бит, пожалуй, самые запутанные из всех. Хотя у них нет инструкции "вычитать с переносом", у них есть бит переноса, который устанавливается инструкцией вычитания, а соглашение зависит от модели процессора. Процессор ST60 использует соглашение "перенос", тогда как процессоры ST62 и ST63 используют соглашение "заимствовать". [5]