mirror of
https://github.com/86Box/86Box.git
synced 2026-02-24 02:18:20 -07:00
Initial progress at RAMRO, RAMHT and RAMFC
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* vid_nv3.h: NV3 Architecture Hardware Reference (open-source)
|
||||
* Last updated 2 January 2025 (STILL WORKING ON IT)
|
||||
* Last updated 9 January 2025 (STILL WORKING ON IT)
|
||||
*
|
||||
*
|
||||
*
|
||||
@@ -204,10 +204,10 @@ extern const device_config_t nv3_config[];
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS 12
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS_DEFAULT 0x0
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_SIZE 16
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_4K 0x0
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_8K 0x1
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_16K 0x2
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_32K 0x3
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_SIZE_4K 0x0
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_SIZE_8K 0x1
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_SIZE_16K 0x2
|
||||
#define NV3_PFIFO_CONFIG_RAMHT_SIZE_32K 0x3
|
||||
|
||||
#define NV3_PFIFO_CONFIG_RAMFC 0x2214
|
||||
#define NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS 9
|
||||
@@ -578,7 +578,7 @@ extern const device_config_t nv3_config[];
|
||||
#define NV3_CRTC_REGISTER_STANDARDVGA_END 0x18
|
||||
|
||||
|
||||
// These are nvidia (25-63)
|
||||
// These are nvidia, licensed from weitek (25-63)
|
||||
#define NV3_CRTC_REGISTER_RPC0 0x19 // What does this mean?
|
||||
#define NV3_CRTC_REGISTER_RPC1 0x1A // What does this mean?
|
||||
#define NV3_CRTC_REGISTER_READ_BANK 0x1D
|
||||
@@ -865,7 +865,7 @@ typedef struct nv3_pramin_ramht_s
|
||||
nv3_pramin_ramht_subchannel_t subchannels[NV3_DMA_CHANNELS][NV3_DMA_SUBCHANNELS_PER_CHANNEL];
|
||||
} nv3_pramin_ramht_t;
|
||||
|
||||
uint32_t nv3_pramin_ramht_hash(nv3_pramin_name_t name, uint32_t channel);
|
||||
uint32_t nv3_ramht_hash(nv3_pramin_name_t name, uint32_t channel);
|
||||
|
||||
// Anti-fuckup device
|
||||
typedef struct nv3_pramin_ramro_s
|
||||
@@ -963,6 +963,16 @@ void nv3_ramin_write8(uint32_t addr, uint8_t val, void* priv);
|
||||
void nv3_ramin_write16(uint32_t addr, uint16_t val, void* priv); // Write 16-bit RAMIN
|
||||
void nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv); // Write 32-bit RAMIN
|
||||
|
||||
bool nv3_pramin_arbitrate_read(uint32_t address, uint32_t* value); // Read arbitration so we can read/write to the structures in the first 64k of ramin
|
||||
bool nv3_pramin_arbitrate_write(uint32_t address, uint32_t value); // Write arbitration so we can read/write to the structures in the first 64k of ramin
|
||||
|
||||
uint32_t nv3_ramfc_read(uint32_t address);
|
||||
void nv3_ramfc_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_ramro_read(uint32_t address);
|
||||
void nv3_ramro_write(uint32_t address, uint32_t value);
|
||||
uint32_t nv3_ramht_read(uint32_t address);
|
||||
void nv3_ramht_write(uint32_t address, uint32_t value);
|
||||
|
||||
// MMIO Arbitration
|
||||
// Determine where the hell in this mess our reads or writes are going
|
||||
uint32_t nv3_mmio_arbitrate_read(uint32_t address);
|
||||
@@ -1018,8 +1028,6 @@ uint32_t nv3_user_read(uint32_t address);
|
||||
void nv3_user_write(uint32_t address, uint32_t value);
|
||||
#define nv3_object_submit_start nv3_user_read
|
||||
#define nv3_object_submit_end nv3_user_write
|
||||
uint32_t nv3_pramin_arbitrate_read(uint32_t address);
|
||||
void nv3_pramin_arbitrate_write(uint32_t address, uint32_t value);
|
||||
// TODO: RAMHT, RAMFC...or maybe handle it inside of nv3_pramin_*
|
||||
|
||||
// GPU subsystems
|
||||
|
||||
@@ -103,8 +103,9 @@ uint32_t nv3_mmio_arbitrate_read(uint32_t address)
|
||||
ret = nv3_vram_read(address);
|
||||
else if (address >= NV3_USER_START && address <= NV3_USER_END)
|
||||
ret = nv3_user_read(address);
|
||||
else if (address >= NV3_PRAMIN_START && address <= NV3_PRAMIN_END)
|
||||
ret = nv3_pramin_arbitrate_read(address); // RAMHT, RAMFC, RAMRO etc dettermined by nv3_ramin_* function
|
||||
// RAMIN is handled by a separate memory mapping in PCI BAR1
|
||||
//else if (address >= NV3_PRAMIN_START && address <= NV3_PRAMIN_END)
|
||||
//ret = nv3_pramin_arbitrate_read(address); // RAMHT, RAMFC, RAMRO etc dettermined by nv3_ramin_* function
|
||||
else
|
||||
{
|
||||
nv_log("NV3: MMIO read arbitration failed, INVALID address NOT mapped to any GPU subsystem 0x%08x [returning 0x00]\n", address);
|
||||
|
||||
@@ -179,14 +179,14 @@ void nv3_pfifo_write(uint32_t address, uint32_t value)
|
||||
|
||||
nv_log("NV3: RAMHT Reconfiguration\n"
|
||||
"Base Address in RAMIN: %d\n"
|
||||
"Size: 0x%08x bytes\n", (value >> 12) & 0x1f, new_size_ramht);
|
||||
"Size: 0x%08x bytes\n", ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12, new_size_ramht);
|
||||
#endif
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMFC:
|
||||
nv3->pfifo.ramfc_config = value;
|
||||
|
||||
nv_log("NV3: RAMFC Reconfiguration\n"
|
||||
"Base Address in RAMIN: %d\n", (value >> 12) & 0x1f);
|
||||
"Base Address in RAMIN: %d\n", ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9);
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMRO:
|
||||
nv3->pfifo.ramro_config = value;
|
||||
@@ -200,7 +200,7 @@ void nv3_pfifo_write(uint32_t address, uint32_t value)
|
||||
|
||||
nv_log("NV3: RAMRO Reconfiguration\n"
|
||||
"Base Address in RAMIN: %d\n"
|
||||
"Size: 0x%08x bytes\n", (value >> 12) & 0x1f, new_size_ramro);
|
||||
"Size: 0x%08x bytes\n", ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9, new_size_ramro);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,11 +48,15 @@ uint8_t nv3_ramin_read8(uint32_t addr, void* priv)
|
||||
|
||||
addr ^= (nv3->nvbase.svga.vram_max- 0x10);
|
||||
|
||||
uint8_t val = nv3->nvbase.svga.vram[addr];
|
||||
uint32_t val = 0x00;
|
||||
|
||||
nv_log("NV3: Read byte from RAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
if (!nv3_pramin_arbitrate_read(addr, &val)) // Oh well
|
||||
{
|
||||
val = (uint8_t)nv3->nvbase.svga.vram[addr];
|
||||
nv_log("NV3: Read byte from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
}
|
||||
|
||||
return val;
|
||||
return (uint8_t)val;
|
||||
}
|
||||
|
||||
// Read 16-bit ramin
|
||||
@@ -68,9 +72,13 @@ uint16_t nv3_ramin_read16(uint32_t addr, void* priv)
|
||||
addr ^= (nv3->nvbase.svga.vram_max - 0x10);
|
||||
addr >>= 1; // what
|
||||
|
||||
uint16_t val = vram_16bit[addr]; // what
|
||||
uint32_t val = 0x00;
|
||||
|
||||
nv_log("NV3: Read word from RAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
if (!nv3_pramin_arbitrate_read(addr, &val))
|
||||
{
|
||||
val = (uint16_t)vram_16bit[addr];
|
||||
nv_log("NV3: Read word from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -88,9 +96,14 @@ uint32_t nv3_ramin_read32(uint32_t addr, void* priv)
|
||||
addr ^= (nv3->nvbase.svga.vram_max - 0x10);
|
||||
addr >>= 2; // what
|
||||
|
||||
uint32_t val = vram_32bit[addr];
|
||||
uint32_t val = 0x00;
|
||||
|
||||
nv_log("NV3: Read dword from RAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
if (!nv3_pramin_arbitrate_read(addr, &val))
|
||||
{
|
||||
val = vram_32bit[addr];
|
||||
|
||||
nv_log("NV3: Read dword from PRAMIN addr=0x%08x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -107,9 +120,15 @@ void nv3_ramin_write8(uint32_t addr, uint8_t val, void* priv)
|
||||
// reversal unit size in this case is 16 bytes, vram size is 2-8mb (but 8mb is zx/nv3t only and 2mb...i haven't found a 22mb card)
|
||||
addr ^= (nv3->nvbase.svga.vram_max - 0x10);
|
||||
|
||||
nv3->nvbase.svga.vram[addr] = val;
|
||||
uint32_t val32 = 0x00;
|
||||
|
||||
if (!nv3_pramin_arbitrate_write(addr, val32))
|
||||
{
|
||||
nv3->nvbase.svga.vram[addr] = val;
|
||||
nv_log("NV3: Write byte to PRAMIN addr=0x%08x val=0x%02x (raw address=0x%08x)\n", addr, val, raw_addr);
|
||||
}
|
||||
|
||||
|
||||
nv_log("NV3: Write byte to RAMIN addr=0x%08x val=0x%02x (raw address=0x%08x)\n", addr, val, raw_addr);
|
||||
}
|
||||
|
||||
// Write 16-bit ramin
|
||||
@@ -125,9 +144,15 @@ void nv3_ramin_write16(uint32_t addr, uint16_t val, void* priv)
|
||||
addr ^= (nv3->nvbase.svga.vram_max - 0x10);
|
||||
addr >>= 1; // what
|
||||
|
||||
vram_16bit[addr] = val;
|
||||
uint32_t val32 = 0x00;
|
||||
|
||||
if (!nv3_pramin_arbitrate_write(addr, val32))
|
||||
{
|
||||
vram_16bit[addr] = val;
|
||||
nv_log("NV3: Write word to PRAMIN addr=0x%08x val=0x%04x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
}
|
||||
|
||||
|
||||
nv_log("NV3: Write word to RAMIN addr=0x%08x val=0x%04x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
}
|
||||
|
||||
// Write 32-bit ramin
|
||||
@@ -143,20 +168,155 @@ void nv3_ramin_write32(uint32_t addr, uint32_t val, void* priv)
|
||||
addr ^= (nv3->nvbase.svga.vram_max - 0x10);
|
||||
addr >>= 2; // what
|
||||
|
||||
vram_32bit[addr] = val;
|
||||
uint32_t val32 = 0x00;
|
||||
|
||||
if (!nv3_pramin_arbitrate_write(addr, val32))
|
||||
{
|
||||
vram_32bit[addr] = val;
|
||||
nv_log("NV3: Write dnv3_pramin_arbitrate_readword to PRAMIN addr=0x%08x val=0x%04x (raw address=0x%08x)\n", addr, raw_addr);
|
||||
}
|
||||
|
||||
nv_log("NV3: Write dword to RAMIN addr=0x%08x val=0x%08x (raw address=0x%08x)\n", addr, val, raw_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
Arbitrates reads and writes to RAMFC, RAMRO, RAMHT and generic RAMIN
|
||||
RAMIN access arbitration functions
|
||||
Arbitrates reads and writes to RAMFC (unused dma context storage), RAMRO (invalid object submission location), RAMHT (hashtable for graphics objectstorage) (RAMAU?)
|
||||
and generic RAMIN
|
||||
|
||||
Takes a pointer to a result integer. This is because we need to check its result in our normal write function.
|
||||
Returns true if a valid "non-generic" address was found (e.g. RAMFC/RAMRO/RAMHT). False if the specified address is a generic RAMIN address
|
||||
*/
|
||||
uint32_t nv3_pramin_arbitrate_read(uint32_t address)
|
||||
bool nv3_pramin_arbitrate_read(uint32_t address, uint32_t* value)
|
||||
{
|
||||
return 0;
|
||||
if (!nv3) return 0x00;
|
||||
|
||||
uint32_t ramht_size = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03);
|
||||
uint32_t ramro_size = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01);
|
||||
|
||||
// Get the addresses of RAMHT, RAMFC, RAMRO
|
||||
// They must be within first 64KB of PRAMIN!
|
||||
uint32_t ramht_start = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12; // Must be 0x1000 aligned
|
||||
uint32_t ramfc_start = ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned
|
||||
uint32_t ramro_start = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned
|
||||
|
||||
// Calculate the RAMHT and RAMRO end points.
|
||||
// (RAMFC is always 0x1000 bytes on NV3.)
|
||||
uint32_t ramht_end = ramht_start;
|
||||
uint32_t ramfc_end = ramfc_start + 0x1000;
|
||||
uint32_t ramro_end = ramro_start;
|
||||
|
||||
switch (ramht_size)
|
||||
{
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_4K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_0;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_8K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_1;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_16K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_2;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_32K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_3;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ramro_size)
|
||||
{
|
||||
case NV3_PFIFO_CONFIG_RAMRO_SIZE_512B:
|
||||
ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_0;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMRO_SIZE_8K:
|
||||
ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (address >= ramht_start
|
||||
&& address <= ramht_end)
|
||||
{
|
||||
*value = nv3_ramht_read(address);
|
||||
return true;
|
||||
}
|
||||
else if (address >= ramfc_start
|
||||
&& address <= ramfc_end)
|
||||
{
|
||||
*value = nv3_ramfc_read(address);
|
||||
return true;
|
||||
}
|
||||
else if (address >= ramro_start
|
||||
&& address <= ramro_end)
|
||||
{
|
||||
*value = nv3_ramro_read(address);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* temp */
|
||||
return false;
|
||||
}
|
||||
|
||||
void nv3_pramin_arbitrate_write(uint32_t address, uint32_t value)
|
||||
bool nv3_pramin_arbitrate_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
|
||||
if (!nv3) return 0x00;
|
||||
|
||||
uint32_t ramht_size = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_SIZE) & 0x03);
|
||||
uint32_t ramro_size = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_SIZE) & 0x01);
|
||||
|
||||
// Get the addresses of RAMHT, RAMFC, RAMRO
|
||||
// They must be within first 64KB of PRAMIN!
|
||||
uint32_t ramht_start = ((nv3->pfifo.ramht_config >> NV3_PFIFO_CONFIG_RAMHT_BASE_ADDRESS) & 0x0F) << 12; // Must be 0x1000 aligned
|
||||
uint32_t ramfc_start = ((nv3->pfifo.ramfc_config >> NV3_PFIFO_CONFIG_RAMFC_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned
|
||||
uint32_t ramro_start = ((nv3->pfifo.ramro_config >> NV3_PFIFO_CONFIG_RAMRO_BASE_ADDRESS) & 0x7F) << 9; // Must be 0x200 aligned
|
||||
|
||||
// Calculate the RAMHT and RAMRO end points.
|
||||
// (RAMFC is always 0x1000 bytes on NV3.)
|
||||
uint32_t ramht_end = ramht_start;
|
||||
uint32_t ramfc_end = ramfc_start + 0x1000;
|
||||
uint32_t ramro_end = ramro_start;
|
||||
|
||||
switch (ramht_size)
|
||||
{
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_4K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_0;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_8K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_1;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_16K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_2;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMHT_SIZE_32K:
|
||||
ramht_end = ramht_start + NV3_PRAMIN_RAMHT_SIZE_3;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ramro_size)
|
||||
{
|
||||
case NV3_PFIFO_CONFIG_RAMRO_SIZE_512B:
|
||||
ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_0;
|
||||
break;
|
||||
case NV3_PFIFO_CONFIG_RAMRO_SIZE_8K:
|
||||
ramro_end = ramro_start + NV3_PRAMIN_RAMRO_SIZE_1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (address >= ramht_start
|
||||
&& address <= ramht_end)
|
||||
{
|
||||
nv3_ramht_write(address, value);
|
||||
return true;
|
||||
}
|
||||
else if (address >= ramfc_start
|
||||
&& address <= ramfc_end)
|
||||
{
|
||||
nv3_ramfc_write(address, value);
|
||||
return true;
|
||||
}
|
||||
else if (address >= ramro_start
|
||||
&& address <= ramro_end)
|
||||
{
|
||||
nv3_ramro_write(address, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -28,3 +28,12 @@
|
||||
#include <86Box/nv/vid_nv.h>
|
||||
#include <86Box/nv/vid_nv3.h>
|
||||
|
||||
uint32_t nv3_ramfc_read(uint32_t address)
|
||||
{
|
||||
nv_log("NV3: RAMFC (Unused DMA channel context) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address);
|
||||
}
|
||||
|
||||
void nv3_ramfc_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_log("NV3: RAMFC (Unused DMA channel context) Write (0x%04x -> 0x%04x), UNIMPLEMENTED", value, address);
|
||||
}
|
||||
@@ -32,9 +32,20 @@
|
||||
It is used to get the offset within RAMHT of a graphics object.
|
||||
*/
|
||||
|
||||
uint32_t nv3_pramin_ramht_hash(nv3_pramin_name_t name, uint32_t channel)
|
||||
uint32_t nv3_ramht_hash(nv3_pramin_name_t name, uint32_t channel)
|
||||
{
|
||||
uint32_t hash = (name.byte_high ^ name.byte_mid2 ^ name.byte_mid1 ^ name.byte_low ^ (uint8_t)channel);
|
||||
nv_log("NV3: Generating RAMHT hash (RAMHT slot=0x%04x (from name 0x%08x for DMA channel 0x%04x)\n)", name, channel);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t nv3_ramht_read(uint32_t address)
|
||||
{
|
||||
nv_log("NV3: RAMHT (Graphics object storage hashtable) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address);
|
||||
}
|
||||
|
||||
void nv3_ramht_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_log("NV3: RAMHT (Graphics object storage hashtable) Write (0x%04x -> 0x%04x), UNIMPLEMENTED", value, address);
|
||||
}
|
||||
|
||||
@@ -28,3 +28,12 @@
|
||||
#include <86Box/nv/vid_nv.h>
|
||||
#include <86Box/nv/vid_nv3.h>
|
||||
|
||||
uint32_t nv3_ramro_read(uint32_t address)
|
||||
{
|
||||
nv_log("NV3: RAM Runout (invalid dma object submission) Read (0x%04x), UNIMPLEMENTED - RETURNING 0x00", address);
|
||||
}
|
||||
|
||||
void nv3_ramro_write(uint32_t address, uint32_t value)
|
||||
{
|
||||
nv_log("NV3: RAM Runout WRITE, OH CRAP!!!! (0x%04x -> 0x%04x), UNIMPLEMENTED\n (Todo: Read the entries...)", value, address);
|
||||
}
|
||||
Reference in New Issue
Block a user