mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
MEK6800D1: early Motorola 6800 design evaluation board
The MIKBUG monitor is working. The terminal support for reading and 'punching' tapes is not yet implemented.
This commit is contained in:
parent
6cb51d5673
commit
92d7227ec0
475
src/mame/drivers/mekd1.cpp
Normal file
475
src/mame/drivers/mekd1.cpp
Normal file
@ -0,0 +1,475 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:68bit
|
||||
/***************************************************************************
|
||||
|
||||
Motorola Evaluation Kit 6800 D1 - MEK6800D1
|
||||
|
||||
The monitor is supplied in the MCM6830L7 ROM and named MIKBUG rev 9. MIKBUG is
|
||||
a 512 byte monitor. The MIKBUG commands are:
|
||||
|
||||
M aaaa - memory examine and change at address 'aaaa'.
|
||||
<space>hh - modify content with hex value 'hh' and increase address. If the
|
||||
memory can not be changed then it prints '?' and exits the
|
||||
memory examine.
|
||||
<space> and any other key exits the memory examine. The documentation
|
||||
suggests using a carriage return.
|
||||
Any other key increases the address.
|
||||
|
||||
R - Register display: CC B A X PC SP. The registers can be modified at:
|
||||
0xa043 CC
|
||||
0xa044 B
|
||||
0xa045 A
|
||||
0xa046 X high
|
||||
0xa047 X low
|
||||
0xa048 PC high
|
||||
0xa049 PC low
|
||||
0xa008 SP high
|
||||
0xa009 SP low
|
||||
|
||||
L - Loads data, in S19 format, as generated by the assembler. If there is a
|
||||
checksum failure then it prints '?' and exits the load. An 'S9' record
|
||||
exits the load. Note that the MIKBUG punch command 'P' does not write a
|
||||
'S9' record so it is necessary to manually enter a 'S9' sequence at the
|
||||
end of the load when loading a MIKBUG generated tape!
|
||||
|
||||
P - Print or Punch memory dump. The start address is loaded from 0xa002 to
|
||||
0xa003, and the end address is loaded from 0xa004 to 0xa005. The output is
|
||||
in S19 format and can be loaded with the 'L' command, but the end-of-file
|
||||
'S9' record is not emitted.
|
||||
|
||||
G - Go to user code. The registers are loaded from the addresses noted above
|
||||
0xa043 to 0xa049 and 0xa008 to 0xa009 for the stack pointer. Breakpoints
|
||||
can be manually set by inserting a SWI (0x3f) instruction, and when these
|
||||
are encountered control returns to MIKBUG and the registers are save and
|
||||
printed.
|
||||
|
||||
An IRQ handler can be defined at 0xa000 to 0xa001.
|
||||
An NMI handler can be defined at 0xa006 to 0xa007.
|
||||
|
||||
MIKBUG was designed to work with the ASR33 Teletypewriter and drives the
|
||||
'reader control' line high during a 'load' operation intended for a reader
|
||||
relay control which was a common modification. There is no signal line driven
|
||||
for a 'punch' operation. TODO might be able to at least use this 'reader
|
||||
control' line to switch to input from a tape.
|
||||
|
||||
MIKBUG was designed to work with the Texas Instruments 733 ASR twin tape
|
||||
cassette terminal with automatic device control and issues the following
|
||||
control codes when loading and 'punching' a tape. TODO perhaps these could
|
||||
be detected and serial I/O diverted to a cassette.
|
||||
Code 0x11 DC1 - Tape playback on
|
||||
Code 0x12 DC2 - Tape record on.
|
||||
Code 0x13 DC4 - Tape playback off.
|
||||
Code 0x14 DC4 - Tape record off.
|
||||
|
||||
The serial bit rate is controlled by a MC14536 timer and is variable. Common
|
||||
rates are 110 baud and 300 baud, for the ASR33 and 733 ASR terminals
|
||||
respectively, but is was practical to run at higher rates up to about 4800
|
||||
baud.
|
||||
|
||||
Memory is expandable off-board with some modifications, to at least 8K. There
|
||||
were versions of the resident editor and assembler for use with MIKBUG, that
|
||||
required the expanded RAM.
|
||||
|
||||
The board hosts a MC6850 ACIA but this is not used by MIKBUG so it is a user
|
||||
ACIA. The clock is supplied off board and the documentation offers a design
|
||||
suggestion using the MC14411 and this is emulated here as documented.
|
||||
|
||||
TODO could add a reset button, and an NMI button, and an LED for the reader
|
||||
relay line. Might want to default the terminal to echo characters.
|
||||
|
||||
References:
|
||||
1. Assembly Instructions for the Motorola M6800 Design Evaluation Kit, 1975.
|
||||
2. Engineering Note 100, MCM6830L7 MIKBUG/MINIBUG ROM.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cpu/m6800/m6800.h"
|
||||
#include "machine/6821pia.h"
|
||||
#include "machine/6850acia.h"
|
||||
#include "machine/mc14411.h"
|
||||
#include "machine/input_merger.h"
|
||||
#include "machine/timer.h"
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "machine/terminal.h"
|
||||
|
||||
class mekd1_state : public driver_device
|
||||
{
|
||||
public:
|
||||
mekd1_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_pia0(*this, "pia0")
|
||||
, m_pia1(*this, "pia1")
|
||||
, m_acia(*this, "acia")
|
||||
, m_brg(*this, "brg")
|
||||
, m_rs232(*this, "rs232")
|
||||
, m_baud_rate(*this, "baud_rate")
|
||||
, m_stop_bits(*this, "stop_bits")
|
||||
, m_acia_baud_rate(*this, "acia_baud_rate")
|
||||
{ }
|
||||
|
||||
void mekd1(machine_config &config);
|
||||
|
||||
enum
|
||||
{
|
||||
TIMER_BIT_RATE,
|
||||
TIMER_BIT_RATE_HALF
|
||||
};
|
||||
|
||||
private:
|
||||
virtual void machine_reset() override;
|
||||
virtual void machine_start() override;
|
||||
|
||||
void mem_map(address_map &map);
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<pia6821_device> m_pia0;
|
||||
required_device<pia6821_device> m_pia1;
|
||||
required_device<acia6850_device> m_acia;
|
||||
required_device<mc14411_device> m_brg;
|
||||
required_device<rs232_port_device> m_rs232;
|
||||
required_ioport m_baud_rate;
|
||||
required_ioport m_stop_bits;
|
||||
required_ioport m_acia_baud_rate;
|
||||
|
||||
DECLARE_READ8_MEMBER(pia0_pa_r);
|
||||
DECLARE_READ8_MEMBER(pia0_pb_r);
|
||||
DECLARE_WRITE8_MEMBER(pia0_pa_w);
|
||||
DECLARE_WRITE8_MEMBER(pia0_pb_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(pia0_cb2_w);
|
||||
|
||||
// Clocks
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f1_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f2_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f4_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f5_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f7_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f8_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f9_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f11_clock);
|
||||
DECLARE_WRITE_LINE_MEMBER(write_f13_clock);
|
||||
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
emu_timer *m_bit_rate_timer;
|
||||
emu_timer *m_bit_rate_half_timer;
|
||||
|
||||
bool m_bit_rate_out;
|
||||
bool m_bit_rate_half_out;
|
||||
bool m_bit_rate_reset;
|
||||
bool m_bit_rate_select;
|
||||
};
|
||||
|
||||
void mekd1_state::mem_map(address_map &map)
|
||||
{
|
||||
map.unmap_value_high();
|
||||
map(0x0000, 0x027f).mirror(0x7c00).ram();
|
||||
|
||||
// The emulated addressing for these is not exact. The hardware uses
|
||||
// A3, A4, and A5 to select between these respectively. For example
|
||||
// the first PIA is selected when A3 is high, but it ignores A4 and
|
||||
// A5, etc. So it is possible that more than one are selected at once
|
||||
// which is not emulated here. Here it is assumed that A3, A4, and A5
|
||||
// are completely decoded and that only one device is selected at a
|
||||
// time.
|
||||
map(0x8004, 0x8007).mirror(0x5fe0).rw(m_pia0, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
|
||||
map(0x8008, 0x800b).mirror(0x5fe0).rw(m_pia1, FUNC(pia6821_device::read), FUNC(pia6821_device::write));
|
||||
map(0x8010, 0x8011).mirror(0x5fe2).rw(m_acia, FUNC(acia6850_device::read), FUNC(acia6850_device::write));
|
||||
|
||||
map(0xa000, 0xa07f).mirror(0x0f80).ram();
|
||||
|
||||
// Although the ROM is 1k, MIKBUG uses only the first 512 bytes and
|
||||
// when using MIKBUG the A9 ROM input is connected to 0V.
|
||||
map(0xe000, 0xe1ff).mirror(0x1e00).rom().region("mcm6830l7", 0);
|
||||
}
|
||||
|
||||
static INPUT_PORTS_START( mekd1 )
|
||||
|
||||
PORT_START("baud_rate")
|
||||
PORT_CONFNAME(0x3fff, 416, "RS232 Baud Rate")
|
||||
PORT_CONFSETTING(9091, "110")
|
||||
PORT_CONFSETTING(3333, "300")
|
||||
PORT_CONFSETTING(1667, "600")
|
||||
PORT_CONFSETTING( 833, "1200")
|
||||
PORT_CONFSETTING( 416, "2400")
|
||||
PORT_CONFSETTING( 208, "4800")
|
||||
PORT_CONFSETTING( 139, "7200")
|
||||
PORT_CONFSETTING( 104, "9600")
|
||||
|
||||
PORT_START("stop_bits")
|
||||
PORT_CONFNAME(0x01, 0, "Stop bits")
|
||||
PORT_CONFSETTING(0x00, "1")
|
||||
PORT_CONFSETTING(0x01, "2")
|
||||
|
||||
PORT_START("acia_baud_rate")
|
||||
PORT_CONFNAME(0xf, 1, "ACIA Baud Rate")
|
||||
PORT_CONFSETTING(13, "110")
|
||||
PORT_CONFSETTING(11, "150")
|
||||
PORT_CONFSETTING(9, "300")
|
||||
PORT_CONFSETTING(8, "600")
|
||||
PORT_CONFSETTING(7, "1200")
|
||||
PORT_CONFSETTING(5, "2400")
|
||||
PORT_CONFSETTING(4, "3600")
|
||||
PORT_CONFSETTING(2, "4800")
|
||||
PORT_CONFSETTING(1, "9600")
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
|
||||
READ8_MEMBER(mekd1_state::pia0_pa_r)
|
||||
{
|
||||
return m_rs232->rxd_r() << 7;
|
||||
}
|
||||
|
||||
READ8_MEMBER(mekd1_state::pia0_pb_r)
|
||||
{
|
||||
bool timer_out;
|
||||
uint8_t stop_bits = m_stop_bits->read();
|
||||
|
||||
if (m_bit_rate_select)
|
||||
timer_out = m_bit_rate_out;
|
||||
else
|
||||
timer_out = m_bit_rate_half_out;
|
||||
|
||||
return (timer_out << 7) | (stop_bits << 6);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(mekd1_state::pia0_pa_w)
|
||||
{
|
||||
m_rs232->write_txd(BIT(data, 0));
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(mekd1_state::pia0_pb_w)
|
||||
{
|
||||
m_bit_rate_select = BIT(data, 2);
|
||||
|
||||
if (BIT(data, 0) == 1)
|
||||
{
|
||||
// Reset
|
||||
m_bit_rate_timer->reset();
|
||||
m_bit_rate_half_timer->reset();
|
||||
m_bit_rate_out = 0;
|
||||
m_bit_rate_half_out = 0;
|
||||
m_bit_rate_reset = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bit_rate_reset)
|
||||
{
|
||||
// Timer has just been taken out of reset.
|
||||
m_bit_rate_reset = 0;
|
||||
uint16_t delay = m_baud_rate->read();
|
||||
// An adjustment is subtracted from the delay for the CPU
|
||||
// instruction processing paths as the CPU polls the timer
|
||||
// output, and this would vary with the CPU clock. In
|
||||
// hardware, variable resisters needed to be tuned to achieve
|
||||
// the correct timing which was not hard at the lower baud
|
||||
// rates.
|
||||
m_bit_rate_timer->adjust(attotime::from_usec(delay - 31));
|
||||
m_bit_rate_half_timer->adjust(attotime::from_usec((delay / 2 ) - 31));
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::pia0_cb2_w)
|
||||
{
|
||||
// This is a tape reader control line.
|
||||
}
|
||||
|
||||
void mekd1_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case TIMER_BIT_RATE:
|
||||
m_bit_rate_out = 1;
|
||||
break;
|
||||
case TIMER_BIT_RATE_HALF:
|
||||
m_bit_rate_half_out = 1;
|
||||
break;
|
||||
default:
|
||||
throw emu_fatalerror("Unknown id in mekd1_state::device_timer");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f1_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 1)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f2_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 2)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f4_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 4)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f5_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 5)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f7_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 7)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f8_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 8)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f9_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 9)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f11_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 11)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(mekd1_state::write_f13_clock)
|
||||
{
|
||||
if (m_acia_baud_rate->read() == 13)
|
||||
{
|
||||
m_acia->write_txc(state);
|
||||
m_acia->write_rxc(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mekd1_state::machine_reset()
|
||||
{
|
||||
m_pia0->reset();
|
||||
m_pia1->reset();
|
||||
m_brg->rsa_w(CLEAR_LINE);
|
||||
m_brg->rsb_w(ASSERT_LINE);
|
||||
m_bit_rate_timer->reset();
|
||||
m_bit_rate_half_timer->reset();
|
||||
m_bit_rate_out = 0;
|
||||
m_bit_rate_half_out = 0;
|
||||
m_bit_rate_select = 0;
|
||||
m_bit_rate_reset = 1;
|
||||
}
|
||||
|
||||
void mekd1_state::machine_start()
|
||||
{
|
||||
// Allocate timers
|
||||
m_bit_rate_timer = timer_alloc(TIMER_BIT_RATE);
|
||||
m_bit_rate_half_timer = timer_alloc(TIMER_BIT_RATE_HALF);
|
||||
|
||||
save_item(NAME(m_bit_rate_out));
|
||||
save_item(NAME(m_bit_rate_half_out));
|
||||
save_item(NAME(m_bit_rate_reset));
|
||||
save_item(NAME(m_bit_rate_select));
|
||||
}
|
||||
|
||||
static DEVICE_INPUT_DEFAULTS_START(terminal)
|
||||
DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0xff, RS232_BAUD_2400)
|
||||
DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_2400)
|
||||
DEVICE_INPUT_DEFAULTS("RS232_STARTBITS", 0xff, RS232_STARTBITS_1)
|
||||
DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0xff, RS232_DATABITS_7)
|
||||
DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0xff, RS232_PARITY_SPACE)
|
||||
DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0xff, RS232_STOPBITS_1)
|
||||
DEVICE_INPUT_DEFAULTS_END
|
||||
|
||||
void mekd1_state::mekd1(machine_config &config)
|
||||
{
|
||||
// The clock rate was adjustable from 100KHz to 1MHz.
|
||||
M6800(config, m_maincpu, 2_MHz_XTAL / 2);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &mekd1_state::mem_map);
|
||||
|
||||
INPUT_MERGER_ANY_HIGH(config, "mainirq").output_handler().set_inputline(m_maincpu, M6800_IRQ_LINE);
|
||||
|
||||
// Terminal I/O.
|
||||
// The design uses a 6820 which is slightly different to the emulated 6821.
|
||||
// PA0 serial output.
|
||||
// PA7 serial input.
|
||||
// PB0 resets the rite rate timer when high.
|
||||
// PB2 selects the bit rate timer output: 0 half time, 1 full time.
|
||||
// PB6 jumper input: 0 for 1 stop bit, 1 for 2 stop bits.
|
||||
// PB7 input from the bit rate timer that goes high after the timer period elapses.
|
||||
// CB2 "reader control" output
|
||||
// IRQA and IRQB are NC.
|
||||
PIA6821(config, m_pia0, 0);
|
||||
m_pia0->readpa_handler().set(FUNC(mekd1_state::pia0_pa_r));
|
||||
m_pia0->readpb_handler().set(FUNC(mekd1_state::pia0_pb_r));
|
||||
m_pia0->writepa_handler().set(FUNC(mekd1_state::pia0_pa_w));
|
||||
m_pia0->writepb_handler().set(FUNC(mekd1_state::pia0_pb_w));
|
||||
m_pia0->cb2_handler().set(FUNC(mekd1_state::pia0_cb2_w));
|
||||
|
||||
// User PIA. All the I/O lines are available at P2.
|
||||
PIA6821(config, m_pia1, 0);
|
||||
m_pia1->irqa_handler().set("mainirq", FUNC(input_merger_device::in_w<0>));
|
||||
m_pia1->irqb_handler().set("mainirq", FUNC(input_merger_device::in_w<1>));
|
||||
|
||||
// User ACIA. Available at P2.
|
||||
// /CTS is pulled low.
|
||||
// /DCD is pulled low.
|
||||
ACIA6850(config, m_acia, 0);
|
||||
m_acia->irq_handler().set("mainirq", FUNC(input_merger_device::in_w<2>));
|
||||
|
||||
// Off-board clock for the on-board MC6850.
|
||||
MC14411(config, m_brg, XTAL(1'843'200));
|
||||
m_brg->out_f<1>().set(FUNC(mekd1_state::write_f1_clock));
|
||||
m_brg->out_f<2>().set(FUNC(mekd1_state::write_f2_clock));
|
||||
m_brg->out_f<4>().set(FUNC(mekd1_state::write_f4_clock));
|
||||
m_brg->out_f<4>().set(FUNC(mekd1_state::write_f5_clock));
|
||||
m_brg->out_f<7>().set(FUNC(mekd1_state::write_f7_clock));
|
||||
m_brg->out_f<8>().set(FUNC(mekd1_state::write_f8_clock));
|
||||
m_brg->out_f<9>().set(FUNC(mekd1_state::write_f9_clock));
|
||||
m_brg->out_f<11>().set(FUNC(mekd1_state::write_f11_clock));
|
||||
m_brg->out_f<13>().set(FUNC(mekd1_state::write_f13_clock));
|
||||
|
||||
RS232_PORT(config, m_rs232, default_rs232_devices, "terminal");
|
||||
m_rs232->set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal));
|
||||
}
|
||||
|
||||
|
||||
/* ROM definition */
|
||||
ROM_START( mekd1 )
|
||||
ROM_REGION( 0x0200, "mcm6830l7", 0 )
|
||||
ROM_LOAD("mikbugv9.bin", 0x0000, 0x0200, CRC(f5ff896f) SHA1(32990115ad9eebe7a1a5a03b4b1ea83360b1820f))
|
||||
ROM_END
|
||||
|
||||
/* Driver */
|
||||
|
||||
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
|
||||
COMP( 1975, mekd1, 0, 0, mekd1, mekd1, mekd1_state, empty_init, "Motorola", "MEK6800D1", MACHINE_NO_SOUND_HW )
|
@ -21524,6 +21524,9 @@ megazonej // GX319 (c) 1983 + Interlogic / Kosuka
|
||||
@source:meijinsn.cpp
|
||||
meijinsn // (c) 1986 SNK
|
||||
|
||||
@source:mekd1.cpp
|
||||
mekd1 // 1975 Motorola Evaluation Kit
|
||||
|
||||
@source:mekd2.cpp
|
||||
mekd2 // 1977 Motorola Evaluation Kit
|
||||
|
||||
|
@ -463,6 +463,7 @@ mccpm.cpp
|
||||
mdisk.cpp
|
||||
megadriv.cpp
|
||||
megadriv_rad.cpp
|
||||
mekd1.cpp
|
||||
mekd2.cpp
|
||||
mekd3.cpp
|
||||
mekd4.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user