2

So here's my code with the given argument; this is what my code ends up printing though.

Test function _strCopy

Please enter a string: test

You just entered : test

Result of _strCopy: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

If both strings are identical, your _strCopy works properly.

Honestly assembly gives me the biggest headache and I'm assuming this was supposed to be easy considering most of the code is already completed for me, I just have to make the functions. Any help would be appreciated thanks.

Edit1: removed unneeded lines Edit2: solved, had to change

    move $t0, $a0
    move $t1, $a1

into

    move $t0, $a1
    move $t1, $a0

and that fixxed it

# Arguments:
#   - $a0: An address of the first character of a source string
#   - $a1: An address of a buffer
# Return Value:
#   - None
_strCopy:
    move $t0, $a0
    move $t1, $a1
strCopy_loop:
    lbu $t3, 0($t1)  # load
    sb $t3, 0($t0)  # write
    addi $t0, $t0, 1
    addi $t1, $t1, 1
    beq $t3, $zero, __strCopy_end   # Return if we hit a null terminator
    j strCopy_loop
__strCopy_loop2:
    addi $t2, $t2, -1
    sb $zero, 0($t2)
__strCopy_end:
    sub $v0, $t0, $a0
    jr $ra
ELlama
  • 33
  • 7
  • What is `a2`? (`add $t2, $a0, $a2` used here without description what value is in). And if this is SPIM/MARS question, run it in debugger, put breakpoint at the start of your function, open window with memory (buffer1 and/or buffer2), and step over instructions line by line to see what is happening to particular register values, and to memory content. – Ped7g Mar 01 '17 at 19:05
  • @Ped7g At a guess, `$a2` is the byte length (i.e. this is `strncpy` since the code implements the byte length limit) – Craig Estey Mar 01 '17 at 19:10
  • Why do you have the `la` instructions? If this is a true function, you want to use `$a0` and `$a1` as passed by caller, so I'd remove the `la`. Otherwise, the function looks pretty good. – Craig Estey Mar 01 '17 at 19:13
  • @CraigEstey sure enough, it's obvious from the code, but the OP didn't specify it. Anyway it looks good, until you read into details, there's some values used in opposite way, etc... and your comment about `la`, I actually even missed that. Anyway, SO is not debugging service, where obvious bugs are going on, the OP should learn to use debugger to see why the buffer2 is not being written to. – Ped7g Mar 01 '17 at 19:20
  • the a2 and t2 stuff were leftover; I removed them just now. Also removed the la instructions. Not sure what to do past here though since results are the same. The tester prints the result of strcopy from buffer2. So I want to save each character in the string at address a0 buffer1 into buffer2 – ELlama Mar 01 '17 at 19:21
  • @Ped7g I missed that. This is `strncpy` _but_ the source and destination pointers are reversed as used [if the top comments are correct]. (i.e.) this implements `strncpy` but should be `strncpy(const char *src,char *dst,int len)` – Craig Estey Mar 01 '17 at 19:22
  • I'm just learning the debugger for C, I'm pretty new to MIPS and used some code from one of my older labs and I think that may be why I'm getting confused with this sorry. I will look into how to use the debugger in mars – ELlama Mar 01 '17 at 19:23
  • If the top comments are correct, your teacher is throwing a curve ball by giving the args reversed. So, try `move $t1,$a0` and `move $t0,$a1`, etc. Otherwise, keep `$t0` and `$t1` so you can calculate the length at end. There is no def for the return value, your code implements length (vs. `strncpy` returning the destination buffer pointer). – Craig Estey Mar 01 '17 at 19:28
  • @CraigEstey omg now it's printing something reasonable; I think I may have an error in my loop though since it's returning for "result of _strCopy" instead of test it returns "[]est" can't seem to post the box it's making so I used brackets instead. Edit2: ok fixxed that thanks. Now it all seems to be working. – ELlama Mar 01 '17 at 19:31
  • Your code looks correct except for question of arg order and return value. In `mars`, debugger is easy. Single step is just clicking `>1` instead of `>`. To set a breakpoint, scroll to the line and click on the box on the left in the code window. – Craig Estey Mar 01 '17 at 19:37
  • Even if it works, you may want to step over it few times in debugger to get better feel how it actually "looks" in the machine, when particular instruction is executed. – Ped7g Mar 01 '17 at 19:39
  • @CraigEstey Ped7g Alright, thanks. Yeah I was playing around with the debugger and actually ended up finding why I was getting []est instead of test from before. Again, thank you guys so much. This is just the beginning of the code I have to be working on but the more I understand it the better. – ELlama Mar 01 '17 at 19:43

1 Answers1

0

Another possible implementation:

.globl my_strcpy
.ent my_strcpy
my_strcpy:
    // Arguments:
    // a0: new str
    // a1: source str
    // a2: number of chars to copy

    li $t0, 0                // New str
    li $t1, 0                // Source str
    li $t2, 0                // Char to copy
    li $t3, 0                // Chars copied

    for:
        addu $t1, $a1, $t3     // Point to next char of source str
        lb $t2, 0($t1)         // Get next char of source str

        addu $t0, $a0, $t3     // Point to next char of new str
        sb $t2, 0($t0)         // Save next char of new str

        addi $t3, $t3, 1       // +1 chars copied   
        bne $a2, $t3, for      // Continue if there are more chars 

    jr $ra                     // Back to caller

.end my_strcpy

It can be tested on a C script like the following:

#include <stdio.h>

extern void my_strcpy( char* d, char* s, size_t n );

void check( char* a, char* b, size_t n ){
    for( size_t i = 0; i < n; i += 1 ){
        if( a[i] != b[i] ){
            printf( "NOT OK \n" );
            return;
        }
    } 
    printf( "OK \n" );
}


int main(){
    char s[14] = "String sample"; // null terminator
    char d[14];
    my_strcpy( d, s, 14 );
    check( d, s, 14 );

    return 0;
}
Esteban
  • 101
  • 3
  • 6
  • `li $t0, 0` and `$t1` are redundant: the first use of those register in the loop is write-only. Also, this is memcpy not strncpy; it doesn't stop on a 0 byte in the string, always copies the requested length. – Peter Cordes Jun 08 '20 at 03:29
  • Also, you could save an instruction inside the loop by calculating an end-pointer before the loop. Then the loop-branch could just be `bne src, end_src, for`, and you increment pointers instead of an index inside the loop. Like C `ends = s + len;` / `do{ *d++ = *s++; }while(s!=ends);`. A function is allowed to modify its `$a0..3` registers. – Peter Cordes Jun 08 '20 at 03:32
  • Also, if this is a real MIPS where you can run C (not the MARS or SPIM simulators), it will normally have branch-delay slots. So you'd fill that with the `addu` to post-increment the destination pointer, like ... / `sb` / `bne` / `addiu dst, dst, 1` – Peter Cordes Jun 08 '20 at 03:33