2017-10-09 12 views
0

J'essaie simplement de lire une chaîne à partir de l'entrée de la console. J'exécute xspim pour simuler mais j'ai besoin de cela pour fonctionner en mode nu, ce qui signifie que je ne peux pas utiliser de pseudo instructions, et la plupart des choses que j'ai trouvées en ligne sont des façons de faire cela. Dans toute la documentation que je suis en train de lire, il est indiqué d'utiliser l'instruction "la" pour stocker la chaîne dans $ a0, mais cette instruction n'est pas disponible pour nous. Je lis à propos de ce que cet enseignement traduit, et il devient effectivement un "lui" suivi d'un "ori". La partie qui me lance est que nous sommes supposés entrer le nombre d'octets entre le premier emplacement de données (toujours 0x 1000 0000) et l'adresse du premier octet dans la chaîne. Je ne suis pas sûr de savoir quel serait le premier octet de ma chaîne. Voici ce que j'ai:Comment obtenir des adresses pour les données statiques dans MIPS fonctionnant en mode nu (pas de pseudo-instruction)

.globl main 
.globl done 
.globl convert 

.data 
prompt: .asciiz "Enter a decimal number, to quit type 'quit':" #45 
result: .asciiz "The number you entered is " #72 
input: .space 64 

.text 
convert: 


main:  addi $v0, $0, 4   #Print prompt to enter number 
      lui $a0, 0x1000   #Address of prompt 
      syscall     #Display prompt 

      addi $v0, $0, 8   #Setting up syscall to read in string 
      lui $at, 4097 
      ori $a0, $at, input  #Where I want my string to be stored 
      addi $a1, $0, 64  #How long my string will be 
      syscall     #Syscall to read in string 
+0

Vous pouvez contourner ce problème en utilisant un tampon sur la pile (pour le tampon d'entrée). –

Répondre

0

assembleurs Normalement + linkers pour les machines RISC prennent en charge les adresses se divisant en deux moitiés, de sorte que vous pouvez écrire lui $reg, upper(input) et ori $reg, $reg, lower(input), les adresses ne doivent être constantes à temps lien, ne pas assembler en temps.

Par exemple, si vous regardez MIPS gcc's assembly output on Godbolt (gcc -O3 -S, pas désassembler le binaire lié):

int my_global; 
int *foo() { return &my_global; } 
    lui  $2,%hi(my_global) 
    j  $31 
    addiu $2,$2,%lo(my_global) # branch-delay slot (SPIM doesn't have a branch-delay slot, but real MIPS does) 

int bar() { return my_global; } 
    lui  $2,%hi(my_global) 
    lw  $2,%lo(my_global)($2) 
    j  $31 
    nop 

    .section  .bss,"aw",@nobits 
    .align 2 
    .type my_global, @object 
    .size my_global, 4 
my_global: 
    .space 4 

Notez que bar utilisé la moitié lo de l'adresse comme un décalage dans lw au lieu de générer l'adresse complète dans un registre, puis en utilisant un décalage de 0 dans une instruction de chargement.


Une optimisation utile si vous savez 2 adresses sont dans le même bloc 64k est de réutiliser le même résultat avec différentes luiori faibles constantes demi. Je pense que c'est le cas ici pour vos données. Mars guarantees that syscall preserves all registers except the result; Je suppose que SPIM est le même.


Si vous devez le faire manuellement (sans éditeur de liens pour vous aider), alors oui, vous devez connaître l'adresse absolue de vos données.

Dans votre cas, il n'y a pas de code de démarrage CRT ou tout autre élément qui place ses données dans la section .data. Les choses dans votre .data section est au tout début du segment de données de votre exécutable, donc prompt: aura l'adresse 0x1000 0000.

Vous n'avez demandé aucun rembourrage ou alignement, donc vous n'en aurez pas. Vos données seront assemblées dans la sortie emballées ensemble. (Contrairement à C, où char prompt[45], result[]; ont aucune garantie d'être contiguës.)

Je ne l'ai pas utilisé SPIM, mais nous espérons qu'il vous permettra d'écrire result-prompt et input-prompt.

par exemple.

main: 
     addi $v0, $0, 4   #Print prompt to enter number 
     lui $a0, 0x1000   #Address of prompt 
     syscall     #Display prompt 

     # $a0 still holds 0x1000 << 16 
     addui $a0, $a0, input-prompt  #buffer address 
     addi $a1, $0, 64     # length 

     addi $v0, $0, 8   #syscall 8 = read string 
     syscall     #read_string(input, 64) 

     addui $t0, $a0, 0  # copy pointer to input 
     addui $a0, $a0, result - input # offset pointer again to point to the output message. 

Ou au lieu de copier le pointeur sur un autre registre, vous pourriez optimiser en ajoutant input-result au décalage dans tous les lb/sb vous utilisez pour accéder input[].