Added the ZEOS Martin.
This commit is contained in:
@@ -24,34 +24,37 @@
|
||||
#include <86box/timer.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/nmi.h>
|
||||
#include <86box/port_92.h>
|
||||
#include <86box/chipset.h>
|
||||
|
||||
typedef struct vl82c480_t {
|
||||
uint8_t idx;
|
||||
uint8_t regs[256];
|
||||
uint8_t idx;
|
||||
uint8_t regs[256];
|
||||
uint32_t banks[4];
|
||||
} vl82c480_t;
|
||||
|
||||
static int
|
||||
vl82c480_shflags(uint8_t access)
|
||||
vl82c480_shflags(uint8_t access, uint8_t access2)
|
||||
{
|
||||
int ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY;
|
||||
int wp = ((access2 & 0x03) == 0x01);
|
||||
|
||||
switch (access) {
|
||||
default:
|
||||
case 0x00:
|
||||
ret = MEM_READ_EXTANY | MEM_WRITE_EXTANY;
|
||||
ret = MEM_READ_EXTANY | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY);
|
||||
break;
|
||||
case 0x01:
|
||||
ret = MEM_READ_EXTANY | MEM_WRITE_INTERNAL;
|
||||
ret = MEM_READ_EXTANY | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
case 0x02:
|
||||
ret = MEM_READ_INTERNAL | MEM_WRITE_EXTANY;
|
||||
ret = MEM_READ_INTERNAL | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_EXTANY);
|
||||
break;
|
||||
case 0x03:
|
||||
ret = MEM_READ_INTERNAL | MEM_WRITE_INTERNAL;
|
||||
ret = MEM_READ_INTERNAL | (wp ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -59,27 +62,60 @@ vl82c480_shflags(uint8_t access)
|
||||
}
|
||||
|
||||
static void
|
||||
vl82c480_recalc(vl82c480_t *dev)
|
||||
vl82c480_recalc_shadow(vl82c480_t *dev)
|
||||
{
|
||||
uint32_t base;
|
||||
uint8_t access;
|
||||
uint8_t access2;
|
||||
|
||||
shadowbios = 0;
|
||||
shadowbios_write = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
for (uint8_t j = 0; j < 8; j += 2) {
|
||||
base = 0x000a0000 + (i << 16) + (j << 13);
|
||||
access = (dev->regs[0x0d + i] >> j) & 3;
|
||||
mem_set_mem_state(base, 0x4000, vl82c480_shflags(access));
|
||||
base = 0x000a0000 + (i << 16) + (j << 13);
|
||||
access = (dev->regs[0x0d + i] >> j) & 3;
|
||||
access2 = (dev->regs[0x13 + i] >> j) & 3;
|
||||
mem_set_mem_state(base, 0x4000, vl82c480_shflags(access, access2));
|
||||
shadowbios |= ((base >= 0xe0000) && (access & 0x02));
|
||||
shadowbios_write |= ((base >= 0xe0000) && (access & 0x01));
|
||||
shadowbios_write |= ((base >= 0xe0000) && (access & 0x01) && !(access2 & 0x01));
|
||||
}
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
}
|
||||
|
||||
static void
|
||||
vl82c480_recalc_banks(vl82c480_t *dev)
|
||||
{
|
||||
uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 };
|
||||
uint8_t shifts[4] = { 0, 4, 0, 4 };
|
||||
uint8_t regs[4] = { 0x02, 0x02, 0x03, 0x03 };
|
||||
uint32_t total = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
uint8_t shift = shifts[i];
|
||||
uint8_t reg = regs[i];
|
||||
uint8_t cfg = (dev->regs[reg] >> shift) & 0x7;
|
||||
uint32_t size = sizes[cfg];
|
||||
|
||||
total += MIN(dev->banks[i], size);
|
||||
}
|
||||
|
||||
if (total > 1024) {
|
||||
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000);
|
||||
mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (total - 1024) << 10);
|
||||
} else {
|
||||
if (total >= 1024)
|
||||
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000);
|
||||
else
|
||||
mem_mapping_disable(&ram_low_mapping);
|
||||
mem_mapping_disable(&ram_high_mapping);
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
}
|
||||
|
||||
static void
|
||||
vl82c480_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
@@ -91,16 +127,24 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
|
||||
case 0xed:
|
||||
if (dev->idx >= 0x01 && dev->idx <= 0x24) {
|
||||
if (((dev->idx >= 0x01) && (dev->idx <= 0x19)) ||
|
||||
((dev->idx >= 0x20) && (dev->idx <= 0x24))) {
|
||||
switch (dev->idx) {
|
||||
default:
|
||||
dev->regs[dev->idx] = val;
|
||||
break;
|
||||
case 0x02: case 0x03:
|
||||
dev->regs[dev->idx] = val;
|
||||
if (!strcmp(machine_get_internal_name(), "martin"))
|
||||
vl82c480_recalc_banks(dev);
|
||||
break;
|
||||
case 0x04:
|
||||
if (dev->regs[0x00] == 0x98)
|
||||
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x08) | (val & 0xf7);
|
||||
else
|
||||
dev->regs[dev->idx] = val;
|
||||
if (!strcmp(machine_get_internal_name(), "martin"))
|
||||
dev->regs[dev->idx] &= 0x1f;
|
||||
break;
|
||||
case 0x05:
|
||||
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x10) | (val & 0xef);
|
||||
@@ -108,14 +152,11 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
|
||||
case 0x07:
|
||||
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x40) | (val & 0xbf);
|
||||
break;
|
||||
case 0x0d:
|
||||
case 0x0e:
|
||||
case 0x0f:
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x0d ... 0x18:
|
||||
dev->regs[dev->idx] = val;
|
||||
vl82c480_recalc(dev);
|
||||
vl82c480_recalc_shadow(dev);
|
||||
if (dev->idx >= 0x13)
|
||||
flushmmucache();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -124,8 +165,8 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
|
||||
/* TODO: This is actually Fast A20 disable. */
|
||||
#if 0
|
||||
case 0xee:
|
||||
if (mem_a20_alt)
|
||||
outb(0x92, inb(0x92) & ~2);
|
||||
mem_a20_alt = 0x00;
|
||||
mem_a20_recalc();
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -146,14 +187,16 @@ vl82c480_read(uint16_t addr, void *priv)
|
||||
break;
|
||||
|
||||
case 0xed:
|
||||
ret = dev->regs[dev->idx];
|
||||
if (((dev->idx >= 0x01) && (dev->idx <= 0x19)) ||
|
||||
((dev->idx >= 0x20) && (dev->idx <= 0x24)))
|
||||
ret = dev->regs[dev->idx];
|
||||
break;
|
||||
|
||||
/* TODO: This is actually Fast A20 enable. */
|
||||
#if 0
|
||||
case 0xee:
|
||||
if (!mem_a20_alt)
|
||||
outb(0x92, inb(0x92) | 2);
|
||||
mem_a20_alt = 0x02;
|
||||
mem_a20_recalc();
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -180,7 +223,9 @@ vl82c480_close(void *priv)
|
||||
static void *
|
||||
vl82c480_init(const device_t *info)
|
||||
{
|
||||
vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t));
|
||||
vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t));
|
||||
uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 };
|
||||
uint32_t ms = mem_size;
|
||||
|
||||
dev->regs[0x00] = info->local;
|
||||
dev->regs[0x01] = 0xff;
|
||||
@@ -191,9 +236,27 @@ vl82c480_init(const device_t *info)
|
||||
dev->regs[0x07] = 0x21;
|
||||
dev->regs[0x08] = 0x38;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
uint32_t size = 0;
|
||||
|
||||
for (uint8_t j = 2; i < 7; j++) {
|
||||
if (ms >= sizes[j])
|
||||
size = sizes[j];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ms -= size;
|
||||
|
||||
dev->banks[i] = size;
|
||||
|
||||
if ((ms == 0) || (size == 0))
|
||||
break;
|
||||
}
|
||||
|
||||
io_sethandler(0x00ec, 0x0004, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, dev);
|
||||
|
||||
device_add(&port_92_device);
|
||||
device_add(&port_92_pci_device);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
@@ -545,6 +545,7 @@ extern int machine_at_exp4349_init(const machine_t *);
|
||||
|
||||
extern int machine_at_vect486vl_init(const machine_t *);
|
||||
extern int machine_at_d824_init(const machine_t *);
|
||||
extern int machine_at_martin_init(const machine_t *);
|
||||
|
||||
extern int machine_at_403tg_init(const machine_t *);
|
||||
extern int machine_at_403tg_d_init(const machine_t *);
|
||||
|
||||
@@ -99,6 +99,7 @@ extern const device_t ami_1994_nvr_device;
|
||||
extern const device_t ami_1995_nvr_device;
|
||||
extern const device_t via_nvr_device;
|
||||
extern const device_t p6rp4_nvr_device;
|
||||
extern const device_t martin_nvr_device;
|
||||
extern const device_t elt_nvr_device;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -724,7 +724,9 @@ machine_at_cmdsl386sx25_init(const machine_t *model)
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(&gd5402_onboard_device);
|
||||
|
||||
machine_at_common_ide_init(model);
|
||||
machine_at_common_init_ex(model, 2);
|
||||
|
||||
device_add(&ide_isa_device);
|
||||
|
||||
device_add(&ali5105_device); /* The FDC is part of the ALi M5105. */
|
||||
device_add(&vl82c113_device); /* The keyboard controller is part of the VL82c113. */
|
||||
|
||||
@@ -412,14 +412,16 @@ machine_at_vect486vl_init(const machine_t *model) // has HDC problems
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
|
||||
machine_at_common_ide_init(model);
|
||||
|
||||
device_add(&vl82c480_device);
|
||||
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(&gd5428_onboard_device);
|
||||
|
||||
machine_at_common_init_ex(model, 2);
|
||||
|
||||
device_add(&vl82c480_device);
|
||||
|
||||
device_add(&vl82c113_device);
|
||||
|
||||
device_add(&ide_isa_device);
|
||||
device_add(&fdc37c651_ide_device);
|
||||
|
||||
return ret;
|
||||
@@ -436,13 +438,13 @@ machine_at_d824_init(const machine_t *model)
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
|
||||
machine_at_common_init(model);
|
||||
|
||||
device_add(&vl82c480_device);
|
||||
|
||||
if (gfxcard[0] == VID_INTERNAL)
|
||||
device_add(&gd5428_onboard_device);
|
||||
|
||||
machine_at_common_init_ex(model, 2);
|
||||
|
||||
device_add(&vl82c480_device);
|
||||
|
||||
/*
|
||||
Technically, it should be the VL82C114 but we do not have
|
||||
a proper datasheet of it that tells us the registers.
|
||||
@@ -455,6 +457,30 @@ machine_at_d824_init(const machine_t *model)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_martin_init(const machine_t *model)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bios_load_linear("roms/machines/martin/NONSCSI.ROM",
|
||||
0x000e0000, 131072, 0);
|
||||
|
||||
if (bios_only || !ret)
|
||||
return ret;
|
||||
|
||||
machine_at_common_init_ex(model, 2);
|
||||
|
||||
device_add(&vl82c480_device);
|
||||
device_add(&vl82c113_device);
|
||||
|
||||
device_add(&ide_vlb_device);
|
||||
device_add(&fdc37c651_ide_device);
|
||||
|
||||
device_add(&intel_flash_bxt_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
machine_at_acera1g_init(const machine_t *model)
|
||||
{
|
||||
|
||||
@@ -6526,7 +6526,7 @@ const machine_t machines[] = {
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* Has a standard IBM PS/2 KBC firmware or a clone thereof. */
|
||||
/* Has a VLSI VL82C114 Combination I/O which holds the KBC. */
|
||||
{
|
||||
.name = "[VLSI 82C481] Siemens Nixdorf D824",
|
||||
.internal_name = "d824",
|
||||
@@ -6554,7 +6554,7 @@ const machine_t machines[] = {
|
||||
.max = 32768,
|
||||
.step = 2048
|
||||
},
|
||||
.nvrmask = 127,
|
||||
.nvrmask = 255,
|
||||
.kbc_device = NULL,
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
@@ -6773,6 +6773,46 @@ const machine_t machines[] = {
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* Has AMI MegaKey KBC. */
|
||||
{
|
||||
.name = "[i420TX] J-Bond PCI400C-A",
|
||||
.internal_name = "pci400ca",
|
||||
.type = MACHINE_TYPE_486_S2,
|
||||
.chipset = MACHINE_CHIPSET_INTEL_420TX,
|
||||
.init = machine_at_pci400ca_init,
|
||||
.p1_handler = NULL,
|
||||
.gpio_handler = NULL,
|
||||
.available_flag = MACHINE_AVAILABLE,
|
||||
.gpio_acpi_handler = NULL,
|
||||
.cpu = {
|
||||
.package = CPU_PKG_SOCKET3,
|
||||
.block = CPU_BLOCK_NONE,
|
||||
.min_bus = 0,
|
||||
.max_bus = 0,
|
||||
.min_voltage = 0,
|
||||
.max_voltage = 0,
|
||||
.min_multi = 0,
|
||||
.max_multi = 0
|
||||
},
|
||||
.bus_flags = MACHINE_PCI,
|
||||
.flags = MACHINE_SCSI,
|
||||
.ram = {
|
||||
.min = 1024,
|
||||
.max = 65536,
|
||||
.step = 1024
|
||||
},
|
||||
.nvrmask = 127,
|
||||
.kbc_device = &keyboard_at_ami_device,
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
.gpio_acpi = 0xffffffff,
|
||||
.device = NULL,
|
||||
.fdc_device = NULL,
|
||||
.sio_device = NULL,
|
||||
.vid_device = NULL,
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* This has a standalone AMI Megakey 1993, which is type 'P'. */
|
||||
{
|
||||
.name = "[IMS 8848] Tekram G486IP",
|
||||
@@ -6934,13 +6974,13 @@ const machine_t machines[] = {
|
||||
.snd_device = NULL,
|
||||
.net_device = NULL
|
||||
},
|
||||
/* Has AMI MegaKey KBC. */
|
||||
/* Has a VLSI VL82C113A SCAMP Combination I/O which holds the KBC. */
|
||||
{
|
||||
.name = "[i420TX] J-Bond PCI400C-A",
|
||||
.internal_name = "pci400ca",
|
||||
.name = "[VLSI 82C480] ZEOS Martin",
|
||||
.internal_name = "martin",
|
||||
.type = MACHINE_TYPE_486_S2,
|
||||
.chipset = MACHINE_CHIPSET_INTEL_420TX,
|
||||
.init = machine_at_pci400ca_init,
|
||||
.chipset = MACHINE_CHIPSET_VLSI_VL82C480,
|
||||
.init = machine_at_martin_init,
|
||||
.p1_handler = NULL,
|
||||
.gpio_handler = NULL,
|
||||
.available_flag = MACHINE_AVAILABLE,
|
||||
@@ -6955,15 +6995,15 @@ const machine_t machines[] = {
|
||||
.min_multi = 0,
|
||||
.max_multi = 0
|
||||
},
|
||||
.bus_flags = MACHINE_PCI,
|
||||
.flags = MACHINE_SCSI,
|
||||
.bus_flags = MACHINE_PS2,
|
||||
.flags = MACHINE_IDE | MACHINE_APM,
|
||||
.ram = {
|
||||
.min = 1024,
|
||||
.min = 2048,
|
||||
.max = 65536,
|
||||
.step = 1024
|
||||
.step = 2048
|
||||
},
|
||||
.nvrmask = 127,
|
||||
.kbc_device = &keyboard_at_ami_device,
|
||||
.kbc_device = NULL,
|
||||
.kbc_p1 = 0xff,
|
||||
.gpio = 0xffffffff,
|
||||
.gpio_acpi = 0xffffffff,
|
||||
@@ -6975,7 +7015,6 @@ const machine_t machines[] = {
|
||||
.net_device = NULL
|
||||
},
|
||||
|
||||
|
||||
/* 486 machines - Socket 3 */
|
||||
/* 486 machines with just the ISA slot */
|
||||
/* Has a Fujitsu MBL8042H KBC. */
|
||||
|
||||
42
src/nvr_at.c
42
src/nvr_at.c
@@ -296,6 +296,7 @@
|
||||
#define FLAG_P6RP4_HACK 0x10
|
||||
#define FLAG_PIIX4 0x20
|
||||
#define FLAG_MULTI_BANK 0x40
|
||||
#define FLAG_MARTIN_HACK 0x80
|
||||
|
||||
typedef struct local_t {
|
||||
int8_t stat;
|
||||
@@ -733,6 +734,13 @@ nvr_read(uint16_t addr, void *priv)
|
||||
ret = REGD_VRT;
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
if (local->flags & FLAG_MARTIN_HACK)
|
||||
ret = nvr->regs[local->addr[addr_id]] | 0x02;
|
||||
else
|
||||
ret = nvr->regs[local->addr[addr_id]];
|
||||
break;
|
||||
|
||||
case 0x2c:
|
||||
if (!nvr->is_new && (local->flags & FLAG_AMI_1994_HACK))
|
||||
ret = nvr->regs[local->addr[addr_id]] & 0x7f;
|
||||
@@ -771,6 +779,17 @@ nvr_read(uint16_t addr, void *priv)
|
||||
ret = checksum >> 8;
|
||||
else
|
||||
ret = checksum & 0xff;
|
||||
} else if (!nvr->is_new && (local->flags & FLAG_MARTIN_HACK)) {
|
||||
for (i = 0x10; i <= 0x2d; i++) {
|
||||
if (i == 0x11)
|
||||
checksum += (nvr->regs[i] | 0x02);
|
||||
else
|
||||
checksum += nvr->regs[i];
|
||||
}
|
||||
if (local->addr[addr_id] == 0x2e)
|
||||
ret = checksum >> 8;
|
||||
else
|
||||
ret = checksum & 0xff;
|
||||
} else
|
||||
ret = nvr->regs[local->addr[addr_id]];
|
||||
break;
|
||||
@@ -1123,9 +1142,11 @@ nvr_at_init(const device_t *info)
|
||||
if (info->local & 0x10) {
|
||||
local->def = 0x00;
|
||||
local->flags |= FLAG_AMI_1992_HACK;
|
||||
} else if (info->local == 36)
|
||||
} else if ((info->local == 36) || (info->local == 68)) {
|
||||
local->def = 0x00;
|
||||
else
|
||||
if (info->local == 68)
|
||||
local->flags |= FLAG_MARTIN_HACK;
|
||||
} else
|
||||
local->def = 0xff;
|
||||
nvr->irq = 8;
|
||||
local->cent = RTC_CENTURY_AT;
|
||||
@@ -1160,6 +1181,9 @@ nvr_at_init(const device_t *info)
|
||||
/* Initialize the generic NVR. */
|
||||
nvr_init(nvr);
|
||||
|
||||
if (nvr->is_new && (local->flags & FLAG_MARTIN_HACK))
|
||||
nvr->regs[0x11] = nvr->regs[0x2f] = 0x02;
|
||||
|
||||
if (nvr_at_inited == 0) {
|
||||
/* Start the timers. */
|
||||
timer_add(&local->update_timer, timer_update, nvr, 0);
|
||||
@@ -1426,6 +1450,20 @@ const device_t amstrad_megapc_nvr_device = {
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t martin_nvr_device = {
|
||||
.name = "Zeos Martin NVRAM",
|
||||
.internal_name = "martin_nvr",
|
||||
.flags = DEVICE_ISA16,
|
||||
.local = 68,
|
||||
.init = nvr_at_init,
|
||||
.close = nvr_at_close,
|
||||
.reset = nvr_at_reset,
|
||||
.available = NULL,
|
||||
.speed_changed = nvr_at_speed_changed,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t elt_nvr_device = {
|
||||
.name = "Epson Equity LT NVRAM",
|
||||
.internal_name = "elt_nvr",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <86box/timer.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/keyboard.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/sio.h>
|
||||
#include <86box/plat_unused.h>
|
||||
@@ -133,7 +134,10 @@ vl82c113_init(UNUSED(const device_t *info))
|
||||
{
|
||||
vl82c113_t *dev = (vl82c113_t *) calloc(1, sizeof(vl82c113_t));
|
||||
|
||||
dev->nvr = device_add(&at_nvr_device);
|
||||
if (!strcmp(machine_get_internal_name(), "martin"))
|
||||
dev->nvr = device_add(&martin_nvr_device);
|
||||
else
|
||||
dev->nvr = device_add(&amstrad_megapc_nvr_device);
|
||||
|
||||
dev->nvr_enabled = 1;
|
||||
dev->nvr_base = 0x0070;
|
||||
|
||||
Reference in New Issue
Block a user