summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/minicom.c
blob: 6d93e5a8182fb13215f320926754496160112daa (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// license:MAME|GPL-2.0+
// copyright-holders: Felipe Sanches
/***************************************************************************

    Ultratec Minicom IV
    http://www.ultratec.com/ttys/non-printing/minicom.php

  Driver by Felipe Sanches

There messages are displayed in a 20 digit 14 segment VFD.

  ***********
 * *   *   * *
 *  *  *  *  *
 *   * * *   *
  ***** *****
 *   * * *   *
 *  *  *  *  *
 * *   *   * *
  ***********  *

Digits seem to be selected by a mux fed by a counter that is incremented by pulses in P1.2
There may be a bit connected to the counter reset signal...

Segment data is sent to each 14seg digit by first writing half of the data to port P0 and
 toggling T0 and then the other half of data is written to P0 again but toggling T1 afterwards.

  Changelog:

   2014 JUL 19 [Felipe Sanches]:
   * Got the display working except for a few glitches

   2014 JUL 16 [Felipe Sanches]:
   * Initial driver skeleton
*/

#define LOG_IO_PORTS 0
#define PRINTER_ATTACHED 1

#include "emu.h"
#include "cpu/mcs51/mcs51.h"
#include "minicom.lh"

class minicom_state : public driver_device
{
public:
	minicom_state(const machine_config &mconfig, device_type type, const char *tag)
		: driver_device(mconfig, type, tag)
		, m_maincpu(*this, "maincpu")
	{ }

	DECLARE_WRITE8_MEMBER(minicom_io_w);
	DECLARE_READ8_MEMBER(minicom_io_r);
	DECLARE_DRIVER_INIT(minicom);
private:
	UINT8 m_p[4];
	UINT16 m_display_data;
	int m_digit_index;
	virtual void machine_start();
	virtual void machine_reset();
	required_device<cpu_device> m_maincpu;
};

static ADDRESS_MAP_START(i87c52_io, AS_IO, 8, minicom_state)
	AM_RANGE(MCS51_PORT_P0, MCS51_PORT_P3) AM_READWRITE(minicom_io_r, minicom_io_w)
ADDRESS_MAP_END

void minicom_state::machine_start()
{
	// zerofill
	memset(m_p, 0, 4);
	m_digit_index = 0;
	m_display_data = 0;

	// register for savestates
	save_item(NAME(m_p));
	save_item(NAME(m_digit_index));
	save_item(NAME(m_display_data));
}

void minicom_state::machine_reset()
{
	m_digit_index = 19;
	m_display_data = 0;

	for (int i=0; i<20; i++)
		output_set_digit_value(i, 0);
}

READ8_MEMBER(minicom_state::minicom_io_r)
{
	switch (offset)
	{
		case 1:
			//P1.3 seems to be an indicator of whether or not we have a printer device attached.
			// at address 0xABF the code checks this flag in order to decide which string to display:
			// "MINIPRINT IS RESET" or "MINICOM IS RESET"
			return PRINTER_ATTACHED << 3;
		case 2:
//          return 0; //para a palestra no Garoa... :-)
			return 1; //to skip the "NO POWER" warning. I'm not sure why.
		default:
#if LOG_IO_PORTS
			printf("Unhandled I/O Read at offset 0x%02X (return 0)\n", offset);
#endif
			return 0;
		}
}

#if LOG_IO_PORTS
static void printbits(UINT8 v) {
	int i;
	for(i = 7; i >= 0; i--) putchar('0' + ((v >> i) & 1));
}
#endif

#define FALLING_EDGE(old_data, new_data, bit) (BIT(old_data ^ new_data, bit) && !BIT(new_data, bit))
#define RISING_EDGE(old_data, new_data, bit) (BIT(old_data ^ new_data, bit) && BIT(new_data, bit))

#define P1_UNKNOWN_BITS (0xFF & ~(1 << 2))
#define P2_UNKNOWN_BITS 0xFF
#define P3_UNKNOWN_BITS (0xFF & ~((1 << 4)|(1 << 5)))
WRITE8_MEMBER(minicom_state::minicom_io_w)
{
	switch (offset)
	{
		case 0x00:
		{
			m_p[offset]=data;
			break;
		}
		case 0x01:
		{
			if (data != m_p[offset])
			{
#if LOG_IO_PORTS
				UINT8 changed = m_p[offset] ^ data;
				if (changed ^ P1_UNKNOWN_BITS)
				{
					printf("Write to P1: %02X changed: (        ) (", data);
					printbits(changed);
					printf(") (        ) (        )\n");
				}
#endif
				if (FALLING_EDGE(m_p[offset], data, 2))
				{
					m_digit_index--;
					if (m_digit_index<0) m_digit_index = 19;
				}
				m_p[offset]=data;
			}
			break;
		}
		case 0x02:
		{
			if (data != m_p[offset])
			{
#if LOG_IO_PORTS
				UINT8 changed = m_p[offset] ^ data;
				if (changed ^ P2_UNKNOWN_BITS)
				{
					printf("Write to P2: %02X changed: (        ) (        ) (", data);
					printbits(changed);
					printf(") (        )\n");
				}
#endif
				m_p[offset]=data;
			}
			break;
		}
		case 0x03:
		{
			if (data != m_p[offset])
			{
				UINT8 changed = m_p[offset] ^ data;
#if LOG_IO_PORTS
				if (changed ^ P3_UNKNOWN_BITS)
				{
					printf("Write to P3: %02X changed: (        ) (        ) (        ) (", data);
					printbits(changed);
					printf(")\n");
				}
#endif

				if (FALLING_EDGE(m_p[offset], data, 4)) //P3.4 = T0
				{
					m_display_data &= 0xFF00;
					m_display_data |= m_p[0];
				}

				if (FALLING_EDGE(m_p[offset], data, 5)) //P3.5 = T1
				{
					m_display_data &= 0xFF;
					m_display_data |= (m_p[0] << 8);
				}

				if (BIT(changed,4) || BIT(changed,5))
				{
					output_set_digit_value(m_digit_index, BITSWAP16(m_display_data,  9,  1,  3, 11, 12,  4,  2, 10, 14, 6,  7, 5,  0, 15,  13, 8) & 0x3FFF);
				}
				m_p[offset]=data;
			}
			break;
		}
	}
}

DRIVER_INIT_MEMBER( minicom_state, minicom )
{
}

static MACHINE_CONFIG_START( minicom, minicom_state )
	/* basic machine hardware */
	MCFG_CPU_ADD("maincpu", I87C52, XTAL_10MHz) /*FIX-ME: verify the correct clock frequency */
	MCFG_CPU_IO_MAP(i87c52_io)

	/* video hardware */
	/* fluorescent 14-segment display forming a row of 20 characters */
	MCFG_DEFAULT_LAYOUT(layout_minicom)

/* TODO: Map the keyboard rows/cols inputs (43-key, 4-row keyboard) */

/* TODO: Treat the modem as a sound device. That may be an interesting challenge... :-) */
MACHINE_CONFIG_END

ROM_START( minicom )
	ROM_REGION( 0x2000, "maincpu", 0 )
	ROM_LOAD( "ultratec_minicom_iv.rom",  0x0000, 0x2000, CRC(22881366) SHA1(fc3faea5ecc1476e5bcb7999638f3150d06c9a81) )
ROM_END

/*    YEAR  NAME      PARENT  COMPAT  MACHINE     INPUT     CLASS          INIT     COMPANY     FULLNAME         FLAGS */
COMP( 1997, minicom,   0,     0,      minicom,    0,        minicom_state, minicom, "Ultratec", "Minicom IV",    GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_NO_SOUND) /* fw release data: 11th Aug 1997 */
//COMP( 2002, minicom,   0,     0,      minicom,    0,        minicom_state, minicom, "Ultratec", "Minicom IV",    GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_NO_SOUND) /* fw release data: 19th Apr 2002 - Seen at a subway station in S??o Paulo, Brazil (Metr?? Trianon MASP) */