3. Jazyk C a jeho překlad do instrukcí procesoru

Osnova cvičení

  1. Zopakování instrukcí sady procesoru
  2. Přepis programu z jazyka C do asembleru (instrukční sada MIPS)
  3. Práce s periferií
  4. Upozornění na 1. domácí úkol (https://dcenet.felk.cvut.cz/apo/)

Náplň cvičení

První část - Význam a použití základních instrukcí

Bližší popis instrukcí:

Instrukce Syntax Operace Význam
add add \$d, \$s, \$t \$d = \$s + \$t; Add: Sečte dva registry \$s + \$t a výsledek uloží do registru \$d
addi addi \$t, \$s, C \$t = \$s + C; Add immediate: Sečte hodnotu v \$s a znaménkově rozšířenou přímou hodnotu, a výsledek uloží do \$t
sub sub \$d,\$s,\$t \$d = \$s - \$t Subtract: Odečte znaménkově obsah registru \$t od \$s a výsledek uloží do \$d
bne bne \$s, \$t, offset if \$s != \$t go to PC+4+4*offset; else go to PC+4 Branch on not equal: Skáče pokud si registry \$s a \$t nejsou rovny
beq beq \$s, \$t, offset if \$s == \$t go to PC+4+4*offset; else go to PC+4 Branch on equal: Skáče pokud si registry \$s a \$t jsou rovny
slt slt \$d,\$s,\$t \$d = (\$s < \$t) Set on less than: Nastavi registr \$d, pokud plati podminka \$s < \$t
sll sll \$d,\$s,C \$d = \$s << C Shift Left Logical: Posune hodnotu v registru o C bitu doleva (ekvivalentni k operaci nasobeni konstantou 2C )
jump j C PC = (PC ∧ 0xf0000000) ∨ 4*C Jump: Skáče bezpodmíněčně na návěstí C
lw lw \$t,C(\$s) \$t = Memory[\$s + C] Load word: Načte slovo z paměti a uloží jej do registru \$t
sw sw \$t,C(\$s) Memory[\$s + C] = \$t Store word: Uloží obsah registru \$t do paměti
lui lui \$t,C \$t = C << 16 Load upper immediate: Uloží předanou přímou hodnotu C do horní části registru. Registr je 32-bitový, C je 16-bitová.
la la \$at, LabelAddr lui \$at, LabelAddr[31:16]; \\ ori \$at,\$at, LabelAddr[15:0] Load Address: 32-bitové návěstí uloží do registru \$at. Jedná se o pseudoinstrukci - tzn. při překladu se rozloží na dílčí instrukce.

Přepis programu z jazyka C do asembleru

V praktických aplikacích se častokrát setkáváme s použitím mediánového filtru. Ten nám pomáhá odstranit ze signálu (nebo obrazu) zcela zjevné výkmity (nebo poškozené pixely). Narozdíl od průměrovacího filtru, který spočítá aritmetický průměr nejakého okolí a stávající hodnotu signálu nahradí vypočteným průměrem, mediánový filtr ji nahradí prostřední hodnotou (mediánem) tohoto okolí. Pro realizaci mediánového filtru je potřebné nejdříve seřadit všechny hodnoty a pak z nich vybrat onu prostřední. Klíčovou roli zde sehrává řazení. Mějme následující problém. V datové paměti nech je uloženo N celých čísel (1 < N < 21) počínaje od nějaké adresy (například 0x00), přičemž jedno číslo v paměti zabírá velikost jednoho slova. Našim úkolem je uvedená čísla vzestupně seřadit. Nejsnažší způsob jak tento problém řešit je použít bublinkové řazení. Princip tohoto algoritmu spočívá v tom, že se postupně a opakovaně prochází seřazované pole, přičemž se porovnávají každé dva sousedící prvky, a pokud nejsou ve správném pořadí, prohodí se. Hodnotu N si zvolte sami.

int pole[5]={5,3,4,1,2};
int main()
{
	int N = 5,i,j,tmp;
	for(i=0; i<N; i++)
		for(j=0; j<N-1-i; j++)
			if(pole[j+1]<pole[j])
			{
				tmp = pole[j+1];
				pole[j+1] = pole[j];
				pole[j] = tmp;
			}
	return 0;
}

Princip algoritmu: Řazení prvků se uskutečňuje ve dvou vnořených cyklech - vnějším a vnitřním. Vnější cyklus zabezpečuje opakované spouštění vnitřního cyklu. Vnitřní cyklus postupně procházení pole a vzájemně vyměňuje dvě sousedící položky pokud nejsou v správném pořadí (má být menší vlevo, větší napravo). Protože vnitřní cyklus prochází polem zleva doprava (od menších indexů k větším) důsledkem je, že na konci pole se objeví vždy největší prvek z celého pole - největší prvek “probublal” na konec pole. Proto při dalším spuštění vnitřního cyklu nemusíme již procházet celým polem, ale jenom doposud neseřazenou částí tohoto pole. Postačuje N spuštění vnitřního cyklu aby se pole seřadilo.

5, 3, 4, 1, 2 –> počáteční stav
3, 4, 1, 2, 5 –> po prvním průchodu vnějším cyklem
3, 1, 2, 4, 5 –> po druhém průchodu vnějším cyklem
1, 2, 3, 4, 5
1, 2, 3, 4, 5
1, 2, 3, 4, 5 –> po pátém průchodu cyklem - seřazeno

Přepište výše uvedený program z jazyka C do asembleru. Vykonávání programu oveřte v simulátoru Mips. Tento program budete potřebovat na příštím cvičení - to co nestihnete na cvičeních bude nutno dodělat doma..


Můžete využít předpripravenou šablonu k tomuto úkolu:

#define t0 $8
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12

#define s0 $16
#define s1 $17
#define s2 $18
#define s3 $19

.globl    pole
.set noat
.set noreorder

.data
.align    2

pole:
.word    5,3,4,1,2

.text
.globl start
.ent start

start:
// Zde muzete psat Vas program
nop
.end start

Příklady přepisu krátkých fragmentů kódu z jazyka C do asembleru

Příkaz if
if (i ==j)
  f = g + h;
 
f = f – i;
//   s0=f, s1=g, s2=h, s3=i, s4=j

  bne s3, s4, L1   // Pokud i!=j, skoč na L1 
  add s0, s1, s2   // if blok: f=g+h
L1:
  sub s0, s0, s3   // f = f-i
Příkaz if-else
if (i ==j)
  f = g + h;
else
  f = f – i;
//   s0=f, s1=g, s2=h, s3=i, s4=j

  bne s3, s4, else  // Když i!=j, skoč na else
  add s0, s1, s2    // if blok: f=g+h
  j L2              // přeskoč blok else
else:
  sub s0, s0, s3    // blok else: f = f-i
L2:
Cyklus while
int pow = 1;
int x = 0;
 
while(pow != 128)
{
  pow = pow*2;
  x = x + 1;
}
// s0=pow, s1=x

  addi s0, $0, 1     // pow = 1
  addi s1, $0, 0     // x = 0
  addi t0, $0, 128   // t0 = 128 pro porovnávání

while:
  beq  s0, t0, done  // Když pow==128, ukončení cyklu while
  sll  s0, s0, 1     // pow = pow*2
  addi s1, s1, 1     // x = x+1
  j    while
done:
Cyklus for
int sum = 0;
int i;
for(i=0; i!=10; i++)
{
  sum = sum + i;
}
//Lze nahradit while:
int sum = 0;
int i = 0;
while(i!=10)
{ sum = sum + i;
  i++;
}
//ale zde i rychlejším do-while, 
//z konst.mezí víme,že se vždy vykoná:
int sum = 0;
int i = 0;
do
{ sum = sum + i;
  i++;
} while(i!=10)
Načtení slova z datové paměti
// Jenom pro účely ukázky...
int a, *pa=0x80020040;
int b, *pb=0x80020044;
int c, *pc=0x00001234;
 
a = *pa;
b = *pb;
c = *pc;
// s0=pa (bazova adresa), s1=a, s2=b, s3=c

lui  s0, 0x8002   // pa = 0x80020000;
lw   s1, 0x40(s0)     // a = *pa;
lw   s2, 0x44(s0)     // b = *pb;

addi s0, $0, 0x1234   // pc = 0x00001234;
lw   s3, 0x0(s0)      // c = *pc;
Inkrementování prvků pole
int pole[4] = { 7, 2, 3, 5 };
 
int main()
{
   int i,tmp;
   for(i=0; i<4; i++)
   {
      tmp = pole[i];
      tmp += 1;
      pole[i] = tmp;
   }
   return 0;
}
Kompletní program v prostředí MipsIt:
#define s0 $16
#define s1 $17
#define s2 $18
#define s3 $19

.globl    pole        // nazev "pole" bude viditelny pro linker
.data                 // direktiva oznacujici zacatek datove casti
.align    2           // zarovnani dat po slovech (4 Bytech)

pole:                 // pojmenovani mista v pameti
.word    7, 2, 3, 5   // inicializace pole...

.text                 // zacatek textove casti / programu
.globl _start	      // opet symbol viditelný pro linker	  
.ent _start	      // vstupní bod		  

_start:               // la je pseudoinstrukce
la   s0, pole         // ulozi do registru s0 adresu pocatku pole
addi s1, $0, 0        // inicializacni prikaz cyklu for: i=0, kde i=s1
addi s2, $0, 4        // nastaveni horni meze cyklu

for:                  // mame konst. meze, lze prelozit jako do-while 
  lw   s3, 0x0(s0)    // nacteni polozky pole do registru s3
  addi s3, s3, 0x1    // inkrementace registru s3
  sw   s3, 0x0(s0)    // prepsani (ulozeni) hodnoty registru s3 do pole
  addi s0, s0, 0x4    // posun na dasli polozku pole
  addi s1, s1, 0x1    // +1 k pocitadlu poctu pruchodu cyklem (i++)
  bne  s1, s2, for    // kdyz s1!=s2 opakuj cyklus skokem na navesti for

konec:
  nop
.end _start


Periferie mapované do paměťového adresního prostoru

Simulátor QtMips nabízí i několik jednoduchých periferií, které jsou mapované do paměťového adresního prostoru.

První periferií je jednoduchý sériový port (UART) napojený na okénko terminálu. Rozložení a funkce registrů odpovídá emulátorům SPIM a MARS. Ty mapují sériový port od adresy 0xffff0000. V simulátoru QtMips je mapovaný jak na tuto adresu, tak na adresu 0xffffc000, která je dosažitelná absolutním adresováním v instrukcích LW a SW proti registru zero.

Adresa Symbolické označení Bity Popis
0xffffc000 SERP_RX_ST_REG Stavový registr přijímače znaků z terminálu
0 Pokud je 1 tak je v SERP_RX_DATA_REG nový přijatý znak
1 Natavením na 1 povoluje přerušení od příjmu podrobněji
0xffffc004 SERP_RX_DATA_REG 7 .. 0 ASCII kód přijatého znaku
0xffffc008 SERP_TX_ST_REG Stavový registr vysílače znaků na terminál
0 Pokud je 1 tak je vysílač připravený na zápis znaku
1 Natavením na 1 povoluje přerušení od vysílání podrobněji
0xffffc00c SERP_TX_DATA_REG 7 .. 0 ASCII kód vysílaného znaku

Další periferie emuluje interakci s reálnými prvky zařízení. Tato periferie přesně odpovídá rozložením registrů a bitů zjednodušené periferii otočných voličů a LED indikátorů, která je použitá pro vstup a výstup na vývojových kitech MicroZed APO, na které budou použité v semestrálních úlohách.

Adresa Symbolické označení Bity Popis
0xffffc104 SPILED_REG_LED_LINE 31 .. 0 Slovo zobrazené binárně, dekadicky a hexadecimálně
0xffffc110 SPILED_REG_LED_RGB1 23 .. 0 Zápis RGB hodnot do PWM registrů pro RGB LED 1
23 .. 16 Červená složka R
15 .. 8 Zelená složka G
7 .. 0 Modrá složka B
0xffffc114 SPILED_REG_LED_RGB2 23 .. 0 Zápis RGB hodnot do PWM registrů pro RGB LED 2
23 .. 16 Červená složka R
15 .. 8 Zelená složka G
7 .. 0 Modrá složka B
0xffffc124 SPILED_REG_KNOBS_8BIT 31 .. 0 Filtrované hodnoty voličů jako 8 bit čísla
7 .. 0 Nastavení modrého voliče B
15 .. 8 Nastavení zeleného voliče G
23 .. 16 Nastavení natočení červeného voliče R

Příklad na práci s perifériemi

.globl _start
.ent _start
.set noat
.set noreorder

.text
_start:
    li $8, 0xffffc100   // base address into memory mapped I/O area
loop:
    lw $9, 0x24($8)     // load packed knob value into $9 (from addr. 0xffffc124)
    
    // depack $9 and store individual knob values into registers
    andi $12, $9, 0xFF  // $12 <-blue knob is in bits 7..0
    srl  $1, $9, 8      // $11 <-green knob is in bits 15..8
    andi $11, $1, 0xFF  
    srl  $1, $9, 16     // $10 <-red knob is in bits 23..16
    andi $10, $1, 0xFF  
    
    sw $9, 0x10($8) //write packed knobs to RGB led_1,(to addr. 0xffffc110)
    sw $9, 4($8)    // and also to LED-line word-box of QtMips,(to addr. 0xffffc104)    
    
    // bit negation of the packed knob value
    addi $1, $0, -1  // $1 = 0xffffffff
    xor $1,$1,$9     // xor with all 1 performs the bit negation of $9
            
    sw $1, 0x14($8)     // write negated value of the packed knob to RGB led_2
                        // (to addr. 0xffffc114)
    
    beq $0, $0, loop    // repeat rd/wr in endless loop
    nop

.end _start

Analýza výsledku kompilace

Jednoduchý program pro čtení polohy otočných voličů a převodu hodnoty na barvu a textový výstup naleznete na laboratorních počítačích v adresáři /opt/apo/binrep/qtmips_binrep. Archiv ke stažení je k dispozici zde.

Zdojový kód je zkompilovaný sekvencí příkazů

mips-elf-gcc -D__ASSEMBLY__ -ggdb -fno-lto -c crt0local.S -o crt0local.o
mips-elf-gcc -ggdb -Os -Wall -fno-lto  -c qtmips_binrep.c -o qtmips_binrep.o
mips-elf-gcc -ggdb -nostartfiles -static -fno-lto crt0local.o qtmips_binrep.o -o qtmips_binrep

Následně je obsah binárního výstup ve formátu ELF převedený do textové podoby příkazem

mips-elf-objdump --source -M no-aliases,reg-names=numeric qtmips_binrep

A doplněný o komentáře.

qtmips_binrep:     file format elf32-bigmips


Disassembly of section .text:

00400018 <main>:

/*
 * The main entry into example program
 */
int main(int argc, char *argv[])
{
  400018:	27bdffe8 	addiu	$29,$29,-24
                           allocate space on the stack for main() function
                           stack frame
  
  40001c:	afbf0014 	sw	$31,20($29)
                           save previous value of the return address register
                           to the stack.

 while (1) {
     uint32_t rgb_knobs_value;
     unsigned int uint_val;

      rgb_knobs_value = *(volatile uint32_t*)(mem_base + SPILED_REG_KNOBS_8BIT_o);
  400020:	8c04c124 	lw	$4,-16092($0)
                           Read value from the address corresponding to the
                           sum of "SPILED_REG_BASE" and "SPILED_REG_KNOBS_8BIT_o"
                           peripheral register offset
                           LW is instruction to load the word. Address is formed
			   from the sum of register $0 (fixed zero) and -16092,
			   which is represented in hexadecimal as 0xffffc124
			   i.e., sum of 0xffffc100 and 0x24. The read value is
			   stored in register $4.

  400024:	00000000 	sll	$0,$0,0x0
                           one NOP instruction to ensure that load finishes before
                           the further value use.

  400028:	00041027 	nor	$2,$0,$4
                           Compute bit complement "~" of the value in the register
			   $4 and store it into register $2

     *(volatile uint32_t*)(mem_base + SPILED_REG_LED_LINE_o) = rgb_knobs_value;
  40002c:	ac04c104 	sw	$4,-16124($0)
                           Store RGB knobs values from register $4to the "LED"
			   line register which is shown in binary decimal
			   and hexadecimal on the QtMips target.
			   Address 0xffffc104

     *(volatile uint32_t*)(mem_base + SPILED_REG_LED_RGB1_o) = rgb_knobs_value;
  400030:	ac04c110 	sw	$4,-16112($0)
                           Store RGB knobs values to the corresponding components
			   controlling a color/brightness of the RGB LED 1
                           Address 0xffffc110


     *(volatile uint32_t*)(mem_base + SPILED_REG_LED_RGB2_o) = ~rgb_knobs_value;
  400034:	ac02c114 	sw	$2,-16108($0)
                           Store complement of RGB knobs values to the corresponding
			   components controlling a color/brightness of the RGB LED 2
                           Address 0xffffc114

     /* Assign value read from knobs to the basic signed and unsigned types */
     uint_val = rgb_knobs_value;
                           the read value resides in the register 4, which
                           correspond to the first argument register a0

     /* Print values */
     serp_send_hex(uint_val);
  400038:	0c100028 	jal	4000a0 <serp_send_hex>
  40003c:	00000000 	sll	$0,$0,0x0
                           call the function to send hexadecimal value to
                           the serial port, one instruction after JAL
                           is executed in its delay-slot, PC pointing
                           after this instruction (0x400040) is stored
                           to the register 31, return address register

     serp_tx_byte('\n');
  400040:	0c100020 	jal	400080 <serp_tx_byte>
  400044:	2404000a 	addiu	$4,$0,10
                           call routine to send new line character to the
                           serial port. The ASCII value corresponding to
                           '\n' is set to argument a0 register in delay slot
                           of JAL. JAL is decoded and in parallel instruction
                           addiu $4,$0,10 is executed then PC pointing to the address
                           0x400048 after delay slot is stored to return address
                           register and next instruction is fetch from the JAL
                           instruction target address, start of the function
                           serp_tx_byte

  400048:	1000fff5 	beqz	$0,400020 <main+0x8>
  40004c:	00000000 	sll	$0,$0,0x0
                           branch back to the start of the loop reading value from
                           the knobs


00400050 <_start>:
	la      $gp, _gp
  400050:	3c1c0041 	lui	$28,0x41
  400054:	279c90e0 	addiu	$28,$28,-28448
                           Load global data base pointer to the global data
                           base register 28 - gp.
			   Symbol _gp is provided by linker.

	addi    $a0, $zero, 0
  400058:	20040000 	addi	$4,$0,0
                           Set regist a0 (the first main function argument)
			   to zero, argc is equal to zero.

	addi    $a1, $zero, 0
  40005c:	20050000 	addi	$5,$0,0
                           Set regist a1 (the second main function argument)
			   to zero, argv is equal to NULL.

	jal     main
  400060:	0c100006 	jal	400018 <main>
	nop
  400064:	00000000 	sll	$0,$0,0x0
                           Call the main function. Return address is stored
			   in the ra ($31) register.


00400068 <quit>:
quit:
	addi    $a0, $zero, 0
  400068:	20040000 	addi	$4,$0,0
                           If the main functio returns, set exit value to 0

	addi    $v0, $zero, 4001  /* SYS_exit */
  40006c:	20020fa1 	addi	$2,$0,4001
                           Set system call number to code representing exit()

	syscall
  400070:	0000000c 	syscall
                           Call the system.

00400074 <loop>:

loop:	break
  400074:	0000000d 	break
                           If there is not a system try to stop the execution
			   by invoking debugging exception

        beq     $zero, $zero, loop
  400078:	1000fffe 	beqz	$0,400074 <loop>
	nop
  40007c:	00000000 	sll	$0,$0,0x0
                           If even this does not stop execution, command CPU
			   to spin in busy loop.

void serp_tx_byte(int data)
{
00400080 <serp_tx_byte>:
  while (!(serp_read_reg(SERIAL_PORT_BASE, SERP_TX_ST_REG_o) &
                SERP_TX_ST_REG_READY_m));
  400080:	8c02c008 	lw	$2,-16376($0)
  400084:	00000000 	sll	$0,$0,0x0
                           Read serial port transmit status register,
                           address 0xffffc008

  while (!(serp_read_reg(SERIAL_PORT_BASE, SERP_TX_ST_REG_o) &
  400088:	30420001 	andi	$2,$2,0x1
  40008c:	1040fffc 	beqz	$2,400080 <serp_tx_byte>
  400090:	00000000 	sll	$0,$0,0x0
                           Wait again till UART is ready to accept
			   character - bit 0 is not zero.
                           NOP in the delayslot.

  *(volatile uint32_t *)(base + reg) = val;
  400094:	ac04c00c 	sw	$4,-16372($0)
                           write value from register 4 (the first argument a0)
                           to the address 0xffffc00c (SERP_TX_DATA_REG_o)
                           serial port tx data register.
}
  400098:	03e00008 	jr	$31
  40009c:	00000000 	sll	$0,$0,0x0
                           jump/return back to continue in callee program
                           address of the next fetch instruction is read
                           from the return address register 32 ra
                           
void serp_send_hex(unsigned int val)
{
004000a0 <serp_send_hex>:
  4000a0:	27bdffe8 	addiu	$29,$29,-24
                           allocate space on the stack for the routine stack frame
                                                      
  4000a4:	00802825 	or	$5,$4,$0
                           copy value of the fisrt argument regsiter 4 (a0)
                           to the register 5

  for (i = 8; i > 0; i--) {
  4000a8:	24030008 	addiu	$3,$0,8
                           set the value of the register 3 to the 8

  4000ac:	afbf0014 	sw	$31,20($29)
                           save previous value of the return address register
                           to the stack.

    char c = (val >> 28) & 0xf;
  4000b0:	00051702 	srl	$2,$5,0x1c
                           shift value in register 5 right by 28 bits and store
                           result in the register 2

  4000b4:	304600ff 	andi	$6,$2,0xff
                           abundant operation to limit value range to the character
                           type variable and store result in the register 6
    if (c < 10 )
  4000b8:	2c42000a 	sltiu	$2,$2,10
                           set register 2 to one if the value is smaller than 10

      c += 'A' - 10;
  4000bc:	10400002 	beqz	$2,4000c8 <serp_send_hex+0x28>
  4000c0:	24c40037 	addiu	$4,$6,55
                           if value is larger or equal (register 2 is 0/false) then add
                           value 55 ('A' - 10)..(0x41 - 0xa) = 0x37 = 55 to the register
                           6 and store result in the register 4. This operation is
                           executed even when the branch arm before else is executed,
                           but result is immediately overwritten by next instruction
      c += '0';
  4000c4:	24c40030 	addiu	$4,$6,48
                           add value 0x30 = 48 = '0' to the value in the register 6
                           and store result in the register 4 - the fisrt argument a0
  
    serp_tx_byte(c);
  4000c8:	0c100020 	jal	400080 <serp_tx_byte>
  4000cc:	2463ffff 	addiu	$3,$3,-1
                           call subroutine to send byte to the serial port
                           decrement loop control variable (i) in delay-slot

  for (i = 8; i > 0; i--) {
  4000d0:	1460fff7 	bnez	$3,4000b0 <serp_send_hex+0x10>
  4000d4:	00052900 	sll	$5,$5,0x4
                           the final condition of for loop converted to do {} while()
                           loop. If not all 8 character send loop again.
                           Shift left value in the register 5 by 4 bit positions.
                           The compiler does not store values of local variables to
                           the stack even does not store values in caller save registers
                           (which requires to save previous values to the function stack frame).
                           Compiler can use this optimization because it knows registers usage
                           of called function serp_tx_byte().
  }
  4000d8:	8fbf0014 	lw	$31,20($29)
  4000dc:	00000000 	sll	$0,$0,0x0
                           restore return address register value to that found at function
                           start
                           
  4000e0:	03e00008 	jr	$31
  4000e4:	27bd0018 	addiu	$29,$29,24
                           return to the caller function. Instruction in jump register
                           delay-slot is used to restore stack pointer/free function frame.

Úkoly

  1. Dokončení a předvedení vlastní implementace algoritmu bubble-sort
  2. Výpis řetězce na terminál
  3. Doplnění programu pro výpočet Fibonacciho posloupnosti o výstup na terminál

Odkazy

  • Křížový překladač GNU pro MIPS-ELF - překladač kompatibilní s GNU překladačem použitým v MipsIT, balíčky pro Debian GNU/Linux x86_64 a i586, konfigurace a kompilace ze zdrojových kódů
  • gcc-binutils-newlib-mips-elf_4.4.4-1_mingw32.zip - MIPS-ELF GCC 4.4.4 zkompilované pro MinGW32 (Windows) - pro složitější programy vyžaduje přidat přepínače -lm -lgcc -lc , pro pokusy v MipsIT pak nejčastěji i další -nostdlib -nodefaultlibs -nostartfiles -Wl,-Ttext,0x80020000
  • Popis procesoru MIPS - včetně kompletní instrukční sady.
    • Missouri State University - Velmi povedený simulátor v jazyce Java
    • Vyžaduje assembler bez makro definic (předzpracovaný). Pro předzpracování lze použít např. GCC

gcc -E assembler.S -o predzpracovany-pro-mips.s

courses/b35apo/tutorials/03/start.txt · Last modified: 2019/04/11 10:13 by pisa