3

I try to realize inline assemble(riscv32) command in one program C and use litex to create the project in vivado and generate bin file. In simulation, part ASM does work (memory position x'10000400 does have value x'40) but when I implement in card digilent basys3(replace bios by bin file), I find variable "key" equals 0 but not 64

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <irq.h>
#include <libbase/uart.h>
#include <libbase/console.h>
#include <generated/csr.h>
 

int main(void)
{
#ifdef CONFIG_CPU_HAS_INTERRUPT
    irq_setmask(0);
    irq_setie(1);
#endif
    uart_init();
    
    int value = 64;
    int key = 0;
    int try_left;
    int provide;
 
    asm volatile (
        "li t0, 0x10000400\n"  
        "sw %0, 0(t0)\n"       
        :
        : "r" (value)          
        : "t0"                 
    );
    asm volatile (
        "li t0, 0x10000400\n"  
        "lw %0, 0(t0)\n"       
        :
        : "r" (key)          
        : "t0"                 
    );
 
 
    for (try_left=3;try_left>0;try_left--) {
        printf("enter key:\n");     
        scanf("%d", &provide);
        printf("enter %d and the key is %d\n", provide, key);
        if (key==provide) {
            try_left=3;
            printf("good key\n");
            return 0;
        }
        else printf("rest %d tries\n", try_left-1);
    }
    return 0;   
}

I have tried also without inline ASM, code like this.

    int key = 0;
volatile unsigned int *mem_ptr = (void*)0x10000000;
    volatile unsigned int i;

    for (i = 0; i < 2048; i++) {
        mem_ptr = &i;
        if (i==256) {
                key = *mem_ptr;
            }
        mem_ptr += 4;
    }

    volatile unsigned int *sram_ptr = (void*)0x40000000;
    volatile unsigned int j;

    for (j = 0; j < 8192; j++) {
            sram_ptr = &j;
            sram_ptr+=4;
    }

"key" get the value 256 but not associated with address x'10000400, also these two block memories are not initialized.

KabiLink
  • 61
  • 5
  • 2
    You don't need inline asm to load from an absolute address, just `volatile uint32_t *ptr = (void*)0x10000400;` or something like that. Then `*ptr = value;` `key = *ptr;`. Then you don't have to worry about your inline asm constraints, like `"=r"` for outputs vs. `"r"` for inputs, which you got wrong. Your `lw` statement tells the compiler it has an input and no outputs, so that's undefined behaviour. – Peter Cordes May 16 '23 at 09:40
  • I have another question. Can I use the same way to initialize a part of memory? Like `volatile uint32_t *mem_ptr = (void*)0x10000000;` `unsigned int i;` `for (i = 0; i <= 0x2000; i++)` `*mem_ptr = i;` `mem_ptr++;` and then `volatile uint32_t *ptr = (void*)0x10000400;` `key = *ptr;` – KabiLink May 16 '23 at 14:25
  • Yes, of course. If that memory region isn't MMIO registers and you only care about the value for later reads from your C program, you don't even need `volatile`. If you were storing the same value to every byte you could just use `memset`, but compilers can still potentially optimize your loop if you don't use volatile. (e.g. using 64-bit stores of two 32-bit halves, with SWAR increments since 0x2000 is less than `UINT32_MAX` so there won't be carry-out between the halves for adding `0x0000000100000001`) – Peter Cordes May 16 '23 at 19:45
  • I have a doubt about pointer. When I use "mem_ptr" to initialize memory block and "ptr" to initialize key, there is an error. I want to know the principle for this problem. – KabiLink May 17 '23 at 08:54
  • Nobody can answer that if you don't show the code and quote the error message. You might as well edit this question with a [mcve] of your new code and the error, since the current version of the question is just a trivial but serious error in using GNU C inline asm operands, one that's not interesting to write an answer about. – Peter Cordes May 17 '23 at 09:21
  • 1
    `mem_ptr = &i;` sets the pointer to point at memory where `i` is stored. If you wanted to change memory contents, use `*mem_ptr = i;` and `mem_ptr++;`. Remember, it's a C pointer, so increment by one is the next `unsigned int`. – Peter Cordes May 23 '23 at 13:21
  • If you don't understand how pointers work in C, [What is the difference between derefencing and assigning the address of a variable to pointer variable in C?](https://stackoverflow.com/q/59598732) is a near duplicate (but they didn't initialize their pointer first.) Also maybe [Pointer dereference in an assignment](https://stackoverflow.com/q/16615813) – Peter Cordes May 23 '23 at 13:24

0 Answers0