Search
Cílem je z programu přistupovat na periferie procesorového zařízení.
Studenti by měli po cvičení utvořit týmy, prostudovat požadavky semestrálního projektu a připravit návrh svého projektu.
S problematikou se seznamte nejdříve v simulátoru QtRvSim. Jednoduchá vstupně výstupní periferie je mapovaná od adresy 0xffffc100.
SPILED_REG_LED_LINE
lui t0, 0xffffc ori t0, t0, 0x100 addi t1, zero, 5 sw t1, 4(t0) slli t1, t1, 1 sw t1, 4(t0) slli t1, t1, 1 sw t1, 4(t0) slli t1, t1, 1 ebreak
lui t0, 0xffffc ori t0, t0, 0x100 addi t1, zero, 0 addi t2, zero, 0 la s0, n lw s0,0(s0) cykl1: slli t1, t1, 1 ori t1, t1, 1 addi t2,t2,1 sw t1, 4(t0) bne s0,t2, cykl1 ebreak .data n: .word 5
li t0, 0xffffc000 // base address into memory mapped I/O area addi t1, zero, 48 addi t6, zero, 1234 addi t2, zero, 10 loop: lw t3, 0x08(t0) andi t3, t3, 1 beq t3, zero, loop sw t1, 0x0c(t0) addi t1, t1, 1 addi t2, t2, -1 bne t2, zero, loop ebreak
li t0, 0xffffc000 // base address into memory mapped I/O area addi t1, zero, 48 addi t6, zero, 1234 addi t2, zero, 10 loop_rx: lw t3, 0x0(t0) andi t3, t3, 1 beq t3, zero, loop_rx lw t1, 4(t0) loop_tx: lw t3, 0x08(t0) andi t3, t3, 1 beq t3, zero, loop_tx sw t1, 0x0c(t0) addi t1, t1, 1 addi t2, t2, -1 bne t2, zero, loop_rx ebreak
Kompletní popis periferií implementovaných v simulátoru QtRvSim naleznete na stránce třetího cvičení v odstavci periferie mapované do paměťového adresního prostoru případně přímo v souboru README.md přímo z projektu. Součástí třetího cvičení je i ukázka překladu z jazyka C do assembleru s rozborem generovaného kódu. Nalézá se tam také archiv s programem. Program naleznete in v adresáři /opt/apo/qtrvsim_binrep. Program se shodnou funkcí pro desku MZ_APO naleznete v adresáři /opt/apo/binrep/mzapo_binrep. Porovnání analýzy kódu zkompilovaného pro architekturu ARM naleznete na konci dnešního cvičení.
/opt/apo/qtrvsim_binrep
/opt/apo/binrep/mzapo_binrep
Program na výpis řetězce na sériový port pro QtRvSim
.equ SERIAL_PORT_BASE, 0xffffc000 #base address of QtRVSim serial port .equ SERP_RX_ST_REG, 0xffffc000 #Receiver status register .equ SERP_RX_ST_REG_o, 0x0000 #Offset of RX_ST_REG .equ SERP_RX_ST_REG_READY_m, 0x1 #Data byte is ready to be read .equ SERP_RX_ST_REG_IE_m, 0x2 #Enable Rx ready interrupt .equ SERP_RX_DATA_REG, 0xffffc004 #Received data byte in 8 LSB bits .equ SERP_RX_DATA_REG_o, 0x0004 #Offset of RX_DATA_REG .equ SERP_TX_ST_REG, 0xffffc008 #Transmitter status register .equ SERP_TX_ST_REG_o, 0x0008 #Offset of TX_ST_REG .equ SERP_TX_ST_REG_READY_m, 0x1 #Transmitter can accept next byte .equ SERP_TX_ST_REG_IE_m, 0x2 #Enable Tx ready interrupt .equ SERP_TX_DATA_REG, 0xffffc00c #Write word to send 8 LSB bits .equ SERP_TX_DATA_REG_o, 0x000c #Offset of TX_DATA_REG write: li a0, SERIAL_PORT_BASE # a0 ukazuje na zacatek pameti UART la a1, text_1 # nacti ukazatel na retezec next_char: lb t1, 0(a1) # nacti znak k odeslani beq t1, zero, end_char # 0 ukoncuje retezec addi a1, a1, 1 # posun ukazatel tx_busy: lw t0, SERP_TX_ST_REG_o(a0) # zjisti statu odesilaci fronty andi t0, t0, SERP_TX_ST_REG_READY_m # vymaskuj bit READY beq t0, zero, tx_busy # pokud neni volno v UARTU cekej zkus to znovu sw t1, SERP_TX_DATA_REG_o(a0) # je volno - zapis bajt j next_char # posli dalsi znak end_char: ebreak # ukonci program .data text_1: .asciz "Hello world.\n" # retezec ukonceny 0
Program čtení ze sériového portu pro QtRvSim
.equ SERIAL_PORT_BASE, 0xffffc000 #base address of QtRVSim serial port .equ SERP_RX_ST_REG, 0xffffc000 #Receiver status register .equ SERP_RX_ST_REG_o, 0x0000 #Offset of RX_ST_REG .equ SERP_RX_ST_REG_READY_m, 0x1 #Data byte is ready to be read .equ SERP_RX_ST_REG_IE_m, 0x2 #Enable Rx ready interrupt .equ SERP_RX_DATA_REG, 0xffffc004 #Received data byte in 8 LSB bits .equ SERP_RX_DATA_REG_o, 0x0004 #Offset of RX_DATA_REG .equ SERP_TX_ST_REG, 0xffffc008 #Transmitter status register .equ SERP_TX_ST_REG_o, 0x0008 #Offset of TX_ST_REG .equ SERP_TX_ST_REG_READY_m, 0x1 #Transmitter can accept next byte .equ SERP_TX_ST_REG_IE_m, 0x2 #Enable Tx ready interrupt .equ SERP_TX_DATA_REG, 0xffffc00c #Write word to send 8 LSB bits .equ SERP_TX_DATA_REG_o, 0x000c #Offset of TX_DATA_REG gets: li a0, SERIAL_PORT_BASE # a0 ukazuje na zacatek pameti UART la a1, text_1 # nacti ukazatel na buffer addi t2, zero, 40 next_char: rx_not_ready: lw t0, SERP_RX_ST_REG_o(a0) # zjisti statu prijimaci fronty andi t0, t0, SERP_RX_ST_REG_READY_m # vymaskuj bit READY beq t0, zero, rx_not_ready # pokud neni znak UARTU cekej zkus to znovu lw t1, SERP_RX_DATA_REG_o(a0) # je znak - precti ho a tim odstran sb t1, 0(a1) # uloz znak do bufferu addi t1, t1, -13 # test je to novy radek? beq t1, zero, end_char # ukoncuje cteni addi a1, a1, 1 # posun ukazatel addi t2, t2, -1 # kontroluj kolik muzeme nacist bne t2, zero, next_char end_char: ebreak # ukonci program .data text_1: .word 0,0,0,0,0,0,0,0,0,0
Program pro práci s otočnými voliči v QtRvSim
#base of SPILED port region .equ SPILED_REG_BASE, 0xffffc100 #RGB LED 1 barevne slozky – 8 bitu kazda .equ SPILED_REG_LED_RGB1, 0xffffc110 .equ SPILED_REG_LED_RGB1_o, 0x0010 #RGB LED 2 barevne slozky – 8 bitu kazda .equ SPILED_REG_LED_RGB2, 0xffffc114 .equ SPILED_REG_LED_RGB2_o, 0x0014 #Tri 8 bitove otocne volice #nejvyssi bajt informace o stitsknuti .equ SPILED_REG_KNOBS_8BIT, 0xffffc124 .equ SPILED_REG_KNOBS_8BIT_o, 0x0024 #32 LEDek kazdy bit jedna LED dioda .equ SPILED_REG_LED_LINE, 0xffffc104 .equ SPILED_REG_LED_LINE_o, 0x0004 li a0, SPILED_REG_BASE # a0 ukazuje na zacatek pameti pro I/O ori t2, t2, -1 loop: lw t0, SPILED_REG_KNOBS_8BIT_o(a0) # nacti data od otocnych volicu sw t0, SPILED_REG_LED_RGB1_o(a0) xor t1, t0, t2 sw t1, SPILED_REG_LED_RGB2_o(a0) srli t0, t0, 24 andi t0, t0, 4 beq t0, zero, loop # pokud nebyl zmacknut cerveny volic ebreak # ukonci program
Dokumentace systémových volání v QtRvSimu
template-os.S
.globl _start .globl __start .option norelax // Linux kernel compatible system calls subset .equ __NR_exit, 93 // void exit(int status) .equ __NR_read, 63 // ssize_t read(int fd, void *buf, size_t count) .equ __NR_write, 64 // ssize_t write(int fd, const void *buf, size_t count) .equ __NR_close, 57 // int close(int fd) .equ __NR_openat, 56 // int openat(int fd, const char *pathname, int flags, mode_t mode) // use fd = -100 for normal open behaviour. Full openat not supported. .equ __NR_brk, 214 // void * brk(void *addr) .equ __NR_ftruncate64, 46 // int ftruncate64(int fd, off_t length) .equ __NR_readv, 65 // ssize_t readv(int fd, const struct iovec *iov, int iovcnt) .equ __NR_writev, 66 // ssize_t writev(int fd, const struct iovec *iov, int iovcnt) .text __start: _start: addi a7, zero, __NR_write // load syscall number addi a0, zero, 1 // load file descriptor addi a1, zero, text_1 // load text address addi a2, zero, text_1_e - text_1 // load text length ecall // print the text addi a7, zero, __NR_exit // load syscall numver addi a0, zero, 0 // load status argument ecall // exit final: ebreak // request developer interaction jal zero, final .data .org 0x400 data_1: .word 1, 2, 3, 4 text_1: .ascii "Hello world.\n" // store ASCII text, no termination text_1_e: