1 // license:BSD-3-Clause
2 // copyright-holders:Miodrag Milanovic
3 /***************************************************************************
4 
5         Busicom 141-PF
6 
7         04/08/2009 Initial driver by Miodrag Milanovic
8 
9 ****************************************************************************/
10 
11 #include "emu.h"
12 #include "includes/busicom.h"
13 
14 #include "screen.h"
15 
16 #include <algorithm>
17 
18 
get_bit_selected(uint32_t val,int num)19 uint8_t busicom_state::get_bit_selected(uint32_t val, int num)
20 {
21 	for (int i = 0; i < num; i++)
22 		if (!BIT(val, i))
23 			return i;
24 
25 	return 0;
26 }
27 
keyboard_r()28 uint8_t busicom_state::keyboard_r()
29 {
30 	return m_input_lines[get_bit_selected(m_keyboard_shifter & 0x3ff, 10)]->read();
31 }
32 
printer_r()33 uint8_t busicom_state::printer_r()
34 {
35 	uint8_t retVal = 0;
36 	if (m_drum_index == 0)
37 		retVal |= 1;
38 	retVal |= (ioport("PAPERADV")->read() & 1) ? 8 : 0;
39 	return retVal;
40 }
41 
42 
shifter_w(uint8_t data)43 void busicom_state::shifter_w(uint8_t data)
44 {
45 	// FIXME: detect edges, maybe make 4003 shifter a device
46 	if (BIT(data, 0))
47 	{
48 		m_keyboard_shifter <<= 1;
49 		m_keyboard_shifter |= BIT(data, 1);
50 	}
51 
52 	if (BIT(data, 2))
53 	{
54 		m_printer_shifter <<= 1;
55 		m_printer_shifter |= BIT(data, 1);
56 	}
57 }
58 
printer_w(uint8_t data)59 void busicom_state::printer_w(uint8_t data)
60 {
61 	if (BIT(data, 0))
62 	{
63 		logerror("color : %02x %02x %d\n", BIT(data, 0), data, m_drum_index);
64 		m_printer_line_color[10] = 1;
65 	}
66 
67 	if (BIT(data, 1))
68 	{
69 		for (u8 i = 3; i < 18; i++)
70 			if (BIT(m_printer_shifter, i))
71 				m_printer_line[10][i - 3] = m_drum_index + 1;
72 
73 		if (BIT(m_printer_shifter, 0))
74 			m_printer_line[10][15] = m_drum_index + 13 + 1;
75 
76 		if (BIT(m_printer_shifter, 1))
77 			m_printer_line[10][16] = m_drum_index + 26 + 1;
78 	}
79 
80 	if (BIT(data, 3))
81 	{
82 		for (u8 j = 0; j < (ARRAY_LENGTH(m_printer_line) - 1); j++)
83 			std::copy(std::begin(m_printer_line[j + 1]), std::end(m_printer_line[j + 1]), std::begin(m_printer_line[j]));
84 		std::copy_n(&m_printer_line_color[1], ARRAY_LENGTH(m_printer_line_color) - 1, &m_printer_line_color[0]);
85 
86 		std::fill(std::begin(m_printer_line[10]), std::end(m_printer_line[10]), 0);
87 		m_printer_line_color[10] = 0;
88 	}
89 }
90 
status_w(uint8_t data)91 void busicom_state::status_w(uint8_t data)
92 {
93 #if 0
94 	uint8_t mem_lamp = BIT(data, 0);
95 	uint8_t over_lamp = BIT(data, 1);
96 	uint8_t minus_lamp = BIT(data, 2);
97 #endif
98 	//logerror("status %c %c %c\n", mem_lamp ? 'M':'x', over_lamp ? 'O':'x', minus_lamp ? '-':'x');
99 }
100 
printer_ctrl_w(uint8_t data)101 void busicom_state::printer_ctrl_w(uint8_t data)
102 {
103 }
104 
busicom_rom(address_map & map)105 void busicom_state::busicom_rom(address_map &map)
106 {
107 	map.unmap_value_high();
108 	map(0x0000, 0x04FF).rom().region("maincpu", 0);
109 }
110 
busicom_mem(address_map & map)111 void busicom_state::busicom_mem(address_map &map)
112 {
113 	map.unmap_value_high();
114 	map(0x0000, 0x07F).ram();
115 }
116 
busicom_stat(address_map & map)117 void busicom_state::busicom_stat(address_map &map)
118 {
119 	map.unmap_value_high();
120 	map(0x0000, 0x01F).ram();
121 }
122 
busicom_rp(address_map & map)123 void busicom_state::busicom_rp(address_map &map)
124 {
125 	map.unmap_value_high();
126 	map(0x0000, 0x000f).mirror(0x0700).w(FUNC(busicom_state::shifter_w)); // ROM0 I/O
127 	map(0x0010, 0x001f).mirror(0x0700).rw(FUNC(busicom_state::keyboard_r), FUNC(busicom_state::printer_ctrl_w)); // ROM1 I/O
128 	map(0x0020, 0x002f).mirror(0x0700).r(FUNC(busicom_state::printer_r));  // ROM2 I/O
129 }
130 
busicom_mp(address_map & map)131 void busicom_state::busicom_mp(address_map &map)
132 {
133 	map(0x00, 0x00).w(FUNC(busicom_state::printer_w)); // RAM0 output
134 	map(0x01, 0x01).w(FUNC(busicom_state::status_w));  // RAM1 output
135 }
136 
137 /* Input ports */
138 static INPUT_PORTS_START( busicom )
139 	PORT_START("LINE0")
PORT_CODE(KEYCODE_1)140 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CM") PORT_CODE(KEYCODE_1)
141 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RM") PORT_CODE(KEYCODE_2)
142 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M-") PORT_CODE(KEYCODE_3)
143 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M+") PORT_CODE(KEYCODE_4)
144 	PORT_START("LINE1")
145 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SQRT") PORT_CODE(KEYCODE_S)
146 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("%") PORT_CODE(KEYCODE_5)
147 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M=-") PORT_CODE(KEYCODE_6)
148 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M=+") PORT_CODE(KEYCODE_7)
149 	PORT_START("LINE2")
150 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("diamond") PORT_CODE(KEYCODE_D)
151 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH_PAD)
152 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("*") PORT_CODE(KEYCODE_ASTERISK)
153 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("=") PORT_CODE(KEYCODE_ENTER_PAD)
154 	PORT_START("LINE3")
155 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS_PAD)
156 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+") PORT_CODE(KEYCODE_PLUS_PAD)
157 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("diamond 2") PORT_CODE(KEYCODE_TILDE)
158 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("000") PORT_CODE(KEYCODE_8)
159 	PORT_START("LINE4")
160 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9_PAD)
161 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6_PAD)
162 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3_PAD)
163 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_DEL_PAD)
164 	PORT_START("LINE5")
165 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8_PAD)
166 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5_PAD)
167 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2_PAD)
168 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("00") PORT_CODE(KEYCODE_9)
169 	PORT_START("LINE6")
170 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7_PAD)
171 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4_PAD)
172 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1_PAD)
173 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0_PAD)
174 	PORT_START("LINE7")
175 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Sign") PORT_CODE(KEYCODE_RALT) PORT_CODE(KEYCODE_LALT)
176 		PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("EX") PORT_CODE(KEYCODE_X)
177 		PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CE") PORT_CODE(KEYCODE_E)
178 		PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C)
179 	PORT_START("LINE8")
180 		PORT_CONFNAME( 0x0f, 0x00, "Digital point")
181 			PORT_CONFSETTING( 0x00, "0" )
182 			PORT_CONFSETTING( 0x01, "1" )
183 			PORT_CONFSETTING( 0x02, "2" )
184 			PORT_CONFSETTING( 0x03, "3" )
185 			PORT_CONFSETTING( 0x04, "4" )
186 			PORT_CONFSETTING( 0x05, "5" )
187 			PORT_CONFSETTING( 0x06, "6" )
188 			PORT_CONFSETTING( 0x08, "8" )
189 	PORT_START("LINE9")
190 		PORT_CONFNAME( 0x0f, 0x00, "Rounding")
191 			PORT_CONFSETTING( 0x01, "/N" )
192 			PORT_CONFSETTING( 0x00, "FL" )
193 			PORT_CONFSETTING( 0x08, "5/4" )
194 	PORT_START("PAPERADV")
195 		PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Paper adv.") PORT_CODE(KEYCODE_SPACE)
196 
197 INPUT_PORTS_END
198 
199 
200 TIMER_DEVICE_CALLBACK_MEMBER(busicom_state::timer_callback)
201 {
202 	m_timer ^= 1;
203 	if (m_timer == 1)
204 		m_drum_index++;
205 	if (m_drum_index == 13)
206 		m_drum_index = 0;
207 	m_maincpu->set_input_line(I4004_TEST_LINE, m_timer);
208 }
209 
machine_start()210 void busicom_state::machine_start()
211 {
212 	save_item(NAME(m_drum_index));
213 	save_item(NAME(m_keyboard_shifter));
214 	save_item(NAME(m_printer_shifter));
215 	save_item(NAME(m_timer));
216 	save_item(NAME(m_printer_line));
217 	save_item(NAME(m_printer_line_color));
218 }
219 
machine_reset()220 void busicom_state::machine_reset()
221 {
222 	m_drum_index = 0;
223 	m_keyboard_shifter = 0;
224 	m_printer_shifter = 0;
225 
226 	for (int i = 0; i < ARRAY_LENGTH(m_printer_line); i++)
227 		std::fill(std::begin(m_printer_line[i]), std::end(m_printer_line[i]), 0);
228 	std::fill(std::begin(m_printer_line_color), std::end(m_printer_line_color), 0);
229 }
230 
busicom(machine_config & config)231 void busicom_state::busicom(machine_config &config)
232 {
233 	/* basic machine hardware */
234 	I4004(config, m_maincpu, 750000);
235 	m_maincpu->set_rom_map(&busicom_state::busicom_rom);
236 	m_maincpu->set_ram_memory_map(&busicom_state::busicom_mem);
237 	m_maincpu->set_rom_ports_map(&busicom_state::busicom_rp);
238 	m_maincpu->set_ram_status_map(&busicom_state::busicom_stat);
239 	m_maincpu->set_ram_ports_map(&busicom_state::busicom_mp);
240 
241 	/* video hardware */
242 	screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
243 	screen.set_refresh_hz(50);
244 	screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
245 	screen.set_size(40*17, 44*11);
246 	screen.set_visarea_full();
247 	screen.set_screen_update(FUNC(busicom_state::screen_update_busicom));
248 	screen.set_palette(m_palette);
249 
250 	PALETTE(config, m_palette, FUNC(busicom_state::busicom_palette), 16);
251 
252 	TIMER(config, "busicom_timer").configure_periodic(FUNC(busicom_state::timer_callback), attotime::from_msec(28*2));
253 }
254 
255 /* ROM definition */
256 ROM_START( busicom )
257 	ROM_REGION( 0x0500, "maincpu", 0 )
258 	ROM_LOAD( "busicom.l01", 0x0000, 0x0100, CRC(51ae2513) SHA1(5cb4097a3945db35af4ed64b629b20b08fc9824f))
259 	ROM_LOAD( "busicom.l02", 0x0100, 0x0100, CRC(a05411ad) SHA1(81503a99a0d34fa29bf1245de0a44af2f174abdd))
260 	ROM_LOAD( "busicom.l05", 0x0200, 0x0100, CRC(6120addf) SHA1(4b7ec183613630120b3c313c782122713d4327c5))
261 	ROM_LOAD( "busicom.l07", 0x0300, 0x0100, CRC(84a90daa) SHA1(e2931753b0fd35144cb5a9d73fcae8e104e5e3ed))
262 	ROM_LOAD( "busicom.l11", 0x0400, 0x0100, CRC(4d2b2942) SHA1(9a59db76eff084369797735ec19da8cbc70d0d39))
263 ROM_END
264 
265 /* Driver */
266 
267 //    YEAR  NAME     PARENT  COMPAT  MACHINE  INPUT    CLASS          INIT        COMPANY                          FULLNAME          FLAGS
268 COMP( 1974, busicom, 0,      0,      busicom, busicom, busicom_state, empty_init, "Business Computer Corporation", "Busicom 141-PF", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE )
269