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