summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/sms_ctrl/smsctrl.h
blob: d88869b9539f180d972b32642aaecda8aec0bd0a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************

    Sega 7-bit I/O port emulation

    Pin                  1      2      3      4      5      6      7      8      9     10
                        Up    Down   Left   Right          TL     TH            TR
                                                           TxD                  RXD
                        PC0    PC1    PC2    PC3           PC4    PC6           PC5
    SC-3000              I      I      I      I     N/C     I     N/C    GND     I
    SG-1000              I      I      I      I     N/C     I     GND    GND     I
    SG-1000 Mark III     I      I      I      I     +5V     I     GND    GND     I
    Master System        I      I      I      I     +5V     I     I/O    GND    I/O
    Mega Drive          I/O    I/O    I/O    I/O    +5V    I/O    I/O    GND    I/O
    Game Gear           I/O    I/O    I/O    I/O    +5V    I/O    I/O    GND    I/O    N/C

    * Male DE-9 connector on most systems.
    * Female DE-9 connector for Mega Drive EXP port.
    * 10-pin tongue connector on Game Gear (Hoshiden HDC-0492).
    * TH/PC6 can latch the VDP's horizontal counter and/or raise
      interrupts on some systems.
    * Mega Drive and Game Gear can route TL/PC4 and TR/PC5 to a
      UART for serial communication.

**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_SMSCTRL_H
#define MAME_BUS_SMS_CTRL_SMSCTRL_H

#pragma once

#include "screen.h"

#include <utility>


//**************************************************************************
//  FORWARD DECLARATIONS
//**************************************************************************

class device_sms_control_interface;



//**************************************************************************
//  CLASS DECLARATIONS
//**************************************************************************

class sms_control_port_device : public device_t, public device_single_card_slot_interface<device_sms_control_interface>
{
public:
	template <typename T>
	sms_control_port_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt) :
		sms_control_port_device(mconfig, tag, owner, 0)
	{
		option_reset();
		opts(*this);
		set_default_option(dflt);
		set_fixed(false);
	}

	sms_control_port_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
	virtual ~sms_control_port_device();

	auto th_handler() { return m_th_handler.bind(); } // 0 for pulled low, 1 for pulled high or high impedance
	template <typename T> void set_screen(T &&tag) { m_screen.set_tag(std::forward<T>(tag)); }

	// Bit  Pin  Signal
	// 0    1    Up
	// 1    2    Down
	// 2    3    Left
	// 3    4    Right
	// 4    6    TL
	// 5    9    TR
	//
	// return bits set for pulled high or high impedance
	// return bits clear for pulled low
	u8 in_r();

	// Bit  Pin  Signal
	// 0    1    Up
	// 1    2    Down
	// 2    3    Left
	// 3    4    Right
	// 4    6    TL
	// 5    9    TR
	// 6    7    TH
	//
	// mem_mask bits set for lines driven by low impedance output
	// mem_mask bits clear for lines with high-impedance pull-up/pull-down
	void out_w(u8 data, u8 mem_mask);

protected:
	virtual void device_start() override ATTR_COLD;

private:
	optional_device<screen_device> m_screen;
	devcb_write_line m_th_handler;

	device_sms_control_interface *m_controller;

	friend class device_sms_control_interface;
};


class device_sms_control_interface : public device_interface
{
public:
	virtual ~device_sms_control_interface();

	virtual u8 in_r();
	virtual void out_w(u8 data, u8 mem_mask);

protected:
	device_sms_control_interface(machine_config const &mconfig, device_t &device);

	template <typename T> void configure_screen(T &&act) { if (m_port) act(std::as_const(m_port->m_screen)); }

	screen_device *screen() const { return m_port ? m_port->m_screen.target() : nullptr; }
	void th_w(int state) { if (m_port) m_port->m_th_handler(state); }

private:
	sms_control_port_device *const m_port;
};



//**************************************************************************
//  INLINE MEMBER FUNCTIONS
//**************************************************************************

inline u8 sms_control_port_device::in_r()
{
	return m_controller ? m_controller->in_r() : 0xff;
}


inline void sms_control_port_device::out_w(u8 data, u8 mem_mask)
{
	if (m_controller)
		m_controller->out_w(data, mem_mask);
}



//**************************************************************************
//  DEVICE TYPE DECLARATIONS
//**************************************************************************

DECLARE_DEVICE_TYPE(SMS_CONTROL_PORT, sms_control_port_device)

#endif // MAME_BUS_SMS_CTRL_SMSCTRL_H