1
1
// license:BSD-3-Clause
2
2
// copyright-holders:Angelo Salese
3
- /* **************************************************************************
3
+ /* *************************************************************************************************
4
4
5
- Casio FP-1100
5
+ Casio FP-1100 (GX-205)
6
6
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)
8
18
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
+ ===================================================================================================
13
20
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:
16
22
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.
18
27
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).
20
30
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.
23
32
24
- The keyboard is a separate unit. It contains a beeper.
33
+ Processors: Z80 @ 4MHz, uPD7801G @ 2MHz
25
34
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.
36
37
38
+ The keyboard is a separate unit. It contains a beeper.
37
39
38
- ****************************************************************************/
40
+ ************************************************************************************************* * /
39
41
40
42
#include " emu.h"
41
43
@@ -114,13 +116,10 @@ class fp1100_state : public driver_device
114
116
u8 portc_r ();
115
117
void portc_w (u8 data);
116
118
void centronics_busy_w (int state);
117
- INTERRUPT_GEN_MEMBER (vblank_irq);
119
+
118
120
MC6845_UPDATE_ROW (crtc_update_row);
119
121
TIMER_DEVICE_CALLBACK_MEMBER (kansas_w);
120
122
121
- void handle_int_to_main ();
122
-
123
- u8 m_irq_mask = 0 ;
124
123
u8 m_slot_num = 0 ;
125
124
u8 m_kbd_row = 0 ;
126
125
u8 m_col_border = 0 ;
@@ -129,7 +128,6 @@ class fp1100_state : public driver_device
129
128
u8 m_centronics_busy = 0 ;
130
129
u8 m_cass_data[4 ]{};
131
130
bool m_bank_sel = false ;
132
- bool m_main_irq_status = false ;
133
131
bool m_sub_irq_status = false ;
134
132
bool m_cassbit = false ;
135
133
bool m_cassold = false ;
@@ -143,6 +141,14 @@ class fp1100_state : public driver_device
143
141
u8 portb = 0 ;
144
142
u8 portc = 0 ;
145
143
}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);
146
152
};
147
153
148
154
MC6845_UPDATE_ROW ( fp1100_state::crtc_update_row )
@@ -197,12 +203,20 @@ void fp1100_state::main_bank_w(u8 data)
197
203
m_slot_num = (m_slot_num & 3 ) | ((data & 1 ) << 2 ); // ??
198
204
}
199
205
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
+ */
201
214
void fp1100_state::irq_mask_w (u8 data)
202
215
{
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 ) );
205
218
219
+ // TODO: this handling doesn't seem enough
206
220
if (BIT (data, 7 ) && !m_sub_irq_status)
207
221
{
208
222
m_subcpu->set_input_line (UPD7810_INTF2, ASSERT_LINE);
@@ -377,44 +391,53 @@ d6 - Centronics strobe
377
391
void fp1100_state::portc_w (u8 data)
378
392
{
379
393
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);
380
397
m_upd7801.portc = data;
381
398
382
- if (BIT (bits, 3 ))
383
- {
384
- LOG (" %s: PortC:%X\n " ,machine ().describe_context (),data);
385
- handle_int_to_main ();
386
- }
387
399
if (BIT (bits, 5 ))
388
400
m_cass->change_state (BIT (data, 5 ) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
389
401
if (BIT (bits, 6 ))
390
402
m_centronics->write_strobe (BIT (data, 6 ));
391
403
}
392
404
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)
395
409
{
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;
406
415
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 ))
407
434
{
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 ;
414
437
}
438
+ return vector;
415
439
}
416
440
417
-
418
441
static INPUT_PORTS_START ( fp1100 )
419
442
PORT_START(" KEY.0" )
420
443
PORT_BIT(0xff , IP_ACTIVE_LOW, IPT_UNUSED)
@@ -648,15 +671,8 @@ TIMER_DEVICE_CALLBACK_MEMBER( fp1100_state::kansas_w )
648
671
m_cass->output (BIT (m_cass_data[3 ], 1 ) ? -1.0 : +1.0 ); // 1200Hz
649
672
}
650
673
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
-
657
674
void fp1100_state::machine_reset ()
658
675
{
659
- m_main_irq_status = false ;
660
676
m_sub_irq_status = false ;
661
677
int i;
662
678
u8 slot_type;
@@ -671,7 +687,7 @@ void fp1100_state::machine_reset()
671
687
672
688
m_bank_sel = false ; // point at rom
673
689
674
- m_irq_mask = 0 ;
690
+ m_interrupt_mask = 0 ;
675
691
m_slot_num = 0 ;
676
692
m_kbd_row = 0 ;
677
693
m_col_border = 0 ;
@@ -680,15 +696,14 @@ void fp1100_state::machine_reset()
680
696
m_upd7801.porta = 0 ;
681
697
m_upd7801.portb = 0 ;
682
698
m_upd7801.portc = 0 ;
683
- m_maincpu->set_input_line_vector (0 , 0xF0 );
684
699
}
685
700
686
701
void fp1100_state::fp1100 (machine_config &config)
687
702
{
688
703
Z80 (config, m_maincpu, MAIN_CLOCK/4 );
689
704
m_maincpu->set_addrmap (AS_PROGRAM, &fp1100_state::main_map);
690
705
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 ));
692
707
693
708
UPD7801 (config, m_subcpu, MAIN_CLOCK/4 );
694
709
m_subcpu->set_addrmap (AS_PROGRAM, &fp1100_state::sub_map);
@@ -701,6 +716,9 @@ void fp1100_state::fp1100(machine_config &config)
701
716
702
717
GENERIC_LATCH_8 (config, " main2sub" );
703
718
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" );
704
722
705
723
CENTRONICS (config, m_centronics, centronics_devices, " printer" );
706
724
m_centronics->busy_handler ().set (FUNC (fp1100_state::centronics_busy_w));
0 commit comments