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
|
// license:BSD-3-Clause
// copyright-holders:Devin Acker
/**********************************************************************
Skeleton for NEC PC-6022 Color Plotter Printer
User manual:
https://archive.org/details/nec-pc-6022-color-plotter-printer-users-manual
Page width is 96mm / 480px.
CPU port A controls the two steppers, and port C controls raising/lowering the pen.
Pen/color selection happens by moving the pen to the left of the print area, then
moving it back and forth 3 times per color change.
**********************************************************************/
#include "emu.h"
#include "pc6022.h"
//#define VERBOSE 1
#include "logmacro.h"
DEFINE_DEVICE_TYPE(PC6022, pc6022_device, "pc6022", "NEC PC-6022 Color Plotter Printer")
ROM_START( pc6022 )
ROM_REGION(0x1000, "cpu", 0)
ROM_LOAD("upd7801g-138.bin", 0x0000, 0x1000, CRC(0a294989) SHA1(fab85e88566ffa10923dec3a1a6b0d8346bc69ec))
ROM_END
const tiny_rom_entry *pc6022_device::device_rom_region() const
{
return ROM_NAME( pc6022 );
}
INPUT_PORTS_START( pc6022 )
PORT_START("PA")
PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_OUTPUT ) // X stepper (pattern is 5, 6, A, 9 for positive/rightward movement)
PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_OUTPUT ) // Y stepper (page feed)
PORT_START("PB")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Pen Right");
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Pen Left");
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Pen Down / Paper Feed");
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Pen Up");
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_TOGGLE PORT_NAME("Step");
PORT_DIPSETTING( 0x00, "1" )
PORT_DIPSETTING( 0x10, "2" )
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_TOGGLE PORT_NAME("Character Set");
PORT_DIPSETTING( 0x00, "Hiragana" )
PORT_DIPSETTING( 0x20, "Katakana" )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Color Change")
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Pen Change")
PORT_START("PC")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OUTPUT ) // TODO (stop/online LED?)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("Stop")
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN ) // TODO
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("busy", FUNC(input_merger_device::in_w<1>))
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(pc6022_device::ack_w));
PORT_BIT( 0x60, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(pc6022_device::pen_ctrl_w));
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) // TODO
INPUT_PORTS_END
ioport_constructor pc6022_device::device_input_ports() const
{
return INPUT_PORTS_NAME( pc6022 );
}
pc6022_device::pc6022_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, PC6022, tag, owner, clock),
device_centronics_peripheral_interface(mconfig, *this),
m_cpu(*this, "cpu"),
m_busy(*this, "busy")
{
}
void pc6022_device::io_map(address_map &map)
{
map.global_mask(0x00ff);
// TODO: does the address actually matter?
map(0x00, 0x00).r(FUNC(pc6022_device::data_r));
}
void pc6022_device::device_add_mconfig(machine_config &config)
{
UPD7801(config, m_cpu, 4'000'000); // actual clock unknown
m_cpu->set_addrmap(AS_IO, &pc6022_device::io_map);
m_cpu->pa_out_cb().set_ioport("PA");
m_cpu->pb_in_cb().set_ioport("PB");
m_cpu->pc_in_cb().set_ioport("PC");
m_cpu->pc_out_cb().set_ioport("PC");
// firmware only manually polls INT1, but BUSY needs to go high faster than that
INPUT_MERGER_ANY_HIGH(config, m_busy);
m_busy->output_handler().set(FUNC(pc6022_device::output_busy));
}
void pc6022_device::device_start()
{
m_data = 0;
m_pen_ctrl = 0;
m_pen_down = 0;
m_ack = 0;
m_strobe = 0;
save_item(NAME(m_data));
save_item(NAME(m_pen_ctrl));
save_item(NAME(m_pen_down));
save_item(NAME(m_ack));
save_item(NAME(m_strobe));
}
void pc6022_device::device_reset()
{
output_select(1);
output_busy(0);
}
void pc6022_device::input_strobe(int state)
{
if (!state && m_strobe)
{
m_busy->in_set<0>();
m_cpu->set_input_line(UPD7810_INTF1, ASSERT_LINE);
}
m_strobe = state;
}
void pc6022_device::ack_w(int state)
{
if (!state && m_ack)
{
m_busy->in_clear<0>();
m_cpu->set_input_line(UPD7810_INTF1, CLEAR_LINE);
}
m_ack = state;
}
void pc6022_device::pen_ctrl_w(int state)
{
if (BIT(state & ~m_pen_ctrl, 0))
{
m_pen_down = 0;
LOG("pen up\n");
}
else if (BIT(state & ~m_pen_ctrl, 1))
{
m_pen_down = 1;
LOG("pen down\n");
}
m_pen_ctrl = state;
}
u8 pc6022_device::data_r()
{
return m_data;
}
|