mirror of
https://github.com/holub/mame
synced 2025-04-22 00:11:58 +03:00
retofinv: use common Taito MCU hookup
This commit is contained in:
parent
8a368007d3
commit
fbb99184b7
@ -3666,7 +3666,6 @@ files {
|
||||
MAME_DIR .. "src/mame/video/rastan.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/retofinv.cpp",
|
||||
MAME_DIR .. "src/mame/includes/retofinv.h",
|
||||
MAME_DIR .. "src/mame/machine/retofinv.cpp",
|
||||
MAME_DIR .. "src/mame/video/retofinv.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/rollrace.cpp",
|
||||
MAME_DIR .. "src/mame/includes/rollrace.h",
|
||||
|
@ -31,11 +31,11 @@ Notes:
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "includes/retofinv.h"
|
||||
|
||||
#include "cpu/z80/z80.h"
|
||||
#include "cpu/m6805/m68705.h"
|
||||
#include "machine/watchdog.h"
|
||||
#include "sound/sn76496.h"
|
||||
#include "includes/retofinv.h"
|
||||
|
||||
|
||||
void retofinv_state::machine_start()
|
||||
@ -43,23 +43,6 @@ void retofinv_state::machine_start()
|
||||
save_item(NAME(m_main_irq_mask));
|
||||
save_item(NAME(m_sub_irq_mask));
|
||||
save_item(NAME(m_cpu2_m6000));
|
||||
|
||||
if (m_68705 != nullptr) // only for the parent (with MCU)
|
||||
{
|
||||
save_item(NAME(m_from_main));
|
||||
save_item(NAME(m_from_mcu));
|
||||
save_item(NAME(m_mcu_sent));
|
||||
save_item(NAME(m_main_sent));
|
||||
save_item(NAME(m_portA_in));
|
||||
save_item(NAME(m_portA_out));
|
||||
save_item(NAME(m_ddrA));
|
||||
save_item(NAME(m_portB_in));
|
||||
save_item(NAME(m_portB_out));
|
||||
save_item(NAME(m_ddrB));
|
||||
save_item(NAME(m_portC_in));
|
||||
save_item(NAME(m_portC_out));
|
||||
save_item(NAME(m_ddrC));
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::cpu1_reset_w)
|
||||
@ -74,9 +57,7 @@ WRITE8_MEMBER(retofinv_state::cpu2_reset_w)
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_reset_w)
|
||||
{
|
||||
/* the bootlegs don't have a MCU, so make sure it's there before trying to reset it */
|
||||
if (m_68705 != nullptr)
|
||||
m_68705->set_input_line(INPUT_LINE_RESET, data ? CLEAR_LINE : ASSERT_LINE);
|
||||
m_68705->reset_w(data ? CLEAR_LINE : ASSERT_LINE);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::cpu2_m6000_w)
|
||||
@ -91,8 +72,8 @@ READ8_MEMBER(retofinv_state::cpu0_mf800_r)
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::soundcommand_w)
|
||||
{
|
||||
m_soundlatch->write(space, 0, data);
|
||||
m_audiocpu->set_input_line(0, HOLD_LINE);
|
||||
m_soundlatch->write(space, 0, data);
|
||||
m_audiocpu->set_input_line(0, HOLD_LINE);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::irq0_ack_w)
|
||||
@ -119,8 +100,17 @@ WRITE8_MEMBER(retofinv_state::coinlockout_w)
|
||||
machine().bookkeeping().coin_lockout_w(0,~data & 1);
|
||||
}
|
||||
|
||||
READ8_MEMBER(retofinv_state::mcu_status_r)
|
||||
{
|
||||
/* bit 4 = when 1, mcu is ready to receive data from main cpu */
|
||||
/* bit 5 = when 1, mcu has sent data to the main cpu */
|
||||
return
|
||||
((CLEAR_LINE == m_68705->host_semaphore_r()) ? 0x10 : 0x00) |
|
||||
((CLEAR_LINE != m_68705->mcu_semaphore_r()) ? 0x20 : 0x00);
|
||||
}
|
||||
|
||||
static ADDRESS_MAP_START( main_map, AS_PROGRAM, 8, retofinv_state )
|
||||
|
||||
static ADDRESS_MAP_START( bootleg_map, AS_PROGRAM, 8, retofinv_state )
|
||||
AM_RANGE(0x0000, 0x5fff) AM_ROM
|
||||
AM_RANGE(0x7fff, 0x7fff) AM_WRITE(coincounter_w)
|
||||
AM_RANGE(0x7b00, 0x7bff) AM_ROM /* space for diagnostic ROM? The code looks */
|
||||
@ -132,7 +122,6 @@ static ADDRESS_MAP_START( main_map, AS_PROGRAM, 8, retofinv_state )
|
||||
AM_RANGE(0xc000, 0xc000) AM_READ_PORT("P1")
|
||||
AM_RANGE(0xc001, 0xc001) AM_READ_PORT("P2")
|
||||
AM_RANGE(0xc002, 0xc002) AM_READNOP /* bit 7 must be 0, otherwise game resets */
|
||||
AM_RANGE(0xc003, 0xc003) AM_READ(mcu_status_r)
|
||||
AM_RANGE(0xc004, 0xc004) AM_READ_PORT("SYSTEM")
|
||||
AM_RANGE(0xc005, 0xc005) AM_READ_PORT("DSW1")
|
||||
AM_RANGE(0xc006, 0xc006) AM_READ_PORT("DSW2")
|
||||
@ -140,16 +129,21 @@ static ADDRESS_MAP_START( main_map, AS_PROGRAM, 8, retofinv_state )
|
||||
AM_RANGE(0xc800, 0xc800) AM_WRITE(irq0_ack_w)
|
||||
AM_RANGE(0xc801, 0xc801) AM_WRITE(coinlockout_w)
|
||||
AM_RANGE(0xc802, 0xc802) AM_WRITE(cpu2_reset_w)
|
||||
AM_RANGE(0xc803, 0xc803) AM_WRITE(mcu_reset_w)
|
||||
// AM_RANGE(0xc804, 0xc804) AM_WRITE(irq1_ack_w) // presumably (meaning memory map is shared with cpu 1)
|
||||
AM_RANGE(0xc805, 0xc805) AM_WRITE(cpu1_reset_w)
|
||||
AM_RANGE(0xd000, 0xd000) AM_DEVWRITE("watchdog", watchdog_timer_device, reset_w)
|
||||
AM_RANGE(0xd800, 0xd800) AM_WRITE(soundcommand_w)
|
||||
AM_RANGE(0xe000, 0xe000) AM_READ(mcu_r)
|
||||
AM_RANGE(0xe800, 0xe800) AM_WRITE(mcu_w)
|
||||
AM_RANGE(0xf800, 0xf800) AM_READ(cpu0_mf800_r)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START( main_map, AS_PROGRAM, 8, retofinv_state )
|
||||
AM_IMPORT_FROM(bootleg_map)
|
||||
AM_RANGE(0xc003, 0xc003) AM_READ(mcu_status_r)
|
||||
AM_RANGE(0xc803, 0xc803) AM_WRITE(mcu_reset_w)
|
||||
AM_RANGE(0xe000, 0xe000) AM_DEVREAD("68705", taito68705_mcu_device, data_r)
|
||||
AM_RANGE(0xe800, 0xe800) AM_DEVWRITE("68705", taito68705_mcu_device, data_w)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START( sub_map, AS_PROGRAM, 8, retofinv_state )
|
||||
AM_RANGE(0x0000, 0x1fff) AM_ROM
|
||||
AM_RANGE(0x8000, 0x87ff) AM_RAM_WRITE(fg_videoram_w) AM_SHARE("fg_videoram")
|
||||
@ -168,18 +162,6 @@ static ADDRESS_MAP_START( sound_map, AS_PROGRAM, 8, retofinv_state )
|
||||
AM_RANGE(0xe000, 0xffff) AM_ROM /* space for diagnostic ROM */
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START( mcu_map, AS_PROGRAM, 8, retofinv_state )
|
||||
ADDRESS_MAP_GLOBAL_MASK(0x7ff)
|
||||
AM_RANGE(0x0000, 0x0000) AM_READWRITE(mcu_portA_r, mcu_portA_w)
|
||||
AM_RANGE(0x0001, 0x0001) AM_READWRITE(mcu_portB_r, mcu_portB_w)
|
||||
AM_RANGE(0x0002, 0x0002) AM_READWRITE(mcu_portC_r, mcu_portC_w)
|
||||
AM_RANGE(0x0004, 0x0004) AM_WRITE(mcu_ddrA_w)
|
||||
AM_RANGE(0x0005, 0x0005) AM_WRITE(mcu_ddrB_w)
|
||||
AM_RANGE(0x0006, 0x0006) AM_WRITE(mcu_ddrC_w)
|
||||
AM_RANGE(0x0010, 0x007f) AM_RAM
|
||||
AM_RANGE(0x0080, 0x07ff) AM_ROM
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
||||
|
||||
static INPUT_PORTS_START( retofinv )
|
||||
@ -382,8 +364,7 @@ static MACHINE_CONFIG_START( retofinv, retofinv_state )
|
||||
MCFG_CPU_PROGRAM_MAP(sound_map)
|
||||
MCFG_CPU_PERIODIC_INT_DRIVER(retofinv_state, nmi_line_pulse, 2*60)
|
||||
|
||||
MCFG_CPU_ADD("68705", M68705,18432000/6) /* 3.072 MHz? */
|
||||
MCFG_CPU_PROGRAM_MAP(mcu_map)
|
||||
MCFG_CPU_ADD("68705", TAITO68705_MCU, 18432000/6) /* 3.072 MHz? */
|
||||
|
||||
MCFG_QUANTUM_TIME(attotime::from_hz(6000)) /* 100 CPU slices per frame - enough for the sound CPU to read all commands */
|
||||
|
||||
@ -418,8 +399,10 @@ MACHINE_CONFIG_END
|
||||
|
||||
/* bootleg has no mcu */
|
||||
static MACHINE_CONFIG_DERIVED( retofinb, retofinv )
|
||||
MCFG_DEVICE_REMOVE("68705")
|
||||
MCFG_CPU_MODIFY("maincpu")
|
||||
MCFG_CPU_PROGRAM_MAP(bootleg_map)
|
||||
|
||||
MCFG_DEVICE_REMOVE("68705")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
@ -441,7 +424,7 @@ ROM_START( retofinv )
|
||||
ROM_REGION( 0x10000, "audiocpu", 0 )
|
||||
ROM_LOAD( "a37-05.17", 0x0000, 0x2000, CRC(9025abea) SHA1(2f03e8572f23624d7cd1215a55109e97fd66e271) )
|
||||
|
||||
ROM_REGION( 0x0800, "68705", 0 ) /* 8k for the microcontroller */
|
||||
ROM_REGION( 0x0800, "68705:mcu", 0 ) /* 2k for the microcontroller */
|
||||
/* the only available dump is from a bootleg board, and is not the real thing (see notes at top of driver) */
|
||||
ROM_LOAD( "a37-09.37", 0x00000, 0x0800, BAD_DUMP CRC(79bd6ded) SHA1(4967e95b4461c1bfb4e933d1804677799014f77b) )
|
||||
|
||||
|
@ -1,56 +1,28 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Jarek Parchanski, Andrea Mazzoleni
|
||||
|
||||
#include "machine/taito68705interface.h"
|
||||
|
||||
#include "machine/gen_latch.h"
|
||||
|
||||
|
||||
class retofinv_state : public driver_device
|
||||
{
|
||||
public:
|
||||
retofinv_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_audiocpu(*this, "audiocpu"),
|
||||
m_subcpu(*this, "sub"),
|
||||
m_68705(*this, "68705"),
|
||||
m_gfxdecode(*this, "gfxdecode"),
|
||||
m_palette(*this, "palette"),
|
||||
m_soundlatch(*this, "soundlatch"),
|
||||
m_fg_videoram(*this, "fg_videoram"),
|
||||
m_sharedram(*this, "sharedram"),
|
||||
m_bg_videoram(*this, "bg_videoram") { }
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<cpu_device> m_audiocpu;
|
||||
required_device<cpu_device> m_subcpu;
|
||||
optional_device<cpu_device> m_68705;
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<generic_latch_8_device> m_soundlatch;
|
||||
|
||||
required_shared_ptr<uint8_t> m_fg_videoram;
|
||||
required_shared_ptr<uint8_t> m_sharedram;
|
||||
required_shared_ptr<uint8_t> m_bg_videoram;
|
||||
|
||||
uint8_t m_main_irq_mask;
|
||||
uint8_t m_sub_irq_mask;
|
||||
uint8_t m_cpu2_m6000;
|
||||
uint8_t m_from_main;
|
||||
uint8_t m_from_mcu;
|
||||
int m_mcu_sent;
|
||||
int m_main_sent;
|
||||
uint8_t m_portA_in;
|
||||
uint8_t m_portA_out;
|
||||
uint8_t m_ddrA;
|
||||
uint8_t m_portB_in;
|
||||
uint8_t m_portB_out;
|
||||
uint8_t m_ddrB;
|
||||
uint8_t m_portC_in;
|
||||
uint8_t m_portC_out;
|
||||
uint8_t m_ddrC;
|
||||
int m_fg_bank;
|
||||
int m_bg_bank;
|
||||
tilemap_t *m_bg_tilemap;
|
||||
tilemap_t *m_fg_tilemap;
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_audiocpu(*this, "audiocpu")
|
||||
, m_subcpu(*this, "sub")
|
||||
, m_68705(*this, "68705")
|
||||
, m_gfxdecode(*this, "gfxdecode")
|
||||
, m_palette(*this, "palette")
|
||||
, m_soundlatch(*this, "soundlatch")
|
||||
, m_fg_videoram(*this, "fg_videoram")
|
||||
, m_sharedram(*this, "sharedram")
|
||||
, m_bg_videoram(*this, "bg_videoram")
|
||||
{
|
||||
}
|
||||
|
||||
DECLARE_WRITE8_MEMBER(cpu1_reset_w);
|
||||
DECLARE_WRITE8_MEMBER(cpu2_reset_w);
|
||||
@ -62,17 +34,6 @@ public:
|
||||
DECLARE_WRITE8_MEMBER(irq1_ack_w);
|
||||
DECLARE_WRITE8_MEMBER(coincounter_w);
|
||||
DECLARE_WRITE8_MEMBER(coinlockout_w);
|
||||
DECLARE_READ8_MEMBER(mcu_portA_r);
|
||||
DECLARE_WRITE8_MEMBER(mcu_portA_w);
|
||||
DECLARE_WRITE8_MEMBER(mcu_ddrA_w);
|
||||
DECLARE_READ8_MEMBER(mcu_portB_r);
|
||||
DECLARE_WRITE8_MEMBER(mcu_portB_w);
|
||||
DECLARE_WRITE8_MEMBER(mcu_ddrB_w);
|
||||
DECLARE_READ8_MEMBER(mcu_portC_r);
|
||||
DECLARE_WRITE8_MEMBER(mcu_portC_w);
|
||||
DECLARE_WRITE8_MEMBER(mcu_ddrC_w);
|
||||
DECLARE_WRITE8_MEMBER(mcu_w);
|
||||
DECLARE_READ8_MEMBER(mcu_r);
|
||||
DECLARE_READ8_MEMBER(mcu_status_r);
|
||||
DECLARE_WRITE8_MEMBER(bg_videoram_w);
|
||||
DECLARE_WRITE8_MEMBER(fg_videoram_w);
|
||||
@ -82,13 +43,36 @@ public:
|
||||
TILE_GET_INFO_MEMBER(bg_get_tile_info);
|
||||
TILE_GET_INFO_MEMBER(fg_get_tile_info);
|
||||
|
||||
virtual void machine_start() override;
|
||||
virtual void video_start() override;
|
||||
DECLARE_PALETTE_INIT(retofinv);
|
||||
|
||||
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
void draw_sprites(bitmap_ind16 &bitmap);
|
||||
|
||||
INTERRUPT_GEN_MEMBER(main_vblank_irq);
|
||||
INTERRUPT_GEN_MEMBER(sub_vblank_irq);
|
||||
|
||||
protected:
|
||||
virtual void machine_start() override;
|
||||
virtual void video_start() override;
|
||||
|
||||
void draw_sprites(bitmap_ind16 &bitmap);
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<cpu_device> m_audiocpu;
|
||||
required_device<cpu_device> m_subcpu;
|
||||
optional_device<taito68705_mcu_device> m_68705;
|
||||
required_device<gfxdecode_device> m_gfxdecode;
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<generic_latch_8_device> m_soundlatch;
|
||||
|
||||
required_shared_ptr<uint8_t> m_fg_videoram;
|
||||
required_shared_ptr<uint8_t> m_sharedram;
|
||||
required_shared_ptr<uint8_t> m_bg_videoram;
|
||||
|
||||
uint8_t m_main_irq_mask;
|
||||
uint8_t m_sub_irq_mask;
|
||||
uint8_t m_cpu2_m6000;
|
||||
int m_fg_bank;
|
||||
int m_bg_bank;
|
||||
tilemap_t *m_bg_tilemap;
|
||||
tilemap_t *m_fg_tilemap;
|
||||
};
|
||||
|
@ -1,133 +0,0 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Jarek Parchanski, Andrea Mazzoleni
|
||||
#include "emu.h"
|
||||
#include "cpu/z80/z80.h"
|
||||
#include "includes/retofinv.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Return of Invaders 68705 protection interface
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
READ8_MEMBER(retofinv_state::mcu_portA_r)
|
||||
{
|
||||
//logerror("%04x: 68705 port A read %02x\n",space.device().safe_pc(),m_portA_in);
|
||||
return (m_portA_out & m_ddrA) | (m_portA_in & ~m_ddrA);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_portA_w)
|
||||
{
|
||||
//logerror("%04x: 68705 port A write %02x\n",space.device().safe_pc(),data);
|
||||
m_portA_out = data;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_ddrA_w)
|
||||
{
|
||||
m_ddrA = data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Port B connections:
|
||||
*
|
||||
* all bits are logical 1 when read (+5V pullup)
|
||||
*
|
||||
* 1 W IRQ ack and enable latch which holds data from main Z80 memory
|
||||
* 2 W loads latch to Z80
|
||||
*/
|
||||
|
||||
|
||||
READ8_MEMBER(retofinv_state::mcu_portB_r)
|
||||
{
|
||||
return (m_portB_out & m_ddrB) | (m_portB_in & ~m_ddrB);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_portB_w)
|
||||
{
|
||||
//logerror("%04x: 68705 port B write %02x\n",space.device().safe_pc(),data);
|
||||
|
||||
if ((m_ddrB & 0x02) && (~data & 0x02) && (m_portB_out & 0x02))
|
||||
{
|
||||
m_portA_in = m_from_main;
|
||||
if (m_main_sent) m_68705->set_input_line(0, CLEAR_LINE);
|
||||
m_main_sent = 0;
|
||||
//logerror("read command %02x from main cpu\n",m_portA_in);
|
||||
}
|
||||
if ((m_ddrB & 0x04) && (data & 0x04) && (~m_portB_out & 0x04))
|
||||
{
|
||||
//logerror("send command %02x to main cpu\n",m_portA_out);
|
||||
m_from_mcu = m_portA_out;
|
||||
m_mcu_sent = 1;
|
||||
}
|
||||
|
||||
m_portB_out = data;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_ddrB_w)
|
||||
{
|
||||
m_ddrB = data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Port C connections:
|
||||
*
|
||||
* all bits are logical 1 when read (+5V pullup)
|
||||
*
|
||||
* 0 R 1 when pending command Z80->68705
|
||||
* 1 R 0 when pending command 68705->Z80
|
||||
*/
|
||||
|
||||
|
||||
READ8_MEMBER(retofinv_state::mcu_portC_r)
|
||||
{
|
||||
m_portC_in = 0;
|
||||
if (m_main_sent) m_portC_in |= 0x01;
|
||||
if (!m_mcu_sent) m_portC_in |= 0x02;
|
||||
//logerror("%04x: 68705 port C read %02x\n",space.device().safe_pc(),m_portC_in);
|
||||
return (m_portC_out & m_ddrC) | (m_portC_in & ~m_ddrC);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_portC_w)
|
||||
{
|
||||
logerror("%04x: 68705 port C write %02x\n",space.device().safe_pc(),data);
|
||||
m_portC_out = data;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_ddrC_w)
|
||||
{
|
||||
m_ddrC = data;
|
||||
}
|
||||
|
||||
|
||||
WRITE8_MEMBER(retofinv_state::mcu_w)
|
||||
{
|
||||
logerror("%04x: mcu_w %02x\n",space.device().safe_pc(),data);
|
||||
m_from_main = data;
|
||||
m_main_sent = 1;
|
||||
m_68705->set_input_line(0, ASSERT_LINE);
|
||||
}
|
||||
|
||||
READ8_MEMBER(retofinv_state::mcu_r)
|
||||
{
|
||||
logerror("%04x: mcu_r %02x\n",space.device().safe_pc(),m_from_mcu);
|
||||
m_mcu_sent = 0;
|
||||
return m_from_mcu;
|
||||
}
|
||||
|
||||
READ8_MEMBER(retofinv_state::mcu_status_r)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
/* bit 4 = when 1, mcu is ready to receive data from main cpu */
|
||||
/* bit 5 = when 1, mcu has sent data to the main cpu */
|
||||
//logerror("%04x: mcu_status_r\n",space.device().safe_pc());
|
||||
if (!m_main_sent) res |= 0x10;
|
||||
if (m_mcu_sent) res |= 0x20;
|
||||
|
||||
return res;
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
matmania.cpp - maniach
|
||||
nycaptor.cpp - nycaptor
|
||||
renegade.cpp - renegade
|
||||
retofinv.cpp - retofinv
|
||||
slapfght.cpp - slapfght
|
||||
xain.cpp - xsleena
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user