1 // license:BSD-3-Clause
2 // copyright-holders:Phill Harvey-Smith, Carl
3 /*
4 machine/rmnimbus.c
5
6 Machine driver for the Research Machines Nimbus.
7
8 Phill Harvey-Smith
9 2009-11-29.
10
11 */
12
13 /*
14
15 SCSI/SASI drives supported by RM Nimbus machines
16
17 Native SCSI - format with HDFORM.EXE
18
19 Drive Capacity Tracks Heads Sec/Track Blocks
20 RO652-20 20MB 306 4 34 41616
21 ST225N 20MB 615 4 17 41721
22 ST125N 20MB 407 4 26 41921
23 8425S-30 20MB 41004
24 CP3020 20MB 623 2 33 41118
25 ST225NP 20MB 615 4 17 41720
26 CP3040 40MB 1026 2 40 82080
27
28 Via Xebec S1410 SASI to MFM bridge board - format with WINFORM.EXE
29 NP05-10S 8MB 160 6 17 16320
30 NP04-20T 16MB 320 6 17 32640
31 NP03-20 15MB 306 6 17 31212
32 R352-10 10MB 306 4 17 20808
33 NP04-50 40MB 699 7 17 83181
34 NP04-55 44MB 754 7 17 89726
35
36 Via Adaptec ACB4070 SCSI to RLL bridge board - format with ADAPT.EXE
37 NEC D5147 60MB 615 8 26 127920
38 ST227R 60MB 820 6 26 127920
39
40 After formating, the drives need to have a partition table put on them with
41 STAMP.EXE and then formatted in the normal way for a dos system drive with
42 Format /s.
43
44 The tracks, heads and sectors/track can be used with chdman createhd
45 to create a blank hard disk which can then be formatted with the RM tools.
46 The important thing when doing this is to make sure that if using the Native
47 SCSI tools, that the disk has the same number of blocks as specified above,
48 even if you have to use unusual geometry to do so !
49 Currently, only the ST225N and ST125N can be formatted as the other native
50 drives and Xebec board expect the WRITE BUFFER (0x3B) and READ BUFFER (0x3C)
51 with mode 0 commands to be implemented and the Adaptec board uses unknown
52 command 0xE4.
53
54
55 for example:
56
57 chdman createhd -o ST125N.chd -chs 41921,1,1 -ss 512
58 (the actual geometry can't be used because the block count won't match)
59
60 */
61
62 #include "emu.h"
63 #include <functional>
64
65 #include "includes/rmnimbus.h"
66 #include "debugger.h"
67 #include "debug/debugcon.h"
68 #include "debug/debugcpu.h"
69 #include "imagedev/floppy.h"
70
71
72
73 /*-------------------------------------------------------------------------*/
74 /* Defines, constants, and global variables */
75 /*-------------------------------------------------------------------------*/
76
77 /* External int vectors for chained interrupts */
78 #define EXTERNAL_INT_DISK 0x80
79 #define EXTERNAL_INT_MSM5205 0x84
80 #define EXTERNAL_INT_MOUSE_YU 0x88
81 #define EXTERNAL_INT_MOUSE_YD 0x89
82 #define EXTERNAL_INT_MOUSE_XL 0x8A
83 #define EXTERNAL_INT_MOUSE_XR 0x8B
84 #define EXTERNAL_INT_PC8031_8C 0x8c
85 #define EXTERNAL_INT_PC8031_8E 0x8E
86 #define EXTERNAL_INT_PC8031_8F 0x8F
87
88 #define HDC_DRQ_MASK 0x40
89 #define FDC_SIDE() ((m_nimbus_drives.reg400 & 0x10) >> 4)
90 #define FDC_MOTOR() ((m_nimbus_drives.reg400 & 0x20) >> 5)
91 #define FDC_DRIVE() (fdc_driveno(m_nimbus_drives.reg400 & 0x0f))
92 #define HDC_DRQ_ENABLED() ((m_nimbus_drives.reg400 & 0x40) ? 1 : 0)
93 #define FDC_DRQ_ENABLED() ((m_nimbus_drives.reg400 & 0x80) ? 1 : 0)
94
95 /* 8031/8051 Peripheral controller */
96
97 #define IPC_OUT_ADDR 0x01
98 #define IPC_OUT_READ_PEND 0x02
99 #define IPC_OUT_BYTE_AVAIL 0x04
100
101 #define IPC_IN_ADDR 0x01
102 #define IPC_IN_BYTE_AVAIL 0x02
103 #define IPC_IN_READ_PEND 0x04
104
105 /* IO unit */
106
107 #define DISK_INT_ENABLE 0x01
108 #define MSM5205_INT_ENABLE 0x04
109 #define MOUSE_INT_ENABLE 0x08
110 #define PC8031_INT_ENABLE 0x10
111
112 enum
113 {
114 MOUSE_PHASE_STATIC = 0,
115 MOUSE_PHASE_POSITIVE,
116 MOUSE_PHASE_NEGATIVE
117 };
118
119 #define MOUSE_INT_ENABLED(state) (((state)->m_iou_reg092 & MOUSE_INT_ENABLE) ? 1 : 0)
120
121 #define LINEAR_ADDR(seg,ofs) ((seg<<4)+ofs)
122
123 #define OUTPUT_SEGOFS(mess,seg,ofs) logerror("%s=%04X:%04X [%08X]\n",mess,seg,ofs,((seg<<4)+ofs))
124
125 #define LOG_SIO 0
126 #define LOG_DISK_HDD 0
127 #define LOG_DISK 0
128 #define LOG_PC8031 0
129 #define LOG_PC8031_186 0
130 #define LOG_PC8031_PORT 0
131 #define LOG_IOU 0
132 #define LOG_RAM 0
133
134 /* Debugging */
135
136 #define DEBUG_SET(flags) ((m_debug_machine & (flags))==(flags))
137 #define DEBUG_SET_STATE(flags) ((state->m_debug_machine & (flags))==(flags))
138
139 #define DEBUG_NONE 0x0000000
140 #define DECODE_BIOS 0x0000002
141 #define DECODE_BIOS_RAW 0x0000004
142 #define DECODE_DOS21 0x0000008
143
144 /* Nimbus sub-bios structures for debugging */
145
146 struct t_area_params
147 {
148 uint16_t ofs_brush;
149 uint16_t seg_brush;
150 uint16_t ofs_data;
151 uint16_t seg_data;
152 uint16_t count;
153 };
154
155 struct t_plot_string_params
156 {
157 uint16_t ofs_font;
158 uint16_t seg_font;
159 uint16_t ofs_data;
160 uint16_t seg_data;
161 uint16_t x;
162 uint16_t y;
163 uint16_t length;
164 };
165
166 struct t_nimbus_brush
167 {
168 uint16_t style;
169 uint16_t style_index;
170 uint16_t colour1;
171 uint16_t colour2;
172 uint16_t transparency;
173 uint16_t boundary_spec;
174 uint16_t boundary_colour;
175 uint16_t save_colour;
176 };
177
178
179 static int instruction_hook(device_t &device, offs_t curpc);
180
external_int(uint8_t vector,bool state)181 void rmnimbus_state::external_int(uint8_t vector, bool state)
182 {
183 if(!state && (vector != m_vector))
184 return;
185
186 m_vector = vector;
187
188 m_maincpu->int0_w(state);
189 }
190
cascade_callback()191 uint8_t rmnimbus_state::cascade_callback()
192 {
193 m_maincpu->int0_w(0);
194 return !m_vector ? m_z80sio->m1_r() : m_vector;
195 }
196
machine_reset()197 void rmnimbus_state::machine_reset()
198 {
199 /* CPU */
200 iou_reset();
201 fdc_reset();
202 hdc_reset();
203 pc8031_reset();
204 rmni_sound_reset();
205 memory_reset();
206 mouse_js_reset();
207
208 /* USER VIA 6522 port B is connected to the BBC user port */
209 m_via->write_pb(0xff);
210 }
211
machine_start()212 void rmnimbus_state::machine_start()
213 {
214 m_nimbus_mouse.m_mouse_timer=timer_alloc(TIMER_MOUSE);
215
216 /* setup debug commands */
217 if (machine().debug_flags & DEBUG_FLAG_ENABLED)
218 {
219 using namespace std::placeholders;
220 machine().debugger().console().register_command("nimbus_debug", CMDFLAG_NONE, 0, 0, 1, std::bind(&rmnimbus_state::debug_command, this, _1, _2));
221
222 /* set up the instruction hook */
223 m_maincpu->debug()->set_instruction_hook(instruction_hook);
224 }
225
226 m_debug_machine=DEBUG_NONE;
227 m_fdc->dden_w(0);
228 }
229
debug_command(int ref,const std::vector<std::string> & params)230 void rmnimbus_state::debug_command(int ref, const std::vector<std::string> ¶ms)
231 {
232 if (params.size() > 0)
233 {
234 int temp;
235 sscanf(params[0].c_str(), "%d", &temp);
236 m_debug_machine = temp;
237 }
238 else
239 {
240 machine().debugger().console().printf("Error usage : nimbus_debug <debuglevel>\n");
241 machine().debugger().console().printf("Current debuglevel=%02X\n", m_debug_machine);
242 }
243 }
244
245 /*-----------------------------------------------
246 instruction_hook - per-instruction hook
247 -----------------------------------------------*/
248
instruction_hook(device_t & device,offs_t curpc)249 static int instruction_hook(device_t &device, offs_t curpc)
250 {
251 rmnimbus_state *state = device.machine().driver_data<rmnimbus_state>();
252 address_space &space = device.memory().space(AS_PROGRAM);
253 uint8_t *addr_ptr;
254
255 addr_ptr = (uint8_t*)space.get_read_ptr(curpc);
256
257 if ((addr_ptr !=nullptr) && (addr_ptr[0]==0xCD))
258 {
259 if(DEBUG_SET_STATE(DECODE_BIOS) && (addr_ptr[1]==0xF0))
260 {
261 if(DEBUG_SET_STATE(DECODE_BIOS_RAW))
262 state->decode_subbios(&device,curpc,1);
263 else
264 state->decode_subbios(&device,curpc,0);
265 }
266
267 if(DEBUG_SET_STATE(DECODE_DOS21) && (addr_ptr[1]==0x21))
268 state->decode_dos21(&device,curpc);
269 }
270
271 return 0;
272 }
273
274 #define set_type(type_name) sprintf(type_str,type_name)
275 #define set_drv(drv_name) sprintf(drv_str,drv_name)
276 #define set_func(func_name) sprintf(func_str,func_name)
277
decode_subbios(device_t * device,offs_t pc,uint8_t raw_flag)278 void rmnimbus_state::decode_subbios(device_t *device,offs_t pc, uint8_t raw_flag)
279 {
280 char type_str[80];
281 char drv_str[80];
282 char func_str[80];
283
284 void (rmnimbus_state::*dump_dssi)(uint16_t, uint16_t, uint8_t) = &rmnimbus_state::decode_dssi_none;
285
286 uint16_t ax = m_maincpu->state_int(I8086_AX);
287 uint16_t bx = m_maincpu->state_int(I8086_BX);
288 uint16_t cx = m_maincpu->state_int(I8086_CX);
289 uint16_t ds = m_maincpu->state_int(I8086_DS);
290 uint16_t si = m_maincpu->state_int(I8086_SI);
291
292 // *** TEMP Don't show f_enquire_display_line calls !
293 if((cx==6) && (ax==43))
294 return;
295 // *** END TEMP
296
297 if(!raw_flag)
298 {
299 logerror("=======================================================================\n");
300 logerror("Sub-bios call at %08X, AX=%04X, BX=%04X, CX=%04X, DS:SI=%04X:%04X\n",pc,ax,bx,cx,ds,si);
301 }
302
303 set_type("invalid");
304 set_drv("invalid");
305 set_func("invalid");
306
307 switch (cx)
308 {
309 case 0 :
310 {
311 set_type("t_mummu");
312 set_drv("d_mummu");
313
314 switch (ax)
315 {
316 case 0 : set_func("f_get_version_number"); break;
317 case 1 : set_func("f_add_type_code"); break;
318 case 2 : set_func("f_del_typc_code"); break;
319 case 3 : set_func("f_get_TCB"); break;
320 case 4 : set_func("f_add_driver_code"); break;
321 case 5 : set_func("f_del_driver_code"); break;
322 case 6 : set_func("f_get_DCB"); break;
323 case 7 : set_func("f_get_copyright"); break;
324 }
325 }; break;
326
327 case 1 :
328 {
329 set_type("t_character");
330 set_drv("d_printer");
331
332 switch(ax)
333 {
334 case 0 : set_func("f_get_version_number"); break;
335 case 1 : set_func("f_get_output_status"); break;
336 case 2 : set_func("f_output_character"); break;
337 case 3 : set_func("f_get_input_status"); break;
338 case 4 : set_func("f_get_and_remove"); break;
339 case 5 : set_func("f_get_no_remove"); break;
340 case 6 : set_func("f_get_last_and_remove"); break;
341 case 7 : set_func("f_get_last_no_remove"); break;
342 case 8 : set_func("f_set_IO_parameters"); break;
343 }
344 }; break;
345
346 case 2 :
347 {
348 set_type("t_disk");
349
350 switch(bx)
351 {
352 case 0 : set_drv("d_floppy"); break;
353 case 1 : set_drv("d_winchester"); break;
354 case 2 : set_drv("d_tape"); break;
355 case 3 : set_drv("d_rompack"); break;
356 case 4 : set_drv("d_eeprom"); break;
357 }
358
359 switch(ax)
360 {
361 case 0 : set_func("f_get_version_number"); break;
362 case 1 : set_func("f_initialise_unit"); break;
363 case 2 : set_func("f_pseudo_init_unit"); break;
364 case 3 : set_func("f_get_device_status"); break;
365 case 4 : set_func("f_read_n_sectors"); dump_dssi = &rmnimbus_state::decode_dssi_f_rw_sectors; break;
366 case 5 : set_func("f_write_n_sectors"); dump_dssi = &rmnimbus_state::decode_dssi_f_rw_sectors; break;
367 case 6 : set_func("f_verify_n_sectors"); break;
368 case 7 : set_func("f_media_check"); break;
369 case 8 : set_func("f_recalibrate"); break;
370 case 9 : set_func("f_motors_off"); break;
371 }
372 dump_dssi = &rmnimbus_state::decode_dssi_f_rw_sectors;
373
374 }; break;
375
376 case 3 :
377 {
378 set_type("t_piconet");
379 set_drv("d_piconet");
380
381 switch(ax)
382 {
383 case 0 : set_func("f_get_version_number"); break;
384 case 1 : set_func("f_get_slave_status"); break;
385 case 2 : set_func("f_get_slave_map"); break;
386 case 3 : set_func("f_change_slave_addr"); break;
387 case 4 : set_func("f_read_slave_control"); break;
388 case 5 : set_func("f_write_slave_control"); break;
389 case 6 : set_func("f_send_data_byte"); break;
390 case 7 : set_func("f_request_data_byte"); break;
391 case 8 : set_func("f_send_data_block"); break;
392 case 9 : set_func("f_request_data_block"); break;
393 case 10 : set_func("f_reset_slave"); break;
394
395 }
396 }; break;
397
398 case 4 :
399 {
400 set_type("t_tick");
401 set_drv("d_tick");
402
403 switch(ax)
404 {
405 case 0 : set_func("f_get_version_number"); break;
406 case 1 : set_func("f_ticks_per_second"); break;
407 case 2 : set_func("f_link_tick_routine"); break;
408 case 3 : set_func("f_unlink_tick_routine"); break;
409 }
410 }; break;
411
412 case 5 :
413 {
414 set_type("t_graphics_input");
415
416 switch(bx)
417 {
418 case 0 : set_drv("d_mouse"); break;
419 case 1 : set_drv("d_joystick_1"); break;
420 case 2 : set_drv("d_joystick_2"); break;
421 }
422
423
424 switch(ax)
425 {
426 case 0 : set_func("f_get_version_number"); break;
427 case 1 : set_func("f_graphics_input_cold_start"); break;
428 case 2 : set_func("f_graphics_input_device_off"); break;
429 case 3 : set_func("f_return_button_status"); break;
430 case 4 : set_func("f_return_switch_and_button_stat"); break;
431 case 5 : set_func("f_start_tracking"); break;
432 case 6 : set_func("f_stop_tracking"); break;
433 case 7 : set_func("f_enquire_position"); break;
434 case 8 : set_func("f_set_position"); break;
435
436 case 10 : set_func("f_return_button_press_info"); break;
437 case 11 : set_func("f_return_button_release_info"); break;
438 case 12 : set_func("f_set_gain/f_set_squeaks_per_pixel_ratio"); break;
439 case 13 : set_func("f_enquire_graphics_in_misc_data"); break;
440 }
441 }; break;
442
443 case 6 :
444 {
445 set_type("t_graphics_output");
446 set_drv("d_ngc_screen");
447
448 switch(ax)
449 {
450 case 0 : set_func("f_get_version_number"); break;
451 case 1 : set_func("f_graphics_output_cold_start"); break;
452 case 2 : set_func("f_graphics_output_warm_start"); break;
453 case 3 : set_func("f_graphics_output_off"); break;
454 case 4 : set_func("f_reinit_graphics_output"); break;
455 case 5 : set_func("f_polymarker"); break;
456 case 6 : set_func("f_polyline"); dump_dssi = &rmnimbus_state::decode_dssi_f_fill_area; break;
457 case 7 : set_func("f_fill_area"); dump_dssi = &rmnimbus_state::decode_dssi_f_fill_area; break;
458 case 8 : set_func("f_flood_fill_area"); break;
459 case 9 : set_func("f_plot_character_string"); dump_dssi = &rmnimbus_state::decode_dssi_f_plot_character_string; break;
460 case 10 : set_func("f_define_graphics_clipping_area"); break;
461 case 11 : set_func("f_enquire_clipping_area_limits"); break;
462 case 12 : set_func("f_select_graphics_clipping_area"); break;
463 case 13 : set_func("f_enq_selctd_graphics_clip_area"); break;
464 case 14 : set_func("f_set_clt_element"); break;
465 case 15 : set_func("f_enquire_clt_element"); break;
466 case 16 : set_func("f_set_new_clt"); dump_dssi = &rmnimbus_state::decode_dssi_f_set_new_clt; break;
467 case 17 : set_func("f_enquire_clt_contents"); break;
468 case 18 : set_func("f_define_dithering_pattern"); break;
469 case 19 : set_func("f_enquire_dithering_pattern"); break;
470 case 20 : set_func("f_draw_sprite"); break;
471 case 21 : set_func("f_move_sprite"); break;
472 case 22 : set_func("f_erase_sprite"); break;
473 case 23 : set_func("f_read_pixel"); break;
474 case 24 : set_func("f_read_to_limit"); break;
475 case 25 : set_func("f_read_area_pixel"); break;
476 case 26 : set_func("f_write_area_pixel"); break;
477 case 27 : set_func("f_copy_area_pixel"); break;
478
479 case 29 : set_func("f_read_area_word"); break;
480 case 30 : set_func("f_write_area_word"); break;
481 case 31 : set_func("f_copy_area_word"); break;
482 case 32 : set_func("f_swap_area_word"); break;
483 case 33 : set_func("f_set_border_colour"); break;
484 case 34 : set_func("f_enquire_border_colour"); break;
485 case 35 : set_func("f_enquire_miscellaneous_data"); break;
486 case 36 : set_func("f_circle"); break;
487
488 case 38 : set_func("f_arc_of_ellipse"); break;
489 case 39 : set_func("f_isin"); break;
490 case 40 : set_func("f_icos"); break;
491 case 41 : set_func("f_define_hatching_pattern"); break;
492 case 42 : set_func("f_enquire_hatching_pattern"); break;
493 case 43 : set_func("f_enquire_display_line"); break;
494 case 44 : set_func("f_plonk_logo"); break;
495 }
496 }; break;
497
498 case 7 :
499 {
500 set_type("t_zend");
501 switch(ax)
502 {
503 case 0 : set_func("f_get_version_number"); break;
504 }
505 }; break;
506
507 case 8 :
508 {
509 set_type("t_zep");
510 switch(ax)
511 {
512 case 0 : set_func("f_get_version_number"); break;
513 }
514 }; break;
515
516 case 9 :
517 {
518 set_type("t_raw_console");
519
520 switch(bx)
521 {
522 case 0 :
523 {
524 set_drv("d_screen");
525
526 switch(ax)
527 {
528 case 0 : set_func("f_get_version_number"); break;
529 case 1 : set_func("f_plonk_char"); dump_dssi = &rmnimbus_state::decode_dssi_f_plonk_char; break;
530 case 2 : set_func("f_plonk_cursor"); break;
531 case 3 : set_func("f_kill_cursor"); break;
532 case 4 : set_func("f_scroll"); break;
533 case 5 : set_func("f_width"); dump_dssi = &rmnimbus_state::decode_dssi_generic; break;
534 case 6 : set_func("f_get_char_set"); break;
535 case 7 : set_func("f_set_char_set"); break;
536 case 8 : set_func("f_reset_char_set"); break;
537 case 9 : set_func("f_set_plonk_parameters"); break;
538 case 10 : set_func("f_set_cursor_flash_rate"); break;
539 }
540 }; break;
541
542 case 1 :
543 {
544 set_drv("d_keyboard");
545
546 switch(ax)
547 {
548 case 0 : set_func("f_get_version_number"); break;
549 case 1 : set_func("f_init_keyboard"); break;
550 case 2 : set_func("f_get_last_key_code"); break;
551 case 3 : set_func("f_get_bitmap"); break;
552 }
553 }; break;
554 }
555 }; break;
556
557 case 10 :
558 {
559 set_type("t_acoustics");
560
561 switch(bx)
562 {
563 case 0 :
564 {
565 set_drv("d_sound");
566
567 switch(ax)
568 {
569 case 0 : set_func("f_get_version_number"); break;
570 case 1 : set_func("f_sound_enable"); break;
571 case 2 : set_func("f_play_note"); break;
572 case 3 : set_func("f_get_queue_status"); break;
573 }
574 }; break;
575
576 case 1 :
577 {
578 set_drv("d_voice");
579
580 switch(ax)
581 {
582 case 0 : set_func("f_get_version_number"); break;
583 case 1 : set_func("f_talk"); break;
584 case 2 : set_func("f_wait_and_talk"); break;
585 case 3 : set_func("f_test_talking"); break;
586 }
587 }
588 }
589 }; break;
590
591 case 11 :
592 {
593 set_type("t_hard_sums");
594 switch(ax)
595 {
596 case 0 : set_func("f_get_version_number"); break;
597 }
598 }; break;
599 }
600
601 if(raw_flag)
602 {
603 (this->*dump_dssi)(ds, si, raw_flag);
604 }
605 else
606 {
607 logerror("Type=%s, Driver=%s, Function=%s\n",type_str,drv_str,func_str);
608
609 (this->*dump_dssi)(ds, si, raw_flag);
610 logerror("=======================================================================\n");
611 }
612 }
613
get_dssi_ptr(address_space & space,uint16_t ds,uint16_t si)614 static inline void *get_dssi_ptr(address_space &space, uint16_t ds, uint16_t si)
615 {
616 int addr;
617
618 addr=((ds<<4)+si);
619 // OUTPUT_SEGOFS("DS:SI",ds,si);
620
621 return space.get_read_ptr(addr);
622 }
623
decode_dssi_none(uint16_t ds,uint16_t si,uint8_t raw_flag)624 void rmnimbus_state::decode_dssi_none(uint16_t ds, uint16_t si, uint8_t raw_flag)
625 {
626 }
627
decode_dssi_generic(uint16_t ds,uint16_t si,uint8_t raw_flag)628 void rmnimbus_state::decode_dssi_generic(uint16_t ds, uint16_t si, uint8_t raw_flag)
629 {
630 address_space &space = m_maincpu->space(AS_PROGRAM);
631 uint16_t *params;
632 int count;
633
634 if(raw_flag)
635 return;
636
637 params=(uint16_t *)get_dssi_ptr(space,ds,si);
638
639 for(count=0; count<10; count++)
640 logerror("%04X ",params[count]);
641
642 logerror("\n");
643 }
644
645
decode_dssi_f_fill_area(uint16_t ds,uint16_t si,uint8_t raw_flag)646 void rmnimbus_state::decode_dssi_f_fill_area(uint16_t ds, uint16_t si, uint8_t raw_flag)
647 {
648 address_space &space = m_maincpu->space(AS_PROGRAM);
649
650 uint16_t *addr_ptr;
651 t_area_params *area_params;
652 t_nimbus_brush *brush;
653 int cocount;
654
655 area_params = (t_area_params *)get_dssi_ptr(space,ds,si);
656
657 if (!raw_flag)
658 OUTPUT_SEGOFS("SegBrush:OfsBrush",area_params->seg_brush,area_params->ofs_brush);
659
660 brush=(t_nimbus_brush *)space.get_read_ptr(LINEAR_ADDR(area_params->seg_brush,area_params->ofs_brush));
661
662 if(raw_flag)
663 {
664 logerror("\tdw\t%04X, %04X, %04X, %04X, %04X, %04X, %04X, %04X, %04X, ",
665 brush->style,brush->style_index,brush->colour1,brush->colour2,
666 brush->transparency,brush->boundary_spec,brush->boundary_colour,brush->save_colour,
667 area_params->count);
668 }
669 else
670 {
671 logerror("Brush params\n");
672 logerror("Style=%04X, StyleIndex=%04X\n",brush->style,brush->style_index);
673 logerror("Colour1=%04X, Colour2=%04X\n",brush->colour1,brush->colour2);
674 logerror("transparency=%04X, boundary_spec=%04X\n",brush->transparency,brush->boundary_spec);
675 logerror("boundary colour=%04X, save colour=%04X\n",brush->boundary_colour,brush->save_colour);
676
677
678 OUTPUT_SEGOFS("SegData:OfsData",area_params->seg_data,area_params->ofs_data);
679 }
680
681 addr_ptr = (uint16_t *)space.get_read_ptr(LINEAR_ADDR(area_params->seg_data,area_params->ofs_data));
682 for(cocount=0; cocount < area_params->count; cocount++)
683 {
684 if(raw_flag)
685 {
686 if(cocount!=(area_params->count-1))
687 logerror("%04X, %04X, ",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
688 else
689 logerror("%04X, %04X ",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
690 }
691 else
692 logerror("x=%d y=%d\n",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
693 }
694
695 if(raw_flag)
696 logerror("\n");
697 }
698
decode_dssi_f_plot_character_string(uint16_t ds,uint16_t si,uint8_t raw_flag)699 void rmnimbus_state::decode_dssi_f_plot_character_string(uint16_t ds, uint16_t si, uint8_t raw_flag)
700 {
701 address_space &space = m_maincpu->space(AS_PROGRAM);
702
703 uint8_t *char_ptr;
704 t_plot_string_params *plot_string_params;
705 int charno;
706
707 if(raw_flag)
708 return;
709
710 plot_string_params=(t_plot_string_params *)get_dssi_ptr(space,ds,si);
711
712 OUTPUT_SEGOFS("SegFont:OfsFont",plot_string_params->seg_font,plot_string_params->ofs_font);
713 OUTPUT_SEGOFS("SegData:OfsData",plot_string_params->seg_data,plot_string_params->ofs_data);
714
715 logerror("x=%d, y=%d, length=%d\n",plot_string_params->x,plot_string_params->y,plot_string_params->length);
716
717 char_ptr=(uint8_t*)space.get_read_ptr(LINEAR_ADDR(plot_string_params->seg_data,plot_string_params->ofs_data));
718
719 if (plot_string_params->length==0xFFFF)
720 logerror("%s",char_ptr);
721 else
722 for(charno=0;charno<plot_string_params->length;charno++)
723 logerror("%c",char_ptr[charno]);
724
725 logerror("\n");
726 }
727
decode_dssi_f_set_new_clt(uint16_t ds,uint16_t si,uint8_t raw_flag)728 void rmnimbus_state::decode_dssi_f_set_new_clt(uint16_t ds, uint16_t si, uint8_t raw_flag)
729 {
730 address_space &space = m_maincpu->space(AS_PROGRAM);
731 uint16_t *new_colours;
732 int colour;
733 new_colours=(uint16_t *)get_dssi_ptr(space,ds,si);
734
735 if(raw_flag)
736 return;
737
738 OUTPUT_SEGOFS("SegColours:OfsColours",ds,si);
739
740 for(colour=0;colour<16;colour++)
741 logerror("colour #%02X=%04X\n",colour,new_colours[colour]);
742
743 }
744
decode_dssi_f_plonk_char(uint16_t ds,uint16_t si,uint8_t raw_flag)745 void rmnimbus_state::decode_dssi_f_plonk_char(uint16_t ds, uint16_t si, uint8_t raw_flag)
746 {
747 address_space &space = m_maincpu->space(AS_PROGRAM);
748 uint16_t *params;
749 params=(uint16_t *)get_dssi_ptr(space,ds,si);
750
751 if(raw_flag)
752 return;
753
754 OUTPUT_SEGOFS("SegParams:OfsParams",ds,si);
755
756 logerror("plonked_char=%c\n",params[0]);
757 }
758
decode_dssi_f_rw_sectors(uint16_t ds,uint16_t si,uint8_t raw_flag)759 void rmnimbus_state::decode_dssi_f_rw_sectors(uint16_t ds, uint16_t si, uint8_t raw_flag)
760 {
761 address_space &space = m_maincpu->space(AS_PROGRAM);
762 uint16_t *params;
763 int param_no;
764
765 if(raw_flag)
766 return;
767
768 params=(uint16_t *)get_dssi_ptr(space,ds,si);
769
770 for(param_no=0;param_no<16;param_no++)
771 logerror("%04X ",params[param_no]);
772
773 logerror("\n");
774 }
775
decode_dos21(device_t * device,offs_t pc)776 void rmnimbus_state::decode_dos21(device_t *device,offs_t pc)
777 {
778 uint16_t ax = m_maincpu->state_int(I8086_AX);
779 uint16_t bx = m_maincpu->state_int(I8086_BX);
780 uint16_t cx = m_maincpu->state_int(I8086_CX);
781 uint16_t dx = m_maincpu->state_int(I8086_DX);
782 uint16_t cs = m_maincpu->state_int(I8086_CS);
783 uint16_t ds = m_maincpu->state_int(I8086_DS);
784 uint16_t es = m_maincpu->state_int(I8086_ES);
785 uint16_t ss = m_maincpu->state_int(I8086_SS);
786
787 uint16_t si = m_maincpu->state_int(I8086_SI);
788 uint16_t di = m_maincpu->state_int(I8086_DI);
789 uint16_t bp = m_maincpu->state_int(I8086_BP);
790
791 logerror("=======================================================================\n");
792 logerror("DOS Int 0x21 call at %05X\n",pc);
793 logerror("AX=%04X, BX=%04X, CX=%04X, DX=%04X\n",ax,bx,cx,dx);
794 logerror("CS=%04X, DS=%04X, ES=%04X, SS=%04X\n",cs,ds,es,ss);
795 logerror("SI=%04X, DI=%04X, BP=%04X\n",si,di,bp);
796 logerror("=======================================================================\n");
797 }
798
799
800 /*
801 The Nimbus has 3 banks of memory each of which can be either 16x4164 or 16x41256 giving
802 128K or 512K per bank. These banks are as follows :
803
804 bank0 on nimbus motherboard.
805 bank1 first half of expansion card.
806 bank2 second half of expansion card.
807
808 The valid combinations are :
809
810 bank0 bank1 bank2 total
811 128K 128K
812 128K 128K 256K
813 128K 128K 128K 384K
814 128K 512K 640K (1)
815 512K 128K 640K (2)
816 512K 512K 1024K
817 512K 512K 512K 1536K
818
819 It will be noted that there are two possible ways of getting 640K, we emulate method 2
820 (above).
821
822 To allow for the greatest flexibility, the Nimbus allows 4 methods of mapping the
823 banks of ram into the 1M addressable by the 81086.
824
825 With only 128K banks present, they are mapped into the first 3 blocks of 128K in
826 the memory map giving a total of up to 384K.
827
828 If any of the blocks are 512K, then the block size is set to 512K and the map arranged
829 so that the bottom block is a 512K block (if both 512K and 128K blocks are available).
830
831 This is all determined by the value written to port 80 :-
832
833 port80 = 0x07 start end
834 block0 0x00000 0x1FFFF
835 block1 0x20000 0x3FFFF
836 block2 0x40000 0x5FFFF
837
838 port80 = 0x1F
839 block0 0x00000 0x7FFFF
840 block1 0x80000 0xEFFFF (0x9FFFF if 128K (2))
841
842 port80 = 0x0F
843 block1 0x00000 0x7FFFF
844 block0 0x80000 0xEFFFF (0x9FFFF if 128K (1))
845
846 port80 = 0x17
847 block1 0x00000 0x7FFFF
848 block2 0x80000 0xEFFFF
849
850 */
851
852 struct nimbus_meminfo
853 {
854 offs_t start; /* start address of bank */
855 offs_t end; /* End address of bank */
856 };
857
858 static const struct nimbus_meminfo memmap[] =
859 {
860 { 0x00000, 0x1FFFF },
861 { 0x20000, 0x3FFFF },
862 { 0x40000, 0x5FFFF },
863 { 0x60000, 0x7FFFF },
864 { 0x80000, 0x9FFFF },
865 { 0xA0000, 0xBFFFF },
866 { 0xC0000, 0xDFFFF },
867 { 0xE0000, 0xEFFFF }
868 };
869
870 struct nimbus_block
871 {
872 int blockbase;
873 int blocksize;
874 };
875
876 typedef nimbus_block nimbus_blocks[3];
877
878 static const nimbus_blocks ramblocks[] =
879 {
880 {{ 0, 128 }, { 000, 000 }, { 000, 000 }} ,
881 {{ 0, 128 }, { 128, 128 }, { 000, 000 }} ,
882 {{ 0, 128 }, { 128, 128 }, { 256, 128 }} ,
883 {{ 0, 512 }, { 000, 000 }, { 000, 000 }} ,
884 {{ 0, 512 }, { 512, 128 }, { 000, 000 }} ,
885 {{ 0, 512 }, { 512, 512 }, { 000, 000 }} ,
886 {{ 0, 512 }, { 512, 512 }, { 1024, 512 } }
887 };
888
nimbus_bank_memory()889 void rmnimbus_state::nimbus_bank_memory()
890 {
891 address_space &space = m_maincpu->space(AS_PROGRAM);
892 int ramsize = m_ram->size();
893 int ramblock = 0;
894 int blockno;
895 char bank[10];
896 uint8_t *ram = &m_ram->pointer()[0];
897 uint8_t *map_blocks[3];
898 uint8_t *map_base;
899 int map_blockno;
900 int block_ofs;
901
902 uint8_t ramsel = (m_mcu_reg080 & 0x1F);
903
904 // Invalid ramsel, return.
905 if((ramsel & 0x07)!=0x07)
906 return;
907
908 switch (ramsize / 1024)
909 {
910 case 128 : ramblock=0; break;
911 case 256 : ramblock=1; break;
912 case 384 : ramblock=2; break;
913 case 512 : ramblock=3; break;
914 case 640 : ramblock=4; break;
915 case 1024 : ramblock=5; break;
916 case 1536 : ramblock=6; break;
917 }
918
919 map_blocks[0] = ram;
920 map_blocks[1] = (ramblocks[ramblock][1].blocksize==0) ? nullptr : &ram[ramblocks[ramblock][1].blockbase*1024];
921 map_blocks[2] = (ramblocks[ramblock][2].blocksize==0) ? nullptr : &ram[ramblocks[ramblock][2].blockbase*1024];
922
923 //if(LOG_RAM) logerror("\n\nmcu_reg080=%02X, ramblock=%d, map_blocks[0]=%X, map_blocks[1]=%X, map_blocks[2]=%X\n",m_mcu_reg080,ramblock,(int)map_blocks[0],(int)map_blocks[1],(int)map_blocks[2]);
924
925 for(blockno=0;blockno<8;blockno++)
926 {
927 sprintf(bank,"bank%d",blockno);
928
929 switch (ramsel)
930 {
931 case 0x07 : (blockno<3) ? map_blockno=blockno : map_blockno=-1; break;
932 case 0x1F : (blockno<4) ? map_blockno=0 : map_blockno=1; break;
933 case 0x0F : (blockno<4) ? map_blockno=1 : map_blockno=0; break;
934 case 0x17 : (blockno<4) ? map_blockno=1 : map_blockno=2; break;
935 default : map_blockno=-1;
936 }
937 block_ofs=(ramsel==0x07) ? 0 : ((blockno % 4)*128);
938
939
940 if(LOG_RAM) logerror("mapped %s",bank);
941
942 if((map_blockno>-1) && (block_ofs < ramblocks[ramblock][map_blockno].blocksize) &&
943 (map_blocks[map_blockno]!=nullptr))
944 {
945 map_base=(ramsel==0x07) ? map_blocks[map_blockno] : &map_blocks[map_blockno][block_ofs*1024];
946
947 membank(bank)->set_base(map_base);
948 space.install_readwrite_bank(memmap[blockno].start, memmap[blockno].end, bank);
949 //if(LOG_RAM) logerror(", base=%X\n",(int)map_base);
950 }
951 else
952 {
953 space.nop_readwrite(memmap[blockno].start, memmap[blockno].end);
954 if(LOG_RAM) logerror("NOP\n");
955 }
956 }
957 }
958
nimbus_mcu_r()959 uint8_t rmnimbus_state::nimbus_mcu_r()
960 {
961 return m_mcu_reg080;
962 }
963
nimbus_mcu_w(uint8_t data)964 void rmnimbus_state::nimbus_mcu_w(uint8_t data)
965 {
966 m_mcu_reg080=data;
967
968 nimbus_bank_memory();
969 }
970
memory_reset()971 void rmnimbus_state::memory_reset()
972 {
973 m_mcu_reg080=0x07;
974 nimbus_bank_memory();
975 }
976
977 /*
978
979 Z80SIO, used for the keyboard interface
980
981 */
982
983 /* Z80 SIO/2 */
984
WRITE_LINE_MEMBER(rmnimbus_state::sio_interrupt)985 WRITE_LINE_MEMBER(rmnimbus_state::sio_interrupt)
986 {
987 if(LOG_SIO)
988 logerror("SIO Interrupt state=%02X\n",state);
989
990 external_int(0, state);
991 }
992
993 /* Floppy disk */
994
fdc_reset()995 void rmnimbus_state::fdc_reset()
996 {
997 m_nimbus_drives.reg400=0;
998 m_scsi_ctrl_out->write(0);
999 }
1000
WRITE_LINE_MEMBER(rmnimbus_state::nimbus_fdc_intrq_w)1001 WRITE_LINE_MEMBER(rmnimbus_state::nimbus_fdc_intrq_w)
1002 {
1003 if(LOG_DISK)
1004 logerror("nimbus_drives_intrq = %d\n",state);
1005
1006 if(m_iou_reg092 & DISK_INT_ENABLE)
1007 {
1008 external_int(EXTERNAL_INT_DISK,state);
1009 }
1010 }
1011
WRITE_LINE_MEMBER(rmnimbus_state::nimbus_fdc_drq_w)1012 WRITE_LINE_MEMBER(rmnimbus_state::nimbus_fdc_drq_w)
1013 {
1014 if(LOG_DISK)
1015 logerror("nimbus_drives_drq_w(%d)\n", state);
1016
1017 m_maincpu->drq1_w(state && FDC_DRQ_ENABLED());
1018 }
1019
fdc_driveno(uint8_t drivesel)1020 uint8_t rmnimbus_state::fdc_driveno(uint8_t drivesel)
1021 {
1022 switch (drivesel)
1023 {
1024 case 0x01: return 0;
1025 case 0x02: return 1;
1026 case 0x04: return 2;
1027 case 0x08: return 3;
1028 case 0x10: return 4;
1029 case 0x20: return 5;
1030 case 0x40: return 6;
1031 case 0x80: return 7;
1032 default: return 0;
1033 }
1034 }
1035
1036 /*
1037 0x410 read bits
1038
1039 0 Ready from floppy
1040 1 Index pulse from floppy
1041 2 Motor on from floppy
1042 3 MSG from HDD
1043 4 !BSY from HDD
1044 5 !I/O from HDD
1045 6 !C/D
1046 7 !REQ from HDD
1047 */
1048
scsi_r(offs_t offset)1049 uint8_t rmnimbus_state::scsi_r(offs_t offset)
1050 {
1051 int result = 0;
1052
1053 int pc=m_maincpu->pc();
1054 char drive[5];
1055 floppy_image_device *floppy;
1056
1057 sprintf(drive, "%d", FDC_DRIVE());
1058 floppy = m_fdc->subdevice<floppy_connector>(drive)->get_device();
1059
1060 switch(offset*2)
1061 {
1062 case 0x00 :
1063 result |= m_scsi_req << 7;
1064 result |= m_scsi_cd << 6;
1065 result |= m_scsi_io << 5;
1066 result |= m_scsi_bsy << 4;
1067 result |= !m_scsi_msg << 3;
1068 if(floppy)
1069 {
1070 result |= FDC_MOTOR() << 2;
1071 result |= (!floppy->idx_r()) << 1;
1072 result |= floppy->ready_r() << 0;
1073 }
1074 break;
1075 case 0x08 :
1076 result = m_scsi_data_in->read();
1077 hdc_post_rw();
1078 default:
1079 break;
1080 }
1081
1082 if(LOG_DISK_HDD)
1083 logerror("Nimbus HDCR at pc=%08X from %04X data=%02X\n",pc,(offset*2)+0x410,result);
1084
1085 return result;
1086 }
1087
1088 /*
1089 0x400 write bits
1090
1091 0 drive 0 select
1092 1 drive 1 select
1093 2 drive 2 select
1094 3 drive 3 select
1095 4 side select
1096 5 fdc motor on
1097 6 hdc drq enabled
1098 7 fdc drq enabled
1099 */
fdc_ctl_w(uint8_t data)1100 void rmnimbus_state::fdc_ctl_w(uint8_t data)
1101 {
1102 uint8_t reg400_old = m_nimbus_drives.reg400;
1103 char drive[5];
1104 floppy_image_device *floppy;
1105
1106 m_nimbus_drives.reg400 = data;
1107
1108 sprintf(drive, "%d", FDC_DRIVE());
1109 floppy = m_fdc->subdevice<floppy_connector>(drive)->get_device();
1110
1111 m_fdc->set_floppy(floppy);
1112 if(floppy)
1113 {
1114 floppy->ss_w(FDC_SIDE());
1115 floppy->mon_w(!FDC_MOTOR());
1116 }
1117
1118 // if we enable hdc drq with a pending condition, act on it
1119 if((data & HDC_DRQ_MASK) && (~reg400_old & HDC_DRQ_MASK))
1120 hdc_drq(true);
1121 }
1122
1123 /*
1124 0x410 write bits
1125
1126 0 SCSI reset
1127 1 SCSI SEL
1128 2 SCSI IRQ Enable
1129 */
1130
scsi_w(offs_t offset,uint8_t data)1131 void rmnimbus_state::scsi_w(offs_t offset, uint8_t data)
1132 {
1133 int pc=m_maincpu->pc();
1134
1135 if(LOG_DISK_HDD)
1136 logerror("Nimbus HDCW at %05X write of %02X to %04X\n",pc,data,(offset*2)+0x410);
1137
1138 switch(offset*2)
1139 {
1140 case 0x00 :
1141 m_scsi_ctrl_out->write(data);
1142 break;
1143
1144 case 0x08 :
1145 m_scsi_data_out->write(data);
1146 hdc_post_rw();
1147 break;
1148 }
1149 }
1150
hdc_reset()1151 void rmnimbus_state::hdc_reset()
1152 {
1153 m_scsi_iena = 0;
1154 m_scsi_msg = 0;
1155 m_scsi_bsy = 0;
1156 m_scsi_io = 0;
1157 m_scsi_cd = 0;
1158 m_scsi_req = 0;
1159 }
1160
check_scsi_irq()1161 void rmnimbus_state::check_scsi_irq()
1162 {
1163 nimbus_fdc_intrq_w(m_scsi_io && m_scsi_cd && m_scsi_req && m_scsi_iena);
1164 }
1165
WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_iena)1166 WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_iena)
1167 {
1168 m_scsi_iena = state;
1169 check_scsi_irq();
1170 }
1171
hdc_post_rw()1172 void rmnimbus_state::hdc_post_rw()
1173 {
1174 if(m_scsi_req)
1175 m_scsibus->write_ack(1);
1176 }
1177
hdc_drq(bool state)1178 void rmnimbus_state::hdc_drq(bool state)
1179 {
1180 m_maincpu->drq1_w(HDC_DRQ_ENABLED() && !m_scsi_cd && state);
1181 }
1182
WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_bsy)1183 WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_bsy )
1184 {
1185 m_scsi_bsy = state;
1186 }
1187
WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_cd)1188 WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_cd )
1189 {
1190 m_scsi_cd = state;
1191 check_scsi_irq();
1192 }
1193
WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_io)1194 WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_io )
1195 {
1196 m_scsi_io = state;
1197
1198 if (m_scsi_io)
1199 {
1200 m_scsi_data_out->write(0);
1201 }
1202 check_scsi_irq();
1203 }
1204
WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_msg)1205 WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_msg )
1206 {
1207 m_scsi_msg = state;
1208 }
1209
WRITE_LINE_MEMBER(rmnimbus_state::write_scsi_req)1210 WRITE_LINE_MEMBER( rmnimbus_state::write_scsi_req )
1211 {
1212 int last = m_scsi_req;
1213 m_scsi_req = state;
1214
1215 if (state)
1216 {
1217 if (!m_scsi_cd && !last)
1218 {
1219 hdc_drq(true);
1220 }
1221 }
1222 else
1223 {
1224 hdc_drq(false);
1225 m_scsibus->write_ack(0);
1226 }
1227 check_scsi_irq();
1228 }
1229
1230 /* 8031/8051 Peripheral controller 80186 side */
1231
pc8031_reset()1232 void rmnimbus_state::pc8031_reset()
1233 {
1234 logerror("peripheral controller reset\n");
1235
1236 memset(&m_ipc_interface,0,sizeof(m_ipc_interface));
1237 }
1238
1239
1240 #if 0
1241 void rmnimbus_state::ipc_dumpregs()
1242 {
1243 logerror("in_data=%02X, in_status=%02X, out_data=%02X, out_status=%02X\n",
1244 m_ipc_interface.ipc_in, m_ipc_interface.status_in,
1245 m_ipc_interface.ipc_out, m_ipc_interface.status_out);
1246
1247 }
1248 #endif
1249
nimbus_pc8031_r(offs_t offset)1250 uint8_t rmnimbus_state::nimbus_pc8031_r(offs_t offset)
1251 {
1252 int pc=m_maincpu->pc();
1253 uint8_t result;
1254
1255 switch(offset*2)
1256 {
1257 case 0x00 : result=m_ipc_interface.ipc_out;
1258 m_ipc_interface.status_in &= ~IPC_IN_READ_PEND;
1259 m_ipc_interface.status_out &= ~IPC_OUT_BYTE_AVAIL;
1260 break;
1261
1262 case 0x02 : result=m_ipc_interface.status_out;
1263 break;
1264
1265 default : result=0; break;
1266 }
1267
1268 if(LOG_PC8031_186)
1269 logerror("Nimbus PCIOR %08X read of %04X returns %02X\n",pc,(offset*2)+0xC0,result);
1270
1271 return result;
1272 }
1273
nimbus_pc8031_w(offs_t offset,uint8_t data)1274 void rmnimbus_state::nimbus_pc8031_w(offs_t offset, uint8_t data)
1275 {
1276 int pc=m_maincpu->pc();
1277
1278 switch(offset*2)
1279 {
1280 case 0x00 : m_ipc_interface.ipc_in=data;
1281 m_ipc_interface.status_in |= IPC_IN_BYTE_AVAIL;
1282 m_ipc_interface.status_in &= ~IPC_IN_ADDR;
1283 m_ipc_interface.status_out |= IPC_OUT_READ_PEND;
1284 break;
1285
1286 case 0x02 : m_ipc_interface.ipc_in=data;
1287 m_ipc_interface.status_in |= IPC_IN_BYTE_AVAIL;
1288 m_ipc_interface.status_in |= IPC_IN_ADDR;
1289 m_ipc_interface.status_out |= IPC_OUT_READ_PEND;
1290 break;
1291 }
1292
1293 if(LOG_PC8031_186)
1294 logerror("Nimbus PCIOW %08X write of %02X to %04X\n",pc,data,(offset*2)+0xC0);
1295
1296 }
1297
1298 /* 8031/8051 Peripheral controller 8031/8051 side */
1299
nimbus_pc8031_iou_r(offs_t offset)1300 uint8_t rmnimbus_state::nimbus_pc8031_iou_r(offs_t offset)
1301 {
1302 int pc=m_iocpu->pc();
1303 uint8_t result = 0;
1304
1305 switch (offset & 0x01)
1306 {
1307 case 0x00 : result=m_ipc_interface.ipc_in;
1308 m_ipc_interface.status_out &= ~IPC_OUT_READ_PEND;
1309 m_ipc_interface.status_in &= ~IPC_IN_BYTE_AVAIL;
1310 break;
1311
1312 case 0x01 : result=m_ipc_interface.status_in;
1313 break;
1314 }
1315
1316 if(((offset==2) || (offset==3)) && (m_iou_reg092 & PC8031_INT_ENABLE))
1317 external_int(EXTERNAL_INT_PC8031_8C, true);
1318
1319 if(LOG_PC8031)
1320 logerror("8031: PCIOR %04X read of %04X returns %02X\n",pc,offset,result);
1321
1322 return result;
1323 }
1324
nimbus_pc8031_iou_w(offs_t offset,uint8_t data)1325 void rmnimbus_state::nimbus_pc8031_iou_w(offs_t offset, uint8_t data)
1326 {
1327 int pc=m_iocpu->pc();
1328
1329 if(LOG_PC8031)
1330 logerror("8031 PCIOW %04X write of %02X to %04X\n",pc,data,offset);
1331
1332 switch(offset & 0x03)
1333 {
1334 case 0x00 : m_ipc_interface.ipc_out=data;
1335 m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
1336 m_ipc_interface.status_out &= ~IPC_OUT_ADDR;
1337 m_ipc_interface.status_in |= IPC_IN_READ_PEND;
1338 break;
1339
1340 case 0x01 : m_ipc_interface.ipc_out=data;
1341 m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
1342 m_ipc_interface.status_out |= IPC_OUT_ADDR;
1343 m_ipc_interface.status_in |= IPC_IN_READ_PEND;
1344 break;
1345
1346 case 0x02 : m_ipc_interface.ipc_out=data;
1347 m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
1348 m_ipc_interface.status_out &= ~IPC_OUT_ADDR;
1349 m_ipc_interface.status_in |= IPC_IN_READ_PEND;
1350 if(m_iou_reg092 & PC8031_INT_ENABLE)
1351 external_int(EXTERNAL_INT_PC8031_8F, true);
1352 break;
1353
1354 case 0x03 : m_ipc_interface.ipc_out=data;
1355 //m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
1356 m_ipc_interface.status_out |= IPC_OUT_ADDR;
1357 m_ipc_interface.status_in |= IPC_IN_READ_PEND;
1358 if(m_iou_reg092 & PC8031_INT_ENABLE)
1359 external_int(EXTERNAL_INT_PC8031_8E, true);
1360 break;
1361 }
1362 }
1363
nimbus_pc8031_port1_r()1364 uint8_t rmnimbus_state::nimbus_pc8031_port1_r()
1365 {
1366 int pc=m_iocpu->pc();
1367 uint8_t result = (m_eeprom_bits & ~4) | (m_eeprom->do_read() << 2);
1368
1369 if(LOG_PC8031_PORT)
1370 logerror("8031: PCPORTR %04X read of P1 returns %02X\n",pc,result);
1371
1372 return result;
1373 }
1374
nimbus_pc8031_port3_r()1375 uint8_t rmnimbus_state::nimbus_pc8031_port3_r()
1376 {
1377 int pc=m_iocpu->pc();
1378 uint8_t result = 0;
1379
1380 if(LOG_PC8031_PORT)
1381 logerror("8031: PCPORTR %04X read of P3 returns %02X\n",pc,result);
1382
1383 return result;
1384 }
1385
nimbus_pc8031_port1_w(uint8_t data)1386 void rmnimbus_state::nimbus_pc8031_port1_w(uint8_t data)
1387 {
1388 int pc=m_iocpu->pc();
1389
1390 m_eeprom->cs_write((data & 8) ? 1 : 0);
1391
1392 if(!(data & 8))
1393 m_eeprom_state = 0;
1394 else if(!(data & 2) || (m_eeprom_state == 2))
1395 m_eeprom_state = 2;
1396 else if((data & 8) && (!(m_eeprom_bits & 8)))
1397 m_eeprom_state = 1;
1398 else if((!(data & 1)) && (m_eeprom_bits & 1) && (m_eeprom_state == 1))
1399 m_eeprom_state = 2; //wait until 1 clk after cs rises to set di else it's seen as a start bit
1400
1401 m_eeprom->di_write(((data & 2) && (m_eeprom_state == 2)) ? 1 : 0);
1402 m_eeprom->clk_write((data & 1) ? 1 : 0);
1403 m_eeprom_bits = data;
1404
1405 if(LOG_PC8031_PORT)
1406 logerror("8031 PCPORTW %04X write of %02X to P1\n",pc,data);
1407 }
1408
nimbus_pc8031_port3_w(uint8_t data)1409 void rmnimbus_state::nimbus_pc8031_port3_w(uint8_t data)
1410 {
1411 int pc=m_iocpu->pc();
1412
1413 if(LOG_PC8031_PORT)
1414 logerror("8031 PCPORTW %04X write of %02X to P3\n",pc,data);
1415 }
1416
1417
1418 /* IO Unit */
nimbus_iou_r(offs_t offset)1419 uint8_t rmnimbus_state::nimbus_iou_r(offs_t offset)
1420 {
1421 int pc=m_maincpu->pc();
1422 uint8_t result=0;
1423
1424 if(offset==0)
1425 {
1426 result=m_iou_reg092;
1427 }
1428
1429 if(LOG_IOU)
1430 logerror("Nimbus IOUR %08X read of %04X returns %02X\n",pc,(offset*2)+0x92,result);
1431
1432 return result;
1433 }
1434
nimbus_iou_w(offs_t offset,uint8_t data)1435 void rmnimbus_state::nimbus_iou_w(offs_t offset, uint8_t data)
1436 {
1437 int pc=m_maincpu->pc();
1438
1439 if(LOG_IOU)
1440 logerror("Nimbus IOUW %08X write of %02X to %04X\n",pc,data,(offset*2)+0x92);
1441
1442 if(offset==0)
1443 {
1444 m_iou_reg092=data;
1445 m_msm->reset_w((data & MSM5205_INT_ENABLE) ? 0 : 1);
1446 }
1447 }
1448
iou_reset()1449 void rmnimbus_state::iou_reset()
1450 {
1451 m_iou_reg092=0x00;
1452 m_eeprom_state = 0;
1453 }
1454
1455 /*
1456 Sound hardware : AY8910
1457
1458 I believe that the IO ports of the 8910 are used to control the ROMPack ports, however
1459 this is currently un-implemented (and may never be as I don't have any rompacks!).
1460
1461 The registers are mapped as so :
1462
1463 Address 0xE0 0xE2
1464 Read Data ????
1465 Write Register Address Data
1466
1467 */
1468
rmni_sound_reset()1469 void rmnimbus_state::rmni_sound_reset()
1470 {
1471 m_msm->reset_w(1);
1472
1473 m_last_playmode = msm5205_device::S48_4B;
1474 m_msm->playmode_w(m_last_playmode);
1475
1476 m_ay8910_a=0;
1477 }
1478
nimbus_sound_ay8910_porta_w(uint8_t data)1479 void rmnimbus_state::nimbus_sound_ay8910_porta_w(uint8_t data)
1480 {
1481 m_msm->data_w(data);
1482
1483 // Mouse code needs a copy of this.
1484 m_ay8910_a=data;
1485 }
1486
nimbus_sound_ay8910_portb_w(uint8_t data)1487 void rmnimbus_state::nimbus_sound_ay8910_portb_w(uint8_t data)
1488 {
1489 if ((data & 0x07) != m_last_playmode)
1490 {
1491 m_last_playmode = (data & 0x07);
1492 m_msm->playmode_w(m_last_playmode);
1493 }
1494 }
1495
WRITE_LINE_MEMBER(rmnimbus_state::nimbus_msm5205_vck)1496 WRITE_LINE_MEMBER(rmnimbus_state::nimbus_msm5205_vck)
1497 {
1498 if(m_iou_reg092 & MSM5205_INT_ENABLE)
1499 external_int(EXTERNAL_INT_MSM5205,state);
1500 }
1501
1502 static const int MOUSE_XYA[3][4] = { { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 1, 0 } };
1503 static const int MOUSE_XYB[3][4] = { { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 1, 1, 0, 0 } };
1504 //static const int MOUSE_XYA[4] = { 1, 1, 0, 0 };
1505 //static const int MOUSE_XYB[4] = { 0, 1, 1, 0 };
1506
mouse_js_reset()1507 void rmnimbus_state::mouse_js_reset()
1508 {
1509 m_nimbus_mouse.m_mouse_px=0;
1510 m_nimbus_mouse.m_mouse_py=0;
1511 m_nimbus_mouse.m_mouse_x=128;
1512 m_nimbus_mouse.m_mouse_y=128;
1513 m_nimbus_mouse.m_mouse_pc=0;
1514 m_nimbus_mouse.m_mouse_pcx=0;
1515 m_nimbus_mouse.m_mouse_pcy=0;
1516 m_nimbus_mouse.m_intstate_x=0;
1517 m_nimbus_mouse.m_intstate_y=0;
1518 m_nimbus_mouse.m_reg0a4=0xC0;
1519
1520 // Setup timer to poll the mouse
1521 m_nimbus_mouse.m_mouse_timer->adjust(attotime::zero, 0, attotime::from_hz(1000));
1522 }
1523
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)1524 void rmnimbus_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
1525 {
1526 uint8_t x = 0;
1527 uint8_t y = 0;
1528 // int pc=m_maincpu->pc();
1529
1530 uint8_t intstate_x;
1531 uint8_t intstate_y;
1532 int xint;
1533 int yint;
1534
1535 m_nimbus_mouse.m_reg0a4 = m_io_mouse_button->read() | 0xC0;
1536 x = m_io_mousex->read();
1537 y = m_io_mousey->read();
1538
1539 uint8_t mxa;
1540 uint8_t mxb;
1541 uint8_t mya;
1542 uint8_t myb;
1543
1544 //logerror("poll_mouse()\n");
1545
1546 if (x == m_nimbus_mouse.m_mouse_x)
1547 {
1548 m_nimbus_mouse.m_mouse_px = MOUSE_PHASE_STATIC;
1549 }
1550 else if (x > m_nimbus_mouse.m_mouse_x)
1551 {
1552 m_nimbus_mouse.m_mouse_px = MOUSE_PHASE_POSITIVE;
1553 }
1554 else if (x < m_nimbus_mouse.m_mouse_x)
1555 {
1556 m_nimbus_mouse.m_mouse_px = MOUSE_PHASE_NEGATIVE;
1557 }
1558
1559 if (y == m_nimbus_mouse.m_mouse_y)
1560 {
1561 m_nimbus_mouse.m_mouse_py = MOUSE_PHASE_STATIC;
1562 }
1563 else if (y > m_nimbus_mouse.m_mouse_y)
1564 {
1565 m_nimbus_mouse.m_mouse_py = MOUSE_PHASE_POSITIVE;
1566 }
1567 else if (y < m_nimbus_mouse.m_mouse_y)
1568 {
1569 m_nimbus_mouse.m_mouse_py = MOUSE_PHASE_NEGATIVE;
1570 }
1571
1572 switch (m_nimbus_mouse.m_mouse_px)
1573 {
1574 case MOUSE_PHASE_STATIC : break;
1575 case MOUSE_PHASE_POSITIVE : m_nimbus_mouse.m_mouse_pcx++; break;
1576 case MOUSE_PHASE_NEGATIVE : m_nimbus_mouse.m_mouse_pcx--; break;
1577 }
1578 m_nimbus_mouse.m_mouse_pcx &= 0x03;
1579
1580 switch (m_nimbus_mouse.m_mouse_py)
1581 {
1582 case MOUSE_PHASE_STATIC : break;
1583 case MOUSE_PHASE_POSITIVE : m_nimbus_mouse.m_mouse_pcy++; break;
1584 case MOUSE_PHASE_NEGATIVE : m_nimbus_mouse.m_mouse_pcy--; break;
1585 }
1586 m_nimbus_mouse.m_mouse_pcy &= 0x03;
1587
1588 // mxb = MOUSE_XYB[state.m_mouse_px][state->m_mouse_pcx]; // XB
1589 // mxa = MOUSE_XYA[state.m_mouse_px][state->m_mouse_pcx]; // XA
1590 // mya = MOUSE_XYA[state.m_mouse_py][state->m_mouse_pcy]; // YA
1591 // myb = MOUSE_XYB[state.m_mouse_py][state->m_mouse_pcy]; // YB
1592
1593 mxb = MOUSE_XYB[1][m_nimbus_mouse.m_mouse_pcx]; // XB
1594 mxa = MOUSE_XYA[1][m_nimbus_mouse.m_mouse_pcx]; // XA
1595 mya = MOUSE_XYA[1][m_nimbus_mouse.m_mouse_pcy]; // YA
1596 myb = MOUSE_XYB[1][m_nimbus_mouse.m_mouse_pcy]; // YB
1597
1598 if ((m_nimbus_mouse.m_mouse_py!=MOUSE_PHASE_STATIC) || (m_nimbus_mouse.m_mouse_px!=MOUSE_PHASE_STATIC))
1599 {
1600 // logerror("mouse_px=%02X, mouse_py=%02X, mouse_pcx=%02X, mouse_pcy=%02X\n",
1601 // state.m_mouse_px,state->m_mouse_py,state->m_mouse_pcx,state->m_mouse_pcy);
1602
1603 // logerror("mxb=%02x, mxa=%02X (mxb ^ mxa)=%02X, (ay8910_a & 0xC0)=%02X, (mxb ^ mxa) ^ ((ay8910_a & 0x80) >> 7)=%02X\n",
1604 // mxb,mxa, (mxb ^ mxa) , (state.m_ay8910_a & 0xC0), (mxb ^ mxa) ^ ((state->m_ay8910_a & 0x40) >> 6));
1605 }
1606
1607 intstate_x = (mxb ^ mxa) ^ ((m_ay8910_a & 0x40) >> 6);
1608 intstate_y = (myb ^ mya) ^ ((m_ay8910_a & 0x80) >> 7);
1609
1610 if (MOUSE_INT_ENABLED(this))
1611 {
1612 if ((intstate_x==1) && (m_nimbus_mouse.m_intstate_x==0))
1613 // if (intstate_x!=state.m_intstate_x)
1614 {
1615 xint=mxa ? EXTERNAL_INT_MOUSE_XR : EXTERNAL_INT_MOUSE_XL;
1616
1617 external_int(xint, true);
1618
1619 // logerror("Xint:%02X, mxb=%02X\n",xint,mxb);
1620 }
1621
1622 if ((intstate_y==1) && (m_nimbus_mouse.m_intstate_y==0))
1623 // if (intstate_y!=state.m_intstate_y)
1624 {
1625 yint=myb ? EXTERNAL_INT_MOUSE_YU : EXTERNAL_INT_MOUSE_YD;
1626
1627 external_int(yint, true);
1628 // logerror("Yint:%02X, myb=%02X\n",yint,myb);
1629 }
1630 }
1631 else
1632 {
1633 m_nimbus_mouse.m_reg0a4 &= 0xF0;
1634 m_nimbus_mouse.m_reg0a4 |= ( mxb & 0x01) << 3; // XB
1635 m_nimbus_mouse.m_reg0a4 |= (~mxb & 0x01) << 2; // XA
1636 m_nimbus_mouse.m_reg0a4 |= (~myb & 0x01) << 1; // YA
1637 m_nimbus_mouse.m_reg0a4 |= ( myb & 0x01) << 0; // YB
1638 }
1639
1640 m_nimbus_mouse.m_mouse_x = x;
1641 m_nimbus_mouse.m_mouse_y = y;
1642
1643 if ((m_nimbus_mouse.m_mouse_py!=MOUSE_PHASE_STATIC) || (m_nimbus_mouse.m_mouse_px!=MOUSE_PHASE_STATIC))
1644 {
1645 // logerror("pc=%05X, reg0a4=%02X, reg092=%02X, ay_a=%02X, x=%02X, y=%02X, px=%02X, py=%02X, intstate_x=%02X, intstate_y=%02X\n",
1646 // pc,state.m_reg0a4,state->m_iou_reg092,state->m_ay8910_a,state->m_mouse_x,state->m_mouse_y,state->m_mouse_px,state->m_mouse_py,intstate_x,intstate_y);
1647 }
1648
1649 m_nimbus_mouse.m_intstate_x=intstate_x;
1650 m_nimbus_mouse.m_intstate_y=intstate_y;
1651 }
1652
nimbus_mouse_js_r()1653 uint8_t rmnimbus_state::nimbus_mouse_js_r()
1654 {
1655 /*
1656
1657 bit description
1658
1659 0 JOY 0-Up or mouse XB
1660 1 JOY 0-Down or mouse XA
1661 2 JOY 0-Left or mouse YA
1662 3 JOY 0-Right or mouse YB
1663 4 JOY 0-b0 or mouse rbutton
1664 5 JOY 0-b1 or mouse lbutton
1665 6 ?? always reads 1
1666 7 ?? always reads 1
1667
1668 */
1669 uint8_t result;
1670 //int pc=m_maincpu->_pc();
1671
1672 if (m_io_config->read() & 0x01)
1673 {
1674 result=m_nimbus_mouse.m_reg0a4;
1675 //logerror("mouse_js_r: pc=%05X, result=%02X\n",pc,result);
1676 }
1677 else
1678 {
1679 result = m_io_joystick0->read();
1680 }
1681
1682 return result;
1683 }
1684
nimbus_mouse_js_w(uint8_t data)1685 void rmnimbus_state::nimbus_mouse_js_w(uint8_t data)
1686 {
1687 }
1688
1689 /**********************************************************************
1690 Parallel printer / User port.
1691 The Nimbus parallel printer port card is almost identical to the circuit
1692 in the BBC micro, so I have borrowed the driver code from the BBC :)
1693
1694 Port A output is buffered before being connected to the printer connector.
1695 This means that they can only be operated as output lines.
1696 CA1 is pulled high by a 4K7 resistor. CA1 normally acts as an acknowledge
1697 line when a printer is used. CA2 is buffered so that it has become an open
1698 collector output only. It usually acts as the printer strobe line.
1699 ***********************************************************************/
1700
1701 /* USER VIA 6522 port B is connected to the BBC user port */
nimbus_via_write_portb(uint8_t data)1702 void rmnimbus_state::nimbus_via_write_portb(uint8_t data)
1703 {
1704 }
1705