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