Автор работы: Пользователь скрыл имя, 14 Апреля 2013 в 11:33, дипломная работа
Цель данной работы состоит в разработке моделей RISC-микропроцессора с MIPS-архитектурой, демонстрирующих возникновения и методы устранения конфликтов по ресурсам, по данным, по управлению.
В результате проведённой работы были разработаны схемы RISC-микропроцессоров с MIPS-архитектурой в системе Logisim , которые могут быть использованы в учебном процессе в подготовке бакалавров и магистров по направлению «Информатика и вычислительная техника».
Введение. 5
1 Обоснование выбора среды моделирования Logisim. 7
2 Общие сведения RISC-микропроцессора с MIPS-архитектурой. 10
3 Структура процессора и его конвейерные стадии. 14
3.1 Основные блоки процессора. 16
3.1.1 Память команд и память данных. 18
3.1.2 Декодер инструкций. 18
3.1.3 Регистровый файл. 19
3.1.4 Арифметико-логическое устройство. 20
3.2 Стадии конвейера процессора. 22
3.2.1 Стадия получения инструкции. 22
3.2.2 Стадия декодирования инструкции и чтения регистров. 23
3.2.3 Стадия выполнения и вычисления адреса. 24
3.2.4 Стадия доступа к памяти. 26
3.2.5 Стадия запись в регистр. 28
4.Конфликты процессора. 30
4.1 Конфликт по данным. 30
4.1.1 Устранение конфликта по данным. 33
4.1.1.1 Устранение конфликта по данным с помощью заглушек (nop). 33
4.1.1.2 Устранение конфликта по данным с помощью введения обратной связи (шунт). 39
4.2 Конфликт по управлению. 46
4.2.1 Устранение конфликта по управлению. 48
4.2.1.1 Устранение конфликта по управлению с помощью заглушек (nop). 48
4.2.1.2 Устранение конфликта по управлению аппаратным путем. 53
5 Использование RISC-микропроцессора с MIPS-архитектурой в телекоммуникациях. 61
Заключение. 65
Список литературы. 66
Самый простой способ избежать конфликта — вставить между инструкциями три псевдоинструкции nop («заглушки»). В таком случае инструкции пройдут стадии WB и ID в нужном нам порядке (таблица 5), но процессор три такта будет простаивать (выполнять «отсутствие операции»). Самый правильный с точки зрения производительности способ обходить конфликты — вставлять между потенциально конфликтующими инструкциями другие инструкции программы, то есть изменять порядок следования инструкций определённым образом. Ассемблер lilpM32asm автоматически обнаруживает потенциально конфликтные ситуации такого рода (когда чтение регистра может произойти до необходимой записи в него) и вставляет столько инструкций nop, сколько необходимо (их число может быть меньше трёх, если программист вставил между ними другие инструкции). Общий вид программы lilpM32asm представлен на рисунке 22.
Рисунок 22. Окно программы lilpM32asm.
В левой части программы пишется программа на ассемблере, а левой части уже сам компилятор пишет машинные коды, которые и будут загружаться в память команд. Листинг hex-файла приведён на рисунке 23.
# lilpM32 program; format:
# xxxxxxxx # instr (opcode, funct)
262b0004 # addiu (09, 00)
00000000 # nop
00000000 # nop
00000000 # nop
256c0002 # addiu (09, 00)
Рисунок 23. Листинг hex-фала.
Здесь видно, что компилятор обнаружил конфликт по данным между двумя командами сложения и поставил заглушки.
Таблица 5. Обход конфликта по данным при чтении из регистра
Инструкция |
Состояние конвейера | ||||||||
addiu |
IF |
ID |
EX |
MEM |
WB |
||||
nop |
IF |
ID |
EX |
MEM |
WB |
||||
nop |
IF |
ID |
EX |
MEM |
WB |
||||
nop |
IF |
ID |
EX |
MEM |
WB |
||||
addiu |
IF |
ID |
EX |
MEM |
WB | ||||
Номер такта |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Если загрузить этот код в схему процессора lilpM32, то можно увидеть, что после выполнения первой инструкции сложения в регистр $t3 и в память данных записалось значение 4. После выполнения второй инструкции сложения, которой требовался результат первой операции, в регистр $t4 и в память данных записалось значение 6.
На рисунке 24 кругом обведено значение, которое получилось при выполнении второй инструкции сложения на выходе арифметико-логического устройства. Это значение получилось равным 6. На рисунке 25 показано, какие значения хранятся в регистрах в регистровом файле, кругом обведены значения, которые записались. На рисунке 26 показано, какие значения записаны в память данных.
Рисунок 24. Выполнение второй инструкции сложения.
Рисунок 25. Записанные значения в регистровом файле.
Рисунок 26. Дамп ячеек памяти данных.
Напишем более сложную программу. Её листинг приведён ниже на рисунке 27.
addiu $t3, $s1, 4 # $t3= $s1 + 4 (4)
addiu $t4, $t3, 2 # $t4= $t3 + 2 (6)
addiu $t5, $t3, 3 # $t5= $t3 + 3 (7)
addiu $t2, $t4, 9 # $t2= $t4 + 9 (15)
addiu $t6, $t3, 5 # $t6= $t3 + 5 (9)
addiu $t3, $0, 5 # $t3= 5
addiu $t5, $t6, 1 # $t5= $t6 + 1 (10)
ori $t3, $t3, 3 # $t3= $t3|| 3 (7)
subu $t6, $t5, $t6 # $t6= $t5-$t6 (1)
addu $t4, $0, $0 # $t4= 0
addu $t3, $0, $0 # $t3= 0
addiu $t3, $t3, 1 # $t3= $t3 + 1 (1)
addiu $t4, $t3, 2 # $t4= $t3 + 2 (3)
Рисунок 27. Листинг программы.
В круглых скобках показаны значения, которые должны быть получены в результате вычислений. При выполнении первой инструкции в регистр $t3 должно записаться значение=4. При выполнении инструкции addiu $t4, $t3, 2 в регистр $t4 должно записаться значение=6 (4+2). При выполнении инструкции addiu $t5, $t3, 3 в регистр $t5 должно записаться значение=7 (4+3). При выполнении инструкции addiu $t2, $t4, 9 в регистр $t2 должно записаться значение=15 (6+9). При выполнении инструкции addiu $t6, $t3, 5 в регистр $t6 должно записаться значение=9 (4+5). При выполнении инструкции addiu $t3, $0, 5 в регистр $t3 должно записаться значение=5 (0+5). При выполнении инструкции addiu $t5, $t6, 1 в регистр $t5 должно записаться значение=10 (9+1). При выполнении инструкции ori $t3, $t3, 3 в регистр $t3 должно записаться значение=7 (5||3). При выполнении инструкции subu $t6, $t5, $t6 в регистр $t6 должно записаться значение=1 (10-9). При выполнении инструкции addu $t4, $0, $0 в регистр $t4 должно записаться значение=0. При выполнении инструкции addu $t3, $0, $0 в регистр $t3 должно записаться значение=0. При выполнении инструкции addiu $t3, $t3, 1 в регистр $t3 должно записаться значение=1. При выполнении инструкции addiu $t4, $t3, 2 в регистр $t4 должно записаться значение=3 (1+2). Листинг hex-файла приведён на рисунке 28.
# lilpM32 program; format:
# xxxxxxxx # instr (opcode, funct)
262b0004 # addiu (09, 00)
00000000 # nop
00000000 # nop
00000000 # nop
256c0002 # addiu (09, 00)
00000000 # nop
00000000 # nop
256d0003 # addiu (09, 00)
258a0009 # addiu (09, 00)
256e0005 # addiu (09, 00)
240b0005 # addiu (09, 00)
00000000 # nop
00000000 # nop
25cd0001 # addiu (09, 00)
00000000 # nop
00000000 # nop
356b0003 # ori (0d, 00)
01ae7023 # subu (00, 23)
00006021 # addu (00, 21)
00005821 # addu (00, 21)
00000000 # nop
00000000 # nop
00000000 # nop
256b0001 # addiu (09, 00)
00000000 # nop
00000000 # nop
00000000 # nop
256c0002 # addiu (09, 00)
Рисунок 28. Листинг hex-файла.
На рисунке 29 показано, какие значения хранятся в регистрах в регистровом файле. На рисунке 30 показано, какие значения записаны в память данных.
Рисунок 29. Записанные значения в регистровом файле.
Рисунок 30. Дамп ячеек памяти данных.
Другой способ избежать конфликта — ввести обратную связь (шунт) на стадию выполнения инструкции. В таком случае результат предыдущей инструкции будет поступать на мультиплексор. И на первый вход арифметико-логического устройства будет поступать либо значение операнда s, либо значение предыдущей операции, либо значение из памяти данных.
Первый мультиплексор пропускает значение или предыдущей операции или памяти данных, когда адрес в блоке конвейера ID/EX больше адреса в блоке EX/MEM. Иначе мультиплексор пропускает значение операнда s.
Другой мультиплексор пропускает данные из памяти, когда записаны нужные данные, иначе пропускается результат предыдущей операции.
На другой вход
арифметико-логического
В данном способе не нужно вставлять пустые инструкции и результат выполнения инструкций тоже будет правильным. На рисунке 31 представлена схема обратной связи для обнаружения конфликта по данным. На рисунке 32 изображён весь процессор с доработанной частью для обнаружения конфликта по данным. В приложении 1 на Э1 показана структурная схема процессора с обнаружением конфликтов по данным.
Рисунок 31. Схема шунта для обнаружения конфликта по данным.
Рисунок 32. Процессор со схемой обратной связи.
Рассмотрим первый пример, но теперь из кода hex-файла уберём пустые инструкции (nop). Полученный листинг кода показывается на рисунке 33.
# lilpM32 program; format:
# xxxxxxxx # instr (opcode, funct)
262b0004 # addiu (09, 00)
256c0002 # addiu (09, 00)
Рисунок 33. Листинг hex-файла.
В данном примере получается, что регистр $t3 запишется значение операции, равным 4 (на рисунке 34 кругом обведены поступления в регистры кодов операций и результат первой инструкции). И сразу же после выполнения первой операции последует вторая операция, и на этот раз результат второй инструкции будет верен. Он получится равным 6 (4+2), на рисунке 35 выделен кругом полученный верный результат.
Рисунок 34. Выполнение первой инструкции.
Рисунок 35. Выполнение второй инструкции.
Рассмотрим теперь второй пример, который показывался в разрешении конфликта по данным с помощью ввода пустых инструкций (nop). Но теперь также как и рассмотренном выше примере из кода hex-файла уберём пустые инструкции (nop). Полученный листинг кода показывается на рисунке 36.
# lilpM32 program; format:
# xxxxxxxx # instr (opcode, funct)
262b0004 # addiu (09, 00)
256c0002 # addiu (09, 00)
256d0003 # addiu (09, 00)
258a0009 # addiu (09, 00)
256e0005 # addiu (09, 00)
240b0005 # addiu (09, 00)
25cd0001 # addiu (09, 00)
356b0003 # ori (0d, 00)
01ae7023 # subu (00, 23)
00006021 # addu (00, 21)
00005821 # addu (00, 21)
256b0001 # addiu (09, 00)
256c0002 # addiu (09, 00)
Рисунок 36. Листинг hex-файла.
На рисунке 37 показано, какие значения хранятся в регистрах в регистровом файле. На рисунке 38 показано, какие значения записаны в память данных.
Рисунок 37. Записанные значения в регистровом файле.
Все записанные значения получились верными, и они нечем не отличаются от значений, показанных на рисунке 29.
Рисунок 38. Дамп ячеек памяти данных.
Существует ещё один класс ситуаций, которые могут вызвать конфликт конвейера.
Конфликт может случиться, если потребуется выполнить вот такую последовательность инструкций, листинг приведён на рисунке 39.
j end # jump end
addiu $t3, $t2, 5 #$t3=$t2+5
end:
Рисунок 39. Листинг программы.
Некоторые инструкции (beq, bne, j, jr, jal, bgt, blt, bge, ble) меняют значение программного счётчика. Записывая следующие за ними инструкции, предполагается, что переход на новый адрес (то есть изменение значения программного счётчика) уже произошёл. Однако фактическое изменение значения происходит только на стадии MEM, а значит, ещё три идущие подряд инструкции будут получены для выполнения (это происходит на стадии IF) из «старого» места в ОЗУ. Если внимательно посмотреть на таблицу состояний конвейера (таблица 6), то видно, что первая инструкция пройдёт стадию MEM позже, чем вторая — стадию IF.
Таблица 6. Конфликт при переходе на новый адрес
Инструкция |
Состояние конвейера | |||||
j |
IF |
ID |
EX |
MEM |
WB |
|
addiu |
IF |
ID |
EX |
MEM |
WB | |
Номер такта |
1 |
2 |
3 |
4 |
5 |
6 |
В данном примере получается, что должен быть вычислен адрес перехода и перейти на метку end, но это произойдёт только на стадии MEM. Следовательно, это означает, что будет выполняться инструкция addiu, которая не должна исполняться. На рисунке 40 обведены кругом стадии конвейера и результат инструкции, которая не должна была выполняться.
Рисунок 40. Иллюстрирование конфликта по управлению.
Чтобы результаты инструкций выдавали правильные значения необходимо исправлять конфликты по управлению. Ниже будет рассмотрено два варианта устранения конфликта по управлению:
Как и случае с конфликтом по данным, здесь самым простым способом избежать конфликта — вставить между инструкциями три псевдоинструкции nop («заглушки»). В таком случае инструкции пройдут стадии MEM и IF в нужном нам порядке, и команда addiu не выполнится, но процессор три такта будет простаивать (выполнять «отсутствие операции»).
Самый правильный с точки зрения производительности способ обходить конфликты — вставлять между потенциально конфликтующими инструкциями другие инструкции программы, то есть изменять порядок следования инструкций определённым образом. Ассемблер lilpM32asm принудительно вставляет три инструкции nop после инструкций, меняющих значение программного счётчика (таблица 7 и прыжок будет совершён на метку). Листинг hex-файла приведён на рисунке 41.
# lilpM32 program; format:
# xxxxxxxx # instr (opcode, funct)
08000005 # j (02, 00)