11// license:BSD-3-Clause
22// copyright-holders:Angelo Salese
3- /* **************************************************************************
3+ /* *************************************************************************************************
44
5- Casio FP-1100
5+ Casio FP-1100 (GX-205)
66
7- Info found at various sites:
7+ TODO:
8+ - Understand how to enter Test Mode, if possible at all from available romsets
9+ (cfr. page 94 of service manual)
10+ - Memory maps and machine configuration for FP-1000 with reduced VRAM;
11+ - Unimplemented instruction PER triggered in sub CPU;
12+ - SCREEN 1 mode has heavy corrupted GFXs and runs at half speed, interlace mode?
13+ - Cassette Load is untested and probably not working, uses a complex 6 pin discrete circuitry;
14+ - Sub CPU is supposed to be in WAIT except in horizontal blanking period, WAIT is not emulated.
15+ - Keyboard not working, should trigger INTF0 on key pressed but that doesn't really work even if
16+ hooked up.
17+ - bus slots (uPD765 FDC, ROMPACK, RAMPACK)
818
9- Casio FP-1000 and FP-1100 are "pre-PC" personal computers, with
10- Cassette, Floppy Disk, Printer and two cartridge/expansion slots. They
11- had 32K ROM, 64K main RAM, 80x25 text display, 320x200, 640x200, 640x400
12- graphics display. Floppy disk is 2x 5 1/4.
19+ ===================================================================================================
1320
14- The FP-1000 had 16K videoram and monochrome only. The monitor had a
15- switch to invert the display (swap foreground and background colours).
21+ Info found at various sites:
1622
17- The FP-1100 had 48K videoram and 8 colours.
23+ Casio FP-1000 and FP-1100 are "pre-PC" personal computers, with
24+ Cassette, Floppy Disk, Printer and two cartridge/expansion slots. They
25+ had 32K ROM, 64K main RAM, 80x25 text display, 320x200, 640x200, 640x400
26+ graphics display. Floppy disk is 2x 5 1/4.
1827
19- Processors: Z80 @ 4MHz, uPD7801G @ 2MHz
28+ The FP-1000 had 16K videoram and monochrome only. The monitor had a
29+ switch to invert the display (swap foreground and background colours).
2030
21- Came with BASIC built in, and you could run CP/M 2.2 from the floppy
22- disk.
31+ The FP-1100 had 48K videoram and 8 colours.
2332
24- The keyboard is a separate unit. It contains a beeper.
33+ Processors: Z80 @ 4MHz, uPD7801G @ 2MHz
2534
26- TODO:
27- - Memory maps and machine configuration for FP-1000 with reduced VRAM.
28- - Unimplemented instruction PER triggered (can be ignored)
29- - Display can be interlaced or non-interlaced. Interlaced not emulated.
30- - Cassette Load is quite complex, using 6 pins of the sub-CPU. Not
31- done.
32- - Sub CPU is supposed to be in WAIT except in horizontal blanking
33- period. WAIT is not emulated in our cpu.
34- - Keyboard not working.
35- - FDC not done.
35+ Came with BASIC built in, and you could run CP/M 2.2 from the floppy
36+ disk.
3637
38+ The keyboard is a separate unit. It contains a beeper.
3739
38- ****************************************************************************/
40+ ************************************************************************************************* * /
3941
4042#include " emu.h"
4143
@@ -114,13 +116,10 @@ class fp1100_state : public driver_device
114116 u8 portc_r ();
115117 void portc_w (u8 data);
116118 void centronics_busy_w (int state);
117- INTERRUPT_GEN_MEMBER (vblank_irq);
119+
118120 MC6845_UPDATE_ROW (crtc_update_row);
119121 TIMER_DEVICE_CALLBACK_MEMBER (kansas_w);
120122
121- void handle_int_to_main ();
122-
123- u8 m_irq_mask = 0 ;
124123 u8 m_slot_num = 0 ;
125124 u8 m_kbd_row = 0 ;
126125 u8 m_col_border = 0 ;
@@ -129,7 +128,6 @@ class fp1100_state : public driver_device
129128 u8 m_centronics_busy = 0 ;
130129 u8 m_cass_data[4 ]{};
131130 bool m_bank_sel = false ;
132- bool m_main_irq_status = false ;
133131 bool m_sub_irq_status = false ;
134132 bool m_cassbit = false ;
135133 bool m_cassold = false ;
@@ -143,6 +141,14 @@ class fp1100_state : public driver_device
143141 u8 portb = 0 ;
144142 u8 portc = 0 ;
145143 }m_upd7801;
144+
145+ u8 m_pending_interrupts = 0 ;
146+ u8 m_active_interrupts = 0 ;
147+ u8 m_interrupt_mask = 0 ;
148+
149+ template <int Line> void int_w (int state);
150+ TIMER_CALLBACK_MEMBER (update_interrupts);
151+ IRQ_CALLBACK_MEMBER (restart_cb);
146152};
147153
148154MC6845_UPDATE_ROW ( fp1100_state::crtc_update_row )
@@ -197,12 +203,20 @@ void fp1100_state::main_bank_w(u8 data)
197203 m_slot_num = (m_slot_num & 3 ) | ((data & 1 ) << 2 ); // ??
198204}
199205
200- // tell sub that latch has a byte
206+ /*
207+ * x--- ---- mask for main to sub (INTF2)
208+ * ---x ---- INTS (sub to main)
209+ * ---- x--- INTD
210+ * ---- -x-- INTC
211+ * ---- --x- INTB (FDC bus slot irq)
212+ * ---- ---x INTA (FDC bus slot drq)
213+ */
201214void fp1100_state::irq_mask_w (u8 data)
202215{
203- m_irq_mask = data;
204- handle_int_to_main ( );
216+ m_interrupt_mask = data;
217+ machine (). scheduler (). synchronize ( timer_expired_delegate ( FUNC (fp1100_state::update_interrupts), this ) );
205218
219+ // TODO: this handling doesn't seem enough
206220 if (BIT (data, 7 ) && !m_sub_irq_status)
207221 {
208222 m_subcpu->set_input_line (UPD7810_INTF2 , ASSERT_LINE );
@@ -377,44 +391,53 @@ d6 - Centronics strobe
377391void fp1100_state::portc_w (u8 data)
378392{
379393 u8 const bits = data ^ m_upd7801.portc ;
394+ const int main_int_state = BIT (data, 3 );
395+ if (BIT (m_upd7801.portc , 3 ) != main_int_state)
396+ int_w<4 >(main_int_state);
380397 m_upd7801.portc = data;
381398
382- if (BIT (bits, 3 ))
383- {
384- LOG (" %s: PortC:%X\n " ,machine ().describe_context (),data);
385- handle_int_to_main ();
386- }
387399 if (BIT (bits, 5 ))
388400 m_cass->change_state (BIT (data, 5 ) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED , CASSETTE_MASK_MOTOR );
389401 if (BIT (bits, 6 ))
390402 m_centronics->write_strobe (BIT (data, 6 ));
391403}
392404
393- // HOLD_LINE used because the interrupt is set and cleared by successive instructions, too fast for the maincpu to notice
394- void fp1100_state::handle_int_to_main ()
405+ // IRQ section (main)
406+ // TODO: merge with skeleton/cdc721.cpp (reuses SN74LS148N)
407+
408+ template <int Line> void fp1100_state::int_w (int state)
395409{
396- // IRQ is on if bit 4 of mask AND bit 3 portC
397- if (BIT (m_upd7801.portc , 3 ) && BIT (m_irq_mask, 4 ))
398- {
399- if (!m_main_irq_status)
400- {
401- m_maincpu->set_input_line (0 , HOLD_LINE );
402- LOG (" %s: Main IRQ asserted\n " ,machine ().describe_context ());
403- // m_main_irq_status = true;
404- }
405- }
410+ if (BIT (m_pending_interrupts, Line) == state)
411+ return ;
412+
413+ if (state)
414+ m_pending_interrupts |= 0x01 << Line;
406415 else
416+ m_pending_interrupts &= ~(0x01 << Line);
417+
418+ machine ().scheduler ().synchronize (timer_expired_delegate (FUNC (fp1100_state::update_interrupts), this ));
419+ }
420+
421+ TIMER_CALLBACK_MEMBER (fp1100_state::update_interrupts)
422+ {
423+ m_active_interrupts = m_pending_interrupts & m_interrupt_mask;
424+ m_maincpu->set_input_line (INPUT_LINE_IRQ0 , m_active_interrupts != 0 ? ASSERT_LINE : CLEAR_LINE );
425+ }
426+
427+ IRQ_CALLBACK_MEMBER (fp1100_state::restart_cb)
428+ {
429+ u8 vector = 0xf0 ;
430+ // INTS > INTA > INTB > INTC > INTD priority order
431+ // INTS uses 0xf0, INTA 0xf2 and so on.
432+ u8 active = bitswap<5 >(m_active_interrupts, 3 , 2 , 1 , 0 , 4 );
433+ while (vector < 0xfa && !BIT (active, 0 ))
407434 {
408- if (m_main_irq_status)
409- {
410- // m_maincpu->set_input_line(0, CLEAR_LINE);
411- // LOG("%s: Main IRQ cleared\n",machine().describe_context());
412- m_main_irq_status = false ;
413- }
435+ active >>= 1 ;
436+ vector += 0x02 ;
414437 }
438+ return vector;
415439}
416440
417-
418441static INPUT_PORTS_START ( fp1100 )
419442 PORT_START(" KEY.0" )
420443 PORT_BIT(0xff , IP_ACTIVE_LOW , IPT_UNUSED )
@@ -648,15 +671,8 @@ TIMER_DEVICE_CALLBACK_MEMBER( fp1100_state::kansas_w )
648671 m_cass->output (BIT (m_cass_data[3 ], 1 ) ? -1.0 : +1.0 ); // 1200Hz
649672}
650673
651- INTERRUPT_GEN_MEMBER ( fp1100_state::vblank_irq )
652- {
653- // if (BIT(m_irq_mask, 4))
654- // m_maincpu->set_input_line_and_vector(0, HOLD_LINE, 0xf8); // Z80
655- }
656-
657674void fp1100_state::machine_reset ()
658675{
659- m_main_irq_status = false ;
660676 m_sub_irq_status = false ;
661677 int i;
662678 u8 slot_type;
@@ -671,7 +687,7 @@ void fp1100_state::machine_reset()
671687
672688 m_bank_sel = false ; // point at rom
673689
674- m_irq_mask = 0 ;
690+ m_interrupt_mask = 0 ;
675691 m_slot_num = 0 ;
676692 m_kbd_row = 0 ;
677693 m_col_border = 0 ;
@@ -680,15 +696,14 @@ void fp1100_state::machine_reset()
680696 m_upd7801.porta = 0 ;
681697 m_upd7801.portb = 0 ;
682698 m_upd7801.portc = 0 ;
683- m_maincpu->set_input_line_vector (0 , 0xF0 );
684699}
685700
686701void fp1100_state::fp1100 (machine_config &config)
687702{
688703 Z80 (config, m_maincpu, MAIN_CLOCK /4 );
689704 m_maincpu->set_addrmap (AS_PROGRAM , &fp1100_state::main_map);
690705 m_maincpu->set_addrmap (AS_IO , &fp1100_state::io_map);
691- m_maincpu->set_vblank_int ( " screen " , FUNC (fp1100_state::vblank_irq ));
706+ m_maincpu->set_irq_acknowledge_callback ( FUNC (fp1100_state::restart_cb ));
692707
693708 UPD7801 (config, m_subcpu, MAIN_CLOCK /4 );
694709 m_subcpu->set_addrmap (AS_PROGRAM , &fp1100_state::sub_map);
@@ -701,6 +716,9 @@ void fp1100_state::fp1100(machine_config &config)
701716
702717 GENERIC_LATCH_8 (config, " main2sub" );
703718 GENERIC_LATCH_8 (config, " sub2main" );
719+ // NOTE: Needs some sync otherwise it outright refuses to boot
720+ config.set_perfect_quantum (" maincpu" );
721+ config.set_perfect_quantum (" sub" );
704722
705723 CENTRONICS (config, m_centronics, centronics_devices, " printer" );
706724 m_centronics->busy_handler ().set (FUNC (fp1100_state::centronics_busy_w));
0 commit comments