.include "address_map.s"
.equ RIBBON_CABLE_INSTALLED, 0
/* Программа демонстрирует различные возможности процессорной системы.
* Она выполняет следующие действия:
* 1. Тестирует статическую память.
* 2. Прокручивает текст на семисегментном дисплее. Если ошибок при тестировании
* статической памяти не обнаружено, то текст содержит слова "dE2" и "PASSEd". Если
* были обнаружены ошибки, то выводится слово "Error".
* 3. Мигает зелеными светодиодами. Скорость мигания светодиодов и прокрутки текста на
* семисегментных индикаторах регулируется прерываниями таймера.
* 4. Подключает переключатели к красным светодиодам.
* 5. Обрабатывает прерывания от кнопок. Нажатие кнопки KEY1 увеличивает скорость
* прокрутки текста. Нажатие кнопки KEY2 снижает скорость, кнопки KEY3 - останавливает
* прокрутку.
* 6. Тестирует порты расширения JP1, JP2.
* 7.Отсылает обратно данные, полученные по интерфейсу JTAG UART (символы, введенные в терминальном окне программы Altera Monitor Program) и наоборот. */
.text
.global _start
_start:
/* инициализируем регистры sp и fp */
|
|
movia sp, 0x03FFFFFC /* Стек начинается с последнего адреса SDRAM памяти
mov fp, sp
/* инициализируем буфер семисегментных индикаторов */
movia r16, DISPLAY_BUFFER
movi r17, 0xde2
stw r17, 0(r16)
stw zero, 4(r16)
stw zero, 8(r16)
/* инициализируем зеленые светодиоды */
movia r2, 0x55555555
movia r16, GREEN_LED_PATTERN
stw r2, 0(r16)
/* инициализируем счетчик задержки, используемый для определения изменений отображаемого текста */
movia r16, EIGHT_SEC
stw zero, 0(r16)
/* инициализируем переключатели */
movia r16, DISPLAY_TOGGLE
stw zero, 0(r16)
/* направление передачи может быть сохранено в SHIFT_DIRECTION,
где 0-влево, 1-вправо */
movi r2, 1
movia r16, SHIFT_DIRECTION
stw r2, 0(r16)
/* запускаем таймер и разрешаем его прерывания */
movia r16, INTERVAL_TIMER_BASE
movi r15, 0b0111 /* START = 1, CONT = 1, ITO = 1
sthio r15, 4(r16)
/* разрешаем прерывания от кнопок */
movia r16, PUSHBUTTON_BASE
movi r15, 0b01110 /* устанавливаем биты маски прерывания в 1
stwio r15, 8(r16)
/* разрешаем прерывания процессора */
movi r15, 0b011 /* разрешаем прерывания от таймера и кнопок
.if RIBBON_CABLE_INSTALLED
ori r15, r15, 0b1000000000000 /* также разрешаем прерывания для порта расширения JP2
.endif
wrctl ienable, r15
movi r15, 1
wrctl status, r15
/* цикл, в котором тестируется статическая память и обновляются семисегментные индикаторы */
movia r15, 0x55555555
movia r17, SRAM_END
DO_DISPLAY:
movia r16, SRAM_BASE
movia r17, SRAM_END
MEM_LOOP:
call UPDATE_HEX_DISPLAY
call UPDATE_RED_LED /* подключаем переключатели к красным светодиодам
call UPDATE_UARTS /* обновление и JTAG порта и последовательного порта
/* тестируем порты расширения, если подключен 40-контактный кабель Ribbon */
.if RIBBON_CABLE_INSTALLED
call TEST_EXPANSION_PORTS /*возвращает 0, если тест закончился неудачей
beq r2, zero, SHOW_ERROR
.endif
stw r15, 0(r16)
ldw r14, 0(r16)
bne r14, r15, SHOW_ERROR
addi r16, r16, 4
ble r16, r17, MEM_LOOP
|
|
xori r15, r15, 0xFFFF
xorhi r15, r15, 0xFFFF
/* обновляем буфер семисегментных индикаторов примерно каждые 8 секунд */
movia r16, EIGHT_SEC
ldw r17, 0(r16)
movi r14, 80 /* 80 прерываний таймера равны примерно 10 секундам
ble r17, r14, DO_DISPLAY
stw zero, 0(r16)
/* выводим на семисегментные индикаторы слова dE2 и PASSEd */
movia r16, DISPLAY_TOGGLE
ldw r17, 0(r16)
beq r17, zero, SHOW_PASSED
stw zero, 0(r16)
/* выводим dE2 */
movia r16, DISPLAY_BUFFER
movi r17, 0xdE2
stw r17, 0(r16)
stw zero, 4(r16)
stw zero, 8(r16)
br DO_DISPLAY
SHOW_PASSED:
movi r17, 1
stw r17, 0(r16)
movia r16, DISPLAY_BUFFER
movia r17, 0xbA55Ed /* слово Passed
stw r17, 0(r16)
stw zero, 4(r16)
stw zero, 8(r16)
br DO_DISPLAY
SHOW_ERROR:
movia r16, DISPLAY_BUFFER
movia r17, 0xe7787 /* слово Error
stw r17, 0(r16)
stw zero, 4(r16)
stw zero, 8(r16)
DO_ERROR:
call UPDATE_HEX_DISPLAY
br DO_ERROR
/*******************************************************************************Обновляем значения, выводимые на семисегментный дисплей. Значения считываются из буфера
*******************************************************************************/
.global UPDATE_HEX_DISPLAy
UPDATE_HEX_DISPLAY:
subi sp, sp, 36 /* резервируем память в стеке
/* сохраняем регистры */
stw ra, 0(sp)
stw fp, 4(sp)
stw r15, 8(sp)
stw r16, 12(sp)
stw r17, 16(sp)
stw r18, 20(sp)
stw r19, 24(sp)
stw r20, 28(sp)
stw r21, 32(sp)
addi fp, sp, 36
/* выводим значения на индикаторы */
movia r15, DISPLAY_BUFFER
ldw r16, 4(r15)
/* Цикл, который заполняет буфер из 2 слов, который подключен к параллельному порту «DE2-70 Media Computer», подключенного к семисегментным индикаторам. Для каждого сегмента отводится 8 бит буфера*/
movia r17, 7
movia r15, HEX3_HEX0
movia r19, SEVEN_SEG_DECODE_TABLE
SEVEN_SEG_DECODER:
mov r18, r16
andi r18, r18, 0x000F
add r20, r19, r18
add r21, zero, zero
ldb r21, 0(r20) /* в r21 загружаем код символа
stb r21, 0(r15) /* сохраняем код в буфере
srli r16, r16, 4
addi r15, r15, 1
subi r17, r17, 1
bge r17, zero, SEVEN_SEG_DECODER
/* выводим на семисегментные индикаторы содержимое буфера */
movia r15, HEX3_HEX0
ldw r16, 0(r15)
movia r17, HEX3_HEX0_BASE
stwio r16, 0(r17)
ldw r16, 4(r15)
movia r17, HEX7_HEX4_BASE
stwio r16, 0(r17)
/* извлекаем из стека регистры */
ldw ra, 0(sp)
ldw fp, 4(sp)
ldw r15, 8(sp)
ldw r16, 12(sp)
ldw r17, 16(sp)
ldw r18, 20(sp)
ldw r19, 24(sp)
ldw r20, 28(sp)
ldw r21, 32(sp)
addi sp, sp, 36 /* освобождаем зарезервированную память стека
ret
/*****************Подключаем переключатели к красным светодиодам****************/
.global UPDATE_RED_LED
UPDATE_RED_LED:
/* сохраняем регистры в стеке */
subi sp, sp, 16 /* резервируем область памяти в стеке
stw ra, 0(sp)
stw fp, 4(sp)
stw r15, 8(sp)
stw r16, 12(sp)
addi fp, sp, 16
/* считываем значение с переключателей */
movia r15, SLIDER_SWITCH_BASE
ldwio r16, 0(r15)
/* выводим его на красные светодиоды */
movia r15, RED_LED_BASE
stwio r16, 0(r15)
/* извлекаем из стека регистры */
ldw ra, 0(sp)
ldw fp, 4(sp)
ldw r15, 8(sp)
ldw r16, 12(sp)
addi sp, sp, 16
ret
/******************************************************************************* Считываем символы из JTAG порта и последовательного
порта UART и отправляем их обратно в оба порта *******************************************************************************/
.global UPDATE_UARTS
UPDATE_UARTS:
/* сохраняем регистры в стеке */
subi sp, sp, 28 /* резервируем область памяти в стеке
stw ra, 0(sp)
stw fp, 4(sp)
stw r15, 8(sp)
stw r16, 12(sp)
stw r17, 16(sp)
stw r18, 20(sp)
stw r19, 24(sp)
addi fp, sp, 28
movia r15, JTAG_UART_BASE
movia r19, UART_BASE
GET_CHAR:
ldwio r17, 0(r15) /* проверяем, имеют ли JTAG или UART порты новые данные
andi r18, r17, 0x8000 /* считываем символ
beq r18, r0, GET_CHAR_UART
andi r16, r17, 0x00ff
PUT_CHAR:
ldwio r17, 4(r15) /* проверяем, готовы ли порты JTAG UART к приему данных
andhi r17, r17, 0xffff
beq r17, r0, PUT_CHAR_UART
stwio r16, 0(r15) /* отправляем символ обратно
PUT_CHAR_UART:
ldwio r17, 4(r19)
andhi r17, r17, 0xffff
beq r17, r0, GET_CHAR_UART
stwio r16, 0(r19)
GET_CHAR_UART:
ldwio r17, 0(r19)
andhi r18, r17, 0xFFFF
beq r18, r0, NO_CHAR
andi r16, r17, 0x00ff
ldwio r17, 4(r19)
andhi r17, r17, 0xffff
beq r17, r0, PUT_CHAR_JTAG
stwio r16, 0(r19)
PUT_CHAR_JTAG:
ldwio r17, 4(r15)
andhi r17, r17, 0xffff
beq r17, r0, NO_CHAR
stwio r16, 0(r15)
NO_CHAR:
/* восстанавливаем из стека регистры */
ldw ra, 0(sp)
ldw fp, 4(sp)
ldw r15, 8(sp)
ldw r16, 12(sp)
ldw r17, 16(sp)
ldw r18, 20(sp)
ldw r19, 24(sp)
addi sp, sp, 28
ret
/*******************************************************************************
Данный код тестирует порты расширения JP1 и JP2. Для этого должен использоваться кабель Ribbon
*******************************************************************************/
.global TEST_EXPANSION_PORTS
TEST_EXPANSION_PORTS:
/* сохраняем регистры в стеке */
subi sp, sp, 24
stw ra, 0(sp)
stw fp, 4(sp)
stw r15, 8(sp)
stw r16, 12(sp)
stw r17, 16(sp)
stw r18, 20(sp)
addi fp, sp, 24
movia r15, JP1_EXPANSION_BASE
movia r16, JP2_EXPANSION_BASE
|
|
movia r17, 0xFFFFFFFF
stwio r17, 4(r15)
add r17, zero, zero
stwio r17, 4(r16)
movia r17, 0x55555555
stwio r17, 0(r15)
add zero, zero, zero
ldwio r18, 0(r16)
bne r17, r18, RET_ERROR
movia r17, 0xAAAAAAAA
stwio r17, 0(r15)
add zero, zero, zero
ldwio r18, 0(r16)
bne r17, r18, RET_ERROR
movia r17, 0x01234567
stwio r17, 0(r15)
add zero, zero, zero
ldwio r18, 0(r16)
bne r17, r18, RET_ERROR
add r17, zero, zero
stwio r17, 4(r15)
movia r17, 0xFFFFFFFF
stwio r17, 4(r16)
movia r17, 0x55555555
stwio r17, 0(r16)
add zero, zero, zero
ldwio r18, 0(r15)
bne r17, r18, RET_ERROR
movia r17, 0xAAAAAAAA
stwio r17, 0(r16)
add zero, zero, zero
ldwio r18, 0(r15)
bne r17, r18, RET_ERROR
movia r17, 0x01234567
stwio r17, 0(r16)
add zero, zero, zero
ldwio r18, 0(r15)
bne r17, r18, RET_ERROR
movi r2, 1
br RETURN
RET_ERROR:
movi r2, 0
RETURN:
ldw ra, 0(sp)
ldw fp, 4(sp)
ldw r15, 8(sp)
ldw r16, 12(sp)
ldw r17, 16(sp)
ldw r18, 20(sp)
addi sp, sp, 24
ret
/****************************** DATA SECTION *********************************/
.data
.global DISPLAY_BUFFER
DISPLAY_BUFFER:
.fill 3, 4, 0
.global SHIFT_DIRECTION
SHIFT_DIRECTION:
.word 0
/* Таблица декодирования семисегментных индикаторов содержит значения включен(1)/выключен(0) для каждого сегмента индикаторов*/
SEVEN_SEG_DECODE_TABLE:
.byte 0b00000000, 0b00000110, 0b01011011, 0b01001111
.byte 0b01100110, 0b01101101, 0b01111100, 0b01010000
.byte 0b01011100, 0b01100111, 0b01110111, 0b01110011
.byte 0b00111001, 0b01011110, 0b01111001, 0b01110001
HEX3_HEX0:
.word 0
HEX7_HEX4:
.word 0
.global GREEN_LED_PATTERN
GREEN_LED_PATTERN:
.word 0
.global EIGHT_SEC
EIGHT_SEC:
.word 0
DISPLAY_TOGGLE:
.word 0
.end
Листинг 2 Исходный файл программы lab1_part3_DE.s
/* Программа осуществляет поиск максимального числа в списке целых чисел. */
.equ LIST, 0x500 /* Адрес начала списка в памяти. Первый элемент списка будет содержать максимальное число, 2-ой - количество чисел в списке*/
.global _start
_start:
movia r4, LIST /* В регистр R4 записывается адрес начала списка */
ldw r5, 4(r4) /* Считываем в регистр R5 значение количества чисел в списке */
addi r6, r4, 8 /* Вычисляем адрес памяти, с которого начинают располагаться числа для поиска*/
ldw r7, (r6) /* В регистр R7 из памяти по адресу R6 считывается первое число списка */
LOOP:
subi r5, r5, 1 /* Уменьшаем значение количества чисел в списке */
beq r5, r0, DONE /* Если значение регистра R5 равно 0, то выходим из цикла */
addi r6, r6, 4 /*Увеличиваем адрес памяти на 4 (переходим к следующему числу */
ldw r8, (r6) /* Считываем из памяти следующее число */
bge r7, r8, LOOP /* Если текущее максимальное число больше или равно считанному, то возвращаемся в начало цикла*/
add r7, r8, r0 /* Иначе, записываем в R7 новое максимальное число */
|
|
br LOOP
DONE:
stw r7, (r4) /* Записываем максимальное число в память по адресу 0x500 */
STOP:
br STOP /* Бесконечный цикл */
.org 0x100
RESULT:
.skip 4 /* Выделяем 4 байта для хранения максимального числа */
N:
.word 7 /* Количество чисел в списке */
NUMBERS:
.word 4, 5, 3, 6, 1, 8, 2 /* Числа из списка */
.end
Листинг 3 Исходный файл программы LCD_DE2_70.s
.include "nios_macros.s"
.text
.equ lcd,0x10003050 /*Адрес регистра lcd*/
.equ clear,0x00000001 /*Код команды очистки экрана lcd*/
.equ set1,0b10000000 /*Код команды установки курсора в первую позицию первой строки*/
.equ set2,0b11000000 /*Код команды установки курсора в начало 2 строки*/
.equ off,0b00001100 /*Код команды выключения курсора*/
.equ right,0b00011100 /*Код команды сдвига экрана вправо*/
.equ left,0b00011000 /*Код команды сдвига курсора влево*/
.global _start
_start:
movia r2,lcd
movi r3,clear /*Код команды очистки lcd*/
stbio r3,0(r2) /*Очищаем экран lcd*/
movi r3,set1
stbio r3,0(r2) /*Устанавливаем курсор в начало первой строки*/
movia r4,String1 /*В регистр R4 записываем адрес первой строки*/
cikl:
ldb r5,0(r4) /*Считываем символ из строки и помещаем его в R5*/
beq r5,zero,met /*Если считанныцй символ равен 0, то выходим из цикла*/
stbio r5,1(r2) /*Записываем из R5 в регистр данных lcd*/
addi r4,r4,1 /*Инкрементируем адрес символа строки*/
br cikl
met:
movi r3,set2
stbio r3,0(r2) /*Устанавливаем курсор в начало второй строки*/
movia r4,String2 /*Выводим вторую строку*/
cikl2:
ldb r5,0(r4)
beq r5,zero,met1
stbio r5,1(r2)
addi r4,r4,1
br cikl2
met1:
movi r3,off
stbio r3,0(r2) /*Выключаем курсор*/
met2:
movi r3,right
stbio r3,0(r2) /*Сдвигаем экран вправо*/
br met2
met3:
movi r3,left
stbio r3,0(r2) /*Сдвигаем экран влево*/
br met3
.data /*Определяем сегмент данных*/
String1:
.asciz "Kreitin konec"
String2:
.asciz "Alexander"
.end
Таблица 2 ASCII - коды символов