1 // license:BSD-3-Clause
2 // copyright-holders:Angelo Salese
3 /**************************************************************************************************
4
5 Toshiba Pasopia 7 (c) 1983 Toshiba
6
7 Preliminary driver by Angelo Salese.
8 2019-10-14 added cassette & beeper [Robbbert]
9
10 Machine unusable due to issues with sound.
11 Cassette works.
12 Beeper is only used for the keyclick, and it works.
13
14 TODO:
15 - floppy support (but floppy images are unobtainable at current time).
16 - SOUND command uses the SN76489 chip, however no sound is produced, and the next SOUND command
17 freezes the machine.
18 - LCD version has gfx bugs, it must use a different ROM charset for instance (apparently a 8 x 4
19 one, 40/80 x 8 tilemap).
20 - Allow BIN files to be loaded (via a rampac presumably).
21 - Allow CAS files to be loaded.
22
23 Reading fdc has been commented out, until the code can be modified to
24 work with new upd765 (was causing a hang at boot).
25
26 Schematics: https://archive.org/details/Io19839/page/n331 (fdc system not included)
27
28 ***************************************************************************************************/
29
30 #include "emu.h"
31 #include "includes/pasopia.h"
32
33 #include "bus/pasopia/pac2.h"
34 #include "cpu/z80/z80.h"
35 #include "imagedev/floppy.h"
36 #include "machine/i8255.h"
37 #include "machine/upd765.h"
38 #include "machine/z80ctc.h"
39 #include "machine/z80pio.h"
40 #include "sound/sn76496.h"
41 #include "video/mc6845.h"
42 #include "imagedev/cassette.h"
43 #include "sound/spkrdev.h"
44 #include "emupal.h"
45 #include "screen.h"
46 #include "speaker.h"
47
48
49 class pasopia7_state : public driver_device
50 {
51 public:
pasopia7_state(const machine_config & mconfig,device_type type,const char * tag)52 pasopia7_state(const machine_config &mconfig, device_type type, const char *tag)
53 : driver_device(mconfig, type, tag)
54 , m_maincpu(*this, "maincpu")
55 , m_screen(*this, "screen")
56 , m_ppi0(*this, "ppi0")
57 , m_ppi1(*this, "ppi1")
58 , m_ppi2(*this, "ppi2")
59 , m_ctc(*this, "ctc")
60 , m_pio(*this, "pio")
61 , m_crtc(*this, "crtc")
62 , m_fdc(*this, "fdc")
63 , m_floppy(*this, "fdc:0:525hd")
64 , m_sn1(*this, "sn1")
65 , m_sn2(*this, "sn2")
66 , m_palette(*this, "palette")
67 , m_keyboard(*this, "KEY.%d", 0)
68 , m_cass(*this, "cassette")
69 , m_pac2(*this, "pac2")
70 , m_speaker(*this, "speaker")
71 , m_font_rom(*this, "font")
72 { }
73
74 void p7_base(machine_config &config);
75 void p7_lcd(machine_config &config);
76 void p7_raster(machine_config &config);
77
78 void init_p7_lcd();
79 void init_p7_raster();
80
81 protected:
82 virtual void machine_start() override;
83
84 private:
85 uint8_t vram_r(offs_t offset);
86 void vram_w(offs_t offset, uint8_t data);
87 void memory_ctrl_w(uint8_t data);
88 void ram_bank_w(offs_t offset, uint8_t data);
89 void pasopia7_6845_w(offs_t offset, uint8_t data);
90 uint8_t io_r(offs_t offset);
91 void io_w(offs_t offset, uint8_t data);
92 uint8_t fdc_r(offs_t offset);
93 void fdc_w(offs_t offset, uint8_t data);
94 uint8_t keyb_r();
95 void mux_w(uint8_t data);
96 uint8_t crtc_portb_r();
97 void screen_mode_w(uint8_t data);
98 void plane_reg_w(uint8_t data);
99 void video_attr_w(uint8_t data);
100 void video_misc_w(uint8_t data);
101 void nmi_mask_w(uint8_t data);
102 uint8_t unk_r();
103 uint8_t nmi_reg_r();
104 void nmi_reg_w(uint8_t data);
105 uint8_t nmi_porta_r();
106 uint8_t nmi_portb_r();
107 DECLARE_WRITE_LINE_MEMBER(speaker_w);
108 TIMER_CALLBACK_MEMBER(pio_timer);
109 DECLARE_VIDEO_START(pasopia7);
110 void p7_lcd_palette(palette_device &palette) const;
111 MC6845_UPDATE_ROW(update_row);
112
113 void pasopia7_io(address_map &map);
114 void pasopia7_mem(address_map &map);
115
116 std::unique_ptr<uint8_t[]> m_work_ram;
117 std::unique_ptr<uint8_t[]> m_vram;
118 uint8_t m_vram_sel;
119 uint8_t m_mio_sel;
120 std::unique_ptr<uint8_t[]> m_p7_pal;
121 uint8_t m_bank_reg;
122 uint8_t m_cursor_blink;
123 uint8_t m_plane_reg;
124 uint8_t m_attr_data;
125 uint8_t m_attr_wrap;
126 uint8_t m_attr_latch;
127 uint8_t m_pal_sel;
128 uint8_t m_x_width;
129 uint8_t m_gfx_mode;
130 uint8_t m_nmi_mask;
131 uint8_t m_nmi_enable_reg;
132 uint8_t m_nmi_trap;
133 uint8_t m_nmi_reset;
134 uint8_t m_screen_type;
135 void pasopia_nmi_trap();
136 uint8_t m_mux_data;
137 u8 m_porta_2;
138 bool m_spr_sw;
139 emu_timer *m_pio_timer;
140 virtual void machine_reset() override;
141 void fdc_irq(bool state);
142 void draw_cg4_line(bitmap_rgb32 &bitmap,int y,int yi,int width,int count);
143 void draw_tv_line(bitmap_rgb32 &bitmap,int y,int yi,int width,int count,int cursor_x);
144 void draw_mixed_line(bitmap_rgb32 &bitmap,int y,int yi,int width,int count,int cursor_x);
145
146 required_device<z80_device> m_maincpu;
147 required_device<screen_device> m_screen;
148 required_device<i8255_device> m_ppi0;
149 required_device<i8255_device> m_ppi1;
150 required_device<i8255_device> m_ppi2;
151 required_device<z80ctc_device> m_ctc;
152 required_device<z80pio_device> m_pio;
153 required_device<mc6845_device> m_crtc;
154 required_device<upd765a_device> m_fdc;
155 required_device<floppy_image_device> m_floppy;
156 required_device<sn76489a_device> m_sn1;
157 required_device<sn76489a_device> m_sn2;
158 required_device<palette_device> m_palette;
159 required_ioport_array<12> m_keyboard;
160 required_device<cassette_image_device> m_cass;
161 required_device<pasopia_pac2_slot_device> m_pac2;
162 required_device<speaker_sound_device> m_speaker;
163 required_region_ptr<uint8_t> m_font_rom;
164 };
165
166 #define VDP_CLOCK 14.318181_MHz_XTAL / 16
167 #define LCD_CLOCK VDP_CLOCK/10
168
machine_start()169 void pasopia7_state::machine_start()
170 {
171 m_work_ram = std::make_unique<uint8_t[]>(0x10000);
172 std::fill(&m_work_ram[0], &m_work_ram[0x10000], 0xff);
173
174 m_vram = make_unique_clear<uint8_t[]>(0x10000);
175 }
176
177 // needed to scan the keyboard, as the pio emulation doesn't do it.
TIMER_CALLBACK_MEMBER(pasopia7_state::pio_timer)178 TIMER_CALLBACK_MEMBER( pasopia7_state::pio_timer )
179 {
180 m_pio->port_b_write(keyb_r());
181 }
182
VIDEO_START_MEMBER(pasopia7_state,pasopia7)183 VIDEO_START_MEMBER(pasopia7_state,pasopia7)
184 {
185 m_p7_pal = std::make_unique<uint8_t[]>(0x10);
186 }
187
draw_cg4_line(bitmap_rgb32 & bitmap,int y,int yi,int width,int count)188 void pasopia7_state::draw_cg4_line(bitmap_rgb32 &bitmap,int y,int yi,int width,int count)
189 {
190 for(int x=0;x<8*width;x+=8)
191 {
192 for(int xi=0;xi<8;xi++)
193 {
194 int pen_b = (m_vram[count+yi+0x0000]>>(7-xi)) & 1;
195 int pen_r = (m_vram[count+yi+0x4000]>>(7-xi)) & 1;
196 int pen_g = 0;//(m_vram[count+yi+0x8000]>>(7-xi)) & 1;
197
198 int color = pen_g<<2 | pen_r<<1 | pen_b<<0;
199
200 bitmap.pix(y, x+xi) = m_palette->pen(color);
201 }
202 count+=8;
203 }
204 }
205
draw_tv_line(bitmap_rgb32 & bitmap,int y,int yi,int width,int count,int cursor_x)206 void pasopia7_state::draw_tv_line(bitmap_rgb32 &bitmap,int y,int yi,int width,int count,int cursor_x)
207 {
208 for(int x=0;x<width;x++)
209 {
210 int tile = m_vram[count+0x8000];
211 int attr = m_vram[count+0xc000];
212 int color = attr & 7;
213
214 for(int xi=0;xi<8;xi++)
215 {
216 int pen = ((m_font_rom[tile*8+yi]>>(7-xi)) & 1) ? color : 0;
217
218 bitmap.pix(y, x*8+xi) = m_palette->pen(pen);
219 }
220
221 // draw cursor
222 if(cursor_x == x)
223 {
224 for(int xc=0;xc<8;xc++)
225 {
226 bitmap.pix(y, x*8+xc) = m_palette->pen(7);
227 }
228 }
229 count+=8;
230 }
231 }
232
draw_mixed_line(bitmap_rgb32 & bitmap,int y,int yi,int width,int count,int cursor_x)233 void pasopia7_state::draw_mixed_line(bitmap_rgb32 &bitmap,int y,int yi,int width,int count,int cursor_x)
234 {
235 for(int x=0;x<width;x++)
236 {
237 int tile = m_vram[count+0x8000];
238 int attr = m_vram[count+0xc000+yi];
239
240 if(attr & 0x80)
241 {
242 for(int xi=0;xi<8;xi++)
243 {
244 int pen_b = (m_vram[count+yi+0x0000]>>(7-xi)) & 1;
245 int pen_r = (m_vram[count+yi+0x4000]>>(7-xi)) & 1;
246 int pen_g = (m_vram[count+yi+0x8000]>>(7-xi)) & 1;
247
248 int pen = pen_g<<2 | pen_r<<1 | pen_b<<0;
249
250 bitmap.pix(y, x*8+xi) = m_palette->pen(pen);
251 }
252 }
253 else
254 {
255 int color = attr & 7;
256
257 for(int xi=0;xi<8;xi++)
258 {
259 int pen = ((m_font_rom[tile*8+yi]>>(7-xi)) & 1) ? color : 0;
260
261 bitmap.pix(y, x*8+xi) = m_palette->pen(pen);
262 }
263 }
264
265 // draw cursor
266 if(cursor_x == x)
267 {
268 for(int xc=0;xc<8;xc++)
269 {
270 bitmap.pix(y, x*8+xc) = m_palette->pen(7);
271 }
272 }
273
274 count+=8;
275 }
276 }
277
MC6845_UPDATE_ROW(pasopia7_state::update_row)278 MC6845_UPDATE_ROW(pasopia7_state::update_row)
279 {
280 if(m_gfx_mode)
281 draw_mixed_line(bitmap,y,ra,x_count,ma*8,cursor_x);
282 else
283 {
284 draw_cg4_line(bitmap,y,ra,x_count,ma*8);
285 draw_tv_line(bitmap,y,ra,x_count,ma*8,cursor_x);
286 }
287 }
288
vram_r(offs_t offset)289 uint8_t pasopia7_state::vram_r(offs_t offset)
290 {
291 uint8_t res;
292
293 if (m_vram_sel == 0)
294 {
295 return m_work_ram[offset+0x8000];
296 }
297
298 if (m_pal_sel && (m_plane_reg & 0x70) == 0x00)
299 return m_p7_pal[offset & 0xf];
300
301 res = 0xff;
302
303 if ((m_plane_reg & 0x11) == 0x11)
304 res &= m_vram[offset | 0x0000];
305 if ((m_plane_reg & 0x22) == 0x22)
306 res &= m_vram[offset | 0x4000];
307 if ((m_plane_reg & 0x44) == 0x44)
308 {
309 res &= m_vram[offset | 0x8000];
310 m_attr_latch = m_vram[offset | 0xc000] & 0x87;
311 }
312
313 return res;
314 }
315
vram_w(offs_t offset,uint8_t data)316 void pasopia7_state::vram_w(offs_t offset, uint8_t data)
317 {
318 if (m_vram_sel)
319 {
320 if (m_pal_sel && (m_plane_reg & 0x70) == 0x00)
321 {
322 m_p7_pal[offset & 0xf] = data & 0xf;
323 return;
324 }
325
326 if (m_plane_reg & 0x10)
327 m_vram[(offset & 0x3fff) | 0x0000] = (m_plane_reg & 1) ? data : 0xff;
328 if (m_plane_reg & 0x20)
329 m_vram[(offset & 0x3fff) | 0x4000] = (m_plane_reg & 2) ? data : 0xff;
330 if (m_plane_reg & 0x40)
331 {
332 m_vram[(offset & 0x3fff) | 0x8000] = (m_plane_reg & 4) ? data : 0xff;
333 m_attr_latch = m_attr_wrap ? m_attr_latch : m_attr_data;
334 m_vram[(offset & 0x3fff) | 0xc000] = m_attr_latch;
335 }
336 }
337 else
338 {
339 m_work_ram[offset+0x8000] = data;
340 }
341 }
342
memory_ctrl_w(uint8_t data)343 void pasopia7_state::memory_ctrl_w(uint8_t data)
344 {
345 uint8_t *work_ram = m_work_ram.get();
346 uint8_t *basic = memregion("basic")->base();
347 uint8_t *bios = memregion("bios")->base();
348
349 switch(data & 3)
350 {
351 case 0:
352 case 3: //select Basic ROM
353 membank("bank1")->set_base(basic + 0x00000);
354 membank("bank2")->set_base(basic + 0x04000);
355 break;
356 case 1: //select Basic ROM + BIOS ROM
357 membank("bank1")->set_base(basic + 0x00000);
358 membank("bank2")->set_base(bios + 0x00000);
359 break;
360 case 2: //select Work RAM
361 membank("bank1")->set_base(work_ram + 0x00000);
362 membank("bank2")->set_base(work_ram + 0x04000);
363 break;
364 }
365
366 m_bank_reg = data & 3;
367 m_vram_sel = data & 4;
368 m_mio_sel = data & 8;
369
370 // bank4 is always RAM
371
372 // printf("%02x\n",m_vram_sel);
373 }
374
375 /* writes always occurs to the RAM banks, even if the ROMs are selected. */
ram_bank_w(offs_t offset,uint8_t data)376 void pasopia7_state::ram_bank_w(offs_t offset, uint8_t data)
377 {
378 m_work_ram[offset] = data;
379 }
380
pasopia7_6845_w(offs_t offset,uint8_t data)381 void pasopia7_state::pasopia7_6845_w(offs_t offset, uint8_t data)
382 {
383 if(offset == 0)
384 {
385 m_crtc->address_w(data);
386 }
387 else
388 {
389 m_crtc->register_w(data);
390
391 /* double pump the pixel clock if we are in 640 x 200 mode */
392 if(m_screen_type == 1) // raster
393 m_crtc->set_unscaled_clock( (m_x_width) ? VDP_CLOCK*2 : VDP_CLOCK);
394 else // lcd
395 m_crtc->set_unscaled_clock( (m_x_width) ? LCD_CLOCK*2 : LCD_CLOCK);
396 }
397 }
398
pasopia_nmi_trap()399 void pasopia7_state::pasopia_nmi_trap()
400 {
401 if(m_nmi_enable_reg)
402 {
403 m_nmi_trap |= 2;
404
405 if(m_nmi_mask == 0)
406 m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
407 }
408 }
409
fdc_r(offs_t offset)410 uint8_t pasopia7_state::fdc_r(offs_t offset)
411 {
412 switch(offset)
413 {
414 case 4: return m_fdc->msr_r();
415 case 5: return m_fdc->fifo_r();
416 //case 6: bit 7 interrupt bit
417 }
418
419 return 0xff;
420 }
421
fdc_w(offs_t offset,uint8_t data)422 void pasopia7_state::fdc_w(offs_t offset, uint8_t data)
423 {
424 switch(offset)
425 {
426 case 0: m_fdc->tc_w(false); break;
427 case 2: m_fdc->tc_w(true); break;
428 case 5: m_fdc->fifo_w(data); break;
429 case 6:
430 if(data & 0x80)
431 m_fdc->reset();
432 /* TODO */
433 m_floppy->mon_w(data & 0x40 ? CLEAR_LINE : ASSERT_LINE);
434 break;
435 }
436 }
437
438
io_r(offs_t offset)439 uint8_t pasopia7_state::io_r(offs_t offset)
440 {
441 if(m_mio_sel)
442 {
443 address_space &ram_space = m_maincpu->space(AS_PROGRAM);
444
445 m_mio_sel = 0;
446 // hack: this is used for reading the keyboard data, we can fake it a little ... (modify fda4)
447 return ram_space.read_byte(offset);
448 }
449
450 u8 io_port = offset & 0xff; //trim down to 8-bit bus
451
452 if(io_port >= 0x08 && io_port <= 0x0b)
453 return m_ppi0->read(io_port & 3);
454 else
455 if(io_port >= 0x0c && io_port <= 0x0f)
456 return m_ppi1->read(io_port & 3);
457 else
458 if(io_port == 0x10)
459 return m_crtc->status_r();
460 else
461 if(io_port == 0x11)
462 return m_crtc->register_r();
463 else
464 if(io_port >= 0x18 && io_port <= 0x1b)
465 return m_pac2->read(io_port & 3);
466 else
467 if(io_port >= 0x20 && io_port <= 0x23)
468 {
469 pasopia_nmi_trap();
470 return m_ppi2->read(io_port & 3);
471 }
472 else
473 if(io_port >= 0x28 && io_port <= 0x2b)
474 return m_ctc->read(io_port & 3);
475 else
476 if(io_port >= 0x30 && io_port <= 0x33)
477 return m_pio->read(io_port & 3);
478 // else if(io_port == 0x3a) { SN1 }
479 // else if(io_port == 0x3b) { SN2 }
480 // else if(io_port == 0x3c) { bankswitch }
481 else
482 // if(io_port >= 0xe0 && io_port <= 0xe6)
483 // return fdc_r(offset & 7);
484 // else
485 {
486 logerror("(PC=%06x) Read i/o address %02x\n",m_maincpu->pc(),io_port);
487 }
488
489 return 0xff;
490 }
491
io_w(offs_t offset,uint8_t data)492 void pasopia7_state::io_w(offs_t offset, uint8_t data)
493 {
494 if(m_mio_sel)
495 {
496 address_space &ram_space = m_maincpu->space(AS_PROGRAM);
497 m_mio_sel = 0;
498 ram_space.write_byte(offset, data);
499 return;
500 }
501
502 u8 io_port = offset & 0xff; //trim down to 8-bit bus
503
504 if(io_port >= 0x08 && io_port <= 0x0b)
505 m_ppi0->write(io_port & 3, data);
506 else
507 if(io_port >= 0x0c && io_port <= 0x0f)
508 m_ppi1->write(io_port & 3, data);
509 else
510 if(io_port >= 0x10 && io_port <= 0x11)
511 pasopia7_6845_w(io_port-0x10, data);
512 else
513 if(io_port >= 0x18 && io_port <= 0x1b)
514 m_pac2->write(io_port & 3, data);
515 else
516 if(io_port >= 0x20 && io_port <= 0x23)
517 {
518 m_ppi2->write(io_port & 3, data);
519 pasopia_nmi_trap();
520 }
521 else
522 if(io_port >= 0x28 && io_port <= 0x2b)
523 m_ctc->write(io_port & 3, data);
524 else
525 if(io_port >= 0x30 && io_port <= 0x33)
526 m_pio->write(io_port & 3, data);
527 else
528 if(io_port == 0x3a)
529 m_sn1->write(data);
530 else
531 if(io_port == 0x3b)
532 m_sn2->write(data);
533 else
534 if(io_port == 0x3c)
535 memory_ctrl_w(data);
536 else
537 if(io_port >= 0xe0 && io_port <= 0xe6)
538 fdc_w(offset & 7, data);
539 else
540 {
541 logerror("(PC=%06x) Write i/o address %02x = %02x\n",m_maincpu->pc(),offset,data);
542 }
543 }
544
pasopia7_mem(address_map & map)545 void pasopia7_state::pasopia7_mem(address_map &map)
546 {
547 map.unmap_value_high();
548 map(0x0000, 0x7fff).w(FUNC(pasopia7_state::ram_bank_w));
549 map(0x0000, 0x3fff).bankr("bank1");
550 map(0x4000, 0x7fff).bankr("bank2");
551 map(0x8000, 0xbfff).rw(FUNC(pasopia7_state::vram_r), FUNC(pasopia7_state::vram_w));
552 map(0xc000, 0xffff).bankrw("bank4");
553 }
554
pasopia7_io(address_map & map)555 void pasopia7_state::pasopia7_io(address_map &map)
556 {
557 map.unmap_value_high();
558 map(0x0000, 0xffff).rw(FUNC(pasopia7_state::io_r), FUNC(pasopia7_state::io_w));
559 }
560
561 static INPUT_PORTS_START( pasopia7 )
562 PASOPIA_KEYBOARD
563 PORT_MODIFY("KEY.2")
564 PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD)
565 PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD)
566 PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS_PAD)
567 PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("+") PORT_CODE(KEYCODE_PLUS_PAD)
568 PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("*") PORT_CODE(KEYCODE_ASTERISK)
569 PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH_PAD)
570 PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_DEL_PAD)
571 PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
572 PORT_MODIFY("KEY.3")
573 PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("RIGHT")
574 PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Label") PORT_CODE(KEYCODE_END)
575 PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("INS/DEL") PORT_CHAR(8)
576 PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("TAB/ESC") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
577 PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED)
578 PORT_MODIFY("KEY.4")
579 PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_NAME("HOME/CLS")
580 PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Kanji") // guess? key has a Japanese label
581 PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGDN) PORT_NAME("Copy")
582 PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_NAME("Stop")
583 PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("LEFT")
584 PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_NAME("UP/DOWN")
585 PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED)
586 PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_NAME("SPACE") PORT_CHAR(' ')
587 INPUT_PORTS_END
588
589 static const gfx_layout p7_chars_8x8 =
590 {
591 8,8,
592 RGN_FRAC(1,1),
593 1,
594 { 0 },
595 { 0, 1, 2, 3, 4, 5, 6, 7 },
596 { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
597 8*8
598 };
599
600 static GFXDECODE_START( gfx_pasopia7 )
601 GFXDECODE_ENTRY( "font", 0x00000, p7_chars_8x8, 0, 0x10 )
602 GFXDECODE_END
603
keyb_r()604 uint8_t pasopia7_state::keyb_r()
605 {
606 u8 data = 0xff;
607 for (u8 j=0; j<3; j++)
608 if (BIT(m_mux_data, 4+j))
609 for (u8 i=0; i<4; i++)
610 if (BIT(m_mux_data, i))
611 data &= m_keyboard[j*4+i]->read();
612
613 return data;
614 }
615
mux_w(uint8_t data)616 void pasopia7_state::mux_w(uint8_t data)
617 {
618 m_mux_data = data;
619 }
620
621 static const z80_daisy_config p7_daisy[] =
622 {
623 { "ctc" },
624 { "pio" },
625 // { "fdc" }, /* TODO */
626 { nullptr }
627 };
628
crtc_portb_r()629 uint8_t pasopia7_state::crtc_portb_r()
630 {
631 // --x- ---- vsync bit
632 // ---x ---- hardcoded bit, defines if the system screen is raster (1) or LCD (0)
633 // ---- x--- disp bit
634 uint8_t vdisp = (m_screen->vpos() < (m_screen_type ? 200 : 28)) ? 0x08 : 0x00; //TODO: check LCD vpos trigger
635 uint8_t vsync = vdisp ? 0x00 : 0x20;
636
637 return 0x40 | (m_attr_latch & 0x87) | vsync | vdisp | (m_screen_type << 4);
638 }
639
screen_mode_w(uint8_t data)640 void pasopia7_state::screen_mode_w(uint8_t data)
641 {
642 if(data & 0x5f)
643 printf("GFX MODE %02x\n",data);
644
645 m_x_width = data & 0x20;
646 m_gfx_mode = data & 0x80;
647
648 // printf("%02x\n",m_gfx_mode);
649 }
650
plane_reg_w(uint8_t data)651 void pasopia7_state::plane_reg_w(uint8_t data)
652 {
653 //if(data & 0x11)
654 //printf("PLANE %02x\n",data);
655 m_plane_reg = data;
656 }
657
video_attr_w(uint8_t data)658 void pasopia7_state::video_attr_w(uint8_t data)
659 {
660 //printf("VIDEO ATTR %02x | TEXT_PAGE %02x\n",data & 0xf,data & 0x70);
661 m_attr_data = (data & 0x7) | ((data & 0x8)<<4);
662 }
663
664 //#include "debugger.h"
665
video_misc_w(uint8_t data)666 void pasopia7_state::video_misc_w(uint8_t data)
667 {
668 /*
669 --x- ---- blinking
670 ---x ---- attribute wrap
671 ---- x--- pal disable
672 ---- xx-- palette selector (both bits enables this, odd hook-up)
673 */
674 //if(data & 2)
675 //{
676 // printf("VIDEO MISC %02x\n",data);
677 // machine().debug_break();
678 //}
679 m_cursor_blink = data & 0x20;
680 m_attr_wrap = data & 0x10;
681 //m_pal_sel = data & 0x02;
682 }
683
nmi_mask_w(uint8_t data)684 void pasopia7_state::nmi_mask_w(uint8_t data)
685 {
686 /*
687 --x- ---- tape motor
688 ---x ---- data rec out
689 ---- --x- sound off
690 ---- ---x reset NMI & trap
691 */
692 // printf("SYSTEM MISC %02x\n",data);
693
694 if(data & 1)
695 {
696 m_nmi_reset &= ~4;
697 m_nmi_trap &= ~2;
698 //m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); //guess
699 }
700 m_cass->output(BIT(data, 4) ? -1.0 : +1.0);
701 u8 changed = data ^ m_porta_2;
702 m_porta_2 = data;
703 if (BIT(changed, 5))
704 m_cass->change_state(BIT(data, 5) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
705 }
706
707 /* TODO: investigate on these. */
unk_r()708 uint8_t pasopia7_state::unk_r()
709 {
710 return 0xff;//machine().rand();
711 }
712
nmi_reg_r()713 uint8_t pasopia7_state::nmi_reg_r()
714 {
715 //printf("C\n");
716 return 0xfc | m_bank_reg;//machine().rand();
717 }
718
nmi_reg_w(uint8_t data)719 void pasopia7_state::nmi_reg_w(uint8_t data)
720 {
721 /*
722 x--- ---- NMI mask
723 -x-- ---- NMI enable trap on PPI8255 2 r/w
724 */
725 m_nmi_mask = data & 0x80;
726 m_nmi_enable_reg = data & 0x40;
727 }
728
nmi_porta_r()729 uint8_t pasopia7_state::nmi_porta_r()
730 {
731 return 0xff;
732 }
733
nmi_portb_r()734 uint8_t pasopia7_state::nmi_portb_r()
735 {
736 u8 data = (m_cass->input() > +0.04) ? 0x20 : 0;
737 return 0xd9 | data | m_nmi_trap | m_nmi_reset;
738 }
739
WRITE_LINE_MEMBER(pasopia7_state::speaker_w)740 WRITE_LINE_MEMBER( pasopia7_state::speaker_w )
741 {
742 if (state)
743 {
744 m_spr_sw ^= 1;
745 if (BIT(m_mux_data, 7))
746 m_speaker->level_w(m_spr_sw);
747 }
748 }
749
machine_reset()750 void pasopia7_state::machine_reset()
751 {
752 uint8_t *bios = memregion("bios")->base();
753
754 membank("bank1")->set_base(bios);
755 membank("bank2")->set_base(bios);
756 // membank("bank3")->set_base(bios);
757 // membank("bank4")->set_base(bios);
758
759 m_nmi_reset |= 4;
760 m_porta_2 = 0xFF;
761 m_cass->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
762 }
763
764 // TODO: palette values are mostly likely to be wrong in there
p7_lcd_palette(palette_device & palette) const765 void pasopia7_state::p7_lcd_palette(palette_device &palette) const
766 {
767 palette.set_pen_color(0, 0xa0, 0xa8, 0xa0);
768
769 for (int i = 1; i < 8; i++)
770 palette.set_pen_color(i, 0x30, 0x38, 0x10);
771 }
772
fdc_irq(bool state)773 void pasopia7_state::fdc_irq(bool state)
774 {
775 m_maincpu->set_input_line(INPUT_LINE_IRQ0, state ? ASSERT_LINE : CLEAR_LINE);
776 }
777
pasopia7_floppies(device_slot_interface & device)778 static void pasopia7_floppies(device_slot_interface &device)
779 {
780 device.option_add("525hd", FLOPPY_525_HD);
781 }
782
p7_base(machine_config & config)783 void pasopia7_state::p7_base(machine_config &config)
784 {
785 /* basic machine hardware */
786 Z80(config, m_maincpu, 15.9744_MHz_XTAL / 4);
787 m_maincpu->set_addrmap(AS_PROGRAM, &pasopia7_state::pasopia7_mem);
788 m_maincpu->set_addrmap(AS_IO, &pasopia7_state::pasopia7_io);
789 m_maincpu->set_daisy_config(p7_daisy);
790
791 /* Audio */
792 SPEAKER(config, "mono").front_center();
793 SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
794
795 SN76489A(config, m_sn1, 15.9744_MHz_XTAL / 8).add_route(ALL_OUTPUTS, "mono", 0.50);
796
797 SN76489A(config, m_sn2, 15.9744_MHz_XTAL / 8).add_route(ALL_OUTPUTS, "mono", 0.50);
798
799 /* Devices */
800 Z80CTC(config, m_ctc, 15.9744_MHz_XTAL / 4);
801 m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
802 m_ctc->set_clk<0>(15.9744_MHz_XTAL / 4);
803 m_ctc->set_clk<2>(15.9744_MHz_XTAL / 4);
804 m_ctc->zc_callback<0>().set(m_ctc, FUNC(z80ctc_device::trg1));
805 m_ctc->zc_callback<1>().set(FUNC(pasopia7_state::speaker_w));
806 m_ctc->zc_callback<2>().set(m_ctc, FUNC(z80ctc_device::trg3));
807
808 Z80PIO(config, m_pio, 15.9744_MHz_XTAL / 4);
809 m_pio->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
810 m_pio->out_pa_callback().set(FUNC(pasopia7_state::mux_w));
811 m_pio->in_pb_callback().set(FUNC(pasopia7_state::keyb_r));
812
813 I8255(config, m_ppi0);
814 m_ppi0->in_pa_callback().set(FUNC(pasopia7_state::unk_r));
815 m_ppi0->out_pa_callback().set(FUNC(pasopia7_state::screen_mode_w));
816 m_ppi0->in_pb_callback().set(FUNC(pasopia7_state::crtc_portb_r));
817
818 I8255(config, m_ppi1);
819 m_ppi1->out_pa_callback().set(FUNC(pasopia7_state::plane_reg_w));
820 m_ppi1->out_pb_callback().set(FUNC(pasopia7_state::video_attr_w));
821 m_ppi1->out_pc_callback().set(FUNC(pasopia7_state::video_misc_w));
822
823 I8255(config, m_ppi2);
824 m_ppi2->in_pa_callback().set(FUNC(pasopia7_state::nmi_porta_r));
825 m_ppi2->out_pa_callback().set(FUNC(pasopia7_state::nmi_mask_w));
826 m_ppi2->in_pb_callback().set(FUNC(pasopia7_state::nmi_portb_r));
827 m_ppi2->in_pc_callback().set(FUNC(pasopia7_state::nmi_reg_r));
828 m_ppi2->out_pc_callback().set(FUNC(pasopia7_state::nmi_reg_w));
829
830 UPD765A(config, m_fdc, 8'000'000, true, true);
831 FLOPPY_CONNECTOR(config, "fdc:0", pasopia7_floppies, "525hd", floppy_image_device::default_floppy_formats);
832 FLOPPY_CONNECTOR(config, "fdc:1", pasopia7_floppies, "525hd", floppy_image_device::default_floppy_formats);
833
834 CASSETTE(config, m_cass);
835 m_cass->set_default_state(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_ENABLED);
836 m_cass->add_route(ALL_OUTPUTS, "mono", 0.05);
837
838 PASOPIA_PAC2(config, m_pac2, pac2_default_devices, nullptr);
839 }
840
p7_raster(machine_config & config)841 void pasopia7_state::p7_raster(machine_config &config)
842 {
843 p7_base(config);
844 SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
845 m_screen->set_refresh_hz(60);
846 m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
847 m_screen->set_size(640, 480);
848 m_screen->set_visarea(0, 640-1, 0, 32-1);
849 m_screen->set_screen_update(m_crtc, FUNC(mc6845_device::screen_update));
850
851 MCFG_VIDEO_START_OVERRIDE(pasopia7_state,pasopia7)
852
853 PALETTE(config, m_palette, palette_device::BRG_3BIT);
854 GFXDECODE(config, "gfxdecode", m_palette, gfx_pasopia7);
855
856 HD6845S(config, m_crtc, VDP_CLOCK); // HD46505S
857 m_crtc->set_screen(m_screen);
858 m_crtc->set_show_border_area(false);
859 m_crtc->set_char_width(8);
860 m_crtc->set_update_row_callback(FUNC(pasopia7_state::update_row));
861 }
862
863
p7_lcd(machine_config & config)864 void pasopia7_state::p7_lcd(machine_config &config)
865 {
866 p7_base(config);
867 SCREEN(config, m_screen, SCREEN_TYPE_LCD);
868 m_screen->set_refresh_hz(60);
869 m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
870 m_screen->set_size(640, 480);
871 m_screen->set_visarea(0, 640-1, 0, 200-1);
872 m_screen->set_screen_update(m_crtc, FUNC(mc6845_device::screen_update));
873
874 MCFG_VIDEO_START_OVERRIDE(pasopia7_state,pasopia7)
875
876 PALETTE(config, m_palette, FUNC(pasopia7_state::p7_lcd_palette), 8);
877 GFXDECODE(config, "gfxdecode", m_palette, gfx_pasopia7);
878
879 HD6845S(config, m_crtc, LCD_CLOCK); /* unknown variant, unknown clock, hand tuned to get ~60 fps */
880 m_crtc->set_screen(m_screen);
881 m_crtc->set_show_border_area(false);
882 m_crtc->set_char_width(8);
883 m_crtc->set_update_row_callback(FUNC(pasopia7_state::update_row));
884 }
885
886 /* ROM definition */
887 ROM_START( pasopia7 )
888 ROM_REGION( 0x4000, "bios", ROMREGION_ERASEFF )
CRC(b8111407)889 ROM_LOAD( "bios.rom", 0x0000, 0x4000, CRC(b8111407) SHA1(ac93ae62db4c67de815f45de98c79cfa1313857d))
890
891 ROM_REGION( 0x8000, "basic", ROMREGION_ERASEFF )
892 ROM_LOAD( "basic.rom", 0x0000, 0x8000, CRC(8a58fab6) SHA1(5e1a91dfb293bca5cf145b0a0c63217f04003ed1))
893
894 ROM_REGION( 0x800, "font", ROMREGION_ERASEFF )
895 ROM_LOAD( "font.rom", 0x0000, 0x0800, CRC(a91c45a9) SHA1(a472adf791b9bac3dfa6437662e1a9e94a88b412))
896 ROM_END
897
898 /* using an identical ROMset from now, but the screen type is different */
899 ROM_START( pasopia7lcd )
900 ROM_REGION( 0x4000, "bios", ROMREGION_ERASEFF )
901 ROM_LOAD( "bios.rom", 0x0000, 0x4000, CRC(b8111407) SHA1(ac93ae62db4c67de815f45de98c79cfa1313857d))
902
903 ROM_REGION( 0x8000, "basic", ROMREGION_ERASEFF )
904 ROM_LOAD( "basic.rom", 0x0000, 0x8000, CRC(8a58fab6) SHA1(5e1a91dfb293bca5cf145b0a0c63217f04003ed1))
905
906 ROM_REGION( 0x800, "font", ROMREGION_ERASEFF )
907 ROM_LOAD( "font.rom", 0x0000, 0x0800, BAD_DUMP CRC(a91c45a9) SHA1(a472adf791b9bac3dfa6437662e1a9e94a88b412))
908 ROM_END
909
910
911 void pasopia7_state::init_p7_raster()
912 {
913 m_screen_type = 1;
914 m_pio_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pasopia7_state::pio_timer), this));
915 m_pio_timer->adjust(attotime::from_hz(5000), 0, attotime::from_hz(5000));
916 }
917
init_p7_lcd()918 void pasopia7_state::init_p7_lcd()
919 {
920 m_screen_type = 0;
921 m_pio_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pasopia7_state::pio_timer), this));
922 m_pio_timer->adjust(attotime::from_hz(5000), 0, attotime::from_hz(5000));
923 }
924
925
926 /* Driver */
927
928 COMP( 1983, pasopia7, 0, 0, p7_raster, pasopia7, pasopia7_state, init_p7_raster, "Toshiba", "Pasopia 7 (Raster)", MACHINE_NOT_WORKING )
929 COMP( 1983, pasopia7lcd, pasopia7, 0, p7_lcd, pasopia7, pasopia7_state, init_p7_lcd, "Toshiba", "Pasopia 7 (LCD)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
930