Skip to content

andyy-garcia/arm-training

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Assembly programming

Some ARM code written in 2019 and 2022, to be played inside the DE1-SoC emulator.

Files

  • quicksort.s was school work requiring to translate quicksort from C code to ASM by hand.
  • calculator.s is a simple calculator supporting addition, subtraction and multiplication, use the mapped 7-segment display of the emulator.
  • vga.s is a recent idea I had to train myself but not finished. I also spent some times around the storebytes function, even if it's not very useful in this case.

Pseudo-code for storebytes routine

I initially wrote this function directly in assembly, to write 1 to 4 bytes at arbitrary location (some ARM configurations require aligned access). I thought it would be simple but due to odds and quirks of my simple implementation, I rewrote it in pseudo-code first (here in C representation) then translated it in assembly by hand following the pseudo-code to keep my mind fresh.

void storebytes(uint32_t desired_addr, uint32_t data, uint32_t size)
{
    uint32_t addr = uint32_t(desired_addr) & ~(4 - 1);                  // Align the address to a multiple of 4 (a word)
    uint32_t start_offset = desired_addr - addr;                        // Start Offset is the index of the desired address in the aligned pointer
    uint32_t end_offset = 4 - (start_offset + size);

    uint32_t old = *(uint32_t*)addr;                                    // obtain the old value we will patch

    if (end_offset < 0)
    {
        size += end_offset;										        // cut size to fit the word only
        uint32_t old_mask = ((1 << (size*8)) - 1);				        // bits where new data takes place are set to 1
        old &= ~old_mask;                                               // clear those bits (using reverse mask) to avoid corrupting data by future OR operation
        size = -end_offset;                                             // set size to size of remaining data
        *(uint32_t*)addr = old | (data >> (size*8));                    // shift right by size of remaining data to only keep data fitting in the first word
        
        // remaining data
        addr += 4;                                                      // switch to next word
        old = *(uint32_t*)addr;
        old &= (-1 >> (size*8));                                        // clear all bits of [size] bytes in old (-1 is 0xffffffff, then we shift right to get zeros on the left part that will receive new value)
        *(uint32_t*)addr = old | (data << (4 - (size*8)));              // shift left data from 4-size to keep only the remaining data
    }
    else
    {
        uint32_t old_mask = ((1 << (size*8)) - 1) << (end_offset * 8);  // bits where new data takes place are set to 1
        old &= ~old_mask;                                               // clear those bits (using reverse mask) to avoid corrupting data by future OR operation
        *(uint32_t*)addr = old | (data << (end_offset*8));
    }
}

About

ARM Assembly training

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published