prg/prg_load [ Functions ]

[ Top ] [ prg ] [ Functions ]

NAME

      prg_load

SYNOPSIS

bool
prg_load(const char* filename, uint32_t prev_load_addr, slots_t* slots, uint32_t* load_addr, prgerr_t* err)

FUNCTION

Loads a program from the host's local filesystem into the emulator's RAM.

After loading, the memory layout will look as follows:

+-----+----------+----------+---------+---------------+-----+

        ... | PRG text | PRG data | PRG BSS |     PRG stack | ...  

+-----+----------+----------+---------+---------------+-----+

            ^                                               ^
            |                                               |
            load_addr                          prev_load_addr
            (aka default evproc PC)   (aka default evproc SP)

INPUTS

      filename        The name of the program file to try and load.

      prev_load_addr  The end of free memory.

      slots           A pointer to the slots_t structure, through which
                      we can access memory as viewed by the RISC-V processor.

      load_addr       Pointer to a variable that will receive the load
                      address of the module, if successful.  If additional
                      modules are to be loaded, this address becomes the
                      prev_load_addr for the next invokation of this
                      function.

      err             Pointer to a variable that will receive an error
                      indication, should this function fail.

 RESULT
      TRUE if successful; FALSE otherwise.  Check the err variable for 
      details.

SEE ALSO

SOURCE

{
        int h = open(filename, O_RDONLY);
        if (!h) {
                fprintf(stderr, "K2PRG010 Failed to open \"%s\"\n", filename);
                goto error_open;
        }

        prg_t ao;
        size_t actual = read(h, &ao, sizeof(ao));
        if (actual != sizeof(ao)) {
                fprintf(stderr, "K2PRG011 File too small\n");
                goto error_read;
        }

        if (ao.magic != PRG_MAGIC) {
                fprintf(stderr, "K2PRG012 Header indicates wrong file format\n");
                goto error_magic;
        }

        // How much code/data yet to read from the file
        uint32_t remainder_size = ao.text_size + ao.data_size;

        // Total amount of memory space required by the program
        uint32_t allocation_size = remainder_size + ao.bss_size + ao.stack_size;

        // Load address
        uint32_t code_base = prev_load_addr - allocation_size;
        fprintf(stderr, "K2PRG013 Code Base = $%08X\n", code_base);

        uint8_t* load_ptr;
        bool error = false;
        slots_translate_address_from_virtual(
                slots, code_base,
                &load_ptr, &error
        );
        if (error) {
                fprintf(stderr, "K2PRG014 Load Address Translation Failure\n");
                goto error_translate;
        }

        actual = read(h, load_ptr, remainder_size);
        if (actual < remainder_size) {
                fprintf(stderr, "K2PRG015 File too small\n");
                goto error_read;
        }

        close(h);
        *load_addr = code_base;
        return true;


error_translate:
        *err = PRGLOAD_MEM_TRANSLATE;
        goto error_;

error_magic:
        *err = PRGLOAD_MAGIC;
        goto error_;

error_read:
        *err = PRGLOAD_ERR_TOO_SMALL;
        goto error_;

error_open:
        *err = PRGLOAD_FILENAME;

error_:
        if (h) close(h);
        return false;
}