2016-10-30 3 views
0

Я пытаюсь написать эквивалент MIPS кода C ниже.Поиск элемента Kth в массиве MIPS

int arrayData[5] = { 1,2,1,3,4 }; 
int K = 3; 
int KCtr = 0; 
int result; 
bool isUnique; 
for (int o = 1; o < 5; o++) 
{ 
    isUnique = true; 
    for (int i = 0; i < o; i++) 
    { 
     if (arrayData[o] == arrayData[i]) 
     { 
      isUnique = false; 
      break; // goto outer loop 
     } 
    } 
    if (isUnique) 
    { 
     KCtr++; 
    } 
    if (KCtr==K) 
    { 
     result = arrayData[o]; 
    } 
} 

Я хочу сохранить результат в $s1 с кодом ниже.

.data 
Array: .word 1, 2, 4, 8, 16, 32, 64, 128 
sze : .word 8 
K : .word 3 
.text 
.globl main 

main: lw $s0,K($0) # K 
     addi $t0,$zero,0 # index for outer loop 
     addi $t1,$zero,0 # index for inner loop 
     lw $t2,sze($0) 
     lw $s1,Array($0) 
     addi $t6,$zero,0 
     #addi $t7,$zero,1 
     #t3 for array[o] 
     #t4 for array[i] 
     #t5 for unique flag 
     #t6 for counter to reach K 
     #t7 for storing 1 
outerloop: 
    beq $t0,$t2,finish 
    lw $t3,Array($t0) 
    addi $t5,$zero,0 
innerloop: 
    lw $t4,Array($t1)  
    bne $t3,$t4,else 
    addi $t5,$zero,1 
else: 

checkifunique: 
    beq $t5,$t7,isnotuniquebypass 
    addi $t6,$zero,1 
isnotuniquebypass: 
    addi $t1,$t1,4 
    blt $t1,$t0,innerloop 

    bne $t6,$s0,notreachedKbypass 
    lw $s1,Array($t0) 

notreachedKbypass: 

    addi $t0,$t0,4 
    b outerloop 


finish: 
     li $v0,10 
     syscall 

В то время как я ожидал увидеть 8 в $s1 регистре, я получаю 1. Что не так, мой код сборки?

ответ

2

Несколько вещей были неправильными.

Ваш код C был неполным. Изучив ваш код asm, я смог добавить недостающий материал в код C.

Вы не настроили некоторые регистры правильно.

Вы также сравнивали смещения массива (ваши итерационные переменные, которые были увеличены на 4) по отношению к индексу/счету массива, поэтому сравнения не будут работать.

Вы настраивали регистр для KCtr 1, вместо того, чтобы делать ассемблерный эквивалент KCtr++

Я создал три примера: фиксированный код C, аннотированный вариант вашего ассемблере показывая некоторые/большинство ошибок. И, очищенная, реорганизованная и рабочая версия.


Вот код C:

#include <stdio.h> 

#if 0 
int Array[] = { 1, 2, 1, 3, 4 }; 
#else 
int Array[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 
#endif 

int 
main(void) 
{ 
    int result; 
    int K = 3; 
    int KCtr = 0; 
    int count = sizeof(Array)/sizeof(Array[0]); 
    int uniqflg; 

    result = -1; 

    for (int o = 1; o < count; o++) { 
     uniqflg = 1; 
     for (int i = 0; i < o; i++) { 
      if (Array[o] == Array[i]) { 
       uniqflg = 0; 
       break; 
      } 
     } 
     if (! uniqflg) 
      continue; 

     KCtr++; 
     if (KCtr == K) { 
      result = Array[o]; 
     } 
    } 

    printf("result=%d\n",result); 

    return result; 
} 

Вот аннотированный версия:

.data 
Array:  .word  1,2,4,8,16,32,64,128 
    sze  : 
    K  : 

    .text 
    .globl main 

# s1 for result 
# t0 for o 
# t1 for i 
# t2 for array count 
# t3 for array[o] 
# t4 for array[i] 
# t5 for unique flag 
# t6 for counter to reach K (i.e. KCtr?) 
# t7 for storing 1 
main: 
    lw  $s0,K($0)    # K 
    addi $t0,$zero,0    # index for outer loop 

# NOTE/BUG: this is misplaced it needs to be moved to just above innerloop 
    addi $t1,$zero,0    # index for inner loop 

    lw  $t2,sze($0)    # get array count 
    lw  $s1,Array($0)   # result = Array[0] 
    addi $t6,$zero,0    # KCtr = 0 
# NOTE/BUG: this was commented out: 
    addi $t7,$zero,1 

outerloop: 
    # NOTE/BUG: based on the increment by 4 to $t0 below, this is comparing an 
    # offset against a count 
    beq  $t0,$t2,finish   # o < count? if no, fly 
    lw  $t3,Array($t0)   # get Array[o] 
    addi $t5,$zero,0    # uniqflg = 0 

innerloop: 
    lw  $t4,Array($t1)   # get Array[i] 
    bne  $t3,$t4,inner_neq  # Array[o] == Array[i]? if no, fly 

# NOTE/BUG: this is just setting one (i.e. KCtr = 1 instead of KCtr++) 
    addi $t5,$zero,1    # uniqflg = 1 

inner_neq: 

checkifunique: 
    beq  $t5,$t7,notuniq   # ??? 
    addi $t6,$zero,1 

notuniq: 
    addi $t1,$t1,4    # advance array offset 

    # NOTE/BUG: this compares an array offset against an index 
    blt  $t1,$t0,innerloop  # at end? if no, loop 

    bne  $t6,$s0,inner_next  # KCtr == K? if no, interate 
    lw  $s1,Array($t0)   # get better result 

inner_next: 
    addi $t0,$t0,4    # advance o [as offset] 
    b  outerloop 

finish: 
    li  $v0,10 
    syscall 

Вот переработан версия. Это несколько отличается от вашего, потому что для того, чтобы заставить его работать, я немного упростил его. Он также использует указатели вместо индексов или смещений для доступа к массиву. Также обратите внимание, что после KCtr == K нет необходимости продолжать цикл.

.data 
Array:  .word  1,2,4,8,16,32,64,128 
ArrEnd: 
K:   .word  3 

    .text 
    .globl main 

# s0 for K 
# s1 for result 
# t0 for o (as pointer) 
# t1 for i (as pointer) 
# t2 for array count 
# t3 for array[o] 
# t4 for array[i] 
# t6 for counter to reach K (i.e. KCtr?) 
main: 
    lw  $s0,K     # K 
    li  $t6,0     # KCtr = 0 

    la  $t2,ArrEnd    # point to end of array 
    la  $t0,Array    # o = &Array[0] 
    lw  $s1,0($t0)    # result = Array[0] 

outerloop: 
    addiu $t0,$t0,4    # advance o [as pointer] 
    bgeu $t0,$t2,finish   # o < ArrEnd? if no, fly 
    lw  $t3,0($t0)    # get Array[o] 

    la  $t1,Array    # i = &Array[0] 

innerloop: 
    lw  $t4,0($t1)    # get Array[i] 
    beq  $t3,$t4,outerloop  # Array[o] == Array[i]? if yes, not unique 

    addiu $t1,$t1,4    # advance array pointer for i 
    bltu $t1,$t0,innerloop  # at end? if no, loop 

    # current array value is unique 
    addi $t6,$t6,1    # KCtr++ 
    bne  $t6,$s0,outerloop  # KCtr == K? if no, wait for next unique 
    lw  $s1,0($t0)    # get better result -- no need to loop more 

finish: 
    li  $v0,1 
    move $a0,$s1 
    syscall 

    li  $v0,10 
    syscall 

UPDATE:

Ваш код, кажется, работает в SPIM. Но я не понял «ArrayEnd». Для него нет значения, но оно работает. Как ?

ArrEnd - это «трюк». Это адрес последнего элемента Array + 1. То есть, в C, если у нас есть int Array[5], то ArrEnd - &Array[5].

Как и в C, мы можем выбрать способ перебора массивов. Мы можем использовать индекс и делать: Array[i]. Или, мы можем использовать указатели int *. В asm мы можем использовать смещения от начала массива (т. Е. index << 2).

Давайте перекодируем программу C на только используйте указатели [а не индексы] для итерации по массиву. Это часто не используется в коде C, но это полезно для asm. Ниже на самом деле является более точным, код C представление о том, что мой второй пример ASM сделал:

#include <stdio.h> 

#if 0 
int Array[] = { 1, 2, 1, 3, 4 }; 
#else 
int Array[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 
#endif 

int 
main(void) 
{ 
    int result; 
    int K = 3; 
    int KCtr = 0; 
    int *ArrEnd = &Array[sizeof(Array)/sizeof(Array[0])]; 
    int uniqflg; 

    result = -1; 

    for (int *o = &Array[1]; o < ArrEnd; o++) { 
     uniqflg = 1; 
     for (int *i = &Array[0]; i < o; i++) { 
      if (*o == *i) { 
       uniqflg = 0; 
       break; 
      } 
     } 
     if (! uniqflg) 
      continue; 

     KCtr++; 
     if (KCtr == K) { 
      result = *o; 
      break; 
     } 
    } 

    printf("result=%d\n",result); 

    return result; 
} 

Вот некоторые идиоматические использует для ArrEnd:

la  $s0,Array    # get array address 
    la  $s1,ArrEnd    # address of array end [one past last] 
    subu $s2,$s1,$s0    # get byte length of array 
    srl  $s3,$s2,2    # get array count 

Теперь, когда у нас есть эти значения, мы можем перебирать через массив с помощью любого из указанных выше трех методов. Использование версии смещения или версии указателя обычно может быть более эффективным.

Чтобы увидеть, как легко ArrEnd делает вещи, комментирует большой массив и добавляет более короткий массив из кода C. ArrEnd трюк будет регулировать вещи автоматически без нуждающейся вручную подсчитать количество элементов в Array


UPDATE # 2:

Я может быть неправильно об этом, но при дальнейшем размышлении, чтобы отвечают требованиям названия вопроса, возможно, потребуется изменить код C [и, следовательно, asm].

Я думаю, что внутренний цикл должен сканировать весь массив [пропуская элемент, где i == o] при поиске дубликатов. В противном случае это может привести к ложному срабатыванию.

Кроме того, кажется, что оригинал никогда не считает элемент индекса 0 уникальным, даже если он есть. Это связано с тем, что цикл o начался с индекса 1.

Я создал два алгоритма. Оригинал, как указано выше. И тот, который выполняет полное сканирование. Я также добавил несколько тестовых примеров, чтобы проиллюстрировать проблему, о которой я думаю.

Вот тестовая программа:

#include <stdio.h> 

int Array0[] = { 1, 2, 1, 3, 4 }; 
int Array1[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; 
int Array2[] = { 1, 2, 4, 4, 8, 16, 32, 64, 128 }; 
int Array3[] = { 1, 2, 4, 8, 16, 32, 64, 128, 2 }; 
int Array4[] = { 1, 2, 4, 8, 16, 32, 64, 128, 2, 4 }; 
int Array5[] = { 1, 2, 3, 4, 5, 6 }; 
int Array6[] = { 1, 2, 3, 4, 5, 6, 1, 3 }; 

int K = 3; 
int sepflg; 
int tstno; 

int 
orig(int *Array,int *ArrEnd) 
{ 
    int result; 
    long residx; 
    int KCtr = 0; 
    int uniqflg; 

    result = -1; 
    residx = -1; 

    for (int *o = &Array[1]; o < ArrEnd; o++) { 
     uniqflg = 1; 
     for (int *i = &Array[0]; i < o; i++) { 
      if (*o == *i) { 
       uniqflg = 0; 
       break; 
      } 
     } 
     if (! uniqflg) 
      continue; 

     printf(" orig: MATCH value=%d index=%ld\n",*o,o - Array); 

     KCtr++; 
     if (KCtr == K) { 
      result = *o; 
      residx = o - Array; 
      break; 
     } 
    } 

    printf(" orig: FINAL result=%d residx=%ld\n",result,residx); 

    return result; 
} 

int 
full(int *Array,int *ArrEnd) 
{ 
    int result; 
    long residx; 
    int KCtr = 0; 
    int uniqflg; 

    result = -1; 
    residx = -1; 

    for (int *o = &Array[0]; o < ArrEnd; o++) { 
     uniqflg = 1; 
     for (int *i = &Array[0]; i < ArrEnd; i++) { 
      if (o == i) 
       continue; 
      if (*o == *i) { 
       uniqflg = 0; 
       break; 
      } 
     } 
     if (! uniqflg) 
      continue; 

     printf(" full: MATCH value=%d index=%ld\n",*o,o - Array); 

     KCtr++; 
     if (KCtr == K) { 
      result = *o; 
      residx = o - Array; 
      break; 
     } 
    } 

    printf(" full: FINAL result=%d residx=%ld\n",result,residx); 

    return result; 
} 

void 
test(int *Array,long siz) 
{ 
    int *ArrEnd = &Array[siz/sizeof(int)]; 
    int oval; 
    int fval; 

    if (sepflg) 
     printf("\n"); 
    sepflg = 1; 

    printf("Array%d:",tstno); 
    for (int *ptr = Array; ptr < ArrEnd; ++ptr) 
     printf(" %4d",*ptr); 
    printf("\n"); 

    oval = orig(Array,ArrEnd); 
    printf("\n"); 
    fval = full(Array,ArrEnd); 

    printf("\n"); 
    printf(" test: %s orig=%d full=%d\n", 
     (oval == fval) ? "PASS" : "FAIL",oval,fval); 

    ++tstno; 
} 

int 
main(void) 
{ 

    test(Array0,sizeof(Array0)); 
    test(Array1,sizeof(Array1)); 
    test(Array2,sizeof(Array2)); 
    test(Array3,sizeof(Array3)); 
    test(Array4,sizeof(Array4)); 
    test(Array5,sizeof(Array5)); 
    test(Array6,sizeof(Array6)); 

    return 0; 
} 

Вот вывод программы:

Array0: 1 2 1 3 4 
    orig: MATCH value=2 index=1 
    orig: MATCH value=3 index=3 
    orig: MATCH value=4 index=4 
    orig: FINAL result=4 residx=4 

    full: MATCH value=2 index=1 
    full: MATCH value=3 index=3 
    full: MATCH value=4 index=4 
    full: FINAL result=4 residx=4 

    test: PASS orig=4 full=4 

Array1: 1 2 4 8 16 32 64 128 
    orig: MATCH value=2 index=1 
    orig: MATCH value=4 index=2 
    orig: MATCH value=8 index=3 
    orig: FINAL result=8 residx=3 

    full: MATCH value=1 index=0 
    full: MATCH value=2 index=1 
    full: MATCH value=4 index=2 
    full: FINAL result=4 residx=2 

    test: FAIL orig=8 full=4 

Array2: 1 2 4 4 8 16 32 64 128 
    orig: MATCH value=2 index=1 
    orig: MATCH value=4 index=2 
    orig: MATCH value=8 index=4 
    orig: FINAL result=8 residx=4 

    full: MATCH value=1 index=0 
    full: MATCH value=2 index=1 
    full: MATCH value=8 index=4 
    full: FINAL result=8 residx=4 

    test: PASS orig=8 full=8 

Array3: 1 2 4 8 16 32 64 128 2 
    orig: MATCH value=2 index=1 
    orig: MATCH value=4 index=2 
    orig: MATCH value=8 index=3 
    orig: FINAL result=8 residx=3 

    full: MATCH value=1 index=0 
    full: MATCH value=4 index=2 
    full: MATCH value=8 index=3 
    full: FINAL result=8 residx=3 

    test: PASS orig=8 full=8 

Array4: 1 2 4 8 16 32 64 128 2 4 
    orig: MATCH value=2 index=1 
    orig: MATCH value=4 index=2 
    orig: MATCH value=8 index=3 
    orig: FINAL result=8 residx=3 

    full: MATCH value=1 index=0 
    full: MATCH value=8 index=3 
    full: MATCH value=16 index=4 
    full: FINAL result=16 residx=4 

    test: FAIL orig=8 full=16 

Array5: 1 2 3 4 5 6 
    orig: MATCH value=2 index=1 
    orig: MATCH value=3 index=2 
    orig: MATCH value=4 index=3 
    orig: FINAL result=4 residx=3 

    full: MATCH value=1 index=0 
    full: MATCH value=2 index=1 
    full: MATCH value=3 index=2 
    full: FINAL result=3 residx=2 

    test: FAIL orig=4 full=3 

Array6: 1 2 3 4 5 6 1 3 
    orig: MATCH value=2 index=1 
    orig: MATCH value=3 index=2 
    orig: MATCH value=4 index=3 
    orig: FINAL result=4 residx=3 

    full: MATCH value=2 index=1 
    full: MATCH value=4 index=3 
    full: MATCH value=5 index=4 
    full: FINAL result=5 residx=4 

    test: FAIL orig=4 full=5 

Простейшие тесты, которые иллюстрируют оба вопроса являются Array5 и Array6

Вот соответствующий ASM код:

.data 
Array:  .word  1, 2, 3, 4, 5, 6, 1, 3 
ArrEnd: 
K:   .word  3 

    .text 
    .globl main 

# s0 for K 
# s1 for result 
# t0 for o (as pointer) 
# t1 for i (as pointer) 
# t2 for array count 
# t3 for array[o] 
# t4 for array[i] 
# t6 for counter to reach K (i.e. KCtr?) 
main: 
    lw  $s0,K     # K 
    li  $t6,0     # KCtr = 0 

    la  $t2,ArrEnd    # point to end of array 
    la  $t0,Array    # o = &Array[0] 
    li  $s1,-1     # get fail value 
    b  outstart 

outerloop: 
    addiu $t0,$t0,4    # advance o [as pointer] 
outstart: 
    bgeu $t0,$t2,finish   # o < ArrEnd? if no, fly 
    lw  $t3,0($t0)    # get Array[o] 

    la  $t1,Array    # i = &Array[0] 

innerloop: 
    lw  $t4,0($t1)    # get Array[i] 
    beq  $t1,$t0,innernext  # o == i? if yes, skip test 
    beq  $t3,$t4,outerloop  # Array[o] == Array[i]? if yes, not unique 
innernext: 
    addiu $t1,$t1,4    # advance array pointer for i 
    bltu $t1,$t2,innerloop  # at end? if no, loop 

    # current array value is unique 
    addi $t6,$t6,1    # KCtr++ 
    bne  $t6,$s0,outerloop  # KCtr == K? if no, wait for next unique 
    lw  $s1,0($t0)    # get better result -- no need to loop more 

finish: 
    li  $v0,1 
    move $a0,$s1 
    syscall 

    li  $v0,10 
    syscall 
+0

Спасибо, я вижу свои глупые ошибки в коде C и Assembly. Ваш код, похоже, работает в spim. Но я не понял «ArrayEnd». Для него нет значения, но оно работает. Как ? –

Смежные вопросы