Почему IA32 не позволяет памяти в память перемещаться?
В архитектуре Intel IA32 такие инструкции, как movl, movw, не разрешают операнды, которые являются обеими ячейками памяти. Например, инструкция movl (%eax), (%edx) недопустима. Зачем?
4 ответа
Ответ предполагает более полное понимание оперативной памяти. Проще говоря, ОЗУ может находиться только в двух состояниях: режиме чтения или записи. Если вы хотите скопировать один байт оперативной памяти в другое место, у вас должна быть временная область памяти вне ОЗУ, когда вы переключаетесь с чтения на запись.
Архитектура, безусловно, может иметь такую инструкцию ОЗУ в ОЗУ, но это будет инструкция высокого уровня, которая в микрокоде преобразуется в копирование данных из ОЗУ в регистр, а затем обратно в ОЗУ. Альтернативно, можно было бы расширить контроллер ОЗУ, чтобы иметь такой временный регистр только для этого копирования данных, но это не принесло бы большой пользы для дополнительной сложности взаимодействия ЦП и аппаратного обеспечения.
РЕДАКТИРОВАТЬ: Стоит отметить, что недавние усовершенствования, такие как Hybrid Memory Cube и High Bandwidth Memory, являются архитектурами, в которых топология RAM стала больше похожа на PCI-e, и теперь возможны прямые передачи RAM в RAM, но это связано с логикой поддержки для технологий, а не самой оперативной памяти. В архитектуре ЦП это будет происходить в виде огромных блоков ОЗУ за раз, например, DMA, а не в виде одной инструкции, плюс кэш ЦП ведет себя как традиционная ОЗУ, поэтому архитектуре придется абстрагировать ее как согласно моему оригинальному объяснению
РЕДАКТИРОВАТЬ 2: Согласно комментарию @PeterCordes, мое первоначальное понимание не было полностью правильным; x86 на самом деле имеет несколько инструкций памяти к памяти. Реальная причина, по которой они недоступны для большинства инструкций (таких как movl и movw), заключается в том, чтобы сохранить сложность кодирования команд на низком уровне, но они могли бы их реализовать. Тем не менее, основная идея в моем первоначальном ответе о том, что вне ОЗУ имеется временное хранилище в виде защелки или регистра, верна, но идея о том, что это причина, по которой эти инструкции не существуют, не верна. Даже старые чипы 1970-х годов, такие как 6502 и 8086, имеют инструкции памяти к памяти, и вы можете легко выполнять такие операции, как INC, непосредственно в ячейке ОЗУ. Это было достигнуто путем фиксации выборки памяти непосредственно в АЛУ и возврата обратно в память без прохождения через регистр, используемый набором команд.
ia32 - это x86, а x86 - это эволюция от Intel 8086 (iAPX 86). Это был небольшой и дешевый чип, основанный на 8-битных наборах команд, и не имел "mov" с двумя явными операндами памяти.
Автор Википедии дает такое объяснение о кодировке инструкций 8086:
Из-за компактного кодирования, основанного на 8-битных процессорах, большинство инструкций являются одноадресными или двухадресными операциями, что означает, что результат сохраняется в одном из операндов. Максимум один из операндов может находиться в памяти, но этот операнд памяти также может быть адресатом, в то время как другой операнд, источник, может быть регистровым или непосредственным. Одна и та же ячейка памяти также часто может использоваться как в качестве источника, так и места назначения, что, помимо других факторов, дополнительно способствует плотности кода, сравнимой (и часто лучше, чем) с большинством восьмибитных машин того времени.
Существовали некоторые CISC с инструкциями память-память (одна инструкция для работы с двумя операндами памяти). В лекции https://www.cis.upenn.edu/~milom/cis501-Fall05/lectures/02_isa.pdf говорится, что VAX может кодировать инструкции память-память:
DEC VAX (расширение виртуального адреса до PDP-11): 1977
- • Инструкции переменной длины: 1-321 байт!!!
- • 14 GPR + ПК + указатель стека + коды условий
- • Размеры данных: 8, 16, 32, 64, 128 бит, десятичные, строковые
- • Память-память инструкции для всех размеров данных
- • Специальные insns: crc, insque, polyf и сотня актеров
Это источник OpenBSD memcpy для VAX (руководство по набору инструкций http://h20565.www2.hpe.com/hpsc/doc/public/display?docId=emr_na-c04623178):
movq 8(ap),r1 /* r1 = src, r2 = length */
movl 4(ap),r3 /* r3 = dst */
...
1: /* move forward */
cmpl r2,r0
bgtru 3f /* stupid movc3 limitation */
movc3 r2,(r1),(r3) /* move it all */
Инструкция "movc3" здесь имеет два операнда памяти, адреса которых хранятся в регистрах.
В x86 есть несколько "строковых" инструкций, которые будут выполнять операции с памятью (*s, особенно movs - http://x86.renejeschke.de/html/file_module_x86_id_203.html), но эта инструкция будет использовать предопределенные регистры SI и DI в качестве адресов (неявные операнды), и два операнда памяти все еще не могут быть закодированы в x86.
Насколько я знаю, как правило, в этой архитектуре разрешен только один доступ к памяти на инструкцию. Это связано с тем, что обработка двух обращений к памяти для каждой инструкции усложнит конвейер выполнения процессора.
Оперативная память поддерживает ввод и вывод, но не копирование. Следовательно, перемещение из памяти в память фактически будет перемещением из памяти в процессор. Теоретически было бы возможно реализовать такую инструкцию, но, вероятно, это было не так, потому что это было бы не очень практично.
Вот некоторые вещи, которые необходимо учитывать для реализации такой инструкции:
Какое временное хранилище мы используем? Регистр?
Если мы используем регистр, какой из них мы угоняем?
Отсутствие такой инструкции оставляет программисту вышеуказанные вопросы.