cardslots/_slots_ram_read [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      _slots_ram_read

SYNOPSIS

static void
_slots_ram_read(
                void*         data,
                privilege_t   priv,
                uint32_t      addr,
                uint8_t       lanes,
                uint16_t*     result,
                bool*         error
               )

FUNCTION

Reads a 16-bit word from emulated RAM.

INPUTS

      data    Base address of the emulator's RAM image.

      priv    The current privilege mode of the processor.  Currently
              unused.

      addr    The hword address to read from.  Note that this is not the
              byte address.

      lanes   A bit-mask indicating which bytes on the emulated bus are
              intended to be active.  Currently unused.

      result  Pointer to a 16-bit value to receive the read data.

      error   Pointer to a boolean flag.

 RESULT

SEE ALSO

      _slots_ram_write

SOURCE

{
        uint16_t* ram = (uint16_t*)data;

        // Squelch compiler warnings about unused parameters.
        // We're RAM; we don't care about privilege.
        (void)priv;
        // We're reading, and reading has no side-effects.  So,
        // we don't care about which byte lanes are active.
        (void)lanes;
        // If the corresponding cardslot_t is configured properly,
        // we shouldn't have to range-check the array index into memory.
        *result = ram[addr];
}

cardslots/_slots_ram_write [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      _slots_ram_write

SYNOPSIS

static void
_slots_ram_write(
                void*        data,
                privilege_t  priv,
                uint32_t     addr,
                uint8_t      lanes,
                uint16_t     value,
                bool*        error
               )

FUNCTION

Writes an 8- or 16-bit value to emulated RAM.

INPUTS

      data    Base address of the emulator's RAM image.

      priv    The current privilege mode of the processor.  Currently
              unused.

      addr    The hword address to write to.  Note that this is not the
              byte address.

      lanes   A bit-mask indicating which bytes on the emulated bus are
              intended to be active.  Bit 0 indicates bits 0-7, bit 1 for
              bits 8-15.

      value   The 16-bit value to write out to emulated RAM.

      error   Pointer to a boolean flag.

 RESULT

SEE ALSO

      _slots_ram_read

SOURCE

{
        uint16_t* ram = (uint16_t*)data;

        // Squelch compiler warnings about unused parameters.
        // We're RAM; we don't care about privilege.
        (void)priv;

        // We are writing, which means that lane-selects now matter.
        // If no selects are selected, there's nothing for us to write.
        if (lanes == 0) {
                return;
        }

        // If both lanes are selected at once, do a full write.
        if (lanes == 3) {
                ram[addr] = value;
                return;
        }

        // Otherwise, tackle individual byte lanes.
        //
        // There's probably an easier way to do this, or a faster way,
        // but for now, I'm going to use a read-modify-write algorith.
        //
        // If the corresponding cardslot_t is configured properly,
        // we shouldn't have to range-check the array index into memory.
        uint16_t intermediate_data = ram[addr];

        if (lanes & 0x01) {
                intermediate_data =
                        (intermediate_data & 0xFF00) | (value & 0x00FF);
        }
        else if (lanes & 0x02) {
                intermediate_data =
                        (intermediate_data & 0x00FF) | (value & 0xFF00);
        }

        ram[addr] = intermediate_data;
}

cardslots/slots_find_card_by_address [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_find_card_by_address

SYNOPSIS

static cardslot_t*
slots_find_card_by_address(slots_t* slots, uint32_t byte_addr)

FUNCTION

Maps a virtual byte address to the cardslot_t responsible for it.

INPUTS

      slots -- pointer to a slots_t, which defines the virtual address space.
      byte_addr -- the virtual address.

 RESULT
      If successful, the pointer to the managing cardslot_t instance is
      returned; otherwise, NULL is returned.

SEE ALSO

SOURCE

{
        for (int i = 0; i < slots->slots_used; i++) {
                const uint32_t and_mask = slots->slots[i].addr_and_mask;
                const uint32_t xor_mask = slots->slots[i].addr_xor_mask;

                if (((byte_addr & and_mask) ^ xor_mask) == 0) {
                        return &slots->slots[i];
                }
        }

        return NULL;
}

cardslots/slots_init [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_init

SYNOPSIS

void
slots_init(slots_t* slots)

FUNCTION

Allocate and initialize resources necessary to properly emulate a Kestrel-2EX.

INPUTS

      slots -- pointer to a slots_t, which defines the virtual address space.

 RESULT
      If successful, the slots_used member of the slots_t structure will
      be non-zero, and the corresponding set of address mappings will be
      configured.

      Otherwise, the slots_used field will be set to zero, and the
      array of configurations will be undefined.

BUGS

      The interface of this function is not ideal; it can potentially lead
      to leaked memory if things go wrong during initialization.  However,
      since failed initializations currently lead the emulator to just
      exit the program entirely, this is a low-priority concern.

SEE ALSO

      slots_init

SOURCE

{
        slots->slots_used = 1;

        // We put the most frequently used resource first in the array
        // so as to minimize latency.

        slots->slots[0].addr_and_mask = 0xC0000000UL;
        slots->slots[0].addr_xor_mask = 0xC0000000UL;
        slots->slots[0].addr_sel_mask = 0x000FFFFFUL;
        slots->slots[0].read = _slots_ram_read;
        slots->slots[0].write = _slots_ram_write;
        slots->slots[0].ifetch = _slots_ram_read;
        k2_alloc(1048576, &slots->slots[0].data);

        if (slots->slots[0].data == NULL) {
                fprintf(stderr, "K2SLT008 OOM; aborting slot assignment\n");
                slots->slots_used = 0;
                return;
        }
}

cardslots/slots_read_byte [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_read_byte

SYNOPSIS

void
slots_read_byte(
                slots_t*    slots,
                privilege_t priv,
                uint32_t    byte_addr,
                uint8_t*    result,
                bool*       error
                )

FUNCTION

Read a value from virtual memory address byte_addr using privilege mode priv.

INPUTS

      slots -- pointer to a slots_t, which defines the virtual address space.
      priv -- the privilege mode with which to make the access.
      byte_addr -- the virtual address to write value to.
      result -- pointer to the 8-bit variable receiving the read value.
      error -- pointer to a bool or gboolean variable.  This cannot be NULL.

 RESULT
      If successful, the value of result will be altered with the read
      value from memory, and *error remains unmodified.

      If there was some kind of virtual hardware failure (e.g.,
      an attempt to read from an unmapped address), *error will be set to
      true.

      *error will never be set to false.

SEE ALSO

      slots_write_byte, slots_write_hword, slots_read_hword

SOURCE

{
        cardslot_t* slot = slots_find_card_by_address(slots, byte_addr);

        if (!slot) {
                fprintf(stderr,
                        "K2SLT007 Attempt to read byte from address "
                        "$%08X; but nothing mapped there.\n", byte_addr
                       );
                *error = true;
                return;
        }

        uint32_t hword_addr = (byte_addr & slot->addr_sel_mask) >> 1;
        uint8_t lanes = (byte_addr & 1) ? 2 : 1;
        uint16_t bus_result;
        slot->read(slot->data, priv, hword_addr, lanes, &bus_result, error);
        if (lanes == 1) {
                *result = (uint8_t)(bus_result & 0x00FF);
        }
        else { // lanes == 2
                *result = (uint8_t)((bus_result & 0xFF00) >> 8);
        }
}

cardslots/slots_read_hword [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_read_hword

SYNOPSIS

void
slots_read_hword(
                slots_t*    slots,
                privilege_t priv,
                uint32_t    byte_addr,
                uint16_t*   result,
                bool*       error
                )

FUNCTION

Read a value from virtual memory address byte_addr using privilege mode priv.

INPUTS

      slots -- pointer to a slots_t, which defines the virtual address space.
      priv -- the privilege mode with which to make the access.
      byte_addr -- the virtual address to write value to.
      result -- pointer to the 16-bit variable receiving the read value.
      error -- pointer to a bool or gboolean variable.  This cannot be NULL.

 RESULT
      If successful, the value of result will be altered with the read
      value from memory, and *error remains unmodified.

      If there was some kind of virtual hardware failure (e.g.,
      an attempt to read a half-word from an odd address), *error
      will be set to true.

      *error will never be set to false.

SEE ALSO

      slots_write_hword, slots_write_byte, slots_read_byte

SOURCE

{
        if ((byte_addr & 1) != 0) {
                *error = true;
                fprintf(stderr,
                        "K2SLT001 Attempt to read hword at odd address "
                        "$%08X\n", byte_addr
                        );
                return;
        }

        cardslot_t* slot = slots_find_card_by_address(slots, byte_addr);

        if (!slot) {
                fprintf(stderr,
                        "K2SLT002 Attempt to read hword from address "
                        "$%08X; but nothing mapped there.\n", byte_addr
                       );
                *error = true;
                return;
        }

        uint32_t hword_addr = (byte_addr & slot->addr_sel_mask) >> 1;
        slot->read(slot->data, priv, hword_addr, 3, result, error);
}

cardslots/slots_terminate [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_terminate

SYNOPSIS

void
slots_terminate(slots_t* slots)

FUNCTION

Dispose of resources allocated by a corresponding call to slots_init().

INPUTS

      slots -- pointer to a slots_t, which defines the virtual address space.

 RESULT

SEE ALSO

      slots_init

SOURCE

{
        if (slots) {
                k2_free(&slots->slots[0].data);
        }

        slots->slots_used = 0;
}

cardslots/slots_translate_address_from_virtual [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_translate_address_from_virtual

SYNOPSIS

void
slots_translate_address_from_virtual(
                slots_t* slots, uint32_t byte_addr,
                uint8_t** local_ptr,
                bool* error
                )

FUNCTION

Given a virtual address to fetch video data from, provide a host- local byte address that can be supplied to other modules (such as Cairo on GTK-based systems, or LibSDL, etc.). The frame buffer is assumed to be contiguous in both virtual and local memory.

This procedure is mainly intended for use by the video display refresh code in gui.c, since it is MUCH more efficient to just deal with raw bitmap data as a single chunk instead of emulating individual memory access beats on the bus.

DO NOT use this on memory-mapped I/O devices.

INPUTS

      slots -- reference to the slots_t which ultimately determines address
              mapping for the virtual machine.
      byte_addr -- the frame buffer's virtual address.
      local_ptr -- pointer to a variable that will receive the local
              address.
      error -- pointer to a bool or gboolean variable.

 RESULT
      If successful, *error is left unmodified, while *local_ptr is set to
      the host-local address corresponding to the video frame buffer at
      virtual address byte_addr.

      Otherwise, *error is set to true, and *local_ptr is left unmodified.

BUGS

      The video frame buffer CANNOT span across multiple memory resources.
      In actual hardware, the worst that would happen is the video fetch
      pointer will just wrap around, and you might get garbage on the screen.
      In the emulator, checking for this condition is somewhat expensive,
      so it isn't done; therefore, if this happens, the worst that could
      happen is a segmentation (POSIX) or general protection/page (Windows)
      fault.

SEE ALSO

      gui/_on_screen_draw

SOURCE

{
        cardslot_t* slot = slots_find_card_by_address(slots, byte_addr);
        if (slot == NULL) {
                fprintf(stderr,
                        "K2SLT003 slots_translate_address_from_virtual: "
                        "address $%08X not mapped!\n", byte_addr
                        );
                *error = true;
                return;
        }

        // Assume the addressed region is a RAM card of some sort.
        // This WILL NOT work for I/O devices.  It MAY possibly crash!
        //
        // Issue: Should we make this a slot-specific method?  It would
        // at least let us catch this kind of error and/or more intelligently
        // emulate its logical behavor.
        
        uint32_t hword_addr = (byte_addr & slot->addr_sel_mask) >> 1;
        uint16_t* ram_ptr = (uint16_t*)slot->data;
        *local_ptr = (uint8_t*)&ram_ptr[hword_addr];
}

cardslots/slots_write_byte [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_write_byte

SYNOPSIS

void
slots_write_byte(
                slots_t*    slots,
                privilege_t priv,
                uint32_t    byte_addr,
                uint8_t     value,
                bool*       error
                )

FUNCTION

Write value to virtual memory address byte_addr using privilege mode priv.

INPUTS

      slots -- pointer to a slots_t, which defines the virtual address space.
      priv -- the privilege mode with which to make the access.
      byte_addr -- the virtual address to write value to.
      value -- the 8-bit value to write.
      error -- pointer to a bool or gboolean variable.  This cannot be NULL.

 RESULT
      If successful, the byte value is written into virtual
      memory at the virtual address provided, and *error remains
      unmodified.

      If there was some kind of virtual hardware failure (e.g.,
      an attempt to write to an unmapped location in memory), *error
      will be set to true.

      *error will never be set to false.

SEE ALSO

      slots_read_byte, slots_write_hword, slots_read_hword

SOURCE

{
        cardslot_t* slot = slots_find_card_by_address(slots, byte_addr);

        if (!slot) {
                fprintf(stderr,
                        "K2SLT006 Attempt to write byte to address "
                        "$%08X; but nothing mapped there.\n", byte_addr
                       );
                *error = true;
                return;
        }

        const uint32_t hword_addr = (byte_addr & slot->addr_sel_mask) >> 1;
        const uint8_t lanes = (byte_addr & 1) ? 2 : 1;
        const uint16_t bus_value = value | (value << 8);
        slot->write(slot->data, priv, hword_addr, lanes, bus_value, error);
}

cardslots/slots_write_hword [ Functions ]

[ Top ] [ cardslots ] [ Functions ]

NAME

      slots_write_hword

SYNOPSIS

void
slots_write_hword(
                slots_t*    slots,
                privilege_t priv,
                uint32_t    byte_addr,
                uint16_t    value,
                bool*       error
                )

FUNCTION

Write value to virtual memory address byte_addr using privilege mode priv.

INPUTS

      slots -- pointer to a slots_t, which defines the virtual address space.
      priv -- the privilege mode with which to make the access.
      byte_addr -- the virtual address to write value to.
      value -- the 16-bit value to write.
      error -- pointer to a bool or gboolean variable.  This cannot be NULL.

 RESULT
      If successful, the half-word value is written into virtual
      memory at the virtual address provided, and *error remains
      unmodified.

      If there was some kind of virtual hardware failure (e.g.,
      an attempt to write a half-word at an odd address), *error
      will be set to true.

      *error will never be set to false.

SEE ALSO

      slots_read_hword, slots_write_byte, slots_read_byte

SOURCE

{
        if ((byte_addr & 1) != 0) {
                *error = true;
                fprintf(stderr,
                        "K2SLT004 Attempt to write hword at odd address "
                        "$%08X\n", byte_addr
                        );
                return;
        }

        cardslot_t* slot = slots_find_card_by_address(slots, byte_addr);

        if (!slot) {
                fprintf(stderr,
                        "K2SLT005 Attempt to write hword to address "
                        "$%08X; but nothing mapped there.\n", byte_addr
                       );
                *error = true;
                return;
        }

        const uint32_t hword_addr = (byte_addr & slot->addr_sel_mask) >> 1;
        slot->write(slot->data, priv, hword_addr, 3, value, error);
}