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);
}