33
33
#define DAFB_MODE_CTRL1 0x8
34
34
#define DAFB_MODE_CTRL2 0xc
35
35
#define DAFB_MODE_SENSE 0x1c
36
+ #define DAFB_INTR_MASK 0x104
37
+ #define DAFB_INTR_STAT 0x108
38
+ #define DAFB_INTR_CLEAR 0x10c
36
39
#define DAFB_RESET 0x200
37
40
#define DAFB_LUT 0x213
38
41
42
+ #define DAFB_INTR_VBL 0x4
43
+
44
+ /* Vertical Blank period (60.15Hz) */
45
+ #define DAFB_INTR_VBL_PERIOD_NS 16625800
39
46
40
47
/*
41
48
* Quadra sense codes taken from Apple Technical Note HW26:
@@ -470,6 +477,36 @@ static void macfb_update_display(void *opaque)
470
477
macfb_draw_graphic (s );
471
478
}
472
479
480
+ static void macfb_update_irq (MacfbState * s )
481
+ {
482
+ uint32_t irq_state = s -> irq_state & s -> irq_mask ;
483
+
484
+ if (irq_state ) {
485
+ qemu_irq_raise (s -> irq );
486
+ } else {
487
+ qemu_irq_lower (s -> irq );
488
+ }
489
+ }
490
+
491
+ static int64_t macfb_next_vbl (void )
492
+ {
493
+ return (qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL ) + DAFB_INTR_VBL_PERIOD_NS ) /
494
+ DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS ;
495
+ }
496
+
497
+ static void macfb_vbl_timer (void * opaque )
498
+ {
499
+ MacfbState * s = opaque ;
500
+ int64_t next_vbl ;
501
+
502
+ s -> irq_state |= DAFB_INTR_VBL ;
503
+ macfb_update_irq (s );
504
+
505
+ /* 60 Hz irq */
506
+ next_vbl = macfb_next_vbl ();
507
+ timer_mod (s -> vbl_timer , next_vbl );
508
+ }
509
+
473
510
static void macfb_reset (MacfbState * s )
474
511
{
475
512
int i ;
@@ -498,6 +535,9 @@ static uint64_t macfb_ctrl_read(void *opaque,
498
535
case DAFB_MODE_CTRL2 :
499
536
val = s -> regs [addr >> 2 ];
500
537
break ;
538
+ case DAFB_INTR_STAT :
539
+ val = s -> irq_state ;
540
+ break ;
501
541
case DAFB_MODE_SENSE :
502
542
val = macfb_sense_read (s );
503
543
break ;
@@ -513,6 +553,8 @@ static void macfb_ctrl_write(void *opaque,
513
553
unsigned int size )
514
554
{
515
555
MacfbState * s = opaque ;
556
+ int64_t next_vbl ;
557
+
516
558
switch (addr ) {
517
559
case DAFB_MODE_VADDR1 :
518
560
case DAFB_MODE_VADDR2 :
@@ -528,8 +570,23 @@ static void macfb_ctrl_write(void *opaque,
528
570
case DAFB_MODE_SENSE :
529
571
macfb_sense_write (s , val );
530
572
break ;
573
+ case DAFB_INTR_MASK :
574
+ s -> irq_mask = val ;
575
+ if (val & DAFB_INTR_VBL ) {
576
+ next_vbl = macfb_next_vbl ();
577
+ timer_mod (s -> vbl_timer , next_vbl );
578
+ } else {
579
+ timer_del (s -> vbl_timer );
580
+ }
581
+ break ;
582
+ case DAFB_INTR_CLEAR :
583
+ s -> irq_state &= ~DAFB_INTR_VBL ;
584
+ macfb_update_irq (s );
585
+ break ;
531
586
case DAFB_RESET :
532
587
s -> palette_current = 0 ;
588
+ s -> irq_state &= ~DAFB_INTR_VBL ;
589
+ macfb_update_irq (s );
533
590
break ;
534
591
case DAFB_LUT :
535
592
s -> color_palette [s -> palette_current ] = val ;
@@ -611,6 +668,7 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
611
668
s -> vram_bit_mask = MACFB_VRAM_SIZE - 1 ;
612
669
memory_region_set_coalescing (& s -> mem_vram );
613
670
671
+ s -> vbl_timer = timer_new_ns (QEMU_CLOCK_VIRTUAL , macfb_vbl_timer , s );
614
672
macfb_update_mode (s );
615
673
return true;
616
674
}
@@ -626,6 +684,16 @@ static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
626
684
627
685
sysbus_init_mmio (SYS_BUS_DEVICE (s ), & ms -> mem_ctrl );
628
686
sysbus_init_mmio (SYS_BUS_DEVICE (s ), & ms -> mem_vram );
687
+
688
+ qdev_init_gpio_out (dev , & ms -> irq , 1 );
689
+ }
690
+
691
+ static void macfb_nubus_set_irq (void * opaque , int n , int level )
692
+ {
693
+ MacfbNubusState * s = NUBUS_MACFB (opaque );
694
+ NubusDevice * nd = NUBUS_DEVICE (s );
695
+
696
+ nubus_set_irq (nd , level );
629
697
}
630
698
631
699
static void macfb_nubus_realize (DeviceState * dev , Error * * errp )
@@ -646,6 +714,19 @@ static void macfb_nubus_realize(DeviceState *dev, Error **errp)
646
714
647
715
memory_region_add_subregion (& nd -> slot_mem , DAFB_BASE , & ms -> mem_ctrl );
648
716
memory_region_add_subregion (& nd -> slot_mem , VIDEO_BASE , & ms -> mem_vram );
717
+
718
+ ms -> irq = qemu_allocate_irq (macfb_nubus_set_irq , s , 0 );
719
+ }
720
+
721
+ static void macfb_nubus_unrealize (DeviceState * dev )
722
+ {
723
+ MacfbNubusState * s = NUBUS_MACFB (dev );
724
+ MacfbNubusDeviceClass * ndc = NUBUS_MACFB_GET_CLASS (dev );
725
+ MacfbState * ms = & s -> macfb ;
726
+
727
+ ndc -> parent_unrealize (dev );
728
+
729
+ qemu_free_irq (ms -> irq );
649
730
}
650
731
651
732
static void macfb_sysbus_reset (DeviceState * d )
@@ -696,6 +777,8 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data)
696
777
697
778
device_class_set_parent_realize (dc , macfb_nubus_realize ,
698
779
& ndc -> parent_realize );
780
+ device_class_set_parent_unrealize (dc , macfb_nubus_unrealize ,
781
+ & ndc -> parent_unrealize );
699
782
dc -> desc = "Nubus Macintosh framebuffer" ;
700
783
dc -> reset = macfb_nubus_reset ;
701
784
dc -> vmsd = & vmstate_macfb ;
0 commit comments