1 // license:BSD-3-Clause
2 // copyright-holders:F. Ulivi
3
4 // **************************
5 // Driver for HP 9825 systems
6 // **************************
7 //
8 // **** Temporary header, will hopefully evolve into proper doc ****
9 //
10 // What's in:
11 // - Emulation of 9825B and 9825T systems
12 // - 12 kw (9825B) or 31kw (9825T) of RAM
13 // - 12 kw of system ROM
14 // - Keyboard (SHIFT LOCK & RESET not implemented)
15 // - Display & run light
16 // - DC100 tape drive
17 // - Printer
18 // - Beeper
19 // - Internal expansion ROMs
20 // - I/O expansion slots: 98032, 98034 & 98035 modules can be connected
21 // - For 9825T: the so-called SKOAL mechanism that transparently overlays RAM & ROM
22 // in the same address space
23 // - External expansion ROMs
24 // What's not yet in:
25 // - Configurable RAM size
26 //
27 // Thanks to Dyke Shaffer for publishing (on https://groups.io/g/VintHPcom)
28 // the source code of 98217 mass memory ROM. The 98217.bin image was reconstructed
29 // by re-assembling the source code (this is the reason why it's marked as
30 // a BAD_DUMP). And thanks to Ansgar Kueckes for adapting his assembler to
31 // handle HP9825 source files.
32 // For what regards the 9825T, I'd like to thank again Dyke Shaffer for
33 // publishing a lot of internal HP docs about the SKOAL card. I recovered the
34 // content of SKOAL ROM from its printed & scanned dump.
35 // I'd also like to thank Paul Berger for providing the images of the optional
36 // mass storage ROMs (see http://www.hpmuseum.net).
37 //
38 // 9825A can also be emulated. At the moment I haven't all the necessary
39 // ROM dumps, though.
40
41 #include "emu.h"
42 #include "cpu/hphybrid/hphybrid.h"
43 #include "machine/timer.h"
44 #include "machine/hp9825_tape.h"
45 #include "machine/hp98x5_io_sys.h"
46 #include "machine/hp9825_optrom.h"
47 #include "bus/hp9845_io/hp9845_io.h"
48 #include "imagedev/bitbngr.h"
49 #include "speaker.h"
50 #include "sound/beep.h"
51 #include "hp9825.lh"
52 #include "softlist.h"
53
54 // Debugging
55 #define VERBOSE 0
56 #include "logmacro.h"
57
58 // CPU clock (generated by a trimmered RC oscillator)
59 constexpr unsigned MAIN_CLOCK = 6000000;
60
61 // KDP chip clock
62 constexpr unsigned KDP_CLOCK = MAIN_CLOCK / 4;
63
64 // Peripheral Addresses (PA)
65 constexpr uint8_t KDP_PA = 0;
66 constexpr uint8_t TAPE_PA = 1;
67 constexpr uint8_t IO_SLOT_FIRST_PA = 2;
68 constexpr uint8_t IO_SLOT_LAST_PA = 15;
69
70 // KDP clocks to print 1 line of dots (~33 ms)
71 // This value is semi-guessed.
72 constexpr unsigned KDP_CLOCKS_PER_LINE = 50000;
73
74 // Beeper constants
75 // Values come from R/C values on schematics
76 constexpr unsigned BEEPER_FREQ = 900;
77 constexpr unsigned BEEPER_MS = 40;
78
79 // Bit manipulation
80 namespace {
BIT_MASK(unsigned n)81 template<typename T> constexpr T BIT_MASK(unsigned n)
82 {
83 return (T)1U << n;
84 }
85
BIT_CLR(T & w,unsigned n)86 template<typename T> void BIT_CLR(T& w , unsigned n)
87 {
88 w &= ~BIT_MASK<T>(n);
89 }
90
BIT_SET(T & w,unsigned n)91 template<typename T> void BIT_SET(T& w , unsigned n)
92 {
93 w |= BIT_MASK<T>(n);
94 }
95 }
96
97 // +--------------+
98 // | hp9825_state |
99 // +--------------+
100 class hp9825_state : public driver_device
101 {
102 public:
hp9825_state(const machine_config & mconfig,device_type type,const char * tag)103 hp9825_state(const machine_config &mconfig, device_type type, const char *tag)
104 : driver_device(mconfig, type, tag)
105 , m_cpu(*this , "cpu")
106 , m_rom_drawers(*this , "drawer%u" , 0U)
107 , m_io_sys(*this , "io_sys")
108 , m_cursor_timer(*this , "cursor_timer")
109 , m_tape(*this , "tape")
110 , m_io_key(*this , "KEY%u" , 0)
111 , m_shift_key(*this , "KEY_SHIFT")
112 , m_prt_alpha_out(*this , "prt_alpha")
113 , m_prt_graph_out(*this , "prt_graph")
114 , m_prt_timer(*this , "prt_timer")
115 , m_beeper(*this , "beeper")
116 , m_beep_timer(*this , "beep_timer")
117 , m_io_slot(*this, "slot%u", 0U)
118 , m_display(*this , "char_%u_%u" , 0U , 0U)
119 , m_run_light(*this , "run_light")
120 {
121 }
122
123 void hp9825_base(machine_config &config);
124
125 protected:
126 virtual void machine_start() override;
127 virtual void device_reset() override;
128 virtual void machine_reset() override;
129
130 required_device<hp_09825_67907_cpu_device> m_cpu;
131 required_device_array<hp9825_optrom_device , 4> m_rom_drawers;
132
133 private:
134 required_device<hp98x5_io_sys_device> m_io_sys;
135 required_device<timer_device> m_cursor_timer;
136 required_device<hp9825_tape_device> m_tape;
137 required_ioport_array<4> m_io_key;
138 required_ioport m_shift_key;
139 required_device<bitbanger_device> m_prt_alpha_out;
140 required_device<bitbanger_device> m_prt_graph_out;
141 required_device<timer_device> m_prt_timer;
142 required_device<beep_device> m_beeper;
143 required_device<timer_device> m_beep_timer;
144 required_device_array<hp9845_io_slot_device , 3> m_io_slot;
145 output_finder<32 , 7> m_display;
146 output_finder<> m_run_light;
147
148 bool m_display_on;
149 uint8_t m_display_mem[ 32 ];
150 uint8_t m_display_idx;
151 bool m_rpl_cursor;
152 bool m_cursor_blink;
153 bool m_any_cursor;
154 uint8_t m_scancode;
155 bool m_key_pressed;
156 bool m_autorepeating;
157 unsigned m_autorepeat_cnt;
158 // Printer
159 uint8_t m_printer_mem[ 16 ];
160 uint8_t m_printer_idx;
161 unsigned m_printer_line; // 0: printer idle, 1..10: line being printed
162 // SC of slots
163 int m_slot_sc[ 3 ];
164
165 void cpu_io_map(address_map &map);
166
167 uint16_t kb_scancode_r();
168 void disp_w(uint16_t data);
169 uint16_t kdp_status_r();
170 void kdp_control_w(uint16_t data);
171 void printer_w(uint16_t data);
172
173 void update_display();
174 TIMER_DEVICE_CALLBACK_MEMBER(cursor_blink);
175 void kb_scan_ioport(ioport_value pressed , ioport_port &port , unsigned idx_base , int& max_seq_len , unsigned& max_seq_idx);
176 TIMER_DEVICE_CALLBACK_MEMBER(kb_scan);
177
178 TIMER_DEVICE_CALLBACK_MEMBER(prt_timer);
179
180 TIMER_DEVICE_CALLBACK_MEMBER(beep_timer);
181
182 // Slot handling
183 void set_irq_slot(unsigned slot , int state);
184 void set_sts_slot(unsigned slot , int state);
185 void set_flg_slot(unsigned slot , int state);
186 void set_dmar_slot(unsigned slot , int state);
187 };
188
machine_start()189 void hp9825_state::machine_start()
190 {
191 m_display.resolve();
192 m_run_light.resolve();
193
194 save_item(NAME(m_display_on));
195 save_item(NAME(m_display_mem));
196 save_item(NAME(m_display_idx));
197 save_item(NAME(m_scancode));
198 }
199
device_reset()200 void hp9825_state::device_reset()
201 {
202 // First, unmap every r/w handler in 1..12 select codes
203 for (unsigned sc = IO_SLOT_FIRST_PA; sc < (IO_SLOT_LAST_PA + 1); sc++) {
204 m_cpu->space(AS_IO).unmap_readwrite(sc * 4 , sc * 4 + 3);
205 }
206
207 // Then, set r/w handlers of all installed I/O cards
208 int sc;
209 read16m_delegate rhandler(*this);
210 write16m_delegate whandler(*this);
211 for (unsigned i = 0; i < 3; i++) {
212 if ((sc = m_io_slot[ i ]->get_rw_handlers(rhandler , whandler)) >= 0) {
213 logerror("Install R/W handlers for slot %u @ SC = %d\n", i, sc);
214 m_cpu->space(AS_IO).install_readwrite_handler(sc * 4 , sc * 4 + 3 , rhandler , whandler);
215 }
216 m_slot_sc[ i ] = sc;
217 }
218 }
219
machine_reset()220 void hp9825_state::machine_reset()
221 {
222 m_display_on = false;
223 m_display_idx = 0;
224 m_rpl_cursor = false;
225 m_cursor_timer->reset();
226 m_cursor_blink = true;
227 update_display();
228 m_scancode = 0;
229 m_key_pressed = false;
230 m_autorepeating = false;
231 m_autorepeat_cnt = 0;
232 m_printer_idx = 0;
233 m_printer_line = 0;
234 m_prt_timer->reset();
235 m_beeper->set_state(0);
236 m_beep_timer->reset();
237 }
238
cpu_io_map(address_map & map)239 void hp9825_state::cpu_io_map(address_map &map)
240 {
241 map.unmap_value_low();
242 map(HP_MAKE_IOADDR(KDP_PA , 0) , HP_MAKE_IOADDR(KDP_PA , 0)).rw(FUNC(hp9825_state::kb_scancode_r) , FUNC(hp9825_state::disp_w));
243 map(HP_MAKE_IOADDR(KDP_PA , 1) , HP_MAKE_IOADDR(KDP_PA , 1)).rw(FUNC(hp9825_state::kdp_status_r) , FUNC(hp9825_state::kdp_control_w));
244 map(HP_MAKE_IOADDR(KDP_PA , 2) , HP_MAKE_IOADDR(KDP_PA , 2)).w(FUNC(hp9825_state::printer_w));
245 map(HP_MAKE_IOADDR(TAPE_PA , 0) , HP_MAKE_IOADDR(TAPE_PA , 3)).rw(m_tape , FUNC(hp9825_tape_device::tape_r) , FUNC(hp9825_tape_device::tape_w));
246 // TODO:
247 }
248
kb_scancode_r()249 uint16_t hp9825_state::kb_scancode_r()
250 {
251 uint8_t res = m_scancode;
252 if (m_shift_key->read()) {
253 BIT_SET(res , 7);
254 }
255 m_io_sys->set_irq(KDP_PA , false);
256 return res;
257 }
258
disp_w(uint16_t data)259 void hp9825_state::disp_w(uint16_t data)
260 {
261 if (m_display_on) {
262 m_display_on = false;
263 m_cursor_timer->reset();
264 m_cursor_blink = true;
265 m_display_idx = 0;
266 update_display();
267 }
268 m_display_mem[ m_display_idx++ ] = uint8_t(data);
269 }
270
kdp_status_r()271 uint16_t hp9825_state::kdp_status_r()
272 {
273 uint16_t res = 8;
274 if (m_io_sys->is_irq_pending(KDP_PA)) {
275 BIT_SET(res , 4);
276 }
277 if (m_printer_line) {
278 BIT_SET(res , 2);
279 }
280
281 return res;
282 }
283
kdp_control_w(uint16_t data)284 void hp9825_state::kdp_control_w(uint16_t data)
285 {
286 bool regen_display = false;
287 if (BIT(data , 1) && !m_display_on) {
288 m_display_on = true;
289 // Cursor should blink at 2^-19 the KDP clock
290 attotime cursor_half_period{ attotime::from_ticks(262144 , KDP_CLOCK) };
291 m_cursor_timer->adjust(cursor_half_period , 0 , cursor_half_period);
292 regen_display = true;
293 }
294 if (BIT(data , 6) && !m_rpl_cursor) {
295 m_rpl_cursor = true;
296 regen_display = true;
297 }
298 if (BIT(data , 5) && m_rpl_cursor) {
299 m_rpl_cursor = false;
300 regen_display = true;
301 }
302 if (BIT(data , 4)) {
303 if (BIT(data , 3)) {
304 m_run_light = !m_run_light;
305 } else {
306 m_run_light = false;
307 }
308 } else if (BIT(data , 3)) {
309 m_run_light = true;
310 }
311 if (BIT(data , 0) && m_printer_line == 0) {
312 // Start printing
313 // Dump text line to alpha bitbanger
314 for (auto c : m_printer_mem) {
315 m_prt_alpha_out->output(c);
316 }
317 m_prt_alpha_out->output('\n');
318 m_printer_idx = 0;
319 m_printer_line++;
320 m_prt_timer->adjust(attotime::from_ticks(KDP_CLOCKS_PER_LINE , KDP_CLOCK));
321 }
322 if (BIT(data , 2)) {
323 // Start beeper
324 m_beeper->set_state(1);
325 m_beep_timer->adjust(attotime::from_msec(BEEPER_MS));
326 }
327 if (regen_display) {
328 update_display();
329 }
330 }
331
printer_w(uint16_t data)332 void hp9825_state::printer_w(uint16_t data)
333 {
334 m_printer_mem[ m_printer_idx ] = uint8_t(data);
335 m_printer_idx = (m_printer_idx + 1) & 0xf;
336 }
337
338 // The character generator was reverse engineered from images of printer & display test patterns.
339 // It is not guaranteed to be pixel-accurate though it looks quite close to the original.
340 static const uint8_t chargen[ 128 ][ 5 ] = {
341 { 0x08,0x1c,0x3e,0x7f,0x00 }, // 00
342 { 0x30,0x48,0x45,0x40,0x30 }, // 01
343 { 0x45,0x29,0x11,0x29,0x45 }, // 02
344 { 0x7d,0x09,0x11,0x21,0x7d }, // 03
345 { 0x38,0x44,0x44,0x38,0x44 }, // 04
346 { 0x7c,0x2a,0x4a,0x4a,0x34 }, // 05
347 { 0x7f,0x01,0x01,0x01,0x03 }, // 06
348 { 0x7d,0x09,0x05,0x05,0x79 }, // 07
349 { 0x60,0x58,0x46,0x58,0x60 }, // 08
350 { 0x38,0x44,0x44,0x3c,0x04 }, // 09
351 { 0x10,0x20,0x7f,0x20,0x10 }, // 0a
352 { 0x62,0x14,0x08,0x10,0x60 }, // 0b
353 { 0x40,0x3c,0x20,0x20,0x1c }, // 0c
354 { 0x08,0x1c,0x2a,0x08,0x08 }, // 0d
355 { 0x10,0x08,0x78,0x08,0x04 }, // 0e
356 { 0x08,0x55,0x7f,0x55,0x08 }, // 0f
357 { 0x3e,0x49,0x49,0x49,0x3e }, // 10
358 { 0x5e,0x61,0x01,0x61,0x5e }, // 11
359 { 0x30,0x4a,0x4d,0x49,0x30 }, // 12
360 { 0x78,0x14,0x15,0x14,0x78 }, // 13
361 { 0x38,0x44,0x45,0x3c,0x40 }, // 14
362 { 0x78,0x15,0x14,0x15,0x78 }, // 15
363 { 0x38,0x45,0x44,0x3d,0x40 }, // 16
364 { 0x3c,0x43,0x42,0x43,0x3c }, // 17
365 { 0x38,0x45,0x44,0x45,0x38 }, // 18
366 { 0x3e,0x41,0x40,0x41,0x3e }, // 19
367 { 0x3c,0x41,0x40,0x41,0x3c }, // 1a
368 { 0x7e,0x09,0x7f,0x49,0x49 }, // 1b
369 { 0x38,0x44,0x38,0x54,0x58 }, // 1c
370 { 0x12,0x19,0x15,0x12,0x00 }, // 1d
371 { 0x48,0x7e,0x49,0x41,0x42 }, // 1e
372 { 0x55,0x2a,0x55,0x2a,0x55 }, // 1f
373 { 0x00,0x00,0x00,0x00,0x00 }, // 20
374 { 0x00,0x5f,0x00,0x00,0x00 }, // 21
375 { 0x00,0x03,0x00,0x03,0x00 }, // 22
376 { 0x14,0x7f,0x14,0x7f,0x14 }, // 23
377 { 0x24,0x2a,0x7f,0x2a,0x12 }, // 24
378 { 0x23,0x13,0x08,0x64,0x62 }, // 25
379 { 0x36,0x49,0x56,0x20,0x50 }, // 26
380 { 0x00,0x0b,0x07,0x00,0x00 }, // 27
381 { 0x00,0x00,0x3e,0x41,0x00 }, // 28
382 { 0x00,0x41,0x3e,0x00,0x00 }, // 29
383 { 0x08,0x2a,0x1c,0x2a,0x08 }, // 2a
384 { 0x08,0x08,0x3e,0x08,0x08 }, // 2b
385 { 0x00,0x58,0x38,0x00,0x00 }, // 2c
386 { 0x08,0x08,0x08,0x08,0x08 }, // 2d
387 { 0x00,0x60,0x60,0x00,0x00 }, // 2e
388 { 0x20,0x10,0x08,0x04,0x02 }, // 2f
389 { 0x3e,0x51,0x49,0x45,0x3e }, // 30
390 { 0x00,0x42,0x7f,0x40,0x00 }, // 31
391 { 0x62,0x51,0x49,0x49,0x46 }, // 32
392 { 0x22,0x41,0x49,0x49,0x36 }, // 33
393 { 0x18,0x14,0x12,0x7f,0x10 }, // 34
394 { 0x27,0x45,0x45,0x45,0x39 }, // 35
395 { 0x3c,0x4a,0x49,0x49,0x30 }, // 36
396 { 0x01,0x71,0x09,0x05,0x03 }, // 37
397 { 0x36,0x49,0x49,0x49,0x36 }, // 38
398 { 0x06,0x49,0x49,0x29,0x1e }, // 39
399 { 0x00,0x36,0x36,0x00,0x00 }, // 3a
400 { 0x00,0x5b,0x3b,0x00,0x00 }, // 3b
401 { 0x00,0x08,0x14,0x22,0x41 }, // 3c
402 { 0x14,0x14,0x14,0x14,0x14 }, // 3d
403 { 0x41,0x22,0x14,0x08,0x00 }, // 3e
404 { 0x06,0x01,0x51,0x09,0x06 }, // 3f
405 { 0x3e,0x41,0x5d,0x55,0x1e }, // 40
406 { 0x7e,0x09,0x09,0x09,0x7e }, // 41
407 { 0x7f,0x49,0x49,0x49,0x36 }, // 42
408 { 0x3e,0x41,0x41,0x41,0x22 }, // 43
409 { 0x7f,0x41,0x41,0x41,0x3e }, // 44
410 { 0x7f,0x49,0x49,0x49,0x41 }, // 45
411 { 0x7f,0x09,0x09,0x09,0x01 }, // 46
412 { 0x3e,0x41,0x41,0x51,0x72 }, // 47
413 { 0x7f,0x08,0x08,0x08,0x7f }, // 48
414 { 0x00,0x41,0x7f,0x41,0x00 }, // 49
415 { 0x20,0x40,0x40,0x40,0x3f }, // 4a
416 { 0x7f,0x08,0x14,0x22,0x41 }, // 4b
417 { 0x7f,0x40,0x40,0x40,0x40 }, // 4c
418 { 0x7f,0x02,0x0c,0x02,0x7f }, // 4d
419 { 0x7f,0x04,0x08,0x10,0x7f }, // 4e
420 { 0x3e,0x41,0x41,0x41,0x3e }, // 4f
421 { 0x7f,0x09,0x09,0x09,0x06 }, // 50
422 { 0x3e,0x41,0x51,0x21,0x5e }, // 51
423 { 0x7f,0x09,0x19,0x29,0x46 }, // 52
424 { 0x26,0x49,0x49,0x49,0x32 }, // 53
425 { 0x01,0x01,0x7f,0x01,0x01 }, // 54
426 { 0x3f,0x40,0x40,0x40,0x3f }, // 55
427 { 0x07,0x18,0x60,0x18,0x07 }, // 56
428 { 0x7f,0x20,0x10,0x20,0x7f }, // 57
429 { 0x63,0x14,0x08,0x14,0x63 }, // 58
430 { 0x03,0x04,0x78,0x04,0x03 }, // 59
431 { 0x61,0x51,0x49,0x45,0x43 }, // 5a
432 { 0x00,0x00,0x7f,0x41,0x41 }, // 5b
433 { 0x20,0x7f,0x01,0x01,0x01 }, // 5c
434 { 0x41,0x41,0x7f,0x00,0x00 }, // 5d
435 { 0x04,0x02,0x7f,0x02,0x04 }, // 5e
436 { 0x40,0x40,0x40,0x40,0x40 }, // 5f
437 { 0x00,0x07,0x0b,0x00,0x00 }, // 60
438 { 0x38,0x44,0x44,0x3c,0x40 }, // 61
439 { 0x7f,0x48,0x44,0x44,0x38 }, // 62
440 { 0x38,0x44,0x44,0x44,0x20 }, // 63
441 { 0x38,0x44,0x44,0x48,0x7f }, // 64
442 { 0x38,0x54,0x54,0x54,0x08 }, // 65
443 { 0x08,0x7e,0x09,0x02,0x00 }, // 66
444 { 0x08,0x14,0x54,0x54,0x3c }, // 67
445 { 0x7f,0x08,0x04,0x04,0x78 }, // 68
446 { 0x00,0x44,0x7d,0x40,0x00 }, // 69
447 { 0x20,0x40,0x44,0x3d,0x00 }, // 6a
448 { 0x7f,0x10,0x28,0x44,0x00 }, // 6b
449 { 0x00,0x41,0x7f,0x40,0x00 }, // 6c
450 { 0x78,0x04,0x18,0x04,0x78 }, // 6d
451 { 0x7c,0x08,0x04,0x04,0x78 }, // 6e
452 { 0x38,0x44,0x44,0x44,0x38 }, // 6f
453 { 0x7c,0x14,0x24,0x24,0x18 }, // 70
454 { 0x18,0x24,0x14,0x7c,0x40 }, // 71
455 { 0x7c,0x08,0x04,0x04,0x00 }, // 72
456 { 0x48,0x54,0x54,0x54,0x20 }, // 73
457 { 0x04,0x3e,0x44,0x20,0x00 }, // 74
458 { 0x3c,0x40,0x40,0x20,0x7c }, // 75
459 { 0x1c,0x20,0x40,0x20,0x1c }, // 76
460 { 0x3c,0x40,0x30,0x40,0x3c }, // 77
461 { 0x44,0x28,0x10,0x28,0x44 }, // 78
462 { 0x04,0x48,0x30,0x08,0x04 }, // 79
463 { 0x44,0x64,0x54,0x4c,0x44 }, // 7a
464 { 0x08,0x7c,0x04,0x7c,0x02 }, // 7b
465 { 0x00,0x00,0x7f,0x00,0x00 }, // 7c
466 { 0x08,0x08,0x2a,0x1c,0x08 }, // 7d
467 { 0x41,0x63,0x55,0x49,0x63 }, // 7e
468 { 0x7f,0x08,0x08,0x08,0x08 } // 7f
469 };
470
update_display()471 void hp9825_state::update_display()
472 {
473 m_any_cursor = false;
474 for (unsigned i = 0; i < 32; ++i) {
475 bool cursor_here = BIT(m_display_mem[ i ] , 7);
476 if (cursor_here) {
477 m_any_cursor = true;
478 }
479 bool show_cursor = m_cursor_blink && cursor_here;
480 uint8_t char_code = m_display_mem[ i ] & 0x7f;
481 for (unsigned j = 0; j < 7; ++j) {
482 uint8_t five_dots = 0;
483 if (m_display_on) {
484 for (unsigned col = 0; col < 5; col++) {
485 uint8_t char_col;
486 if (show_cursor) {
487 if (m_rpl_cursor) {
488 // Replace cursor: all pixels lit
489 char_col = ~0;
490 } else {
491 // Insert cursor: character code 0
492 char_col = chargen[ 0 ][ col ];
493 }
494 } else {
495 char_col = chargen[ char_code ][ col ];
496 }
497 if (BIT(char_col , j)) {
498 BIT_SET(five_dots , col);
499 }
500 }
501 }
502 m_display[ i ][ j ] = five_dots;
503 }
504 }
505 }
506
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::cursor_blink)507 TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::cursor_blink)
508 {
509 m_cursor_blink = !m_cursor_blink;
510 if (m_any_cursor) {
511 update_display();
512 }
513 }
514
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::kb_scan)515 TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::kb_scan)
516 {
517 ioport_value input[ 4 ]
518 { m_io_key[ 0 ]->read(),
519 m_io_key[ 1 ]->read(),
520 m_io_key[ 2 ]->read(),
521 m_io_key[ 3 ]->read()
522 };
523
524 if (m_key_pressed) {
525 // Still pressed ?
526 m_key_pressed = BIT(input[ m_scancode / 32 ] , m_scancode % 32);
527 } else {
528 int max_seq_len = 0;
529 unsigned max_seq_idx = 0;
530 for (unsigned i = 0; i < 4; i++) {
531 kb_scan_ioport(input[ i ] , *m_io_key[ i ] , i << 5 , max_seq_len , max_seq_idx);
532 }
533 if (max_seq_len) {
534 m_scancode = max_seq_idx;
535 m_key_pressed = true;
536 m_io_sys->set_irq(KDP_PA , true);
537 }
538 }
539
540 if (m_key_pressed) {
541 auto prev_cnt = m_autorepeat_cnt;
542 m_autorepeat_cnt++;
543 // Auto-repeat initial delay & frequency are entirely guessed..
544 if (BIT(m_autorepeat_cnt , 5)) {
545 // Initial delay passed
546 m_autorepeating = true;
547 }
548 if (m_autorepeating && BIT(~prev_cnt & m_autorepeat_cnt , 3)) {
549 // Repeat key every time bit 3 of autorepeat counter goes 0->1
550 m_io_sys->set_irq(KDP_PA , true);
551 }
552 } else {
553 m_autorepeating = false;
554 m_autorepeat_cnt = 0;
555 }
556 }
557
kb_scan_ioport(ioport_value pressed,ioport_port & port,unsigned idx_base,int & max_seq_len,unsigned & max_seq_idx)558 void hp9825_state::kb_scan_ioport(ioport_value pressed , ioport_port &port , unsigned idx_base , int& max_seq_len , unsigned& max_seq_idx)
559 {
560 while (pressed) {
561 unsigned bit_no = 31 - count_leading_zeros(pressed);
562 ioport_value mask = BIT_MASK<ioport_value>(bit_no);
563 int seq_len = port.field(mask)->seq().length();
564 if (seq_len > max_seq_len) {
565 max_seq_len = seq_len;
566 max_seq_idx = bit_no + idx_base;
567 }
568 pressed &= ~mask;
569 }
570 }
571
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::prt_timer)572 TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::prt_timer)
573 {
574 if (m_printer_line == 1 || m_printer_line == 9 || m_printer_line == 10) {
575 // Empty lines
576 for (unsigned i = 0; i < 110; i++) {
577 m_prt_graph_out->output(' ');
578 }
579 } else {
580 for (unsigned i = 0; i < 16; i++) {
581 for (unsigned col = 0; col < 5; col++) {
582 uint8_t pixels = chargen[ m_printer_mem[ i ] & 0x7f ][ col ];
583 m_prt_graph_out->output(BIT(pixels , m_printer_line - 2) ? '*' : ' ');
584 }
585 m_prt_graph_out->output(' ');
586 m_prt_graph_out->output(' ');
587 }
588 }
589 m_prt_graph_out->output('\n');
590 m_printer_line++;
591 if (m_printer_line <= 10) {
592 m_prt_timer->adjust(attotime::from_ticks(KDP_CLOCKS_PER_LINE , KDP_CLOCK));
593 } else {
594 m_printer_line = 0;
595 }
596 }
597
TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::beep_timer)598 TIMER_DEVICE_CALLBACK_MEMBER(hp9825_state::beep_timer)
599 {
600 m_beeper->set_state(0);
601 }
602
set_irq_slot(unsigned slot,int state)603 void hp9825_state::set_irq_slot(unsigned slot , int state)
604 {
605 int sc = m_slot_sc[ slot ];
606 assert(sc >= 0);
607 m_io_sys->set_irq(uint8_t(sc) , state);
608 }
609
set_sts_slot(unsigned slot,int state)610 void hp9825_state::set_sts_slot(unsigned slot , int state)
611 {
612 int sc = m_slot_sc[ slot ];
613 assert(sc >= 0);
614 m_io_sys->set_sts(uint8_t(sc) , state);
615 }
616
set_flg_slot(unsigned slot,int state)617 void hp9825_state::set_flg_slot(unsigned slot , int state)
618 {
619 int sc = m_slot_sc[ slot ];
620 assert(sc >= 0);
621 m_io_sys->set_flg(uint8_t(sc) , state);
622 }
623
set_dmar_slot(unsigned slot,int state)624 void hp9825_state::set_dmar_slot(unsigned slot , int state)
625 {
626 int sc = m_slot_sc[ slot ];
627 assert(sc >= 0);
628 m_io_sys->set_dmar(uint8_t(sc) , state);
629 }
630
hp9825_base(machine_config & config)631 void hp9825_state::hp9825_base(machine_config &config)
632 {
633 HP_09825_67907(config , m_cpu , MAIN_CLOCK);
634 // Just guessing... settings borrowed from hp9845
635 m_cpu->set_rw_cycles(6 , 6);
636 m_cpu->set_relative_mode(false);
637 m_cpu->set_addrmap(AS_IO , &hp9825_state::cpu_io_map);
638 m_cpu->int_cb().set(m_io_sys , FUNC(hp98x5_io_sys_device::int_r));
639 m_cpu->pa_changed_cb().set(m_io_sys , FUNC(hp98x5_io_sys_device::pa_w));
640
641 // Needed when 98035 RTC module is connected or time advances at about 1/4 the correct speed (NP misses a lot of 1kHz interrupts)
642 config.set_maximum_quantum(attotime::from_hz(5000));
643
644 HP98X5_IO_SYS(config , m_io_sys , 0);
645 m_io_sys->irl().set_inputline(m_cpu, HPHYBRID_IRL);
646 m_io_sys->irh().set_inputline(m_cpu, HPHYBRID_IRH);
647 m_io_sys->sts().set(m_cpu , FUNC(hp_09825_67907_cpu_device::status_w));
648 m_io_sys->flg().set(m_cpu , FUNC(hp_09825_67907_cpu_device::flag_w));
649 m_io_sys->dmar().set(m_cpu , FUNC(hp_09825_67907_cpu_device::dmar_w));
650
651 TIMER(config , m_cursor_timer , 0).configure_generic(FUNC(hp9825_state::cursor_blink));
652
653 // Keyboard scan timer. A scan of the whole keyboard should take 2^14 KDP clocks.
654 TIMER(config , "kb_timer" , 0).configure_periodic(FUNC(hp9825_state::kb_scan), attotime::from_ticks(16384 , KDP_CLOCK));
655
656 // Tape drive
657 HP9825_TAPE(config , m_tape , 0);
658 m_tape->flg().set([this](int state) { m_io_sys->set_flg(TAPE_PA , state); });
659 m_tape->sts().set([this](int state) { m_io_sys->set_sts(TAPE_PA , state); });
660 m_tape->dmar().set([this](int state) { m_io_sys->set_dmar(TAPE_PA , state); });
661
662 // Printer
663 BITBANGER(config , m_prt_alpha_out , 0);
664 BITBANGER(config , m_prt_graph_out , 0);
665 TIMER(config , m_prt_timer , 0).configure_generic(FUNC(hp9825_state::prt_timer));
666
667 // Beeper
668 SPEAKER(config, "mono").front_center();
669 BEEP(config, m_beeper, BEEPER_FREQ).add_route(ALL_OUTPUTS, "mono", 1.00);
670 TIMER(config , m_beep_timer , 0).configure_generic(FUNC(hp9825_state::beep_timer));
671
672 // I/O slots
673 for (unsigned slot = 0; slot < 3; slot++) {
674 auto& finder = m_io_slot[ slot ];
675 hp9845_io_slot_device& tmp( HP9845_IO_SLOT(config , finder , 0) );
676 tmp.irq().set([this , slot](int state) { set_irq_slot(slot , state); });
677 tmp.sts().set([this , slot](int state) { set_sts_slot(slot , state); });
678 tmp.flg().set([this , slot](int state) { set_flg_slot(slot , state); });
679 tmp.dmar().set([this , slot](int state) { set_dmar_slot(slot , state); });
680 }
681
682 // Optional ROM slots
683 for (auto& finder : m_rom_drawers) {
684 HP9825_OPTROM(config , finder);
685 }
686
687 config.set_default_layout(layout_hp9825);
688 }
689
690 #define IOP_MASK(x) BIT_MASK<ioport_value>((x))
691
692 static INPUT_PORTS_START(hp9825)
693 // Keyboard is arranged in a 8 x 16 matrix. Of the 128 possible positions, 102 are used.
694 // Keys are mapped on bit b of KEYn
695 // where b = (row & 1) << 4 + column, n = row >> 1
696 // column = [0..15]
697 // row = [0..7]
698 // 4 more keys are not in the matrix: 2 SHIFTs, 1 SHIFT LOCK and RESET key.
699 // Fun fact: alphanumeric keys are arranged in the matrix so that their scancode (row/column number)
700 // equals the lower case ASCII code. The person in charge of routing the keyboard PCB
701 // must have loved this arrangement...
702 PORT_START("KEY0")
703 PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,0: N/U
704 PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_NAME("Stop") // 0,1: Stop
705 PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Rewind") // 0,2: Rewind
706 PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,3: N/U
707 PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,4: N/U
708 PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,5: N/U
709 PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_UNUSED) // 0,6: N/U
710 PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Result") // 0,7: Result
711 PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line insert") // 0,8: Line insert
712 PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line delete") // 0,9: Line delete
713 PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_NAME("Execute") // 0,10: Execute
714 PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line recall") // 0,11: Line recall
715 PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Run") // 0,12: Run
716 PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Store") // 0,13: Store
717 PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Display left") // 0,14: Display left
718 PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Display right") // 0,15: Display right
719 PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME("Display down") // 1,0: Display down
720 PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME("Display up") // 1,1: Display up
721 PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_NAME("Clear") // 1,2: Clear
722 PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Print all") // 1,3: Print all
723 PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Char back") // 1,4: Char back
724 PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Char forward") // 1,5: Char forward
725 PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_INSERT) PORT_NAME("Char ins/rpl") // 1,6: Char ins/rpl
726 PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_NAME("Char delete") // 1,7: Char delete
727 PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Step") // 1,8: Step
728 PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_NAME("Continue") PORT_CHAR(13) // 1,9: Continue
729 PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_UNUSED) // 1,10: N/U
730 PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("List") // 1,11: List
731 PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Line fetch") // 1,12: Line fetch
732 PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Erase") // 1,13: Erase
733 PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Record") // 1,14: Record
734 PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Load") // 1,15: Load
735
736 PORT_START("KEY1")
737 PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 2,0: Space
738 PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,1: N/U
739 PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,2: N/U
740 PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,3: N/U
741 PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,4: N/U
742 PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,5: N/U
743 PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,6: N/U
744 PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_UNUSED) // 2,7: N/U
745 PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('(') PORT_NAME("Keypad (") // 2,8: KP (
746 PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(')') PORT_NAME("Keypad )") // 2,9: KP )
747 PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) // 2,10: KP *
748 PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) // 2,11: KP +
749 PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') // 2,12: ,
750 PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 2,13: KP -
751 PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') // 2,14: .
752 PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // 2,15: KP /
753 PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('\'') // 3,0: 0
754 PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 3,1: 1
755 PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') // 3,2: 2
756 PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 3,3: 3
757 PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 3,4: 4
758 PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 3,5: 5
759 PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') // 3,6: 6
760 PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('@') // 3,7: 7
761 PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('[') // 3,8: 8
762 PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(']') // 3,9: 9
763 PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_UNUSED) // 3,10: N/U
764 PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') // 3,11: ;
765 PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_UNUSED) // 3,12: N/U
766 PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS_PAD) PORT_CHAR(UCHAR_MAMEKEY(EQUALS_PAD)) // 3,13: =
767 PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_UNUSED) // 3,14: N/U
768 PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('?') PORT_CHAR(':') // 3,15: ?
769
770 PORT_START("KEY2")
771 PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_UNUSED) // 4,0: N/U
772 PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("f0") // 4,1: f0
773 PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("f1") // 4,2: f1
774 PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("f2") // 4,3: f2
775 PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("f3") // 4,4: f3
776 PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("f4") // 4,5: f4
777 PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("f5") // 4,6: f5
778 PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("f6") // 4,7: f6
779 PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("f7") // 4,8: f7
780 PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("f8") // 4,9: f8
781 PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) PORT_NAME("f9") // 4,10: f9
782 PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_NAME("f10") // 4,11: f10
783 PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) PORT_NAME("f11") // 4,12: f11
784 PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_UNUSED) // 4,13: N/U
785 PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) // 4,14: KP 0
786 PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 4,15: KP 1
787 PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 5,0: KP 2
788 PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 5,1: KP 3
789 PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) // 5,2: KP 4
790 PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) // 5,3: KP 5
791 PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 5,4: KP 6
792 PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) // 5,5: KP 7
793 PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) // 5,6: KP 8
794 PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) // 5,7: KP 9
795 PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) // 5,8: KP .
796 PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD)) // 5,9: KP ,
797 PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,10: N/U
798 PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,11: N/U
799 PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,12: N/U
800 PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,13: N/U
801 PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_NAME(u8"\u2191 \u221A") // 5,14: ^ (↑ √)
802 PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_UNUSED) // 5,15: N/U
803
804 PORT_START("KEY3")
805 PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME("Enter exp _") // 6,0: Enter exp
806 PORT_BIT(IOP_MASK(1) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 6,1: A
807 PORT_BIT(IOP_MASK(2) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 6,2: B
808 PORT_BIT(IOP_MASK(3) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // 6,3: C
809 PORT_BIT(IOP_MASK(4) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // 6,4: D
810 PORT_BIT(IOP_MASK(5) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 6,5: E
811 PORT_BIT(IOP_MASK(6) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 6,6: F
812 PORT_BIT(IOP_MASK(7) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 6,7: G
813 PORT_BIT(IOP_MASK(8) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 6,8: H
814 PORT_BIT(IOP_MASK(9) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 6,9: I
815 PORT_BIT(IOP_MASK(10) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // 6,10: J
816 PORT_BIT(IOP_MASK(11) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 6,11: K
817 PORT_BIT(IOP_MASK(12) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 6,12: L
818 PORT_BIT(IOP_MASK(13) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 6,13: M
819 PORT_BIT(IOP_MASK(14) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 6,14: N
820 PORT_BIT(IOP_MASK(15) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 6,15: O
821 PORT_BIT(IOP_MASK(16) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // 7,0: P
822 PORT_BIT(IOP_MASK(17) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 7,1: Q
823 PORT_BIT(IOP_MASK(18) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 7,2: R
824 PORT_BIT(IOP_MASK(19) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 7,3: S
825 PORT_BIT(IOP_MASK(20) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 7,4: T
826 PORT_BIT(IOP_MASK(21) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 7,5: U
827 PORT_BIT(IOP_MASK(22) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 7,6: V
828 PORT_BIT(IOP_MASK(23) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 7,7: W
829 PORT_BIT(IOP_MASK(24) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // 7,8: X
830 PORT_BIT(IOP_MASK(25) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 7,9: Y
831 PORT_BIT(IOP_MASK(26) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 7,10: Z
832 PORT_BIT(IOP_MASK(27) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_NAME(u8"π |") // 7,11: Pi
833 PORT_BIT(IOP_MASK(28) , IP_ACTIVE_HIGH , IPT_UNUSED) // 7,12: N/U
834 PORT_BIT(IOP_MASK(29) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_END) PORT_NAME(u8"\u2192") // 7,13: Gazinta (→)
835 PORT_BIT(IOP_MASK(30) , IP_ACTIVE_HIGH , IPT_UNUSED) // 7,14: N/U
836 PORT_BIT(IOP_MASK(31) , IP_ACTIVE_HIGH , IPT_UNUSED) // 7,15: N/U
837
838 PORT_START("KEY_SHIFT")
839 PORT_BIT(IOP_MASK(0) , IP_ACTIVE_HIGH , IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // Shift
840 INPUT_PORTS_END
841
842 // +---------------+
843 // | hp9825b_state |
844 // +---------------+
845 class hp9825b_state : public hp9825_state
846 {
847 public:
hp9825b_state(const machine_config & mconfig,device_type type,const char * tag)848 hp9825b_state(const machine_config &mconfig, device_type type, const char *tag)
849 : hp9825_state(mconfig , type , tag)
850 {
851 }
852
853 void hp9825b(machine_config &config);
854
855 protected:
856 virtual void device_reset() override;
857
858 private:
859 void cpu_mem_map(address_map &map);
860 };
861
hp9825b(machine_config & config)862 void hp9825b_state::hp9825b(machine_config &config)
863 {
864 hp9825_base(config);
865 m_cpu->set_addrmap(AS_PROGRAM , &hp9825b_state::cpu_mem_map);
866
867 for (auto& finder : m_rom_drawers) {
868 finder->set_rom_limit(0x5000);
869 }
870
871 SOFTWARE_LIST(config, "optrom_list").set_original("hp9825b_rom");
872 }
873
device_reset()874 void hp9825b_state::device_reset()
875 {
876 hp9825_state::device_reset();
877
878 auto space = &m_cpu->space(AS_PROGRAM);
879
880 for (auto& finder : m_rom_drawers) {
881 finder->install_rw_handlers(space , nullptr);
882 }
883 }
884
cpu_mem_map(address_map & map)885 void hp9825b_state::cpu_mem_map(address_map &map)
886 {
887 map.unmap_value_low();
888 map(0x0000 , 0x2fff).rom();
889 map(0x3400 , 0x3bff).rom();
890 map(0x4000 , 0x4fff).rom();
891 map(0x5000 , 0x7fff).ram();
892 }
893
894 // +---------------+
895 // | hp9825t_state |
896 // +---------------+
897 class hp9825t_state : public hp9825_state,
898 public device_memory_interface
899 {
900 public:
hp9825t_state(const machine_config & mconfig,device_type type,const char * tag)901 hp9825t_state(const machine_config &mconfig, device_type type, const char *tag)
902 : hp9825_state(mconfig , type , tag)
903 , device_memory_interface(mconfig , *this)
904 , m_skoalrom(*this , "skoalrom")
905 , m_ram_space_config("ram" , ENDIANNESS_BIG , 16 , 15 , -1)
906 , m_rom_space_config("rom" , ENDIANNESS_BIG , 16 , 15 , -1)
907 {
908 }
909
910 void hp9825t(machine_config &config);
911
912 protected:
913 virtual void machine_start() override;
914 virtual void device_reset() override;
915
916 // device_memory_interface overrides
917 virtual space_config_vector memory_space_config() const override;
918
919 private:
920 required_memory_region m_skoalrom;
921 address_space_config m_ram_space_config;
922 address_space *m_ram_space;
923 address_space_config m_rom_space_config;
924 address_space *m_rom_space;
925
926 uint8_t m_cycle_type;
927
928 // SKOAL state
929 bool m_skoalbit; // U53
930 bool m_second_access; // U57-3
931 bool m_mref; // U57-4
932 bool m_ifetch_4400; // U57-5
933 uint8_t m_special_opt; // U42
934 uint16_t m_fetch_addr;
935
936 void cpu_mem_map(address_map &map);
937 void ram_mem_map(address_map &map);
938 void rom_mem_map(address_map &map);
939 uint16_t cpu_mem_r(offs_t offset, uint16_t mem_mask = ~0);
940 void cpu_mem_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
941 void stm(uint8_t cycle_type);
942 void on_cycle_end();
943 void opcode_fetch(uint16_t opcode);
944 uint8_t get_skoalrom(uint16_t addr);
945 bool is_rom(uint16_t addr , uint8_t cycle_type) const;
946 };
947
hp9825t(machine_config & config)948 void hp9825t_state::hp9825t(machine_config &config)
949 {
950 hp9825_base(config);
951 m_cpu->set_addrmap(AS_PROGRAM , &hp9825t_state::cpu_mem_map);
952 m_cpu->stm_cb().set(FUNC(hp9825t_state::stm));
953 m_cpu->opcode_cb().set(FUNC(hp9825t_state::opcode_fetch));
954 set_addrmap(0 , &hp9825t_state::ram_mem_map);
955 set_addrmap(1 , &hp9825t_state::rom_mem_map);
956
957 for (auto& finder : m_rom_drawers) {
958 finder->set_rom_limit(0x6000);
959 }
960
961 SOFTWARE_LIST(config, "optrom_list").set_original("hp9825b_rom");
962 }
963
machine_start()964 void hp9825t_state::machine_start()
965 {
966 hp9825_state::machine_start();
967
968 m_ram_space = &space(0);
969 m_rom_space = &space(1);
970 }
971
device_reset()972 void hp9825t_state::device_reset()
973 {
974 hp9825_state::device_reset();
975
976 for (auto& finder : m_rom_drawers) {
977 finder->install_rw_handlers(m_rom_space , m_ram_space);
978 }
979
980 // This has to be done before CPU reset or first instruction won't be fetched correctly
981 m_cycle_type = 0;
982 m_special_opt = 0xf;
983 }
984
memory_space_config() const985 device_memory_interface::space_config_vector hp9825t_state::memory_space_config() const
986 {
987 return space_config_vector {
988 std::make_pair(0 , &m_ram_space_config),
989 std::make_pair(1 , &m_rom_space_config)
990 };
991 }
992
cpu_mem_map(address_map & map)993 void hp9825t_state::cpu_mem_map(address_map &map)
994 {
995 map.unmap_value_low();
996 map(0x0000 , 0x7fff).rw(FUNC(hp9825t_state::cpu_mem_r) , FUNC(hp9825t_state::cpu_mem_w));
997 }
998
ram_mem_map(address_map & map)999 void hp9825t_state::ram_mem_map(address_map &map)
1000 {
1001 // 32 kw of RAM covering the whole address space (1st kw not accessible)
1002 map(0x0000 , 0x7fff).ram();
1003 }
1004
rom_mem_map(address_map & map)1005 void hp9825t_state::rom_mem_map(address_map &map)
1006 {
1007 map.unmap_value_low();
1008 map(0x0000 , 0x2fff).rom().region(":rom" , 0);
1009 map(0x3400 , 0x3bff).rom().region(":rom" , 0x6800);
1010 map(0x4000 , 0x53ff).rom().region(":rom" , 0x8000);
1011 }
1012
cpu_mem_r(offs_t offset,uint16_t mem_mask)1013 uint16_t hp9825t_state::cpu_mem_r(offs_t offset, uint16_t mem_mask)
1014 {
1015 bool from_rom;
1016
1017 if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_RD_MASK) {
1018 if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_IFETCH_MASK) {
1019 m_fetch_addr = offset;
1020 }
1021 from_rom = is_rom(offset , m_cycle_type);
1022 LOG("rd @%04x CYC=%x %d%d%d%d ROM=%d\n" , offset , m_cycle_type , m_skoalbit , m_second_access , m_mref , m_ifetch_4400 , from_rom);
1023 if (!(m_cycle_type & (hp_hybrid_cpu_device::CYCLE_IFETCH_MASK | hp_hybrid_cpu_device::CYCLE_DMA_MASK))) {
1024 on_cycle_end();
1025 }
1026 m_cycle_type = 0;
1027 // TODO: diagnostic read
1028 } else {
1029 // Read coming from debugger and not from CPU: fake an ifetch
1030 from_rom = is_rom(offset , hp_hybrid_cpu_device::CYCLE_IFETCH_MASK);
1031 }
1032
1033 return from_rom ? m_rom_space->read_word(offset , mem_mask) : m_ram_space->read_word(offset , mem_mask);
1034 }
1035
cpu_mem_w(offs_t offset,uint16_t data,uint16_t mem_mask)1036 void hp9825t_state::cpu_mem_w(offs_t offset, uint16_t data, uint16_t mem_mask)
1037 {
1038 if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_WR_MASK) {
1039 if (!(m_cycle_type & hp_hybrid_cpu_device::CYCLE_DMA_MASK)) {
1040 on_cycle_end();
1041 }
1042 m_cycle_type = 0;
1043 }
1044 // All write cycles go to RAM
1045 m_ram_space->write_word(offset , data , mem_mask);
1046 }
1047
stm(uint8_t cycle_type)1048 void hp9825t_state::stm(uint8_t cycle_type)
1049 {
1050 LOG("stm %x\n" , cycle_type);
1051 m_cycle_type = cycle_type;
1052 if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_IFETCH_MASK) {
1053 m_second_access = false;
1054 m_mref = false;
1055 m_ifetch_4400 = false;
1056 // In case of ifetch from register area this is kept at 0 (because cpu_mem_r is not called)
1057 // In case of ifetch from RAM/ROM this is set by cpu_mem_r to the fetch address
1058 m_fetch_addr = 0;
1059 } else if (m_cycle_type & hp_hybrid_cpu_device::CYCLE_RAL_MASK) {
1060 if (!(m_cycle_type & hp_hybrid_cpu_device::CYCLE_DMA_MASK)) {
1061 on_cycle_end();
1062 }
1063 m_cycle_type = 0;
1064 }
1065 }
1066
on_cycle_end()1067 void hp9825t_state::on_cycle_end()
1068 {
1069 m_second_access = false;
1070 }
1071
opcode_fetch(uint16_t opcode)1072 void hp9825t_state::opcode_fetch(uint16_t opcode)
1073 {
1074 LOG("oc %04x\n" , opcode);
1075 m_cycle_type = 0;
1076 // memory referencing instructions
1077 m_mref = (opcode & 0x7000) != 0x7000;
1078 m_second_access = true;
1079 m_ifetch_4400 = (m_fetch_addr & 0x7f00) == 0x0900;
1080 if (BIT(m_special_opt , 3) && BIT(m_special_opt , 2)) {
1081 // Set SKOAL bit
1082 if (m_fetch_addr < 0x20) {
1083 // Fetch from registers -> SKOAL bit = 0
1084 m_skoalbit = false;
1085 } else if ((m_fetch_addr & 0x6000) == 0x6000) {
1086 // Fetch in [6000..7fff] range -> SKOAL bit = 0
1087 m_skoalbit = false;
1088 } else {
1089 uint8_t tmp = get_skoalrom(m_fetch_addr);
1090 m_skoalbit = (tmp >> ((~m_fetch_addr >> 12) & 7)) & 1;
1091 }
1092 }
1093 // Decode SKOAL instructions. They are ignored by the hybrid processor
1094 // as they are not recognized.
1095 if ((opcode & 0xffc0) == 0x7040) {
1096 m_special_opt = opcode & 0xf;
1097 if (!BIT(m_special_opt , 3)) {
1098 // RAM/ == 0
1099 m_skoalbit = false;
1100 } else if (!BIT(m_special_opt , 2)) {
1101 // ROM/ == 0
1102 m_skoalbit = true;
1103 }
1104 }
1105 }
1106
get_skoalrom(uint16_t addr)1107 uint8_t hp9825t_state::get_skoalrom(uint16_t addr)
1108 {
1109 return m_skoalrom->as_u8(~addr & 0x0fff);
1110 }
1111
is_rom(uint16_t addr,uint8_t cycle_type) const1112 bool hp9825t_state::is_rom(uint16_t addr , uint8_t cycle_type) const
1113 {
1114 if ((addr & 0x6000) == 0x6000) {
1115 // [6000..7fff] -> always RAM
1116 return false;
1117 } else if ((cycle_type & hp_hybrid_cpu_device::CYCLE_DMA_MASK) != 0 ||
1118 !BIT(m_special_opt , 1)) {
1119 // DMA cycle or BIT/ == 0 -> RAM
1120 return false;
1121 } else if (addr >= 0x400 && !BIT(m_special_opt , 0)) {
1122 // [0400..5fff] and BIN/ == 0 -> RAM
1123 return false;
1124 } else {
1125 bool addr_0800_7fff = (addr & 0x7800) != 0;
1126 bool addr_0400_07ff = !addr_0800_7fff && BIT(addr , 10);
1127 bool addr_0000_03ff = !addr_0800_7fff && !BIT(addr , 10);
1128
1129 // U58-6
1130 bool force_rom;
1131
1132 // ROM when one or more of these is true:
1133 // - addr in [0000..03ff]
1134 // - Ifetch cycle and addr in [0800..5fff]
1135 // - 2nd access of a memory-referencing instruction not in [0400..07ff] range
1136 // - skoalbit = 1 and instruction fetched in [0900..09ff] range
1137 force_rom =
1138 addr_0000_03ff ||
1139 ((cycle_type & hp_hybrid_cpu_device::CYCLE_IFETCH_MASK) != 0 && addr_0800_7fff) ||
1140 (m_second_access && m_mref && (!BIT(m_special_opt , 2) || !addr_0400_07ff)) ||
1141 (m_skoalbit && m_ifetch_4400);
1142
1143 if (force_rom) {
1144 return true;
1145 } else if (addr_0400_07ff && BIT(m_special_opt , 2)) {
1146 return false;
1147 } else {
1148 return m_skoalbit;
1149 }
1150 }
1151 }
1152
1153 ROM_START(hp9825b)
1154 ROM_REGION(0xa000 , "cpu" , ROMREGION_16BIT | ROMREGION_BE)
1155 ROM_LOAD("sysrom1.bin" , 0x0000 , 0x2000 , CRC(fe429268) SHA1(f2fe7c5abca92bd13f81b4385fc4fce0cafb0da0))
1156 ROM_LOAD("sysrom2.bin" , 0x2000 , 0x2000 , CRC(96093b5d) SHA1(c6ec4cafd019887df0fa849b3c7070bb74faee54))
1157 ROM_LOAD("sysrom3.bin" , 0x4000 , 0x2000 , CRC(f9470f67) SHA1(b80cb4a366d93bd7acc3508ce987bb11c5986b2a))
1158 ROM_LOAD("genio_t.bin" , 0x6800 , 0x0800 , CRC(ade1d1ed) SHA1(9af74a65b29ef1885f74164238ecf8d16ac995d6))
1159 ROM_LOAD("plot72.bin" , 0x7000 , 0x0800 , CRC(0a9cb8db) SHA1(d0d126fca108f2715e1e408cb31b09ba69385ac4))
1160 ROM_LOAD("advpgm_t.bin", 0x8000 , 0x0800 , CRC(965b5e5a) SHA1(ff44dd15f8fa4ca03dfd970ed8b200e8a071ec13))
1161 ROM_LOAD("extio_t.bin" , 0x8800 , 0x1000 , CRC(a708b978) SHA1(baf53c8a2b24d059f95252baf1452188eaf6e4be))
1162 ROM_LOAD("strings_t.bin",0x9800 , 0x0800 , CRC(b5ca5da5) SHA1(af13abb3c15836c566863c656e1659f7e6f96d04))
1163 ROM_END
1164
1165 ROM_START(hp9825t)
1166 ROM_REGION(0xa800 , ":rom" , ROMREGION_16BIT | ROMREGION_BE | ROMREGION_ERASE | ROMREGION_ERASE00)
1167 ROM_LOAD("sysrom1.bin" , 0x0000 , 0x2000 , CRC(fe429268) SHA1(f2fe7c5abca92bd13f81b4385fc4fce0cafb0da0))
1168 ROM_LOAD("sysrom2.bin" , 0x2000 , 0x2000 , CRC(96093b5d) SHA1(c6ec4cafd019887df0fa849b3c7070bb74faee54))
1169 ROM_LOAD("sysrom3.bin" , 0x4000 , 0x2000 , CRC(f9470f67) SHA1(b80cb4a366d93bd7acc3508ce987bb11c5986b2a))
1170 ROM_LOAD("genio_t.bin" , 0x6800 , 0x0800 , CRC(ade1d1ed) SHA1(9af74a65b29ef1885f74164238ecf8d16ac995d6))
1171 ROM_LOAD("plot72.bin" , 0x7000 , 0x0800 , CRC(0a9cb8db) SHA1(d0d126fca108f2715e1e408cb31b09ba69385ac4))
1172 ROM_LOAD("advpgm_t.bin", 0x8000 , 0x0800 , CRC(965b5e5a) SHA1(ff44dd15f8fa4ca03dfd970ed8b200e8a071ec13))
1173 ROM_LOAD("extio_t.bin" , 0x8800 , 0x1000 , CRC(a708b978) SHA1(baf53c8a2b24d059f95252baf1452188eaf6e4be))
1174 ROM_LOAD("strings_t.bin",0x9800 , 0x0800 , CRC(b5ca5da5) SHA1(af13abb3c15836c566863c656e1659f7e6f96d04))
1175 ROM_LOAD("syspgm.bin" , 0xa000 , 0x0800 , CRC(8915588f) SHA1(037f497b5ecc3216fb6b8356767cc361fb0b2945))
1176
1177 ROM_REGION(0x1000 , "skoalrom" , 0)
1178 ROM_LOAD("skoalrom.bin" , 0 , 0x1000 , CRC(5e8124d5) SHA1(dedf7f8a10c62b444f04213956083089e97bf219))
1179 ROM_END
1180
1181 // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
1182 COMP(1980, hp9825b, 0, 0, hp9825b, hp9825, hp9825b_state,empty_init, "Hewlett-Packard", "HP 9825B", 0)
1183 COMP(1980, hp9825t, 0, 0, hp9825t, hp9825, hp9825t_state,empty_init, "Hewlett-Packard", "HP 9825T", 0)
1184